AllegroGL: win.c Source File

AllegroGL 0.4.4

- Main Page
- Related Pages
- Modules
- Files

- File List
- Globals

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 = {
33 GFX_OPENGL_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 */
44 allegro_gl_create_video_bitmap,
45 allegro_gl_destroy_video_bitmap,
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 = {
68 GFX_OPENGL_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 */
79 allegro_gl_create_video_bitmap,
80 allegro_gl_destroy_video_bitmap,
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,
1571 w, h, allegro_gl_get(AGL_COLOR_DEPTH));
1572 }
1573 else {
1574 allegro_gl_screen= allegro_gl_create_screen(&gfx_allegro_gl_windowed,
1575 w, h, allegro_gl_get(AGL_COLOR_DEPTH));
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",
1585 w, h, allegro_gl_get(AGL_COLOR_DEPTH));
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
GFX_OPENGL_FULLSCREEN
#define GFX_OPENGL_FULLSCREEN
Fullscreen OpenGL graphics driver for Allegro.
Definition: alleggl.h:435
allegro_gl_opengl_version
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
allegro_gl_get
int allegro_gl_get(int option)
Reads the setting of a configuration option.
Definition: alleggl.c:421
allegro_gl_extensions_GL
struct AGL_EXTENSION_LIST_GL allegro_gl_extensions_GL
List of OpenGL extensions supported by AllegroGL.
Definition: glext.c:55
AGL_WINDOW_X
#define AGL_WINDOW_X
Requests a placement of the window to a specified pixel location.
Definition: alleggl.h:296
AGL_WINDOW_Y
#define AGL_WINDOW_Y
Same as AGL_WINDOW_X, but for the y-axis.
Definition: alleggl.h:300
AGL_COLOR_DEPTH
#define AGL_COLOR_DEPTH
Specify the total color depth of the frame buffer.
Definition: alleggl.h:223
GFX_OPENGL_WINDOWED
#define GFX_OPENGL_WINDOWED
Windowed OpenGL graphics driver for Allegro.
Definition: alleggl.h:433
allegro_gl_destroy_video_bitmap
void allegro_gl_destroy_video_bitmap(BITMAP *bmp)
destroy_video_bitmap() overload.
Definition: videovtb.c:308
allegro_gl_is_extension_supported
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
alleggl.h
Main header file for AllegroGL.
allegro_gl_screen
BITMAP * allegro_gl_screen
Direct-mode GL `screen&#39; bitmap.
Definition: alleggl.c:62
allegro_gl_create_video_bitmap
BITMAP * allegro_gl_create_video_bitmap(int w, int h)
create_video_bitmap() overload.
Definition: videovtb.c:344