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

Generated on Sun Nov 11 15:52:55 2007 for AllegroGL by  doxygen 1.5.2