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

Generated on Tue Aug 21 22:43:00 2007 for AllegroGL by  doxygen 1.5.2