AllegroGL  0.4.4
win.c
1 /* This code is (C) AllegroGL contributors, and double licensed under
2  * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
3  */
4 #include <string.h>
5 #include <allegro.h>
6 #include <allegro/internal/aintern.h>
7 
8 
9 #include "alleggl.h"
10 #include "glvtable.h"
11 #include "allglint.h"
12 
13 
14 static BITMAP *allegro_gl_win_init_windowed(int w, int h, int v_w, int v_h,
15  int color_depth);
16 static BITMAP *allegro_gl_win_init_fullscreen(int w, int h, int v_w, int v_h,
17  int color_depth);
18 static void allegro_gl_win_exit(struct BITMAP *b);
19 static GFX_MODE_LIST* allegro_gl_win_fetch_mode_list(void);
20 
21 static struct allegro_gl_driver allegro_gl_win;
22 
23 #define PREFIX_I "agl-win INFO: "
24 #define PREFIX_W "agl-win WARNING: "
25 #define PREFIX_E "agl-win ERROR: "
26 
27 
28 static BITMAP *allegro_gl_screen = NULL;
29 
30 
31 /* Windowed mode driver */
32 GFX_DRIVER gfx_allegro_gl_windowed = {
34  EMPTY_STRING,
35  EMPTY_STRING,
36  "AllegroGL Windowed (Win32)",
37  allegro_gl_win_init_windowed,
38  allegro_gl_win_exit,
39  NULL, /* scrolling not implemented */
40  NULL, /* vsync, may use for flip? */
41  NULL, /* No h/w pallete, not using indexed mode */
42  NULL, NULL, /* Still no scrolling */
43  NULL, /* No triple buffering */
46  NULL, NULL, /* No show/request video bitmaps */
47  NULL, NULL, /* No system bitmaps */
48  allegro_gl_set_mouse_sprite,
49  allegro_gl_show_mouse,
50  allegro_gl_hide_mouse,
51  allegro_gl_move_mouse,
52  allegro_gl_drawing_mode,
53  NULL, NULL, /* No video state stuff */
54  allegro_gl_set_blender_mode,
55  NULL, /* No fetch_mode_list */
56  0,0, /* physical (not virtual!) screen size */
57  0, /* true if video memory is linear */
58  0, /* bank size, in bytes */
59  0, /* bank granularity, in bytes */
60  0, /* video memory size, in bytes */
61  0, /* physical address of video memory */
62  TRUE /* Windowed mode */
63 };
64 
65 
66 /* Fullscreen driver */
67 GFX_DRIVER gfx_allegro_gl_fullscreen = {
69  EMPTY_STRING,
70  EMPTY_STRING,
71  "AllegroGL Fullscreen (Win32)",
72  allegro_gl_win_init_fullscreen,
73  allegro_gl_win_exit,
74  NULL, /* scrolling not implemented */
75  NULL, /* vsync, may use for flip? */
76  NULL, /* No h/w pallete, not using indexed mode */
77  NULL, NULL, /* Still no scrolling */
78  NULL, /* No triple buffering */
81  NULL, NULL, /* No show/request video bitmaps */
82  NULL, NULL, /* No system bitmaps */
83  allegro_gl_set_mouse_sprite,
84  allegro_gl_show_mouse,
85  allegro_gl_hide_mouse,
86  allegro_gl_move_mouse,
87  allegro_gl_drawing_mode,
88  NULL, NULL, /* No video state stuff */
89  allegro_gl_set_blender_mode,
90  allegro_gl_win_fetch_mode_list, /* fetch_mode_list */
91  0,0, /* physical (not virtual!) screen size */
92  0, /* true if video memory is linear */
93  0, /* bank size, in bytes */
94  0, /* bank granularity, in bytes */
95  0, /* video memory size, in bytes */
96  0, /* physical address of video memory */
97  FALSE /* Windowed mode */
98 };
99 
100 
101 /* XXX <rohannessian> We should move those variable definitions into a struct,
102  * for when multiple windows end up being supported.
103  */
104 
105 /* Device Context used for the Allegro window. Note that only one window
106  * is supported, so only onyl HDC is needed. This is shared by the AGL
107  * extension code.
108  */
109 HDC __allegro_gl_hdc = NULL;
110 
111 /* Render Context used by AllegroGL, once screen mode was set. Note that only
112  * a single window is supported.
113  */
114 static HGLRC allegro_glrc = NULL;
115 
116 /* Full-screen flag, for the current context. */
117 static int fullscreen = 0;
118 
119 /* Current window handle */
120 static HWND wnd = NULL;
121 
122 /* If AGL was initialized */
123 static int initialized = 0;
124 
125 /* XXX <rohannessian> Put those globals as function parameters */
126 /* Note - these globals should really end up as parameters to functions.
127  */
128 static DWORD style_saved, exstyle_saved;
129 static DEVMODE dm_saved;
130 static int test_windows_created = 0;
131 static int new_w = 0, new_h = 0;
132 
133 static PIXELFORMATDESCRIPTOR pfd = {
134  sizeof(PIXELFORMATDESCRIPTOR), /* size of this pfd */
135  1, /* version number */
136  PFD_DRAW_TO_WINDOW /* support window */
137  | PFD_SUPPORT_OPENGL /* support OpenGL */
138  | PFD_DOUBLEBUFFER, /* double buffered */
139  PFD_TYPE_RGBA, /* RGBA type */
140  24, /* 24-bit color depth */
141  0, 0, 0, 0, 0, 0, /* color bits ignored */
142  0, /* no alpha buffer */
143  0, /* shift bit ignored */
144  0, /* no accumulation buffer */
145  0, 0, 0, 0, /* accum bits ignored */
146  0, /* z-buffer */
147  0, /* no stencil buffer */
148  0, /* no auxiliary buffer */
149  PFD_MAIN_PLANE, /* main layer */
150  0, /* reserved */
151  0, 0, 0 /* layer masks ignored */
152 };
153 
154 
155 
156 /* Logs a Win32 error/warning message in the log file.
157  */
158 static void log_win32_msg(const char *prefix, const char *func,
159  const char *error_msg, DWORD err) {
160 
161  char *err_msg = NULL;
162  BOOL free_msg = TRUE;
163 
164  /* Get the formatting error string from Windows. Note that only the
165  * bottom 14 bits matter - the rest are reserved for various library
166  * IDs and type of error.
167  */
168  if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
169  | FORMAT_MESSAGE_FROM_SYSTEM
170  | FORMAT_MESSAGE_IGNORE_INSERTS,
171  NULL, err & 0x3FFF,
172  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
173  (LPTSTR) &err_msg, 0, NULL)) {
174  err_msg = "(Unable to decode error code) ";
175  free_msg = FALSE;
176  }
177 
178  /* Remove two trailing characters */
179  if (err_msg && strlen(err_msg) > 1)
180  *(err_msg + strlen(err_msg) - 2) = '\0';
181 
182  TRACE("%s%s(): %s %s (0x%08lx)\n", prefix, func,
183  error_msg ? error_msg : "",
184  err_msg ? err_msg : "(null)",
185  (unsigned long)err);
186 
187  if (free_msg) {
188  LocalFree(err_msg);
189  }
190 
191  return;
192 }
193 
194 
195 
196 /* Logs an error */
197 static void log_win32_error(const char *func, const char *error_msg,
198  DWORD err) {
199  log_win32_msg(PREFIX_E, func, error_msg, err);
200 }
201 
202 
203 
204 /* Logs a warning */
205 static void log_win32_warning(const char *func, const char *error_msg,
206  DWORD err) {
207  log_win32_msg(PREFIX_W, func, error_msg, err);
208 }
209 
210 
211 
212 /* Logs a note */
213 static void log_win32_note(const char *func, const char *error_msg, DWORD err) {
214  log_win32_msg(PREFIX_I, func, error_msg, err);
215 }
216 
217 
218 
219 /* Define the AllegroGL Test window class */
220 #define ALLEGROGL_TEST_WINDOW_CLASS "AllegroGLTestWindow"
221 
222 
223 /* Registers the test window
224  * Returns 0 on success, non-zero on failure.
225  */
226 static int register_test_window()
227 {
228  WNDCLASS wc;
229 
230  memset(&wc, 0, sizeof(wc));
231  wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
232  wc.lpfnWndProc = DefWindowProc;
233  wc.hInstance = GetModuleHandle(NULL);
234  wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
235  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
236  wc.lpszClassName = ALLEGROGL_TEST_WINDOW_CLASS;
237 
238  if (!RegisterClass(&wc)) {
239  DWORD err = GetLastError();
240 
241  if (err != ERROR_CLASS_ALREADY_EXISTS) {
242  log_win32_error("register_test_window",
243  "Unable to register the window class!", err);
244  return -1;
245  }
246  }
247 
248  return 0;
249 }
250 
251 
252 
253 
254 /* Creates the test window.
255  * The window class must have already been registered.
256  * Returns the window handle, or NULL on failure.
257  */
258 static HWND create_test_window()
259 {
260  HWND wnd = CreateWindow(ALLEGROGL_TEST_WINDOW_CLASS,
261  "AllegroGL Test Window",
262  WS_POPUP | WS_CLIPCHILDREN,
263  0, 0, new_w, new_h,
264  NULL, NULL,
265  GetModuleHandle(NULL),
266  NULL);
267 
268  if (!wnd) {
269  log_win32_error("create_test_window",
270  "Unable to create a test window!", GetLastError());
271  return NULL;
272  }
273 
274  test_windows_created++;
275  return wnd;
276 }
277 
278 
279 
280 /* Print the pixel format info */
281 static void print_pixel_format(struct allegro_gl_display_info *dinfo) {
282 
283  if (!dinfo) {
284  return;
285  }
286 
287  TRACE(PREFIX_I "Acceleration: %s\n", ((dinfo->rmethod == 0) ? "No"
288  : ((dinfo->rmethod == 1) ? "Yes" : "Unknown")));
289  TRACE(PREFIX_I "RGBA: %i.%i.%i.%i\n", dinfo->pixel_size.rgba.r,
290  dinfo->pixel_size.rgba.g, dinfo->pixel_size.rgba.b,
291  dinfo->pixel_size.rgba.a);
292 
293  TRACE(PREFIX_I "Accum: %i.%i.%i.%i\n", dinfo->accum_size.rgba.r,
294  dinfo->accum_size.rgba.g, dinfo->accum_size.rgba.b,
295  dinfo->accum_size.rgba.a);
296 
297  TRACE(PREFIX_I "DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i\n",
298  dinfo->doublebuffered, dinfo->depth_size, dinfo->stereo,
299  dinfo->aux_buffers, dinfo->stencil_size);
300 
301  TRACE(PREFIX_I "Shift: %i.%i.%i.%i\n", dinfo->r_shift, dinfo->g_shift,
302  dinfo->b_shift, dinfo->a_shift);
303 
304  TRACE(PREFIX_I "Sample Buffers: %i Samples: %i\n",
305  dinfo->sample_buffers, dinfo->samples);
306 
307  TRACE(PREFIX_I "Decoded bpp: %i\n", dinfo->colour_depth);
308 }
309 
310 
311 
312 /* Decodes the pixel format into an agl_display_info struct and logs the pixel
313  * format in the trace file.
314  */
315 static int decode_pixel_format(PIXELFORMATDESCRIPTOR * pfd, HDC hdc, int format,
316  struct allegro_gl_display_info *dinfo,
317  int desktop_depth)
318 {
319  TRACE(PREFIX_I "Decoding: \n");
320  /* Not interested if it doesn't support OpenGL and RGBA */
321  if (!(pfd->dwFlags & PFD_SUPPORT_OPENGL)) {
322  TRACE(PREFIX_I "OpenGL Unsupported\n");
323  return -1;
324  }
325  if (pfd->iPixelType != PFD_TYPE_RGBA) {
326  TRACE(PREFIX_I "Not RGBA mode\n");
327  return -1;
328  }
329 
330  if ((pfd->cColorBits != desktop_depth)
331  && (pfd->cColorBits != 32 || desktop_depth < 24)) {
332  TRACE(PREFIX_I "Current color depth != "
333  "pixel format color depth\n");
334  //return -1; /* XXX <rohannessian> Why is this a bad thing? */
335  }
336 
337 
338  /* hardware acceleration */
339  if (((pfd->dwFlags & PFD_GENERIC_ACCELERATED)
340  && (pfd->dwFlags & PFD_GENERIC_FORMAT))
341  || (!(pfd->dwFlags & PFD_GENERIC_ACCELERATED)
342  && !(pfd->dwFlags & PFD_GENERIC_FORMAT)))
343  dinfo->rmethod = 1;
344  else
345  dinfo->rmethod = 0;
346 
347 
348  /* Depths of colour buffers */
349  dinfo->pixel_size.rgba.r = pfd->cRedBits;
350  dinfo->pixel_size.rgba.g = pfd->cGreenBits;
351  dinfo->pixel_size.rgba.b = pfd->cBlueBits;
352  dinfo->pixel_size.rgba.a = pfd->cAlphaBits;
353 
354  /* Depths of accumulation buffer */
355  dinfo->accum_size.rgba.r = pfd->cAccumRedBits;
356  dinfo->accum_size.rgba.g = pfd->cAccumGreenBits;
357  dinfo->accum_size.rgba.b = pfd->cAccumBlueBits;
358  dinfo->accum_size.rgba.a = pfd->cAccumAlphaBits;
359 
360  /* Miscellaneous settings */
361  dinfo->doublebuffered = pfd->dwFlags & PFD_DOUBLEBUFFER;
362  dinfo->stereo = pfd->dwFlags & PFD_STEREO;
363  dinfo->aux_buffers = pfd->cAuxBuffers;
364  dinfo->depth_size = pfd->cDepthBits;
365  dinfo->stencil_size = pfd->cStencilBits;
366 
367  /* These are the component shifts, like Allegro's _rgb_*_shift_*. */
368  dinfo->r_shift = pfd->cRedShift;
369  dinfo->g_shift = pfd->cGreenShift;
370  dinfo->b_shift = pfd->cBlueShift;
371  dinfo->a_shift = pfd->cAlphaShift;
372 
373  /* Multisampling isn't supported under Windows if we don't also use
374  * WGL_ARB_pixel_format or WGL_EXT_pixel_format.
375  */
376  dinfo->sample_buffers = 0;
377  dinfo->samples = 0;
378 
379  /* Float depth/color isn't supported under Windows if we don't also use
380  * AGL_ARB_pixel_format or WGL_EXT_pixel_format.
381  */
382  dinfo->float_color = 0;
383  dinfo->float_depth = 0;
384 
385  /* This bit is the same as the X code, setting some things based on
386  * what we've read out of the PFD. */
387  dinfo->colour_depth = 0;
388  if (dinfo->pixel_size.rgba.r == 5 && dinfo->pixel_size.rgba.b == 5) {
389  if (dinfo->pixel_size.rgba.g == 5)
390  dinfo->colour_depth = 15;
391  if (dinfo->pixel_size.rgba.g == 6)
392  dinfo->colour_depth = 16;
393  }
394  if (dinfo->pixel_size.rgba.r == 8
395  && dinfo->pixel_size.rgba.g == 8 && dinfo->pixel_size.rgba.b == 8) {
396  if (dinfo->pixel_size.rgba.a == 8)
397  dinfo->colour_depth = 32;
398  else
399  dinfo->colour_depth = 24;
400  }
401 
402 
403  dinfo->allegro_format = (dinfo->colour_depth != 0)
404  && (dinfo->g_shift == dinfo->pixel_size.rgba.b)
405  && (dinfo->r_shift * dinfo->b_shift == 0)
406  && (dinfo->r_shift + dinfo->b_shift ==
407  dinfo->pixel_size.rgba.b + dinfo->pixel_size.rgba.g);
408 
409  return 0;
410 }
411 
412 
413 
414 /* Decodes the pixel format into an agl_display_info struct and logs the pixel
415  * format in the trace file.
416  */
417 static int decode_pixel_format_attrib(struct allegro_gl_display_info *dinfo,
418  int num_attribs, const int *attrib, const int *value,
419  int desktop_depth) {
420  int i;
421 
422  TRACE(PREFIX_I "Decoding: \n");
423 
424  dinfo->samples = 0;
425  dinfo->sample_buffers = 0;
426  dinfo->float_depth = 0;
427  dinfo->float_color = 0;
428 
429  for (i = 0; i < num_attribs; i++) {
430 
431  /* Not interested if it doesn't support OpenGL or window drawing or
432  * RGBA.
433  */
434  if (attrib[i] == WGL_SUPPORT_OPENGL_ARB && value[i] == 0) {
435  TRACE(PREFIX_I "OpenGL Unsupported\n");
436  return -1;
437  }
438  else if (attrib[i] == WGL_DRAW_TO_WINDOW_ARB && value[i] == 0) {
439  TRACE(PREFIX_I "Can't draw to window\n");
440  return -1;
441  }
442  else if (attrib[i] == WGL_PIXEL_TYPE_ARB &&
443  (value[i] != WGL_TYPE_RGBA_ARB
444  && value[i] != WGL_TYPE_RGBA_FLOAT_ARB)) {
445  TRACE(PREFIX_I "Not RGBA mode\n");
446  return -1;
447  }
448  /* Check for color depth matching */
449  else if (attrib[i] == WGL_COLOR_BITS_ARB) {
450  if ((value[i] != desktop_depth)
451  && (value[i] != 32 || desktop_depth < 24)) {
452  TRACE(PREFIX_I "Current color depth != "
453  "pixel format color depth\n");
454  //return -1; /* XXX <rohannessian> Why is this a bad thing? */
455  }
456  }
457  /* hardware acceleration */
458  else if (attrib[i] == WGL_ACCELERATION_ARB) {
459  dinfo->rmethod = (value[i] == WGL_NO_ACCELERATION_ARB) ? 0 : 1;
460  }
461  /* Depths of colour buffers */
462  else if (attrib[i] == WGL_RED_BITS_ARB) {
463  dinfo->pixel_size.rgba.r = value[i];
464  }
465  else if (attrib[i] == WGL_GREEN_BITS_ARB) {
466  dinfo->pixel_size.rgba.g = value[i];
467  }
468  else if (attrib[i] == WGL_BLUE_BITS_ARB) {
469  dinfo->pixel_size.rgba.b = value[i];
470  }
471  else if (attrib[i] == WGL_ALPHA_BITS_ARB) {
472  dinfo->pixel_size.rgba.a = value[i];
473  }
474  /* Shift of color components */
475  else if (attrib[i] == WGL_RED_SHIFT_ARB) {
476  dinfo->r_shift = value[i];
477  }
478  else if (attrib[i] == WGL_GREEN_SHIFT_ARB) {
479  dinfo->g_shift = value[i];
480  }
481  else if (attrib[i] == WGL_BLUE_SHIFT_ARB) {
482  dinfo->b_shift = value[i];
483  }
484  else if (attrib[i] == WGL_ALPHA_SHIFT_ARB) {
485  dinfo->a_shift = value[i];
486  }
487 
488  /* Depths of accumulation buffer */
489  else if (attrib[i] == WGL_ACCUM_RED_BITS_ARB) {
490  dinfo->accum_size.rgba.r = value[i];
491  }
492  else if (attrib[i] == WGL_ACCUM_GREEN_BITS_ARB) {
493  dinfo->accum_size.rgba.g = value[i];
494  }
495  else if (attrib[i] == WGL_ACCUM_BLUE_BITS_ARB) {
496  dinfo->accum_size.rgba.b = value[i];
497  }
498  else if (attrib[i] == WGL_ACCUM_ALPHA_BITS_ARB) {
499  dinfo->accum_size.rgba.a = value[i];
500  }
501  /* Miscellaneous settings */
502  else if (attrib[i] == WGL_DOUBLE_BUFFER_ARB) {
503  dinfo->doublebuffered = value[i];
504  }
505  else if (attrib[i] == WGL_STEREO_ARB) {
506  dinfo->stereo = value[i];
507  }
508  else if (attrib[i] == WGL_AUX_BUFFERS_ARB) {
509  dinfo->aux_buffers = value[i];
510  }
511  else if (attrib[i] == WGL_DEPTH_BITS_ARB) {
512  dinfo->depth_size = value[i];
513  }
514  else if (attrib[i] == WGL_STENCIL_BITS_ARB) {
515  dinfo->stencil_size = value[i];
516  }
517  /* Multisampling bits */
518  else if (attrib[i] == WGL_SAMPLE_BUFFERS_ARB) {
519  dinfo->sample_buffers = value[i];
520  }
521  else if (attrib[i] == WGL_SAMPLES_ARB) {
522  dinfo->samples = value[i];
523  }
524  /* Float color */
525  if (attrib[i] == WGL_PIXEL_TYPE_ARB
526  && value[i] == WGL_TYPE_RGBA_FLOAT_ARB) {
527  dinfo->float_color = TRUE;
528  }
529  /* Float depth */
530  else if (attrib[i] == WGL_DEPTH_FLOAT_EXT) {
531  dinfo->float_depth = value[i];
532  }
533  }
534 
535  /* This bit is the same as the X code, setting some things based on
536  * what we've read out of the PFD. */
537  dinfo->colour_depth = 0;
538  if (dinfo->pixel_size.rgba.r == 5 && dinfo->pixel_size.rgba.b == 5) {
539  if (dinfo->pixel_size.rgba.g == 5)
540  dinfo->colour_depth = 15;
541  if (dinfo->pixel_size.rgba.g == 6)
542  dinfo->colour_depth = 16;
543  }
544  if (dinfo->pixel_size.rgba.r == 8
545  && dinfo->pixel_size.rgba.g == 8 && dinfo->pixel_size.rgba.b == 8) {
546  if (dinfo->pixel_size.rgba.a == 8)
547  dinfo->colour_depth = 32;
548  else
549  dinfo->colour_depth = 24;
550  }
551 
552  dinfo->allegro_format = (dinfo->colour_depth != 0)
553  && (dinfo->g_shift == dinfo->pixel_size.rgba.b)
554  && (dinfo->r_shift * dinfo->b_shift == 0)
555  && (dinfo->r_shift + dinfo->b_shift ==
556  dinfo->pixel_size.rgba.b + dinfo->pixel_size.rgba.g);
557 
558  return 0;
559 }
560 
561 
562 
563 typedef struct format_t {
564  int score;
565  int format;
566 } format_t;
567 
568 
569 
570 /* Helper function for sorting pixel formats by score */
571 static int select_pixel_format_sorter(const void *p0, const void *p1) {
572  format_t *f0 = (format_t*)p0;
573  format_t *f1 = (format_t*)p1;
574 
575  if (f0->score == f1->score) {
576  return 0;
577  }
578  else if (f0->score > f1->score) {
579  return -1;
580  }
581  else {
582  return 1;
583  }
584 }
585 
586 
587 
588 /* Describes the pixel format and assigns it a score */
589 int describe_pixel_format_old(HDC dc, int fmt, int desktop_depth,
590  format_t *formats, int *num_formats,
591  struct allegro_gl_display_info *pdinfo) {
592 
593  struct allegro_gl_display_info dinfo;
594  PIXELFORMATDESCRIPTOR pfd;
595  int score = -1;
596 
597  int result = DescribePixelFormat(dc, fmt, sizeof(pfd), &pfd);
598 
599  /* Remember old settings */
600  if (pdinfo) {
601  dinfo = *pdinfo;
602  }
603 
604  if (!result) {
605  log_win32_warning("describe_pixel_format_old",
606  "DescribePixelFormat() failed!", GetLastError());
607  return -1;
608  }
609 
610  result = !decode_pixel_format(&pfd, dc, fmt, &dinfo, desktop_depth);
611 
612  if (result) {
613  print_pixel_format(&dinfo);
614  score = __allegro_gl_score_config(fmt, &dinfo);
615  }
616 
617  if (score < 0) {
618  return -1; /* Reject non-compliant pixel formats */
619  }
620 
621  if (formats && num_formats) {
622  formats[*num_formats].score = score;
623  formats[*num_formats].format = fmt;
624  (*num_formats)++;
625  }
626 
627  if (pdinfo) {
628  *pdinfo = dinfo;
629  }
630 
631  return 0;
632 }
633 
634 
635 
636 static AGL_GetPixelFormatAttribivARB_t __wglGetPixelFormatAttribivARB = NULL;
637 static AGL_GetPixelFormatAttribivEXT_t __wglGetPixelFormatAttribivEXT = NULL;
638 
639 
640 
641 /* Describes the pixel format and assigns it a score */
642 int describe_pixel_format_new(HDC dc, int fmt, int desktop_depth,
643  format_t *formats, int *num_formats,
644  struct allegro_gl_display_info *pdinfo) {
645 
646  struct allegro_gl_display_info dinfo;
647  int score = -1;
648 
649  /* Note: Even though we use te ARB suffix, all those enums are compatible
650  * with EXT_pixel_format.
651  */
652  int attrib[] = {
653  WGL_SUPPORT_OPENGL_ARB,
654  WGL_DRAW_TO_WINDOW_ARB,
655  WGL_PIXEL_TYPE_ARB,
656  WGL_ACCELERATION_ARB,
657  WGL_DOUBLE_BUFFER_ARB,
658  WGL_DEPTH_BITS_ARB,
659  WGL_COLOR_BITS_ARB,
660  WGL_RED_BITS_ARB,
661  WGL_GREEN_BITS_ARB,
662  WGL_BLUE_BITS_ARB,
663  WGL_ALPHA_BITS_ARB,
664  WGL_RED_SHIFT_ARB,
665  WGL_GREEN_SHIFT_ARB,
666  WGL_BLUE_SHIFT_ARB,
667  WGL_ALPHA_SHIFT_ARB,
668  WGL_STENCIL_BITS_ARB,
669  WGL_STEREO_ARB,
670  WGL_ACCUM_BITS_ARB,
671  WGL_ACCUM_RED_BITS_ARB,
672  WGL_ACCUM_GREEN_BITS_ARB,
673  WGL_ACCUM_BLUE_BITS_ARB,
674  WGL_ACCUM_ALPHA_BITS_ARB,
675  WGL_AUX_BUFFERS_ARB,
676 
677  /* The following are used by extensions that add to WGL_pixel_format.
678  * If WGL_p_f isn't supported though, we can't use the (then invalid)
679  * enums. We can't use any magic number either, so we settle for
680  * replicating one. The pixel format decoder
681  * (decode_pixel_format_attrib()) doesn't care about duplicates.
682  */
683  WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_SAMPLE_BUFFERS_ARB */
684  WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_SAMPLES_ARB */
685  WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_DEPTH_FLOAT_EXT */
686  };
687 
688  const int num_attribs = sizeof(attrib) / sizeof(attrib[0]);
689  int *value = (int*)malloc(sizeof(int) * num_attribs);
690  int result;
691  BOOL ret;
692  int old_valid = __allegro_gl_valid_context;
693 
694  /* Can't allocate mem? */
695  if (!value) {
696  TRACE(PREFIX_E "describe_pixel_format_new(): Unable to allocate "
697  "memory for pixel format descriptor!\n");
698  return -1;
699  }
700 
701  /* Remember old settings */
702  if (pdinfo) {
703  dinfo = *pdinfo;
704  }
705 
706 
707  /* If multisampling is supported, query for it. Note - we need to tell
708  * allegro_gl_is_extension_supported() that we have a valid context,
709  * even though AGL is not initialized yet.
710  */
711  __allegro_gl_valid_context = 1;
712  if (allegro_gl_is_extension_supported("WGL_ARB_multisample")) {
713  attrib[num_attribs - 3] = WGL_SAMPLE_BUFFERS_ARB;
714  attrib[num_attribs - 2] = WGL_SAMPLES_ARB;
715  }
716  if (allegro_gl_is_extension_supported("WGL_EXT_depth_float")) {
717  attrib[num_attribs - 1] = WGL_DEPTH_FLOAT_EXT;
718  }
719  __allegro_gl_valid_context = old_valid;
720 
721 
722  /* Get the pf attributes */
723  if (__wglGetPixelFormatAttribivARB) {
724  ret = __wglGetPixelFormatAttribivARB(dc, fmt, 0, num_attribs,
725  attrib, value);
726  }
727  else if (__wglGetPixelFormatAttribivEXT) {
728  ret = __wglGetPixelFormatAttribivEXT(dc, fmt, 0, num_attribs,
729  attrib, value);
730  }
731  else {
732  ret = 0;
733  }
734 
735  /* wglGetPixelFormatAttrib() failed? Abort and revert to old path */
736  if (!ret) {
737  log_win32_error("describe_pixel_format_new",
738  "wglGetPixelFormatAttrib failed!", GetLastError());
739  free(value);
740  return -1;
741  }
742 
743  /* Convert to AllegroGL format for scoring */
744  result = !decode_pixel_format_attrib(&dinfo, num_attribs, attrib, value,
745  desktop_depth);
746  free(value);
747 
748  if (result) {
749  print_pixel_format(&dinfo);
750  score = __allegro_gl_score_config(fmt, &dinfo);
751  }
752 
753  if (score < 0) {
754  return 0; /* Reject non-compliant pixel formats */
755  }
756 
757  if (formats && num_formats) {
758  formats[*num_formats].score = score;
759  formats[*num_formats].format = fmt;
760  (*num_formats)++;
761  }
762 
763  if (pdinfo) {
764  *pdinfo = dinfo;
765  }
766 
767  return 0;
768 }
769 
770 
771 
772 /* Returns the number of pixel formats we should investigate */
773 int get_num_pixel_formats(HDC dc, int *new_pf_code) {
774 
775  /* DescribePixelFormat() returns maximum pixel format index in the old
776  * code. wglGetPixelFormatAttribivARB() does it in the new code.
777  */
778  if (new_pf_code && *new_pf_code) {
779  int attrib[1];
780  int value[1];
781 
782  TRACE(PREFIX_I "get_num_pixel_formats(): Attempting to use WGL_pf.\n");
783  attrib[0] = WGL_NUMBER_PIXEL_FORMATS_ARB;
784  if ((__wglGetPixelFormatAttribivARB
785  && __wglGetPixelFormatAttribivARB(dc, 0, 0, 1, attrib, value)
786  == GL_FALSE)
787  || (__wglGetPixelFormatAttribivEXT
788  && __wglGetPixelFormatAttribivEXT(dc, 0, 0, 1, attrib, value)
789  == GL_FALSE)) {
790  log_win32_note("get_num_pixel_formats",
791  "WGL_ARB/EXT_pixel_format use failed!", GetLastError());
792  *new_pf_code = 0;
793  }
794  else {
795  return value[0];
796  }
797  }
798 
799  if (!new_pf_code || !*new_pf_code) {
800  PIXELFORMATDESCRIPTOR pfd;
801  int ret;
802 
803  TRACE(PREFIX_I "get_num_pixel_formats(): Using DescribePixelFormat.\n");
804  ret = DescribePixelFormat(dc, 1, sizeof(pfd), &pfd);
805 
806  if (!ret) {
807  log_win32_error("get_num_pixel_formats",
808  "DescribePixelFormat failed!", GetLastError());
809  }
810 
811  return ret;
812  }
813 
814  return 0;
815 }
816 
817 
818 
819 /* Pick the best matching pixel format */
820 static int select_pixel_format(PIXELFORMATDESCRIPTOR * pfd)
821 {
822  int i;
823  int result, maxindex;
824  int desktop_depth;
825 
826  HWND testwnd = NULL;
827  HDC testdc = NULL;
828  HGLRC testrc = NULL;
829 
830  format_t *format = NULL;
831  int num_formats = 0;
832  int new_pf_code = 0;
833 
834 
835  __allegro_gl_reset_scorer();
836 
837  /* Read again the desktop depth */
838  desktop_depth = desktop_color_depth();
839 
840  if (register_test_window() < 0) {
841  return 0;
842  }
843 
844  testwnd = create_test_window();
845 
846  if (!testwnd) {
847  return 0;
848  }
849 
850  testdc = GetDC(testwnd);
851 
852  /* Check if we can support new pixel format code */
853  TRACE(PREFIX_I "select_pixel_format(): Trying to set up temporary RC\n");
854  {
855  HDC old_dc = __allegro_gl_hdc;
856  int old_valid = __allegro_gl_valid_context;
857  PIXELFORMATDESCRIPTOR pfd;
858  int pf;
859 
860  new_pf_code = 0;
861 
862  /* We need to create a dummy window with a pixel format to get the
863  * list of valid PFDs
864  */
865  memset(&pfd, 0, sizeof(pfd));
866  pfd.nSize = sizeof(pfd);
867  pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL
868  | PFD_DOUBLEBUFFER_DONTCARE | PFD_STEREO_DONTCARE;
869  pfd.iPixelType = PFD_TYPE_RGBA;
870  pfd.iLayerType = PFD_MAIN_PLANE;
871  pfd.cColorBits = 32;
872 
873  TRACE(PREFIX_I "select_pixel_format(): ChoosePixelFormat()\n");
874  pf = ChoosePixelFormat(testdc, &pfd);
875 
876  if (!pf) {
877  log_win32_warning("select_pixel_format",
878  "Unable to chose a temporary pixel format!",
879  GetLastError());
880  goto fail_pf;
881  }
882 
883  /* Set up a GL context there */
884  TRACE(PREFIX_I "select_pixel_format(): SetPixelFormat()\n");
885  memset(&pfd, 0, sizeof(pfd));
886  if (!SetPixelFormat(testdc, pf, &pfd)) {
887  log_win32_warning("select_pixel_format",
888  "Unable to set a temporary pixel format!",
889  GetLastError());
890  goto fail_pf;
891  }
892 
893  TRACE(PREFIX_I "select_pixel_format(): CreateContext()\n");
894  testrc = wglCreateContext(testdc);
895 
896  if (!testrc) {
897  log_win32_warning("select_pixel_format",
898  "Unable to create a render context!",
899  GetLastError());
900  goto fail_pf;
901  }
902 
903  TRACE(PREFIX_I "select_pixel_format(): MakeCurrent()\n");
904  if (!wglMakeCurrent(testdc, testrc)) {
905  log_win32_warning("select_pixel_format",
906  "Unable to set the render context as current!",
907  GetLastError());
908  goto fail_pf;
909  }
910 
911  __allegro_gl_hdc = testdc;
912  __allegro_gl_valid_context = TRUE;
913 
914 
915  /* This is a workaround for a bug in old NVidia drivers. We need to
916  * call wglGetExtensionsStringARB() for it to properly initialize.
917  */
918  TRACE(PREFIX_I "select_pixel_format(): GetExtensionsStringARB()\n");
919  if (strstr((AL_CONST char*)glGetString(GL_VENDOR), "NVIDIA")) {
920  AGL_GetExtensionsStringARB_t __wglGetExtensionsStringARB = NULL;
921 
922  __wglGetExtensionsStringARB = (AGL_GetExtensionsStringARB_t)
923  wglGetProcAddress("wglGetExtensionsStringARB");
924 
925  TRACE(PREFIX_I "select_pixel_format(): Querying for "
926  "WGL_ARB_extension_string\n");
927 
928  if (__wglGetExtensionsStringARB) {
929  TRACE(PREFIX_I "select_pixel_format(): Calling "
930  "__wglGetExtensionsStringARB\n");
931  __wglGetExtensionsStringARB(testdc);
932  }
933  }
934 
935 
936  /* Check that we support ARB/EXT_pixel_format */
937  if (!allegro_gl_is_extension_supported("WGL_ARB_pixel_format")
938  && !allegro_gl_is_extension_supported("WGL_EXT_pixel_format")) {
939  TRACE(PREFIX_I "select_pixel_format(): WGL_ARB/EXT_pf unsupported.\n");
940  goto fail_pf;
941  }
942 
943  /* Load the ARB_p_f symbol - Note, we shouldn't use the AGL extension
944  * mechanism here, because AGL hasn't been initialized yet!
945  */
946  TRACE(PREFIX_I "select_pixel_format(): GetProcAddress()\n");
947  __wglGetPixelFormatAttribivARB = (AGL_GetPixelFormatAttribivARB_t)
948  wglGetProcAddress("wglGetPixelFormatAttribivARB");
949  __wglGetPixelFormatAttribivEXT = (AGL_GetPixelFormatAttribivEXT_t)
950  wglGetProcAddress("wglGetPixelFormatAttribivEXT");
951 
952  if (!__wglGetPixelFormatAttribivARB
953  && !__wglGetPixelFormatAttribivEXT) {
954  TRACE(PREFIX_E "select_pixel_format(): WGL_ARB/EXT_pf not "
955  "correctly supported!\n");
956  goto fail_pf;
957  }
958 
959  new_pf_code = 1;
960  goto exit_pf;
961 
962 fail_pf:
963  wglMakeCurrent(NULL, NULL);
964  if (testrc) {
965  wglDeleteContext(testrc);
966  }
967  testrc = NULL;
968 
969  __wglGetPixelFormatAttribivARB = NULL;
970  __wglGetPixelFormatAttribivEXT = NULL;
971 exit_pf:
972  __allegro_gl_hdc = old_dc;
973  __allegro_gl_valid_context = old_valid;
974  }
975 
976  maxindex = get_num_pixel_formats(testdc, &new_pf_code);
977 
978  /* Check if using the new pf code failed. Likely due to driver bug.
979  * maxindex is still valid though, so we can continue.
980  */
981  if (!new_pf_code && testrc) {
982  TRACE(PREFIX_W "select_pixel_format(): WGL_ARB_pf call failed - "
983  "reverted to plain old WGL.\n");
984  wglMakeCurrent(NULL, NULL);
985  wglDeleteContext(testrc);
986  testrc = NULL;
987  __wglGetPixelFormatAttribivARB = NULL;
988  __wglGetPixelFormatAttribivEXT = NULL;
989  }
990 
991  TRACE(PREFIX_I "select_pixel_format(): %i formats.\n", maxindex);
992 
993  if (maxindex < 1) {
994  TRACE(PREFIX_E "select_pixel_format(): Didn't find any pixel "
995  "formats at all!\n");
996  goto bail;
997  }
998 
999  format = malloc((maxindex + 1) * sizeof(format_t));
1000 
1001  if (!format) {
1002  TRACE(PREFIX_E "select_pixel_format(): Unable to allocate memory for "
1003  "pixel format scores!\n");
1004  goto bail;
1005  }
1006 
1007  /* First, pixel formats are sorted by decreasing order */
1008  TRACE(PREFIX_I "select_pixel_format(): Testing pixel formats:\n");
1009  for (i = 1; i <= maxindex; i++) {
1010 
1011  int use_old = !new_pf_code;
1012 
1013  TRACE(PREFIX_I "Format %i:\n", i);
1014 
1015  if (new_pf_code) {
1016  if (describe_pixel_format_new(testdc, i, desktop_depth,
1017  format, &num_formats, NULL) < 0) {
1018  TRACE(PREFIX_W "select_pixel_format(): Wasn't able to use "
1019  "WGL_PixelFormat - reverting to old WGL code.\n");
1020  use_old = 1;
1021  }
1022  }
1023 
1024  if (use_old) {
1025  if (describe_pixel_format_old(testdc, i, desktop_depth,
1026  format, &num_formats, NULL) < 0) {
1027  TRACE(PREFIX_W "select_pixel_format(): Unable to rely on "
1028  "unextended WGL to describe this pixelformat.\n");
1029  }
1030  }
1031  }
1032 
1033  if (new_pf_code) {
1034  wglMakeCurrent(NULL, NULL);
1035  wglDeleteContext(testrc);
1036  testrc = NULL;
1037  }
1038  if (testwnd) {
1039  ReleaseDC(testwnd, testdc);
1040  testdc = NULL;
1041  DestroyWindow(testwnd);
1042  testwnd = NULL;
1043  }
1044 
1045  if (num_formats < 1) {
1046  TRACE(PREFIX_E "select_pixel_format(): Didn't find any available "
1047  "pixel formats!\n");
1048  goto bail;
1049  }
1050 
1051  qsort(format, num_formats, sizeof(format_t), select_pixel_format_sorter);
1052 
1053 
1054  /* Sorted pixel formats are tested until one of them succeeds to
1055  * make a GL context current */
1056  for (i = 0; i < num_formats ; i++) {
1057  HGLRC rc;
1058 
1059  /* Recreate our test windows */
1060  testwnd = create_test_window();
1061  testdc = GetDC(testwnd);
1062 
1063  if (SetPixelFormat(testdc, format[i].format, pfd)) {
1064  rc = wglCreateContext(testdc);
1065  if (!rc) {
1066  TRACE(PREFIX_I "select_pixel_format(): Unable to create RC!\n");
1067  }
1068  else {
1069  if (wglMakeCurrent(testdc, rc)) {
1070  wglMakeCurrent(NULL, NULL);
1071  wglDeleteContext(rc);
1072  rc = NULL;
1073 
1074  TRACE(PREFIX_I "select_pixel_format(): Best config is: %i"
1075  "\n", format[i].format);
1076 
1077  /* XXX <rohannessian> DescribePixelFormat may fail on
1078  * extended pixel format (WGL_ARB_p_f)
1079  */
1080  if (!DescribePixelFormat(testdc, format[i].format,
1081  sizeof *pfd, pfd)) {
1082  TRACE(PREFIX_E "Cannot describe this pixel format\n");
1083  ReleaseDC(testwnd, testdc);
1084  DestroyWindow(testwnd);
1085  testdc = NULL;
1086  testwnd = NULL;
1087  continue;
1088  }
1089 
1090  ReleaseDC(testwnd, testdc);
1091  DestroyWindow(testwnd);
1092 
1093  result = format[i].format;
1094 
1095  free(format);
1096  return result;
1097  }
1098  else {
1099  wglMakeCurrent(NULL, NULL);
1100  wglDeleteContext(rc);
1101  rc = NULL;
1102  log_win32_warning("select_pixel_format",
1103  "Couldn't make the temporary render context "
1104  "current for the this pixel format.",
1105  GetLastError());
1106  }
1107  }
1108  }
1109  else {
1110  log_win32_note("select_pixel_format",
1111  "Unable to set pixel format!", GetLastError());
1112  }
1113 
1114  ReleaseDC(testwnd, testdc);
1115  DestroyWindow(testwnd);
1116  testdc = NULL;
1117  testwnd = NULL;
1118  }
1119 
1120  TRACE(PREFIX_E "select_pixel_format(): All modes have failed...\n");
1121 bail:
1122  if (format) {
1123  free(format);
1124  }
1125  if (new_pf_code) {
1126  wglMakeCurrent(NULL, NULL);
1127  if (testrc) {
1128  wglDeleteContext(testrc);
1129  }
1130  }
1131  if (testwnd) {
1132  ReleaseDC(testwnd, testdc);
1133  DestroyWindow(testwnd);
1134  }
1135 
1136  return 0;
1137 }
1138 
1139 
1140 
1141 static void allegrogl_init_window(int w, int h, DWORD style, DWORD exstyle)
1142 {
1143  RECT rect;
1144 
1145 #define req __allegro_gl_required_settings
1146 #define sug __allegro_gl_suggested_settings
1147 
1148  int x = 32, y = 32;
1149 
1150  if (req & AGL_WINDOW_X || sug & AGL_WINDOW_X)
1151  x = allegro_gl_display_info.x;
1152  if (req & AGL_WINDOW_Y || sug & AGL_WINDOW_Y)
1153  y = allegro_gl_display_info.y;
1154 
1155 #undef req
1156 #undef sug
1157 
1158  if (!fullscreen) {
1159  rect.left = x;
1160  rect.right = x + w;
1161  rect.top = y;
1162  rect.bottom = y + h;
1163  }
1164  else {
1165  rect.left = 0;
1166  rect.right = w;
1167  rect.top = 0;
1168  rect.bottom = h;
1169  }
1170 
1171  /* save original Allegro styles */
1172  style_saved = GetWindowLong(wnd, GWL_STYLE);
1173  exstyle_saved = GetWindowLong(wnd, GWL_EXSTYLE);
1174 
1175  /* set custom AllegroGL style */
1176  SetWindowLong(wnd, GWL_STYLE, style);
1177  SetWindowLong(wnd, GWL_EXSTYLE, exstyle);
1178 
1179  if (!fullscreen) {
1180  AdjustWindowRectEx(&rect, style, FALSE, exstyle);
1181  }
1182 
1183  /* make the changes visible */
1184  SetWindowPos(wnd, 0, rect.left, rect.top,
1185  rect.right - rect.left, rect.bottom - rect.top,
1186  SWP_NOZORDER | SWP_FRAMECHANGED);
1187 
1188  return;
1189 }
1190 
1191 
1192 
1193 static BITMAP *allegro_gl_create_screen (GFX_DRIVER *drv, int w, int h,
1194  int depth)
1195 {
1196  BITMAP *bmp;
1197  int is_linear = drv->linear;
1198 
1199  drv->linear = 1;
1200  bmp = _make_bitmap (w, h, 0, drv, depth, 0);
1201 
1202  if (!bmp) {
1203  return NULL;
1204  }
1205 
1206  bmp->id = BMP_ID_VIDEO | 1000;
1207  drv->linear = is_linear;
1208 
1209  drv->w = w;
1210  drv->h = h;
1211 
1212  return bmp;
1213 }
1214 
1215 
1216 static LRESULT CALLBACK dummy_wnd_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
1217 {
1218  return DefWindowProc(wnd, message, wparam, lparam);
1219 }
1220 
1221 static HWND dummy_wnd;
1222 
1223 static void dummy_window(void)
1224 {
1225  WNDCLASS wnd_class;
1226 
1227  wnd_class.style = CS_HREDRAW | CS_VREDRAW;
1228  wnd_class.lpfnWndProc = dummy_wnd_proc;
1229  wnd_class.cbClsExtra = 0;
1230  wnd_class.cbWndExtra = 0;
1231  wnd_class.hInstance = GetModuleHandle(NULL);
1232  wnd_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1233  wnd_class.hCursor = LoadCursor(NULL, IDC_ARROW);
1234  wnd_class.hbrBackground = NULL;
1235  wnd_class.lpszMenuName = NULL;
1236  wnd_class.lpszClassName = "allegro focus";
1237 
1238  RegisterClass(&wnd_class);
1239 
1240  dummy_wnd = CreateWindow("allegro focus", "Allegro", WS_POPUP | WS_VISIBLE,
1241  0, 0, 200, 200,
1242  NULL, NULL, GetModuleHandle(NULL), NULL);
1243 
1244  ShowWindow(dummy_wnd, SW_SHOWNORMAL);
1245  SetForegroundWindow(dummy_wnd);
1246 }
1247 
1248 static void remove_dummy_window(void)
1249 {
1250  DestroyWindow(dummy_wnd);
1251  UnregisterClass("allegro focus", GetModuleHandle(NULL));
1252 }
1253 
1254 
1255 static BITMAP *allegro_gl_win_init(int w, int h, int v_w, int v_h)
1256 {
1257  static int first_time = 1;
1258 
1259  DWORD style=0, exstyle=0;
1260  int refresh_rate = _refresh_rate_request;
1261  int desktop_depth;
1262  int pf=0;
1263 
1264  new_w = w;
1265  new_h = h;
1266 
1267  /* virtual screen are not supported */
1268  if ((v_w != 0 && v_w != w) || (v_h != 0 && v_h != h)) {
1269  TRACE(PREFIX_E "win_init(): Virtual screens are not supported in "
1270  "AllegroGL!\n");
1271  return NULL;
1272  }
1273 
1274  /* Fill in missing color depth info */
1275  __allegro_gl_fill_in_info();
1276 
1277  /* Be sure the current desktop color depth is at least 15bpp */
1278  /* We may want to change this, so try to set a better depth, or
1279  to at least report an error somehow */
1280  desktop_depth = desktop_color_depth();
1281 
1282  if (desktop_depth < 15)
1283  return NULL;
1284 
1285  TRACE(PREFIX_I "win_init(): Requested color depth: %i "
1286  "Desktop color depth: %i\n", allegro_gl_display_info.colour_depth,
1287  desktop_depth);
1288 
1289  /* In the moment the main window is destroyed, Allegro loses focus, and
1290  * focus can only be returned by actual user input under Windows XP. So
1291  * we need to create a dummy window which retains focus for us, until
1292  * the new window is up.
1293  */
1294  if (fullscreen) dummy_window();
1295 
1296  /* Need to set the w and h driver members at this point to avoid assertion
1297  * failure in set_mouse_range() when win_set_window() is called.
1298  */
1299  if (fullscreen) {
1300  gfx_allegro_gl_fullscreen.w = w;
1301  gfx_allegro_gl_fullscreen.h = h;
1302  }
1303  else {
1304  gfx_allegro_gl_windowed.w = w;
1305  gfx_allegro_gl_windowed.h = h;
1306  }
1307 
1308  /* request a fresh new window from Allegro... */
1309  /* Set a NULL window to get Allegro to generate a new HWND. This is needed
1310  * because we can only set the pixel format once per window. Thus, calling
1311  * set_gfx_mode() multiple times will fail without this code.
1312  */
1313  if (!first_time) {
1314  win_set_window(NULL);
1315  }
1316  first_time = 0;
1317 
1318  /* ...and retrieve its handle */
1319  wnd = win_get_window();
1320  if (!wnd)
1321  return NULL;
1322 
1323  /* set up the AllegroGL window */
1324  if (fullscreen) {
1325  style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
1326  exstyle = WS_EX_APPWINDOW | WS_EX_TOPMOST;
1327  }
1328  else {
1329  style = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_CLIPCHILDREN
1330  | WS_CLIPSIBLINGS;
1331  exstyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
1332  }
1333 
1334  TRACE(PREFIX_I "win_init(): Setting up window.\n");
1335  allegrogl_init_window(w, h, style, exstyle);
1336 
1337  __allegro_gl_hdc = GetDC(wnd); /* get the device context of our window */
1338  if (!__allegro_gl_hdc) {
1339  goto Error;
1340  }
1341 
1342  TRACE(PREFIX_I "win_init(): Driver selected fullscreen: %s\n",
1343  fullscreen ? "Yes" : "No");
1344 
1345  if (fullscreen)
1346  {
1347  DEVMODE dm;
1348  DEVMODE fallback_dm;
1349  int fallback_dm_valid = 0;
1350 
1351  int bpp_to_check[] = {16, 32, 24, 15, 0};
1352  int bpp_checked[] = {0, 0, 0, 0, 0};
1353  int bpp_index = 0;
1354  int i, j, result, modeswitch, done = 0;
1355 
1356  for (j = 0; j < 4; j++)
1357  {
1358  if (bpp_to_check[j] == allegro_gl_get(AGL_COLOR_DEPTH))
1359  {
1360  bpp_index = j;
1361  break;
1362  }
1363  }
1364 
1365  dm.dmSize = sizeof(DEVMODE);
1366  dm_saved.dmSize = sizeof(DEVMODE);
1367 
1368  /* Save old mode */
1369  EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm_saved);
1370  dm.dmBitsPerPel = desktop_depth; /* Go around Win95's bug */
1371 
1372  do
1373  {
1374  if (!bpp_to_check[bpp_index])
1375  {
1376  TRACE(PREFIX_E "win_init(): No more color depths to test.\n"
1377  "\tUnable to find appropriate full screen mode and pixel "
1378  "format.\n");
1379  goto Error;
1380  }
1381 
1382  TRACE(PREFIX_I "win_init(): Testing color depth: %i\n",
1383  bpp_to_check[bpp_index]);
1384 
1385  memset(&dm, 0, sizeof(DEVMODE));
1386  dm.dmSize = sizeof(DEVMODE);
1387 
1388  i = 0;
1389  do
1390  {
1391  modeswitch = EnumDisplaySettings(NULL, i, &dm);
1392  if (!modeswitch)
1393  break;
1394 
1395  if ((dm.dmPelsWidth == (unsigned) w)
1396  && (dm.dmPelsHeight == (unsigned) h)
1397  && (dm.dmBitsPerPel == (unsigned) bpp_to_check[bpp_index])
1398  && (dm.dmDisplayFrequency != (unsigned) refresh_rate)) {
1399  /* Keep it as fallback if refresh rate request could not
1400  * be satisfied. Try to get as close to 60Hz as possible though,
1401  * it's a bit better for a fallback than just blindly picking
1402  * something like 47Hz or 200Hz.
1403  */
1404  if (!fallback_dm_valid) {
1405  fallback_dm = dm;
1406  fallback_dm_valid = 1;
1407  }
1408  else if (dm.dmDisplayFrequency >= 60) {
1409  if (dm.dmDisplayFrequency < fallback_dm.dmDisplayFrequency) {
1410  fallback_dm = dm;
1411  }
1412  }
1413  }
1414 
1415  i++;
1416  }
1417  while ((dm.dmPelsWidth != (unsigned) w)
1418  || (dm.dmPelsHeight != (unsigned) h)
1419  || (dm.dmBitsPerPel != (unsigned) bpp_to_check[bpp_index])
1420  || (dm.dmDisplayFrequency != (unsigned) refresh_rate));
1421 
1422  if (!modeswitch && !fallback_dm_valid) {
1423  TRACE(PREFIX_I "win_init(): Unable to set mode, continuing "
1424  "with next color depth\n");
1425  }
1426  else {
1427  if (!modeswitch && fallback_dm_valid)
1428  dm = fallback_dm;
1429 
1430  TRACE(PREFIX_I "win_init(): bpp_to_check[bpp_index] = %i\n",
1431  bpp_to_check[bpp_index]);
1432  TRACE(PREFIX_I "win_init(): dm.dmBitsPerPel = %i\n",
1433  (int)dm.dmBitsPerPel);
1434 
1435  dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL
1436  | DM_DISPLAYFREQUENCY;
1437 
1438  result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
1439 
1440  if (result == DISP_CHANGE_SUCCESSFUL)
1441  {
1442  TRACE(PREFIX_I "win_init(): Setting pixel format.\n");
1443  pf = select_pixel_format(&pfd);
1444  if (pf) {
1445  TRACE(PREFIX_I "mode found\n");
1446  _set_current_refresh_rate(dm.dmDisplayFrequency);
1447  done = 1;
1448  }
1449  else {
1450  TRACE(PREFIX_I "win_init(): Couldn't find compatible "
1451  "GL context. Trying another screen mode.\n");
1452  }
1453  }
1454  }
1455 
1456  fallback_dm_valid = 0;
1457  bpp_checked[bpp_index] = 1;
1458 
1459  bpp_index = 0;
1460  while (bpp_checked[bpp_index]) {
1461  bpp_index++;
1462  }
1463  } while (!done);
1464  }
1465  else {
1466  DEVMODE dm;
1467 
1468  memset(&dm, 0, sizeof(DEVMODE));
1469  dm.dmSize = sizeof(DEVMODE);
1470  if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) != 0) {
1471  _set_current_refresh_rate(dm.dmDisplayFrequency);
1472  }
1473  }
1474 
1475  if (!fullscreen) {
1476  TRACE(PREFIX_I "win_init(): Setting pixel format.\n");
1477  pf = select_pixel_format(&pfd);
1478  if (pf == 0)
1479  goto Error;
1480  }
1481 
1482  /* set the pixel format */
1483  if (!SetPixelFormat(__allegro_gl_hdc, pf, &pfd)) {
1484  log_win32_error("win_init",
1485  "Unable to set pixel format.",
1486  GetLastError());
1487  goto Error;
1488  }
1489 
1490  /* create an OpenGL context */
1491  allegro_glrc = wglCreateContext(__allegro_gl_hdc);
1492 
1493  if (!allegro_glrc) { /* make the context the current one */
1494  log_win32_error("win_init",
1495  "Unable to create a render context!",
1496  GetLastError());
1497  goto Error;
1498  }
1499  if (!wglMakeCurrent(__allegro_gl_hdc, allegro_glrc)) {
1500  log_win32_error("win_init",
1501  "Unable to make the context current!",
1502  GetLastError());
1503  goto Error;
1504  }
1505 
1506 
1507  if (__wglGetPixelFormatAttribivARB || __wglGetPixelFormatAttribivEXT) {
1508  describe_pixel_format_new(__allegro_gl_hdc, pf, desktop_depth,
1509  NULL, NULL, &allegro_gl_display_info);
1510  }
1511  else {
1512  describe_pixel_format_old(__allegro_gl_hdc, pf, desktop_depth,
1513  NULL, NULL, &allegro_gl_display_info);
1514  }
1515 
1516 
1517  __allegro_gl_set_allegro_image_format(FALSE);
1518  set_color_depth(allegro_gl_display_info.colour_depth);
1519  allegro_gl_display_info.w = w;
1520  allegro_gl_display_info.h = h;
1521 
1522 
1523  /* <rohannessian> Win98/2k/XP's window forground rules don't let us
1524  * make our window the topmost window on launch. This causes issues on
1525  * full-screen apps, as DInput loses input focus on them.
1526  * We use this trick to force the window to be topmost, when switching
1527  * to full-screen only. Note that this only works for Win98 and greater.
1528  * Win95 will ignore our SystemParametersInfo() calls.
1529  *
1530  * See http://support.microsoft.com:80/support/kb/articles/Q97/9/25.asp
1531  * for details.
1532  */
1533  {
1534  DWORD lock_time;
1535 
1536 #define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000
1537 #define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001
1538  if (fullscreen) {
1539  SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,
1540  0, (LPVOID)&lock_time, 0);
1541  SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
1542  0, (LPVOID)0,
1543  SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
1544  }
1545 
1546  ShowWindow(wnd, SW_SHOWNORMAL);
1547  SetForegroundWindow(wnd);
1548  /* In some rare cases, it doesn't seem to work without the loop. And we
1549  * absolutely need this to succeed, else we trap the user in a
1550  * fullscreen window without input.
1551  */
1552  while (GetForegroundWindow() != wnd) {
1553  rest(100);
1554  SetForegroundWindow(wnd);
1555  }
1556  UpdateWindow(wnd);
1557 
1558  if (fullscreen) {
1559  SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
1560  0, (LPVOID)lock_time,
1561  SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
1562  }
1563 #undef SPI_GETFOREGROUNDLOCKTIMEOUT
1564 #undef SPI_SETFOREGROUNDLOCKTIMEOUT
1565  }
1566 
1567  win_grab_input();
1568 
1569  if (fullscreen) {
1570  allegro_gl_screen= allegro_gl_create_screen(&gfx_allegro_gl_fullscreen,
1572  }
1573  else {
1574  allegro_gl_screen= allegro_gl_create_screen(&gfx_allegro_gl_windowed,
1576  }
1577 
1578  if (!allegro_gl_screen) {
1579  ChangeDisplaySettings(NULL, 0);
1580  goto Error;
1581  }
1582 
1583 
1584  TRACE(PREFIX_I "win_init(): GLScreen: %ix%ix%i\n",
1586 
1587  allegro_gl_screen->id |= BMP_ID_VIDEO | BMP_ID_MASK;
1588 
1589  __allegro_gl_valid_context = TRUE;
1590  __allegro_gl_driver = &allegro_gl_win;
1591  initialized = 1;
1592 
1593  /* Print out OpenGL version info */
1594  TRACE(PREFIX_I "OpenGL Version: %s\n", (AL_CONST char*)glGetString(GL_VERSION));
1595  TRACE(PREFIX_I "Vendor: %s\n", (AL_CONST char*)glGetString(GL_VENDOR));
1596  TRACE(PREFIX_I "Renderer: %s\n\n", (AL_CONST char*)glGetString(GL_RENDERER));
1597 
1598  /* Detect if the GL driver is based on Mesa */
1599  allegro_gl_info.is_mesa_driver = FALSE;
1600  if (strstr((AL_CONST char*)glGetString(GL_VERSION),"Mesa")) {
1601  AGL_LOG(1, "OpenGL driver based on Mesa\n");
1602  allegro_gl_info.is_mesa_driver = TRUE;
1603  }
1604 
1605  /* init the GL extensions */
1606  __allegro_gl_manage_extensions();
1607 
1608  /* Update screen vtable in order to use AGL's */
1609  __allegro_gl__glvtable_update_vtable(&allegro_gl_screen->vtable);
1610  memcpy(&_screen_vtable, allegro_gl_screen->vtable, sizeof(GFX_VTABLE));
1611  allegro_gl_screen->vtable = &_screen_vtable;
1612 
1613  /* Print out WGL extension info */
1614  if (wglGetExtensionsStringARB) {
1615  AGL_LOG(1, "WGL Extensions :\n");
1616 #if LOGLEVEL >= 1
1617  __allegro_gl_print_extensions((AL_CONST char*)wglGetExtensionsStringARB(wglGetCurrentDC()));
1618 #endif
1619  }
1620  else {
1621  TRACE(PREFIX_I "win_init(): No WGL Extensions available\n");
1622  }
1623 
1624  gfx_capabilities |= GFX_HW_CURSOR;
1625 
1626  /* Initialize a reasonable viewport. Those should be OpenGL defaults,
1627  * but some drivers don't implement this correctly.
1628  */
1629  glViewport(0, 0, SCREEN_W, SCREEN_H);
1630  glMatrixMode(GL_PROJECTION);
1631  glLoadIdentity();
1632  glMatrixMode(GL_MODELVIEW);
1633  glLoadIdentity();
1634 
1635  if (allegro_gl_extensions_GL.ARB_multisample) {
1636  /* Workaround some "special" drivers that do not export the extension
1637  * once it was promoted to core.*/
1638  if (allegro_gl_opengl_version() >= 1.3)
1639  glSampleCoverage(1.0, GL_FALSE);
1640  else
1641  glSampleCoverageARB(1.0, GL_FALSE);
1642  }
1643 
1644  /* Set up some variables that some GL drivers omit */
1645  glBindTexture(GL_TEXTURE_2D, 0);
1646 
1647  screen = allegro_gl_screen;
1648 
1649  if (fullscreen)
1650  remove_dummy_window();
1651 
1652  return allegro_gl_screen;
1653 
1654 Error:
1655  if (allegro_glrc) {
1656  wglDeleteContext(allegro_glrc);
1657  }
1658  if (__allegro_gl_hdc) {
1659  ReleaseDC(wnd, __allegro_gl_hdc);
1660  }
1661  __allegro_gl_hdc = NULL;
1662  ChangeDisplaySettings(NULL, 0);
1663  allegro_gl_win_exit(NULL);
1664 
1665  return NULL;
1666 }
1667 
1668 
1669 
1670 static BITMAP *allegro_gl_win_init_windowed(int w, int h, int v_w, int v_h,
1671  int color_depth)
1672 {
1673  fullscreen = 0;
1674  return allegro_gl_win_init(w, h, v_w, v_h);
1675 }
1676 
1677 
1678 
1679 static BITMAP *allegro_gl_win_init_fullscreen(int w, int h, int v_w, int v_h,
1680  int color_depth)
1681 {
1682  fullscreen = 1;
1683  return allegro_gl_win_init(w, h, v_w, v_h);
1684 }
1685 
1686 
1687 
1688 static void allegro_gl_win_exit(struct BITMAP *b)
1689 {
1690  /* XXX <rohannessian> For some reason, uncommenting this line will blank
1691  * out the log file.
1692  */
1693  //TRACE(PREFIX_I "allegro_gl_win_exit: Shutting down.\n");
1694  __allegro_gl_unmanage_extensions();
1695 
1696  if (allegro_glrc) {
1697  wglDeleteContext(allegro_glrc);
1698  allegro_glrc = NULL;
1699  }
1700 
1701  if (__allegro_gl_hdc) {
1702  ReleaseDC(wnd, __allegro_gl_hdc);
1703  __allegro_gl_hdc = NULL;
1704  }
1705 
1706  if (fullscreen && initialized) {
1707  /* Restore screen */
1708  ChangeDisplaySettings(NULL, 0);
1709  _set_current_refresh_rate(0);
1710  }
1711  initialized = 0;
1712 
1713  /* Note: Allegro will destroy screen (== allegro_gl_screen),
1714  * so don't destroy it here.
1715  */
1716  //destroy_bitmap(allegro_gl_screen);
1717  allegro_gl_screen = NULL;
1718 
1719  /* hide the window */
1720  system_driver->restore_console_state();
1721 
1722  /* restore original Allegro styles */
1723  SetWindowLong(wnd, GWL_STYLE, style_saved);
1724  SetWindowLong(wnd, GWL_EXSTYLE, exstyle_saved);
1725  SetWindowPos(wnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER
1726  | SWP_FRAMECHANGED);
1727 
1728  __allegro_gl_valid_context = FALSE;
1729 
1730  return;
1731 }
1732 
1733 
1734 /*
1735  Returns TRUE is dm doesn't match any mode in mode_list, FALSE otherwise.
1736 */
1737 static int is_mode_entry_unique(GFX_MODE_LIST *mode_list, DEVMODE *dm) {
1738  int i;
1739 
1740  for (i = 0; i < mode_list->num_modes; ++i) {
1741  if (mode_list->mode[i].width == (int)dm->dmPelsWidth
1742  && mode_list->mode[i].height == (int)dm->dmPelsHeight
1743  && mode_list->mode[i].bpp == (int)dm->dmBitsPerPel)
1744  return FALSE;
1745  }
1746 
1747  return TRUE;
1748 }
1749 
1750 
1751 
1752 /* Returns a list of valid video modes */
1753 static GFX_MODE_LIST* allegro_gl_win_fetch_mode_list(void)
1754 {
1755  int c, modes_count;
1756  GFX_MODE_LIST *mode_list;
1757  DEVMODE dm;
1758 
1759  dm.dmSize = sizeof(DEVMODE);
1760 
1761  /* Allocate space for mode list. */
1762  mode_list = malloc(sizeof(GFX_MODE_LIST));
1763  if (!mode_list) {
1764  return NULL;
1765  }
1766 
1767  /* Allocate and fill the first mode in case EnumDisplaySettings fails at
1768  * first call.
1769  */
1770  mode_list->mode = malloc(sizeof(GFX_MODE));
1771  if (!mode_list->mode) {
1772  free(mode_list);
1773  return NULL;
1774  }
1775  mode_list->mode[0].width = 0;
1776  mode_list->mode[0].height = 0;
1777  mode_list->mode[0].bpp = 0;
1778  mode_list->num_modes = 0;
1779 
1780  modes_count = 0;
1781  c = 0;
1782  while (EnumDisplaySettings(NULL, c, &dm)) {
1783  mode_list->mode = realloc(mode_list->mode,
1784  sizeof(GFX_MODE) * (modes_count + 2));
1785  if (!mode_list->mode) {
1786  free(mode_list);
1787  return NULL;
1788  }
1789 
1790  /* Filter modes with bpp lower than 9, and those which are already
1791  * in there.
1792  */
1793  if (dm.dmBitsPerPel > 8 && is_mode_entry_unique(mode_list, &dm)) {
1794  mode_list->mode[modes_count].width = dm.dmPelsWidth;
1795  mode_list->mode[modes_count].height = dm.dmPelsHeight;
1796  mode_list->mode[modes_count].bpp = dm.dmBitsPerPel;
1797  ++modes_count;
1798  mode_list->mode[modes_count].width = 0;
1799  mode_list->mode[modes_count].height = 0;
1800  mode_list->mode[modes_count].bpp = 0;
1801  mode_list->num_modes = modes_count;
1802  }
1803  ++c;
1804  };
1805 
1806  return mode_list;
1807 }
1808 
1809 
1810 
1811 
1812 /* AllegroGL driver routines */
1813 
1814 static void flip(void)
1815 {
1816  SwapBuffers(__allegro_gl_hdc);
1817 }
1818 
1819 
1820 
1821 static void gl_on(void)
1822 {
1823  return;
1824 }
1825 
1826 
1827 
1828 static void gl_off(void)
1829 {
1830  return;
1831 }
1832 
1833 
1834 
1835 /* AllegroGL driver */
1836 
1837 static struct allegro_gl_driver allegro_gl_win = {
1838  flip, gl_on, gl_off, NULL
1839 };
1840 
#define GFX_OPENGL_FULLSCREEN
Fullscreen OpenGL graphics driver for Allegro.
Definition: alleggl.h:435
float allegro_gl_opengl_version(void)
Returns the OpenGL version number of the client (the computer the program is running on)...
Definition: alleggl.c:971
int allegro_gl_get(int option)
Reads the setting of a configuration option.
Definition: alleggl.c:421
struct AGL_EXTENSION_LIST_GL allegro_gl_extensions_GL
List of OpenGL extensions supported by AllegroGL.
Definition: glext.c:55
#define AGL_WINDOW_X
Requests a placement of the window to a specified pixel location.
Definition: alleggl.h:296
#define AGL_WINDOW_Y
Same as AGL_WINDOW_X, but for the y-axis.
Definition: alleggl.h:300
#define AGL_COLOR_DEPTH
Specify the total color depth of the frame buffer.
Definition: alleggl.h:223
#define GFX_OPENGL_WINDOWED
Windowed OpenGL graphics driver for Allegro.
Definition: alleggl.h:433
void allegro_gl_destroy_video_bitmap(BITMAP *bmp)
destroy_video_bitmap() overload.
Definition: videovtb.c:308
int allegro_gl_is_extension_supported(AL_CONST char *extension)
This function is an helper to determine whether an OpenGL extension is available or not...
Definition: glext.c:306
Main header file for AllegroGL.
BITMAP * allegro_gl_screen
Direct-mode GL `screen&#39; bitmap.
Definition: alleggl.c:62
BITMAP * allegro_gl_create_video_bitmap(int w, int h)
create_video_bitmap() overload.
Definition: videovtb.c:344