win.c

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

Generated on Mon Apr 3 18:20:13 2006 for AllegroGL by  doxygen 1.4.6