win.c

00001 /* This code is (C) AllegroGL contributors, and double licensed under
00002  * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
00003  */
00004 #include <string.h>
00005 #include <allegro.h>
00006 #include <allegro/internal/aintern.h>
00007 
00008 
00009 #include "alleggl.h"
00010 #include "glvtable.h"
00011 #include "allglint.h"
00012 
00013 
00014 static BITMAP *allegro_gl_win_init_windowed(int w, int h, int v_w, int v_h,
00015                                             int color_depth);
00016 static BITMAP *allegro_gl_win_init_fullscreen(int w, int h, int v_w, int v_h,
00017                                               int color_depth);
00018 static void allegro_gl_win_exit(struct BITMAP *b);
00019 static GFX_MODE_LIST* allegro_gl_win_fetch_mode_list(void);
00020 
00021 static struct allegro_gl_driver allegro_gl_win;
00022 
00023 #define PREFIX_I                "agl-win INFO: "
00024 #define PREFIX_W                "agl-win WARNING: "
00025 #define PREFIX_E                "agl-win ERROR: "
00026 
00027 
00028 static BITMAP *allegro_gl_screen = NULL;
00029 
00030 
00031 /* Windowed mode driver */
00032 GFX_DRIVER gfx_allegro_gl_windowed = {
00033     GFX_OPENGL_WINDOWED,
00034     EMPTY_STRING,
00035     EMPTY_STRING,
00036     "AllegroGL Windowed (Win32)",
00037     allegro_gl_win_init_windowed,
00038     allegro_gl_win_exit,
00039     NULL,                       /* scrolling not implemented */
00040     NULL,                       /* vsync, may use for flip? */
00041     NULL,                       /* No h/w pallete, not using indexed mode */
00042     NULL, NULL,                 /* Still no scrolling */
00043     NULL,                       /* No triple buffering */
00044     allegro_gl_create_video_bitmap,
00045     allegro_gl_destroy_video_bitmap,
00046     NULL, NULL,                 /* No show/request video bitmaps */
00047     NULL, NULL,                 /* No system bitmaps */
00048     allegro_gl_set_mouse_sprite,
00049     allegro_gl_show_mouse,
00050     allegro_gl_hide_mouse,
00051     allegro_gl_move_mouse,
00052     NULL, NULL, NULL,           /* No video state stuff */
00053 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 18)
00054     NULL,                       /* set_blender_mode */
00055 #endif
00056     NULL,                       /* No fetch_mode_list */
00057     0,0,                        /* physical (not virtual!) screen size */
00058     0,                          /* true if video memory is linear */
00059     0,                          /* bank size, in bytes */
00060     0,                          /* bank granularity, in bytes */
00061     0,                          /* video memory size, in bytes */
00062     0,                          /* physical address of video memory */
00063     TRUE                        /* Windowed mode */
00064 };
00065 
00066 
00067 /* Fullscreen driver */
00068 GFX_DRIVER gfx_allegro_gl_fullscreen = {
00069     GFX_OPENGL_FULLSCREEN,
00070     EMPTY_STRING,
00071     EMPTY_STRING,
00072     "AllegroGL Fullscreen (Win32)",
00073     allegro_gl_win_init_fullscreen,
00074     allegro_gl_win_exit,
00075     NULL,                       /* scrolling not implemented */
00076     NULL,                       /* vsync, may use for flip? */
00077     NULL,                       /* No h/w pallete, not using indexed mode */
00078     NULL, NULL,                 /* Still no scrolling */
00079     NULL,                       /* No triple buffering */
00080     allegro_gl_create_video_bitmap,
00081     allegro_gl_destroy_video_bitmap,
00082     NULL, NULL,                 /* No show/request video bitmaps */
00083     NULL, NULL,                 /* No system bitmaps */
00084     allegro_gl_set_mouse_sprite,
00085     allegro_gl_show_mouse,
00086     allegro_gl_hide_mouse,
00087     allegro_gl_move_mouse,
00088     NULL, NULL, NULL,           /* No video state stuff */
00089 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 18)
00090     NULL,                       /* set_blender_mode */
00091 #endif
00092     allegro_gl_win_fetch_mode_list, /* fetch_mode_list */
00093     0,0,                        /* physical (not virtual!) screen size */
00094     0,                          /* true if video memory is linear */
00095     0,                          /* bank size, in bytes */
00096     0,                          /* bank granularity, in bytes */
00097     0,                          /* video memory size, in bytes */
00098     0,                          /* physical address of video memory */
00099     FALSE                       /* Windowed mode */
00100 };
00101 
00102 
00103 /* XXX <rohannessian> We should move those variable definitions into a struct,
00104  * for when multiple windows end up being supported.
00105  */
00106 
00107 /* Device Context used for the Allegro window. Note that only one window
00108  * is supported, so only onyl HDC is needed. This is shared by the AGL
00109  * extension code.
00110  */
00111 HDC __allegro_gl_hdc = NULL;
00112 
00113 /* Render Context used by AllegroGL, once screen mode was set. Note that only
00114  * a single window is supported.
00115  */
00116 static HGLRC allegro_glrc = NULL;
00117 
00118 /* Full-screen flag, for the current context. */
00119 static int fullscreen = 0;
00120 
00121 /* Current window handle */
00122 static HWND wnd = NULL;
00123 
00124 /* If AGL was initialized */
00125 static int initialized = 0;
00126 
00127 /* XXX <rohannessian> Put those globals as function parameters */
00128 /* Note - these globals should really end up as parameters to functions.
00129  */
00130 static DWORD style_saved, exstyle_saved;
00131 static DEVMODE dm_saved;
00132 static int test_windows_created = 0;
00133 static int new_w = 0, new_h = 0;
00134 
00135 static PIXELFORMATDESCRIPTOR pfd = {
00136     sizeof(PIXELFORMATDESCRIPTOR),  /* size of this pfd */
00137     1,                          /* version number */
00138     PFD_DRAW_TO_WINDOW          /* support window */
00139         | PFD_SUPPORT_OPENGL    /* support OpenGL */
00140         | PFD_DOUBLEBUFFER,     /* double buffered */
00141     PFD_TYPE_RGBA,              /* RGBA type */
00142     24,                         /* 24-bit color depth */
00143     0, 0, 0, 0, 0, 0,           /* color bits ignored */
00144     0,                          /* no alpha buffer */
00145     0,                          /* shift bit ignored */
00146     0,                          /* no accumulation buffer */
00147     0, 0, 0, 0,                 /* accum bits ignored */
00148     0,                          /* z-buffer */
00149     0,                          /* no stencil buffer */
00150     0,                          /* no auxiliary buffer */
00151     PFD_MAIN_PLANE,             /* main layer */
00152     0,                          /* reserved */
00153     0, 0, 0                     /* layer masks ignored */
00154 };
00155 
00156 
00157 
00158 /* Logs a Win32 error/warning message in the log file.
00159  */
00160 static void log_win32_msg(const char *prefix, const char *func,
00161                           const char *error_msg, DWORD err) {
00162 
00163     char *err_msg = NULL;
00164     BOOL free_msg = TRUE;
00165 
00166     /* Get the formatting error string from Windows. Note that only the
00167      * bottom 14 bits matter - the rest are reserved for various library
00168      * IDs and type of error.
00169      */
00170     if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
00171                      | FORMAT_MESSAGE_FROM_SYSTEM
00172                      | FORMAT_MESSAGE_IGNORE_INSERTS,
00173                      NULL, err & 0x3FFF,
00174                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00175                      (LPTSTR) &err_msg, 0, NULL)) {
00176         err_msg = "(Unable to decode error code)  ";
00177         free_msg = FALSE;
00178     }
00179 
00180     /* Remove two trailing characters */
00181     if (err_msg && strlen(err_msg) > 1)
00182         *(err_msg + strlen(err_msg) - 2) = '\0';
00183 
00184     TRACE("%s%s(): %s %s (0x%08lx)\n", prefix, func,
00185           error_msg ? error_msg : "",
00186           err_msg ? err_msg : "(null)",
00187           (unsigned long)err);
00188 
00189     if (free_msg) {
00190         LocalFree(err_msg);
00191     }
00192 
00193     return;
00194 }
00195 
00196 
00197 
00198 /* Logs an error */
00199 static void log_win32_error(const char *func, const char *error_msg,
00200                             DWORD err) {
00201     log_win32_msg(PREFIX_E, func, error_msg, err);
00202 }
00203 
00204 
00205 
00206 /* Logs a warning */
00207 static void log_win32_warning(const char *func, const char *error_msg,
00208                               DWORD err) {
00209     log_win32_msg(PREFIX_W, func, error_msg, err);
00210 }
00211 
00212 
00213 
00214 /* Logs a note */
00215 static void log_win32_note(const char *func, const char *error_msg, DWORD err) {
00216     log_win32_msg(PREFIX_I, func, error_msg, err);
00217 }
00218 
00219 
00220 
00221 /* Define the AllegroGL Test window class */
00222 #define ALLEGROGL_TEST_WINDOW_CLASS "AllegroGLTestWindow"
00223 
00224 
00225 /* Registers the test window
00226  * Returns 0 on success, non-zero on failure.
00227  */
00228 static int register_test_window()
00229 {
00230     WNDCLASS wc;
00231 
00232     memset(&wc, 0, sizeof(wc));
00233     wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
00234     wc.lpfnWndProc = DefWindowProc;
00235     wc.hInstance = GetModuleHandle(NULL);
00236     wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
00237     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
00238     wc.lpszClassName = ALLEGROGL_TEST_WINDOW_CLASS;
00239 
00240     if (!RegisterClass(&wc)) {
00241         DWORD err = GetLastError();
00242 
00243         if (err != ERROR_CLASS_ALREADY_EXISTS) {
00244             log_win32_error("register_test_window",
00245                             "Unable to register the window class!", err);
00246             return -1;
00247         }
00248     }
00249 
00250     return 0;
00251 }
00252 
00253 
00254 
00255 
00256 /* Creates the test window.
00257  * The window class must have already been registered.
00258  * Returns the window handle, or NULL on failure.
00259  */
00260 static HWND create_test_window()
00261 {
00262     HWND wnd = CreateWindow(ALLEGROGL_TEST_WINDOW_CLASS,
00263                             "AllegroGL Test Window",
00264                             WS_POPUP | WS_CLIPCHILDREN,
00265                             0, 0, new_w, new_h,
00266                             NULL, NULL,
00267                             GetModuleHandle(NULL),
00268                             NULL);
00269 
00270     if (!wnd) {
00271         log_win32_error("create_test_window",
00272                         "Unable to create a test window!", GetLastError());
00273         return NULL;
00274     }       
00275 
00276     test_windows_created++;
00277     return wnd;
00278 }
00279 
00280 
00281 
00282 /* Print the pixel format info */
00283 static void print_pixel_format(struct allegro_gl_display_info *dinfo) {
00284 
00285     if (!dinfo) {
00286         return;
00287     }
00288     
00289     TRACE(PREFIX_I "Acceleration: %s\n", ((dinfo->rmethod == 0) ? "No"
00290                              : ((dinfo->rmethod == 1) ? "Yes" : "Unknown")));
00291     TRACE(PREFIX_I "RGBA: %i.%i.%i.%i\n", dinfo->pixel_size.rgba.r,
00292           dinfo->pixel_size.rgba.g, dinfo->pixel_size.rgba.b,
00293           dinfo->pixel_size.rgba.a);
00294     
00295     TRACE(PREFIX_I "Accum: %i.%i.%i.%i\n", dinfo->accum_size.rgba.r,
00296           dinfo->accum_size.rgba.g, dinfo->accum_size.rgba.b,
00297           dinfo->accum_size.rgba.a);
00298     
00299     TRACE(PREFIX_I "DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i\n",
00300           dinfo->doublebuffered, dinfo->depth_size, dinfo->stereo,
00301           dinfo->aux_buffers, dinfo->stencil_size);
00302     
00303     TRACE(PREFIX_I "Shift: %i.%i.%i.%i\n", dinfo->r_shift, dinfo->g_shift,
00304           dinfo->b_shift, dinfo->a_shift);
00305 
00306     TRACE(PREFIX_I "Sample Buffers: %i Samples: %i\n",
00307           dinfo->sample_buffers, dinfo->samples);
00308     
00309     TRACE(PREFIX_I "Decoded bpp: %i\n", dinfo->colour_depth);   
00310 }
00311 
00312 
00313 
00314 /* Decodes the pixel format into an agl_display_info struct and logs the pixel
00315  * format in the trace file.
00316  */
00317 static int decode_pixel_format(PIXELFORMATDESCRIPTOR * pfd, HDC hdc, int format,
00318                                struct allegro_gl_display_info *dinfo,
00319                                int desktop_depth)
00320 {
00321     TRACE(PREFIX_I "Decoding: \n");
00322     /* Not interested if it doesn't support OpenGL and RGBA */
00323     if (!(pfd->dwFlags & PFD_SUPPORT_OPENGL)) {
00324         TRACE(PREFIX_I "OpenGL Unsupported\n");
00325         return -1;
00326     }
00327     if (pfd->iPixelType != PFD_TYPE_RGBA) {
00328         TRACE(PREFIX_I "Not RGBA mode\n");
00329         return -1;
00330     }
00331 
00332     if ((pfd->cColorBits != desktop_depth)
00333      && (pfd->cColorBits != 32 || desktop_depth < 24)) {
00334         TRACE(PREFIX_I "Current color depth != "
00335               "pixel format color depth\n");
00336         //return -1;  /* XXX <rohannessian> Why is this a bad thing? */
00337     }
00338     
00339 
00340     /* hardware acceleration */
00341     if (((pfd->dwFlags & PFD_GENERIC_ACCELERATED)
00342          && (pfd->dwFlags & PFD_GENERIC_FORMAT))
00343         || (!(pfd->dwFlags & PFD_GENERIC_ACCELERATED)
00344             && !(pfd->dwFlags & PFD_GENERIC_FORMAT)))
00345         dinfo->rmethod = 1;
00346     else
00347         dinfo->rmethod = 0;
00348 
00349 
00350     /* Depths of colour buffers */
00351     dinfo->pixel_size.rgba.r = pfd->cRedBits;
00352     dinfo->pixel_size.rgba.g = pfd->cGreenBits;
00353     dinfo->pixel_size.rgba.b = pfd->cBlueBits;
00354     dinfo->pixel_size.rgba.a = pfd->cAlphaBits;
00355 
00356     /* Depths of accumulation buffer */
00357     dinfo->accum_size.rgba.r = pfd->cAccumRedBits;
00358     dinfo->accum_size.rgba.g = pfd->cAccumGreenBits;
00359     dinfo->accum_size.rgba.b = pfd->cAccumBlueBits;
00360     dinfo->accum_size.rgba.a = pfd->cAccumAlphaBits;
00361 
00362     /* Miscellaneous settings */
00363     dinfo->doublebuffered = pfd->dwFlags & PFD_DOUBLEBUFFER;
00364     dinfo->stereo = pfd->dwFlags & PFD_STEREO;
00365     dinfo->aux_buffers = pfd->cAuxBuffers;
00366     dinfo->depth_size = pfd->cDepthBits;
00367     dinfo->stencil_size = pfd->cStencilBits;
00368 
00369     /* These are the component shifts, like Allegro's _rgb_*_shift_*. */
00370     dinfo->r_shift = pfd->cRedShift;
00371     dinfo->g_shift = pfd->cGreenShift;
00372     dinfo->b_shift = pfd->cBlueShift;
00373     dinfo->a_shift = pfd->cAlphaShift;
00374 
00375     /* Multisampling isn't supported under Windows if we don't also use
00376      * WGL_ARB_pixel_format or WGL_EXT_pixel_format.
00377      */
00378     dinfo->sample_buffers = 0;
00379     dinfo->samples = 0;
00380 
00381     /* Float depth/color isn't supported under Windows if we don't also use
00382      * AGL_ARB_pixel_format or WGL_EXT_pixel_format.
00383      */
00384     dinfo->float_color = 0;
00385     dinfo->float_depth = 0;
00386 
00387     /* This bit is the same as the X code, setting some things based on
00388      * what we've read out of the PFD. */
00389     dinfo->colour_depth = 0;
00390     if (dinfo->pixel_size.rgba.r == 5 && dinfo->pixel_size.rgba.b == 5) {
00391         if (dinfo->pixel_size.rgba.g == 5)
00392             dinfo->colour_depth = 15;
00393         if (dinfo->pixel_size.rgba.g == 6)
00394             dinfo->colour_depth = 16;
00395     }
00396     if (dinfo->pixel_size.rgba.r == 8
00397         && dinfo->pixel_size.rgba.g == 8 && dinfo->pixel_size.rgba.b == 8) {
00398         if (dinfo->pixel_size.rgba.a == 8)
00399             dinfo->colour_depth = 32;
00400         else
00401             dinfo->colour_depth = 24;
00402     }
00403 
00404 
00405     dinfo->allegro_format = (dinfo->colour_depth != 0)
00406         && (dinfo->g_shift == dinfo->pixel_size.rgba.b)
00407         && (dinfo->r_shift * dinfo->b_shift == 0)
00408         && (dinfo->r_shift + dinfo->b_shift ==
00409             dinfo->pixel_size.rgba.b + dinfo->pixel_size.rgba.g);
00410 
00411     return 0;
00412 }
00413 
00414 
00415 
00416 /* Decodes the pixel format into an agl_display_info struct and logs the pixel
00417  * format in the trace file.
00418  */
00419 static int decode_pixel_format_attrib(struct allegro_gl_display_info *dinfo,
00420                           int num_attribs, const int *attrib, const int *value,
00421                           int desktop_depth) {
00422     int i;
00423     
00424     TRACE(PREFIX_I "Decoding: \n");
00425 
00426     dinfo->samples = 0;
00427     dinfo->sample_buffers = 0;
00428     dinfo->float_depth = 0;
00429     dinfo->float_color = 0;
00430 
00431     for (i = 0; i < num_attribs; i++) {
00432 
00433         /* Not interested if it doesn't support OpenGL or window drawing or
00434          * RGBA.
00435          */
00436         if (attrib[i] == WGL_SUPPORT_OPENGL_ARB && value[i] == 0) { 
00437             TRACE(PREFIX_I "OpenGL Unsupported\n");
00438             return -1;
00439         }
00440         else if (attrib[i] == WGL_DRAW_TO_WINDOW_ARB && value[i] == 0) {    
00441             TRACE(PREFIX_I "Can't draw to window\n");
00442             return -1;
00443         }
00444         else if (attrib[i] == WGL_PIXEL_TYPE_ARB &&
00445                 (value[i] != WGL_TYPE_RGBA_ARB
00446                  && value[i] != WGL_TYPE_RGBA_FLOAT_ARB)) { 
00447             TRACE(PREFIX_I "Not RGBA mode\n");
00448             return -1;
00449         }
00450         /* Check for color depth matching */
00451         else if (attrib[i] == WGL_COLOR_BITS_ARB) {
00452             if ((value[i] != desktop_depth)
00453              && (value[i] != 32 || desktop_depth < 24)) {
00454                 TRACE(PREFIX_I "Current color depth != "
00455                       "pixel format color depth\n");
00456                 //return -1; /* XXX <rohannessian> Why is this a bad thing? */
00457             }
00458         }
00459         /* hardware acceleration */
00460         else if (attrib[i] == WGL_ACCELERATION_ARB) {
00461             dinfo->rmethod = (value[i] == WGL_NO_ACCELERATION_ARB) ? 0 : 1;
00462         }
00463         /* Depths of colour buffers */
00464         else if (attrib[i] == WGL_RED_BITS_ARB) {
00465             dinfo->pixel_size.rgba.r = value[i];
00466         }
00467         else if (attrib[i] == WGL_GREEN_BITS_ARB) {
00468             dinfo->pixel_size.rgba.g = value[i];
00469         }
00470         else if (attrib[i] == WGL_BLUE_BITS_ARB) {
00471             dinfo->pixel_size.rgba.b = value[i];
00472         }
00473         else if (attrib[i] == WGL_ALPHA_BITS_ARB) {
00474             dinfo->pixel_size.rgba.a = value[i];
00475         }
00476         /* Shift of color components */
00477         else if (attrib[i] == WGL_RED_SHIFT_ARB) {
00478             dinfo->r_shift = value[i];
00479         }
00480         else if (attrib[i] == WGL_GREEN_SHIFT_ARB) {
00481             dinfo->g_shift = value[i];
00482         }
00483         else if (attrib[i] == WGL_BLUE_SHIFT_ARB) {
00484             dinfo->b_shift = value[i];
00485         }
00486         else if (attrib[i] == WGL_ALPHA_SHIFT_ARB) {
00487             dinfo->a_shift = value[i];
00488         }
00489 
00490         /* Depths of accumulation buffer */
00491         else if (attrib[i] == WGL_ACCUM_RED_BITS_ARB) {
00492             dinfo->accum_size.rgba.r = value[i];
00493         }
00494         else if (attrib[i] == WGL_ACCUM_GREEN_BITS_ARB) {
00495             dinfo->accum_size.rgba.g = value[i];
00496         }
00497         else if (attrib[i] == WGL_ACCUM_BLUE_BITS_ARB) {
00498             dinfo->accum_size.rgba.b = value[i];
00499         }
00500         else if (attrib[i] == WGL_ACCUM_ALPHA_BITS_ARB) {
00501             dinfo->accum_size.rgba.a = value[i];
00502         }   
00503         /* Miscellaneous settings */
00504         else if (attrib[i] == WGL_DOUBLE_BUFFER_ARB) {
00505             dinfo->doublebuffered = value[i];
00506         }
00507         else if (attrib[i] == WGL_STEREO_ARB) {
00508             dinfo->stereo = value[i];
00509         }
00510         else if (attrib[i] == WGL_AUX_BUFFERS_ARB) {
00511             dinfo->aux_buffers = value[i];
00512         }
00513         else if (attrib[i] == WGL_DEPTH_BITS_ARB) {
00514             dinfo->depth_size = value[i];
00515         }
00516         else if (attrib[i] == WGL_STENCIL_BITS_ARB) {
00517             dinfo->stencil_size = value[i];
00518         }
00519         /* Multisampling bits */
00520         else if (attrib[i] == WGL_SAMPLE_BUFFERS_ARB) {
00521             dinfo->sample_buffers = value[i];
00522         }
00523         else if (attrib[i] == WGL_SAMPLES_ARB) {
00524             dinfo->samples = value[i];
00525         }
00526         /* Float color */
00527         if (attrib[i] == WGL_PIXEL_TYPE_ARB
00528           && value[i] == WGL_TYPE_RGBA_FLOAT_ARB) {
00529             dinfo->float_color = TRUE;
00530         }
00531         /* Float depth */
00532         else if (attrib[i] == WGL_DEPTH_FLOAT_EXT) {
00533             dinfo->float_depth = value[i];
00534         }
00535     }
00536 
00537     /* This bit is the same as the X code, setting some things based on
00538      * what we've read out of the PFD. */
00539     dinfo->colour_depth = 0;
00540     if (dinfo->pixel_size.rgba.r == 5 && dinfo->pixel_size.rgba.b == 5) {
00541         if (dinfo->pixel_size.rgba.g == 5)
00542             dinfo->colour_depth = 15;
00543         if (dinfo->pixel_size.rgba.g == 6)
00544             dinfo->colour_depth = 16;
00545     }
00546     if (dinfo->pixel_size.rgba.r == 8
00547         && dinfo->pixel_size.rgba.g == 8 && dinfo->pixel_size.rgba.b == 8) {
00548         if (dinfo->pixel_size.rgba.a == 8)
00549             dinfo->colour_depth = 32;
00550         else
00551             dinfo->colour_depth = 24;
00552     }
00553 
00554     dinfo->allegro_format = (dinfo->colour_depth != 0)
00555         && (dinfo->g_shift == dinfo->pixel_size.rgba.b)
00556         && (dinfo->r_shift * dinfo->b_shift == 0)
00557         && (dinfo->r_shift + dinfo->b_shift ==
00558             dinfo->pixel_size.rgba.b + dinfo->pixel_size.rgba.g);
00559 
00560     return 0;
00561 }
00562 
00563 
00564 
00565 typedef struct format_t {
00566     int score;
00567     int format;
00568 } format_t;
00569 
00570 
00571 
00572 /* Helper function for sorting pixel formats by score */
00573 static int select_pixel_format_sorter(const void *p0, const void *p1) {
00574     format_t *f0 = (format_t*)p0;
00575     format_t *f1 = (format_t*)p1;
00576 
00577     if (f0->score == f1->score) {
00578         return 0;
00579     }
00580     else if (f0->score > f1->score) {
00581         return -1;
00582     }
00583     else {
00584         return 1;
00585     }
00586 }
00587 
00588 
00589 
00590 /* Describes the pixel format and assigns it a score */
00591 int describe_pixel_format_old(HDC dc, int fmt, int desktop_depth,
00592                                format_t *formats, int *num_formats,
00593                                struct allegro_gl_display_info *pdinfo) {
00594 
00595     struct allegro_gl_display_info dinfo;
00596     PIXELFORMATDESCRIPTOR pfd;
00597     int score = -1;
00598     
00599     int result = DescribePixelFormat(dc, fmt, sizeof(pfd), &pfd);
00600 
00601     /* Remember old settings */
00602     if (pdinfo) {
00603         dinfo = *pdinfo;
00604     }
00605 
00606     if (!result) {
00607         log_win32_warning("describe_pixel_format_old",
00608                           "DescribePixelFormat() failed!", GetLastError());
00609         return -1;
00610     }
00611     
00612     result = !decode_pixel_format(&pfd, dc, fmt, &dinfo, desktop_depth);
00613     
00614     if (result) {
00615         print_pixel_format(&dinfo);
00616         score = __allegro_gl_score_config(fmt, &dinfo);
00617     }
00618             
00619     if (score < 0) {
00620         return -1; /* Reject non-compliant pixel formats */
00621     }
00622 
00623     if (formats && num_formats) {
00624         formats[*num_formats].score  = score;
00625         formats[*num_formats].format = fmt;
00626         (*num_formats)++;
00627     }
00628 
00629     if (pdinfo) {
00630         *pdinfo = dinfo;
00631     }
00632 
00633     return 0;
00634 }
00635 
00636 
00637 
00638 static AGL_GetPixelFormatAttribivARB_t __wglGetPixelFormatAttribivARB = NULL;
00639 static AGL_GetPixelFormatAttribivEXT_t __wglGetPixelFormatAttribivEXT = NULL;
00640 
00641 
00642 
00643 /* Describes the pixel format and assigns it a score */
00644 int describe_pixel_format_new(HDC dc, int fmt, int desktop_depth,
00645                               format_t *formats, int *num_formats,
00646                               struct allegro_gl_display_info *pdinfo) {
00647 
00648     struct allegro_gl_display_info dinfo;
00649     int score = -1;
00650 
00651     /* Note: Even though we use te ARB suffix, all those enums are compatible
00652      * with EXT_pixel_format.
00653      */
00654     int attrib[] = {
00655         WGL_SUPPORT_OPENGL_ARB,
00656         WGL_DRAW_TO_WINDOW_ARB,
00657         WGL_PIXEL_TYPE_ARB,
00658         WGL_ACCELERATION_ARB,
00659         WGL_DOUBLE_BUFFER_ARB,
00660         WGL_DEPTH_BITS_ARB,
00661         WGL_COLOR_BITS_ARB,
00662         WGL_RED_BITS_ARB,
00663         WGL_GREEN_BITS_ARB,
00664         WGL_BLUE_BITS_ARB,
00665         WGL_ALPHA_BITS_ARB,
00666         WGL_RED_SHIFT_ARB,
00667         WGL_GREEN_SHIFT_ARB,
00668         WGL_BLUE_SHIFT_ARB,
00669         WGL_ALPHA_SHIFT_ARB,
00670         WGL_STENCIL_BITS_ARB,
00671         WGL_STEREO_ARB,
00672         WGL_ACCUM_BITS_ARB,
00673         WGL_ACCUM_RED_BITS_ARB,
00674         WGL_ACCUM_GREEN_BITS_ARB,
00675         WGL_ACCUM_BLUE_BITS_ARB,
00676         WGL_ACCUM_ALPHA_BITS_ARB,
00677         WGL_AUX_BUFFERS_ARB,
00678 
00679         /* The following are used by extensions that add to WGL_pixel_format.
00680          * If WGL_p_f isn't supported though, we can't use the (then invalid)
00681          * enums. We can't use any magic number either, so we settle for 
00682          * replicating one. The pixel format decoder
00683          * (decode_pixel_format_attrib()) doesn't care about duplicates.
00684          */
00685         WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_SAMPLE_BUFFERS_ARB */
00686         WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_SAMPLES_ARB        */
00687         WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_DEPTH_FLOAT_EXT    */
00688     };
00689 
00690     const int num_attribs = sizeof(attrib) / sizeof(attrib[0]);
00691     int *value = (int*)malloc(sizeof(int) * num_attribs);
00692     int result;
00693     BOOL ret;
00694     int old_valid = __allegro_gl_valid_context;
00695 
00696     /* Can't allocate mem? */
00697     if (!value) {
00698         TRACE(PREFIX_E "describe_pixel_format_new(): Unable to allocate "
00699               "memory for pixel format descriptor!\n");
00700         return -1;
00701     }
00702 
00703     /* Remember old settings */
00704     if (pdinfo) {
00705         dinfo = *pdinfo;
00706     }
00707     
00708 
00709     /* If multisampling is supported, query for it. Note - we need to tell
00710      * allegro_gl_is_extension_supported() that we have a valid context,
00711      * even though AGL is not initialized yet.
00712      */
00713     __allegro_gl_valid_context = 1;
00714     if (allegro_gl_is_extension_supported("WGL_ARB_multisample")) {
00715         attrib[num_attribs - 3] = WGL_SAMPLE_BUFFERS_ARB;
00716         attrib[num_attribs - 2] = WGL_SAMPLES_ARB;
00717     }
00718     if (allegro_gl_is_extension_supported("WGL_EXT_depth_float")) {
00719         attrib[num_attribs - 1] = WGL_DEPTH_FLOAT_EXT;
00720     }
00721     __allegro_gl_valid_context = old_valid;
00722 
00723     
00724     /* Get the pf attributes */
00725     if (__wglGetPixelFormatAttribivARB) {
00726         ret = __wglGetPixelFormatAttribivARB(dc, fmt, 0, num_attribs,
00727                                              attrib, value);
00728     }
00729     else if (__wglGetPixelFormatAttribivEXT) {
00730         ret = __wglGetPixelFormatAttribivEXT(dc, fmt, 0, num_attribs,
00731                                              attrib, value);
00732     }
00733     else {
00734         ret = 0;
00735     }   
00736 
00737     /* wglGetPixelFormatAttrib() failed? Abort and revert to old path */
00738     if (!ret) {
00739         log_win32_error("describe_pixel_format_new",
00740                         "wglGetPixelFormatAttrib failed!", GetLastError());
00741         free(value);
00742         return -1;
00743     }
00744 
00745     /* Convert to AllegroGL format for scoring */
00746     result = !decode_pixel_format_attrib(&dinfo, num_attribs, attrib, value,
00747                                          desktop_depth);
00748     free(value);
00749 
00750     if (result) {
00751         print_pixel_format(&dinfo); 
00752         score = __allegro_gl_score_config(fmt, &dinfo);
00753     }
00754 
00755     if (score < 0) {
00756         return 0; /* Reject non-compliant pixel formats */
00757     }
00758 
00759     if (formats && num_formats) {
00760         formats[*num_formats].score  = score;
00761         formats[*num_formats].format = fmt;
00762         (*num_formats)++;
00763     }
00764 
00765     if (pdinfo) {
00766         *pdinfo = dinfo;
00767     }
00768 
00769     return 0;
00770 }
00771 
00772 
00773 
00774 /* Returns the number of pixel formats we should investigate */
00775 int get_num_pixel_formats(HDC dc, int *new_pf_code) {
00776     
00777     /* DescribePixelFormat() returns maximum pixel format index in the old
00778      * code. wglGetPixelFormatAttribivARB() does it in the new code.
00779      */
00780     if (new_pf_code && *new_pf_code) {
00781         int attrib[1];
00782         int value[1];
00783         
00784         TRACE(PREFIX_I "get_num_pixel_formats(): Attempting to use WGL_pf.\n");
00785         attrib[0] = WGL_NUMBER_PIXEL_FORMATS_ARB;
00786         if ((__wglGetPixelFormatAttribivARB
00787           && __wglGetPixelFormatAttribivARB(dc, 0, 0, 1, attrib, value)
00788                                                                  == GL_FALSE)
00789          || (__wglGetPixelFormatAttribivEXT
00790           && __wglGetPixelFormatAttribivEXT(dc, 0, 0, 1, attrib, value)
00791                                                                  == GL_FALSE)) {
00792             log_win32_note("get_num_pixel_formats",
00793                         "WGL_ARB/EXT_pixel_format use failed!", GetLastError());
00794             *new_pf_code = 0;
00795         }
00796         else {
00797             return value[0];
00798         }
00799     }
00800 
00801     if (!new_pf_code || !*new_pf_code) {
00802         PIXELFORMATDESCRIPTOR pfd;
00803         int ret;
00804         
00805         TRACE(PREFIX_I "get_num_pixel_formats(): Using DescribePixelFormat.\n");
00806         ret = DescribePixelFormat(dc, 1, sizeof(pfd), &pfd);
00807 
00808         if (!ret) {
00809             log_win32_error("get_num_pixel_formats",
00810                         "DescribePixelFormat failed!", GetLastError());
00811         }
00812         
00813         return ret;
00814     }
00815 
00816     return 0;
00817 }
00818 
00819 
00820 
00821 /* Pick the best matching pixel format */
00822 static int select_pixel_format(PIXELFORMATDESCRIPTOR * pfd)
00823 {
00824     int i;
00825     int result, maxindex;
00826     int desktop_depth;
00827 
00828     HWND testwnd = NULL;
00829     HDC testdc   = NULL;
00830     HGLRC testrc = NULL;
00831     
00832     format_t *format = NULL;
00833     int num_formats = 0;
00834     int new_pf_code = 0;
00835 
00836     
00837     __allegro_gl_reset_scorer();
00838 
00839     /* Read again the desktop depth */
00840     desktop_depth = desktop_color_depth();
00841  
00842     if (register_test_window() < 0) {
00843         return 0;
00844     }
00845 
00846     testwnd = create_test_window();
00847 
00848     if (!testwnd) {
00849         return 0;
00850     }
00851 
00852     testdc = GetDC(testwnd);
00853 
00854     /* Check if we can support new pixel format code */
00855     TRACE(PREFIX_I "select_pixel_format(): Trying to set up temporary RC\n");
00856     {
00857         HDC old_dc = __allegro_gl_hdc;
00858         int old_valid = __allegro_gl_valid_context;
00859         PIXELFORMATDESCRIPTOR pfd;
00860         int pf;
00861         
00862         new_pf_code = 0;
00863         
00864         /* We need to create a dummy window with a pixel format to get the
00865          * list of valid PFDs
00866          */
00867         memset(&pfd, 0, sizeof(pfd));
00868         pfd.nSize = sizeof(pfd);
00869         pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL
00870                     | PFD_DOUBLEBUFFER_DONTCARE | PFD_STEREO_DONTCARE;
00871         pfd.iPixelType = PFD_TYPE_RGBA;
00872         pfd.iLayerType = PFD_MAIN_PLANE;
00873         pfd.cColorBits = 32;
00874 
00875         TRACE(PREFIX_I "select_pixel_format(): ChoosePixelFormat()\n");
00876         pf = ChoosePixelFormat(testdc, &pfd);
00877 
00878         if (!pf) {
00879             log_win32_warning("select_pixel_format",
00880                         "Unable to chose a temporary pixel format!",
00881                         GetLastError());
00882             goto fail_pf;
00883         }
00884 
00885         /* Set up a GL context there */
00886         TRACE(PREFIX_I "select_pixel_format(): SetPixelFormat()\n");
00887         memset(&pfd, 0, sizeof(pfd));
00888         if (!SetPixelFormat(testdc, pf, &pfd)) {
00889             log_win32_warning("select_pixel_format",
00890                         "Unable to set a temporary pixel format!",
00891                         GetLastError());
00892             goto fail_pf;
00893         }
00894 
00895         TRACE(PREFIX_I "select_pixel_format(): CreateContext()\n");
00896         testrc = wglCreateContext(testdc);
00897 
00898         if (!testrc) {
00899             log_win32_warning("select_pixel_format",
00900                         "Unable to create a render context!",
00901                         GetLastError());
00902             goto fail_pf;
00903         }
00904         
00905         TRACE(PREFIX_I "select_pixel_format(): MakeCurrent()\n");
00906         if (!wglMakeCurrent(testdc, testrc)) {
00907             log_win32_warning("select_pixel_format",
00908                         "Unable to set the render context as current!",
00909                         GetLastError());
00910             goto fail_pf;
00911         }
00912 
00913         __allegro_gl_hdc = testdc;
00914         __allegro_gl_valid_context = TRUE;
00915 
00916 
00917         /* This is a workaround for a bug in old NVidia drivers. We need to
00918          * call wglGetExtensionsStringARB() for it to properly initialize.
00919          */
00920         TRACE(PREFIX_I "select_pixel_format(): GetExtensionsStringARB()\n");
00921         if (strstr(glGetString(GL_VENDOR), "NVIDIA")) {
00922             AGL_GetExtensionsStringARB_t __wglGetExtensionsStringARB = NULL;
00923             
00924             __wglGetExtensionsStringARB = (AGL_GetExtensionsStringARB_t)
00925                            wglGetProcAddress("wglGetExtensionsStringARB");
00926 
00927             TRACE(PREFIX_I "select_pixel_format(): Querying for "
00928                   "WGL_ARB_extension_string\n");
00929             
00930             if (__wglGetExtensionsStringARB) {
00931                 TRACE(PREFIX_I "select_pixel_format(): Calling "
00932                       "__wglGetExtensionsStringARB\n");
00933                 __wglGetExtensionsStringARB(testdc);
00934             }
00935         }
00936 
00937         
00938         /* Check that we support ARB/EXT_pixel_format */
00939         if (!allegro_gl_is_extension_supported("WGL_ARB_pixel_format")
00940          && !allegro_gl_is_extension_supported("WGL_EXT_pixel_format")) {
00941             TRACE(PREFIX_I "select_pixel_format(): WGL_ARB/EXT_pf unsupported.\n");
00942             goto fail_pf;
00943         }
00944         
00945         /* Load the ARB_p_f symbol - Note, we shouldn't use the AGL extension
00946          * mechanism here, because AGL hasn't been initialized yet!
00947          */
00948         TRACE(PREFIX_I "select_pixel_format(): GetProcAddress()\n");        
00949         __wglGetPixelFormatAttribivARB = (AGL_GetPixelFormatAttribivARB_t)
00950                        wglGetProcAddress("wglGetPixelFormatAttribivARB");
00951         __wglGetPixelFormatAttribivEXT = (AGL_GetPixelFormatAttribivEXT_t)
00952                        wglGetProcAddress("wglGetPixelFormatAttribivEXT");
00953 
00954         if (!__wglGetPixelFormatAttribivARB
00955          && !__wglGetPixelFormatAttribivEXT) {
00956             TRACE(PREFIX_E "select_pixel_format(): WGL_ARB/EXT_pf not "
00957                   "correctly supported!\n");
00958             goto fail_pf;
00959         }
00960 
00961         new_pf_code = 1;
00962         goto exit_pf;
00963 
00964 fail_pf:
00965         wglMakeCurrent(NULL, NULL);
00966         if (testrc) {
00967             wglDeleteContext(testrc);
00968         }
00969         testrc = NULL;
00970 
00971         __wglGetPixelFormatAttribivARB = NULL;
00972         __wglGetPixelFormatAttribivEXT = NULL;
00973 exit_pf:
00974         __allegro_gl_hdc = old_dc;
00975         __allegro_gl_valid_context = old_valid;
00976     }
00977 
00978     maxindex = get_num_pixel_formats(testdc, &new_pf_code);
00979 
00980     /* Check if using the new pf code failed. Likely due to driver bug.
00981      * maxindex is still valid though, so we can continue.
00982      */
00983     if (!new_pf_code && testrc) {
00984         TRACE(PREFIX_W "select_pixel_format(): WGL_ARB_pf call failed - "
00985               "reverted to plain old WGL.\n");
00986         wglMakeCurrent(NULL, NULL);
00987         wglDeleteContext(testrc);
00988         testrc  = NULL;
00989         __wglGetPixelFormatAttribivARB = NULL;
00990         __wglGetPixelFormatAttribivEXT = NULL;
00991     }
00992 
00993     TRACE(PREFIX_I "select_pixel_format(): %i formats.\n", maxindex);
00994 
00995     if (maxindex < 1) {
00996         TRACE(PREFIX_E "select_pixel_format(): Didn't find any pixel "
00997               "formats at all!\n");
00998         goto bail;
00999     }
01000     
01001     format = malloc((maxindex + 1) * sizeof(format_t));
01002     
01003     if (!format) {
01004         TRACE(PREFIX_E "select_pixel_format(): Unable to allocate memory for "
01005               "pixel format scores!\n");
01006         goto bail;
01007     }
01008 
01009     /* First, pixel formats are sorted by decreasing order */
01010     TRACE(PREFIX_I "select_pixel_format(): Testing pixel formats:\n");
01011     for (i = 1; i <= maxindex; i++) {
01012 
01013         int use_old = !new_pf_code;
01014         
01015         TRACE(PREFIX_I "Format %i:\n", i);
01016         
01017         if (new_pf_code) {
01018             if (describe_pixel_format_new(testdc, i, desktop_depth,
01019                                           format, &num_formats, NULL) < 0) {
01020                 TRACE(PREFIX_W "select_pixel_format(): Wasn't able to use "
01021                       "WGL_PixelFormat - reverting to old WGL code.\n");
01022                 use_old = 1;
01023             }
01024         }
01025 
01026         if (use_old) {
01027             if (describe_pixel_format_old(testdc, i, desktop_depth,
01028                                       format, &num_formats, NULL) < 0) {
01029                 TRACE(PREFIX_W "select_pixel_format(): Unable to rely on "
01030                       "unextended WGL to describe this pixelformat.\n");
01031             }
01032         }
01033     }
01034 
01035     if (new_pf_code) {
01036         wglMakeCurrent(NULL, NULL);
01037         wglDeleteContext(testrc);
01038         testrc = NULL;
01039     }
01040     if (testwnd) {
01041         ReleaseDC(testwnd, testdc);
01042         testdc = NULL;
01043         DestroyWindow(testwnd);
01044         testwnd = NULL;
01045     }
01046 
01047     if (num_formats < 1) {
01048         TRACE(PREFIX_E "select_pixel_format(): Didn't find any available "
01049               "pixel formats!\n");
01050         goto bail;
01051     }
01052 
01053     qsort(format, num_formats, sizeof(format_t), select_pixel_format_sorter);
01054 
01055 
01056     /* Sorted pixel formats are tested until one of them succeeds to
01057      * make a GL context current */
01058     for (i = 0; i < num_formats ; i++) {
01059         HGLRC rc;
01060 
01061         /* Recreate our test windows */
01062         testwnd = create_test_window();
01063         testdc = GetDC(testwnd);
01064         
01065         if (SetPixelFormat(testdc, format[i].format, pfd)) {
01066             rc = wglCreateContext(testdc);
01067             if (!rc) {
01068                 TRACE(PREFIX_I "select_pixel_format(): Unable to create RC!\n");
01069             }
01070             else {
01071                 if (wglMakeCurrent(testdc, rc)) {
01072                     wglMakeCurrent(NULL, NULL);
01073                     wglDeleteContext(rc);
01074                     rc = NULL;
01075 
01076                     TRACE(PREFIX_I "select_pixel_format(): Best config is: %i"
01077                           "\n", format[i].format);
01078 
01079                     /* XXX <rohannessian> DescribePixelFormat may fail on 
01080                      * extended pixel format (WGL_ARB_p_f)
01081                      */
01082                     if (!DescribePixelFormat(testdc, format[i].format,
01083                                         sizeof *pfd, pfd)) {
01084                         TRACE(PREFIX_E "Cannot describe this pixel format\n");
01085                         ReleaseDC(testwnd, testdc);
01086                         DestroyWindow(testwnd);
01087                         testdc = NULL;
01088                         testwnd = NULL;
01089                         continue;
01090                     }
01091 
01092                     ReleaseDC(testwnd, testdc);
01093                     DestroyWindow(testwnd);
01094 
01095                     result = format[i].format;
01096                     
01097                     free(format);
01098                     return result;
01099                 }
01100                 else {
01101                     wglMakeCurrent(NULL, NULL);
01102                     wglDeleteContext(rc);
01103                     rc = NULL;
01104                     log_win32_warning("select_pixel_format",
01105                             "Couldn't make the temporary render context "
01106                             "current for the this pixel format.",
01107                             GetLastError());
01108                 }
01109             }
01110         }
01111         else {
01112             log_win32_note("select_pixel_format",
01113                         "Unable to set pixel format!", GetLastError());
01114         }
01115         
01116         ReleaseDC(testwnd, testdc);
01117         DestroyWindow(testwnd);
01118         testdc = NULL;
01119         testwnd = NULL;
01120     }
01121 
01122     TRACE(PREFIX_E "select_pixel_format(): All modes have failed...\n");
01123 bail:
01124     if (format) {
01125         free(format);
01126     }
01127     if (new_pf_code) {
01128         wglMakeCurrent(NULL, NULL);
01129         if (testrc) {
01130             wglDeleteContext(testrc);
01131         }
01132     }
01133     if (testwnd) {
01134         ReleaseDC(testwnd, testdc);
01135         DestroyWindow(testwnd);
01136     }
01137     
01138     return 0;
01139 }
01140 
01141 
01142 
01143 static void allegrogl_init_window(int w, int h, DWORD style, DWORD exstyle)
01144 {
01145     RECT rect;
01146 
01147 #define req __allegro_gl_required_settings
01148 #define sug __allegro_gl_suggested_settings
01149 
01150     int x = 32, y = 32;
01151     
01152     if (req & AGL_WINDOW_X || sug & AGL_WINDOW_X)
01153         x = allegro_gl_display_info.x;
01154     if (req & AGL_WINDOW_Y || sug & AGL_WINDOW_Y)
01155         y = allegro_gl_display_info.y;
01156 
01157 #undef req
01158 #undef sug
01159     
01160     if (!fullscreen) {
01161         rect.left = x;
01162         rect.right = x + w;
01163         rect.top = y;
01164         rect.bottom = y + h;
01165     }
01166     else {
01167         rect.left = 0;
01168         rect.right = w;
01169         rect.top  = 0;
01170         rect.bottom = h;
01171     }
01172 
01173     /* save original Allegro styles */
01174     style_saved = GetWindowLong(wnd, GWL_STYLE);
01175     exstyle_saved = GetWindowLong(wnd, GWL_EXSTYLE);
01176 
01177     /* set custom AllegroGL style */
01178     SetWindowLong(wnd, GWL_STYLE, style);
01179     SetWindowLong(wnd, GWL_EXSTYLE, exstyle);
01180 
01181     if (!fullscreen) {
01182         AdjustWindowRectEx(&rect, style, FALSE, exstyle);
01183     }
01184 
01185     /* make the changes visible */
01186     SetWindowPos(wnd, 0, rect.left, rect.top,
01187         rect.right - rect.left, rect.bottom - rect.top,
01188         SWP_NOZORDER | SWP_FRAMECHANGED);
01189     
01190     return;
01191 }
01192 
01193 
01194 
01195 static BITMAP *allegro_gl_create_screen (GFX_DRIVER *drv, int w, int h,
01196                                          int depth)
01197 {
01198     BITMAP *bmp;
01199     int is_linear = drv->linear;
01200 
01201     drv->linear = 1;
01202     bmp = _make_bitmap (w, h, 0, drv, depth, 0);
01203     
01204     if (!bmp) {
01205         return NULL;
01206     }
01207 
01208     bmp->id = BMP_ID_VIDEO | 1000;
01209     drv->linear = is_linear;
01210 
01211     drv->w = w;
01212     drv->h = h;
01213 
01214     return bmp;
01215 }
01216 
01217 
01218 static LRESULT CALLBACK dummy_wnd_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
01219 {
01220     return DefWindowProc(wnd, message, wparam, lparam);
01221 }
01222 
01223 static HWND dummy_wnd;
01224 
01225 static void dummy_window(void)
01226 {
01227     WNDCLASS wnd_class;
01228 
01229     wnd_class.style = CS_HREDRAW | CS_VREDRAW;
01230     wnd_class.lpfnWndProc = dummy_wnd_proc;
01231     wnd_class.cbClsExtra = 0;
01232     wnd_class.cbWndExtra = 0;
01233     wnd_class.hInstance = GetModuleHandle(NULL);
01234     wnd_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
01235     wnd_class.hCursor = LoadCursor(NULL, IDC_ARROW);
01236     wnd_class.hbrBackground = NULL;
01237     wnd_class.lpszMenuName = NULL;
01238     wnd_class.lpszClassName = "allegro focus";
01239 
01240     RegisterClass(&wnd_class);
01241 
01242     dummy_wnd = CreateWindow("allegro focus", "Allegro", WS_POPUP | WS_VISIBLE,
01243             0, 0, 200, 200,
01244             NULL, NULL, GetModuleHandle(NULL), NULL);
01245 
01246     ShowWindow(dummy_wnd, SW_SHOWNORMAL);
01247     SetForegroundWindow(dummy_wnd);
01248 }
01249 
01250 static void remove_dummy_window(void)
01251 {
01252     DestroyWindow(dummy_wnd);
01253     UnregisterClass("allegro focus", GetModuleHandle(NULL));
01254 }
01255 
01256 
01257 static BITMAP *allegro_gl_win_init(int w, int h, int v_w, int v_h)
01258 {
01259     static int first_time = 1;
01260     
01261     DWORD style=0, exstyle=0;
01262     int refresh_rate = _refresh_rate_request;
01263     int desktop_depth;
01264     int pf=0;
01265 
01266     new_w = w;
01267     new_h = h;
01268 
01269     /* virtual screen are not supported */
01270     if ((v_w != 0 && v_w != w) || (v_h != 0 && v_h != h)) {
01271         TRACE(PREFIX_E "win_init(): Virtual screens are not supported in "
01272               "AllegroGL!\n");
01273         return NULL;
01274     }
01275         
01276     /* Fill in missing color depth info */
01277     __allegro_gl_fill_in_info();
01278 
01279     /* Be sure the current desktop color depth is at least 15bpp */
01280     /* We may want to change this, so try to set a better depth, or
01281        to at least report an error somehow */
01282     desktop_depth = desktop_color_depth();
01283 
01284     if (desktop_depth < 15)
01285         return NULL;
01286 
01287     TRACE(PREFIX_I "win_init(): Requested color depth: %i  "
01288           "Desktop color depth: %i\n", allegro_gl_display_info.colour_depth,
01289           desktop_depth);
01290 
01291         /* In the moment the main window is destroyed, Allegro loses focus, and
01292          * focus can only be returned by actual user input under Windows XP. So
01293          * we need to create a dummy window which retains focus for us, until
01294          * the new window is up.
01295          */
01296         if (fullscreen) dummy_window();
01297 
01298     /* Need to set the w and h driver members at this point to avoid assertion
01299      * failure in set_mouse_range() when win_set_window() is called.
01300      */
01301     if (fullscreen) {
01302         gfx_allegro_gl_fullscreen.w = w;
01303         gfx_allegro_gl_fullscreen.h = h;
01304     }
01305     else {
01306         gfx_allegro_gl_windowed.w = w;
01307         gfx_allegro_gl_windowed.h = h;
01308     }
01309 
01310     /* request a fresh new window from Allegro... */
01311     /* Set a NULL window to get Allegro to generate a new HWND. This is needed
01312      * because we can only set the pixel format once per window. Thus, calling
01313      * set_gfx_mode() multiple times will fail without this code.
01314      */
01315     if (!first_time) {
01316         win_set_window(NULL);
01317     }
01318     first_time = 0;
01319 
01320     /* ...and retrieve its handle */
01321     wnd = win_get_window();
01322     if (!wnd)
01323         return NULL;
01324 
01325     /* set up the AllegroGL window */
01326     if (fullscreen) {
01327         style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
01328         exstyle = WS_EX_APPWINDOW | WS_EX_TOPMOST;
01329     }
01330     else {
01331         style = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_CLIPCHILDREN
01332               | WS_CLIPSIBLINGS;
01333         exstyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
01334     }
01335 
01336     TRACE(PREFIX_I "win_init(): Setting up window.\n");
01337     allegrogl_init_window(w, h, style, exstyle);
01338 
01339     __allegro_gl_hdc = GetDC(wnd); /* get the device context of our window */
01340     if (!__allegro_gl_hdc) {
01341         goto Error;
01342     }
01343 
01344     TRACE(PREFIX_I "win_init(): Driver selected fullscreen: %s\n",
01345           fullscreen ? "Yes" : "No");
01346 
01347     if (fullscreen)
01348     {
01349         DEVMODE dm;
01350         DEVMODE fallback_dm;
01351         int fallback_dm_valid = 0;
01352 
01353         int bpp_to_check[] = {16, 32, 24, 15, 0};
01354         int bpp_checked[] = {0, 0, 0, 0, 0};
01355         int bpp_index = 0;
01356         int i, j, result, modeswitch, done = 0;
01357 
01358         for (j = 0; j < 4; j++)
01359         {
01360             if (bpp_to_check[j] == allegro_gl_get(AGL_COLOR_DEPTH))
01361             {
01362                 bpp_index = j;
01363                 break;
01364             }
01365         }
01366 
01367         dm.dmSize = sizeof(DEVMODE);
01368         dm_saved.dmSize = sizeof(DEVMODE);
01369         
01370         /* Save old mode */
01371         EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm_saved);
01372         dm.dmBitsPerPel = desktop_depth; /* Go around Win95's bug */
01373 
01374         do
01375         {
01376             if (!bpp_to_check[bpp_index])
01377             {
01378                 TRACE(PREFIX_E "win_init(): No more color depths to test.\n"
01379                       "\tUnable to find appropriate full screen mode and pixel "
01380                       "format.\n");
01381                 goto Error;
01382             }
01383 
01384             TRACE(PREFIX_I "win_init(): Testing color depth: %i\n",
01385                   bpp_to_check[bpp_index]);
01386             
01387             memset(&dm, 0, sizeof(DEVMODE));
01388             dm.dmSize = sizeof(DEVMODE);
01389             
01390             i = 0;
01391             do 
01392             {
01393                 modeswitch = EnumDisplaySettings(NULL, i, &dm);
01394                 if (!modeswitch)
01395                     break;
01396 
01397                 if ((dm.dmPelsWidth  == (unsigned) w)
01398                  && (dm.dmPelsHeight == (unsigned) h)
01399                  && (dm.dmBitsPerPel == (unsigned) bpp_to_check[bpp_index])
01400                  && (dm.dmDisplayFrequency != (unsigned) refresh_rate)) {
01401                     /* Keep it as fallback if refresh rate request could not
01402                      * be satisfied. Try to get as close to 60Hz as possible though,
01403                      * it's a bit better for a fallback than just blindly picking
01404                      * something like 47Hz or 200Hz.
01405                      */
01406                     if (!fallback_dm_valid) {
01407                         fallback_dm = dm;
01408                         fallback_dm_valid = 1;
01409                     }
01410                     else if (dm.dmDisplayFrequency >= 60) {
01411                         if (dm.dmDisplayFrequency < fallback_dm.dmDisplayFrequency) {
01412                             fallback_dm = dm;
01413                         }
01414                     }
01415                 }
01416         
01417                 i++;
01418             }
01419             while ((dm.dmPelsWidth  != (unsigned) w)
01420                 || (dm.dmPelsHeight != (unsigned) h)
01421                 || (dm.dmBitsPerPel != (unsigned) bpp_to_check[bpp_index])
01422                 || (dm.dmDisplayFrequency != (unsigned) refresh_rate));
01423 
01424             if (!modeswitch && !fallback_dm_valid) {
01425                 TRACE(PREFIX_I "win_init(): Unable to set mode, continuing "
01426                       "with next color depth\n");
01427             }
01428             else {
01429                 if (!modeswitch && fallback_dm_valid)
01430                     dm = fallback_dm;
01431 
01432                 TRACE(PREFIX_I "win_init(): bpp_to_check[bpp_index] = %i\n",
01433                       bpp_to_check[bpp_index]);
01434                 TRACE(PREFIX_I "win_init(): dm.dmBitsPerPel = %i\n",
01435                       (int)dm.dmBitsPerPel);
01436 
01437                 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL
01438                             | DM_DISPLAYFREQUENCY;
01439 
01440                 result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
01441 
01442                 if (result == DISP_CHANGE_SUCCESSFUL) 
01443                 {
01444                     TRACE(PREFIX_I "win_init(): Setting pixel format.\n");
01445                     pf = select_pixel_format(&pfd);
01446                     if (pf) {
01447                         TRACE(PREFIX_I "mode found\n");
01448                         _set_current_refresh_rate(dm.dmDisplayFrequency);
01449                         done = 1;
01450                     }
01451                     else {
01452                         TRACE(PREFIX_I "win_init(): Couldn't find compatible "
01453                               "GL context. Trying another screen mode.\n");
01454                     }
01455                 }
01456             }
01457 
01458             fallback_dm_valid = 0;
01459             bpp_checked[bpp_index] = 1;
01460 
01461             bpp_index = 0;
01462             while (bpp_checked[bpp_index]) {
01463                 bpp_index++;
01464             }
01465         } while (!done);
01466     }
01467     else {
01468         DEVMODE dm;
01469 
01470         memset(&dm, 0, sizeof(DEVMODE));
01471         dm.dmSize = sizeof(DEVMODE);
01472         if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) != 0) {
01473             _set_current_refresh_rate(dm.dmDisplayFrequency);
01474         }
01475     }
01476 
01477     if (!fullscreen) {
01478         TRACE(PREFIX_I "win_init(): Setting pixel format.\n");
01479         pf = select_pixel_format(&pfd);
01480         if (pf == 0)
01481             goto Error;
01482     }
01483 
01484     /* set the pixel format */
01485     if (!SetPixelFormat(__allegro_gl_hdc, pf, &pfd)) { 
01486         log_win32_error("win_init",
01487                     "Unable to set pixel format.",
01488                     GetLastError());
01489         goto Error;
01490     }
01491 
01492     /* create an OpenGL context */
01493     allegro_glrc = wglCreateContext(__allegro_gl_hdc);
01494     
01495     if (!allegro_glrc) { /* make the context the current one */
01496         log_win32_error("win_init",
01497                     "Unable to create a render context!",
01498                     GetLastError());
01499         goto Error;
01500     }
01501     if (!wglMakeCurrent(__allegro_gl_hdc, allegro_glrc)) {
01502         log_win32_error("win_init",
01503                     "Unable to make the context current!",
01504                     GetLastError());
01505         goto Error;
01506     }
01507 
01508 
01509     if (__wglGetPixelFormatAttribivARB || __wglGetPixelFormatAttribivEXT) {
01510         describe_pixel_format_new(__allegro_gl_hdc, pf, desktop_depth,
01511                                   NULL, NULL, &allegro_gl_display_info);
01512     }
01513     else {
01514         describe_pixel_format_old(__allegro_gl_hdc, pf, desktop_depth,
01515                                   NULL, NULL, &allegro_gl_display_info);
01516     }
01517     
01518     
01519     __allegro_gl_set_allegro_image_format(FALSE);
01520     set_color_depth(allegro_gl_display_info.colour_depth);
01521     allegro_gl_display_info.w = w;
01522     allegro_gl_display_info.h = h;
01523 
01524     
01525     /* <rohannessian> Win98/2k/XP's window forground rules don't let us
01526      * make our window the topmost window on launch. This causes issues on 
01527      * full-screen apps, as DInput loses input focus on them.
01528      * We use this trick to force the window to be topmost, when switching
01529      * to full-screen only. Note that this only works for Win98 and greater.
01530      * Win95 will ignore our SystemParametersInfo() calls.
01531      * 
01532      * See http://support.microsoft.com:80/support/kb/articles/Q97/9/25.asp
01533      * for details.
01534      */
01535     {
01536         DWORD lock_time;
01537 
01538 #define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000
01539 #define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001
01540         if (fullscreen) {
01541             SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,
01542                                  0, (LPVOID)&lock_time, 0);
01543             SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
01544                                  0, (LPVOID)0,
01545                                  SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
01546         }
01547 
01548         ShowWindow(wnd, SW_SHOWNORMAL);
01549         SetForegroundWindow(wnd);
01550         /* In some rare cases, it doesn't seem to work without the loop. And we
01551          * absolutely need this to succeed, else we trap the user in a
01552          * fullscreen window without input.
01553          */
01554         while (GetForegroundWindow() != wnd) {
01555             rest(100);
01556             SetForegroundWindow(wnd);
01557         }
01558         UpdateWindow(wnd);
01559 
01560         if (fullscreen) {
01561             SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
01562                                  0, (LPVOID)lock_time,
01563                                  SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
01564         }
01565 #undef SPI_GETFOREGROUNDLOCKTIMEOUT
01566 #undef SPI_SETFOREGROUNDLOCKTIMEOUT
01567     }
01568         
01569     win_grab_input();
01570     
01571     if (fullscreen) {
01572         allegro_gl_screen= allegro_gl_create_screen(&gfx_allegro_gl_fullscreen,
01573                                         w, h, allegro_gl_get(AGL_COLOR_DEPTH));
01574     }
01575     else {
01576         allegro_gl_screen= allegro_gl_create_screen(&gfx_allegro_gl_windowed,
01577                                         w, h, allegro_gl_get(AGL_COLOR_DEPTH));
01578     }
01579 
01580     if (!allegro_gl_screen) {
01581         ChangeDisplaySettings(NULL, 0);
01582         goto Error;
01583     }
01584     
01585 
01586     TRACE(PREFIX_I "win_init(): GLScreen: %ix%ix%i\n",
01587           w, h, allegro_gl_get(AGL_COLOR_DEPTH));
01588 
01589     allegro_gl_screen->id |= BMP_ID_VIDEO | BMP_ID_MASK;
01590 
01591     __allegro_gl_valid_context = TRUE;
01592     __allegro_gl_driver = &allegro_gl_win;
01593     initialized = 1;
01594 
01595     /* Print out OpenGL version info */
01596     TRACE(PREFIX_I "OpenGL Version: %s\n", (AL_CONST char*)glGetString(GL_VERSION));
01597     TRACE(PREFIX_I "Vendor: %s\n", (AL_CONST char*)glGetString(GL_VENDOR));
01598     TRACE(PREFIX_I "Renderer: %s\n\n", (AL_CONST char*)glGetString(GL_RENDERER));
01599 
01600     /* Detect if the GL driver is based on Mesa */
01601     allegro_gl_info.is_mesa_driver = FALSE;
01602     if (strstr((AL_CONST char*)glGetString(GL_VERSION),"Mesa")) {
01603         AGL_LOG(1, "OpenGL driver based on Mesa\n");
01604         allegro_gl_info.is_mesa_driver = TRUE;
01605     }
01606 
01607     /* init the GL extensions */
01608     __allegro_gl_manage_extensions();
01609     
01610     /* Update screen vtable in order to use AGL's */
01611     __allegro_gl__glvtable_update_vtable(&allegro_gl_screen->vtable);
01612     memcpy(&_screen_vtable, allegro_gl_screen->vtable, sizeof(GFX_VTABLE));
01613     allegro_gl_screen->vtable = &_screen_vtable;
01614 
01615     /* Print out WGL extension info */
01616     if (wglGetExtensionsStringARB) {
01617         AGL_LOG(1, "WGL Extensions :\n");
01618 #if LOGLEVEL >= 1
01619         __allegro_gl_print_extensions((AL_CONST char*)wglGetExtensionsStringARB(wglGetCurrentDC()));
01620 #endif
01621     }
01622     else {
01623         TRACE(PREFIX_I "win_init(): No WGL Extensions available\n");
01624     }
01625 
01626     gfx_capabilities |= GFX_HW_CURSOR;
01627 
01628     /* Initialize a reasonable viewport. Those should be OpenGL defaults,
01629      * but some drivers don't implement this correctly.
01630      */ 
01631     glViewport(0, 0, SCREEN_W, SCREEN_H);
01632     glMatrixMode(GL_PROJECTION);
01633     glLoadIdentity();
01634     glMatrixMode(GL_MODELVIEW);
01635     glLoadIdentity();
01636 
01637     if (allegro_gl_extensions_GL.ARB_multisample) {
01638         /* Workaround some "special" drivers that do not export the extension
01639          * once it was promoted to core.*/
01640         if (allegro_gl_opengl_version() >= 1.3)
01641             glSampleCoverage(1.0, GL_FALSE);
01642         else
01643             glSampleCoverageARB(1.0, GL_FALSE);
01644     }
01645     
01646     /* Set up some variables that some GL drivers omit */
01647     glBindTexture(GL_TEXTURE_2D, 0);
01648     
01649     screen = allegro_gl_screen;
01650 
01651     if (fullscreen)
01652         remove_dummy_window();
01653 
01654     return allegro_gl_screen;
01655     
01656 Error:
01657     if (allegro_glrc) {
01658         wglDeleteContext(allegro_glrc);
01659     }
01660     if (__allegro_gl_hdc) {
01661         ReleaseDC(wnd, __allegro_gl_hdc);
01662     }
01663     __allegro_gl_hdc = NULL;
01664     ChangeDisplaySettings(NULL, 0);
01665     allegro_gl_win_exit(NULL);
01666 
01667     return NULL;
01668 }
01669 
01670 
01671 
01672 static BITMAP *allegro_gl_win_init_windowed(int w, int h, int v_w, int v_h,
01673                                             int color_depth)
01674 {
01675     fullscreen = 0;
01676     return allegro_gl_win_init(w, h, v_w, v_h);
01677 }
01678 
01679 
01680 
01681 static BITMAP *allegro_gl_win_init_fullscreen(int w, int h, int v_w, int v_h,
01682                                               int color_depth)
01683 {
01684     fullscreen = 1;
01685     return allegro_gl_win_init(w, h, v_w, v_h);
01686 }
01687 
01688 
01689 
01690 static void allegro_gl_win_exit(struct BITMAP *b)
01691 {
01692     /* XXX <rohannessian> For some reason, uncommenting this line will blank
01693      * out the log file.
01694      */
01695     //TRACE(PREFIX_I "allegro_gl_win_exit: Shutting down.\n");
01696     __allegro_gl_unmanage_extensions();
01697     
01698     if (allegro_glrc) {
01699         wglDeleteContext(allegro_glrc);
01700         allegro_glrc = NULL;
01701     }
01702         
01703     if (__allegro_gl_hdc) {
01704         ReleaseDC(wnd, __allegro_gl_hdc);
01705         __allegro_gl_hdc = NULL;
01706     }
01707 
01708     if (fullscreen && initialized) {
01709         /* Restore screen */
01710         ChangeDisplaySettings(NULL, 0);
01711         _set_current_refresh_rate(0);
01712     }
01713     initialized = 0;
01714 
01715     /* Note: Allegro will destroy screen (== allegro_gl_screen),
01716      * so don't destroy it here.
01717      */
01718     //destroy_bitmap(allegro_gl_screen);
01719     allegro_gl_screen = NULL;
01720     
01721     /* hide the window */
01722     system_driver->restore_console_state();
01723 
01724     /* restore original Allegro styles */
01725     SetWindowLong(wnd, GWL_STYLE, style_saved);
01726     SetWindowLong(wnd, GWL_EXSTYLE, exstyle_saved);
01727     SetWindowPos(wnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER
01728                                    | SWP_FRAMECHANGED);
01729 
01730     __allegro_gl_valid_context = FALSE;
01731     
01732     return;
01733 }
01734 
01735 
01736 /* 
01737    Returns TRUE is dm doesn't match any mode in mode_list, FALSE otherwise.
01738 */
01739 static int is_mode_entry_unique(GFX_MODE_LIST *mode_list, DEVMODE *dm) {
01740     int i;
01741     
01742     for (i = 0; i < mode_list->num_modes; ++i) {
01743         if (mode_list->mode[i].width == (int)dm->dmPelsWidth
01744             && mode_list->mode[i].height == (int)dm->dmPelsHeight
01745             && mode_list->mode[i].bpp == (int)dm->dmBitsPerPel)
01746             return FALSE;
01747     }
01748     
01749     return TRUE;
01750 }
01751 
01752 
01753 
01754 /* Returns a list of valid video modes */
01755 static GFX_MODE_LIST* allegro_gl_win_fetch_mode_list(void)
01756 {
01757     int c, modes_count;
01758     GFX_MODE_LIST *mode_list;
01759     DEVMODE dm;
01760 
01761     dm.dmSize = sizeof(DEVMODE);
01762 
01763     /* Allocate space for mode list. */
01764     mode_list = malloc(sizeof(GFX_MODE_LIST));
01765     if (!mode_list) {
01766         return NULL;
01767     }
01768 
01769     /* Allocate and fill the first mode in case EnumDisplaySettings fails at
01770      * first call.
01771      */
01772     mode_list->mode = malloc(sizeof(GFX_MODE));
01773     if (!mode_list->mode) {
01774         free(mode_list);
01775         return NULL;
01776     }
01777     mode_list->mode[0].width = 0;
01778     mode_list->mode[0].height = 0;
01779     mode_list->mode[0].bpp = 0;
01780     mode_list->num_modes = 0;
01781 
01782     modes_count = 0;
01783     c = 0;
01784     while (EnumDisplaySettings(NULL, c, &dm)) {
01785         mode_list->mode = realloc(mode_list->mode,
01786                                 sizeof(GFX_MODE) * (modes_count + 2));
01787         if (!mode_list->mode) {
01788             free(mode_list);
01789             return NULL;
01790         }
01791 
01792         /* Filter modes with bpp lower than 9, and those which are already
01793          * in there.
01794          */
01795         if (dm.dmBitsPerPel > 8 && is_mode_entry_unique(mode_list, &dm)) {
01796             mode_list->mode[modes_count].width = dm.dmPelsWidth;
01797             mode_list->mode[modes_count].height = dm.dmPelsHeight;
01798             mode_list->mode[modes_count].bpp = dm.dmBitsPerPel;
01799             ++modes_count;
01800             mode_list->mode[modes_count].width = 0;
01801             mode_list->mode[modes_count].height = 0;
01802             mode_list->mode[modes_count].bpp = 0;
01803             mode_list->num_modes = modes_count;
01804         }
01805         ++c;
01806     };
01807 
01808     return mode_list;
01809 }
01810 
01811 
01812 
01813 
01814 /* AllegroGL driver routines */
01815 
01816 static void flip(void)
01817 {
01818     SwapBuffers(__allegro_gl_hdc);
01819 }
01820 
01821 
01822 
01823 static void gl_on(void)
01824 {
01825     return;
01826 }
01827 
01828 
01829 
01830 static void gl_off(void)
01831 {
01832     return;
01833 }
01834 
01835 
01836 
01837 /* AllegroGL driver */
01838 
01839 static struct allegro_gl_driver allegro_gl_win = {
01840     flip, gl_on, gl_off, NULL
01841 };
01842 

Generated on Sun Dec 3 18:06:50 2006 for AllegroGL by  doxygen 1.5.1