Panda3D
wglGraphicsStateGuardian.cxx
1 // Filename: wglGraphicsStateGuardian.cxx
2 // Created by: drose (27Jan03)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "wglGraphicsStateGuardian.h"
16 #include "wglGraphicsBuffer.h"
17 #include "string_utils.h"
18 
19 TypeHandle wglGraphicsStateGuardian::_type_handle;
20 
21 const char * const wglGraphicsStateGuardian::_twindow_class_name = "wglGraphicsStateGuardian";
22 bool wglGraphicsStateGuardian::_twindow_class_registered = false;
23 
24 ////////////////////////////////////////////////////////////////////
25 // Function: wglGraphicsStateGuardian::Constructor
26 // Access: Public
27 // Description:
28 ////////////////////////////////////////////////////////////////////
29 wglGraphicsStateGuardian::
30 wglGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
31  wglGraphicsStateGuardian *share_with) :
32  GLGraphicsStateGuardian(engine, pipe),
33  _share_with(share_with)
34 {
35  _made_context = false;
36  _context = (HGLRC)NULL;
37 
38  _twindow = (HWND)0;
39  _twindow_dc = (HDC)0;
40 
41  _pfnum = -1;
42  _pfnum_supports_pbuffer = false;
43  _pfnum_properties.clear();
44 
45  _supports_pbuffer = false;
46  _supports_pixel_format = false;
47  _supports_wgl_multisample = false;
48  _supports_wgl_render_texture = false;
49 
51  atexit(atexit_function);
52 }
53 
54 ////////////////////////////////////////////////////////////////////
55 // Function: wglGraphicsStateGuardian::Destructor
56 // Access: Public
57 // Description:
58 ////////////////////////////////////////////////////////////////////
59 wglGraphicsStateGuardian::
60 ~wglGraphicsStateGuardian() {
61  release_twindow();
62  if (_context != (HGLRC)NULL) {
63  wglDeleteContext(_context);
64  _context = (HGLRC)NULL;
65  }
66 }
67 
68 ////////////////////////////////////////////////////////////////////
69 // Function: wglGraphicsStateGuardian::fail_pfnum
70 // Access: Public
71 // Description: This is called by wglGraphicsWindow when it finds it
72 // cannot use the pfnum determined by the GSG. Assuming
73 // this pfnum corresponds to an "advanced" frame buffer
74 // determined by wglChoosePixelFormatARB, this asks the
75 // GSG to swap out that pfnum for the earlier,
76 // "preliminary" pfnum determined via
77 // DescribePixelFormat().
78 //
79 // This is a one-way operation. Once called, you can
80 // never go back to the advanced pfnum.
81 //
82 // This method returns true if a change was successfully
83 // made, or false if there was no second tier to fall
84 // back to.
85 ////////////////////////////////////////////////////////////////////
88  if (_pfnum == _pre_pfnum) {
89  return false;
90  }
91 
92  _pfnum = _pre_pfnum;
93  _pfnum_supports_pbuffer = false;
94  _pfnum_properties = _pre_pfnum_properties;
95  return true;
96 }
97 
98 ////////////////////////////////////////////////////////////////////
99 // Function: wglGraphicsStateGuardian::get_properties
100 // Access: Private
101 // Description: Gets the FrameBufferProperties to match the
102 // indicated pixel format descriptor.
103 ////////////////////////////////////////////////////////////////////
105 get_properties(FrameBufferProperties &properties, HDC hdc, int pfnum) {
106 
107  PIXELFORMATDESCRIPTOR pfd;
108  ZeroMemory(&pfd,sizeof(PIXELFORMATDESCRIPTOR));
109  pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
110  pfd.nVersion = 1;
111 
112  DescribePixelFormat(hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
113 
114  properties.clear();
115  properties.set_all_specified();
116 
117  if (((pfd.dwFlags & PFD_SUPPORT_OPENGL) == 0)||
118  ((pfd.dwFlags & PFD_DRAW_TO_WINDOW) == 0)) {
119  // Return without setting either RGB or Indexed Color.
120  // This indicates a window that can't do anything at all.
121  return;
122  }
123 
124  if (pfd.iPixelType == PFD_TYPE_COLORINDEX) {
125  properties.set_indexed_color(1);
126  properties.set_color_bits(pfd.cColorBits);
127  properties.set_alpha_bits(pfd.cAlphaBits);
128  } else {
129  properties.set_rgb_color(1);
130  properties.set_rgba_bits(pfd.cRedBits, pfd.cGreenBits,
131  pfd.cBlueBits, pfd.cAlphaBits);
132  }
133 
134  int mode = 0;
135  if (pfd.dwFlags & PFD_DOUBLEBUFFER) {
136  properties.set_back_buffers(1);
137  }
138  if (pfd.dwFlags & PFD_STEREO) {
139  properties.set_stereo(1);
140  }
141  if (pfd.dwFlags & PFD_GENERIC_FORMAT) {
142  properties.set_force_software(1);
143  } else {
144  properties.set_force_hardware(1);
145  }
146 
147  if (pfd.cDepthBits != 0) {
148  properties.set_depth_bits(pfd.cDepthBits);
149  }
150  if (pfd.cStencilBits != 0) {
151  properties.set_stencil_bits(pfd.cStencilBits);
152  }
153 
154  // The basic API doesn't do accum or multisample.
155 }
156 
157 ////////////////////////////////////////////////////////////////////
158 // Function: wglGraphicsStateGuardian::get_properties_advanced
159 // Access: Private
160 // Description: Gets the FrameBufferProperties to match the
161 // indicated pixel format descriptor, using the WGL
162 // extensions.
163 ////////////////////////////////////////////////////////////////////
166  HDC window_dc, int pfnum) {
167 
168  static const int max_attrib_list = 32;
169  int iattrib_list[max_attrib_list];
170  int ivalue_list[max_attrib_list];
171  int ni = 0;
172 
173  int acceleration_i, pixel_type_i, double_buffer_i, stereo_i,
174  color_bits_i, red_bits_i, green_bits_i, blue_bits_i, alpha_bits_i,
175  accum_bits_i, depth_bits_i, stencil_bits_i, multisamples_i,
176  srgb_capable_i;
177 
178  iattrib_list[acceleration_i = ni++] = WGL_ACCELERATION_ARB;
179  iattrib_list[pixel_type_i = ni++] = WGL_PIXEL_TYPE_ARB;
180  iattrib_list[double_buffer_i = ni++] = WGL_DOUBLE_BUFFER_ARB;
181  iattrib_list[stereo_i = ni++] = WGL_STEREO_ARB;
182  iattrib_list[color_bits_i = ni++] = WGL_COLOR_BITS_ARB;
183  iattrib_list[red_bits_i = ni++] = WGL_RED_BITS_ARB;
184  iattrib_list[green_bits_i = ni++] = WGL_GREEN_BITS_ARB;
185  iattrib_list[blue_bits_i = ni++] = WGL_BLUE_BITS_ARB;
186  iattrib_list[alpha_bits_i = ni++] = WGL_ALPHA_BITS_ARB;
187  iattrib_list[accum_bits_i = ni++] = WGL_ACCUM_BITS_ARB;
188  iattrib_list[depth_bits_i = ni++] = WGL_DEPTH_BITS_ARB;
189  iattrib_list[stencil_bits_i = ni++] = WGL_STENCIL_BITS_ARB;
190  iattrib_list[srgb_capable_i = ni++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
191 
192  if (_supports_wgl_multisample) {
193  iattrib_list[multisamples_i = ni++] = WGL_SAMPLES_ARB;
194  }
195 
196  // Terminate the list.
197  nassertr(ni <= max_attrib_list, false);
198 
199  if (!_wglGetPixelFormatAttribivARB(window_dc, pfnum, 0,
200  ni, iattrib_list, ivalue_list)) {
201  return false;
202  }
203 
204  properties.clear();
205  properties.set_all_specified();
206 
207  int frame_buffer_mode = 0;
208  if (ivalue_list[acceleration_i] == WGL_NO_ACCELERATION_ARB) {
209  properties.set_force_software(true);
210  } else {
211  properties.set_force_hardware(true);
212  }
213 
214  if (ivalue_list[pixel_type_i] == WGL_TYPE_COLORINDEX_ARB) {
215  properties.set_indexed_color(true);
216  properties.set_color_bits(ivalue_list[color_bits_i]);
217  properties.set_alpha_bits(ivalue_list[alpha_bits_i]);
218  } else {
219  properties.set_rgb_color(true);
220  properties.set_rgba_bits(ivalue_list[red_bits_i],
221  ivalue_list[green_bits_i],
222  ivalue_list[blue_bits_i],
223  ivalue_list[alpha_bits_i]);
224  }
225 
226  if (ivalue_list[double_buffer_i]) {
227  properties.set_back_buffers(1);
228  }
229 
230  if (ivalue_list[stereo_i]) {
231  properties.set_stereo(true);
232  }
233 
234  if (ivalue_list[srgb_capable_i]) {
235  properties.set_srgb_color(true);
236  }
237 
238  if (ivalue_list[accum_bits_i] != 0) {
239  properties.set_accum_bits(ivalue_list[accum_bits_i]);
240  }
241 
242  if (ivalue_list[depth_bits_i] != 0) {
243  properties.set_depth_bits(ivalue_list[depth_bits_i]);
244  }
245 
246  if (ivalue_list[stencil_bits_i] != 0) {
247  properties.set_stencil_bits(ivalue_list[stencil_bits_i]);
248  }
249 
250  if (_supports_wgl_multisample) {
251  if (ivalue_list[multisamples_i] != 0) {
252  properties.set_multisamples(ivalue_list[multisamples_i]);
253  }
254  }
255 
256  return true;
257 }
258 
259 ////////////////////////////////////////////////////////////////////
260 // Function: wglGraphicsStateGuardian::choose_pixel_format
261 // Access: Private
262 // Description: Selects a pixel format for all the windows and
263 // buffers that use this gsg.
264 ////////////////////////////////////////////////////////////////////
267  bool need_pbuffer) {
268 
269  //// Choose best format available using DescribePixelFormat.
270  //
271  // In the process, we need a DC to examine the available
272  // pixel formats. We'll use the screen DC.
273 
274  if (gl_force_pixfmt.has_value()) {
275  wgldisplay_cat.info()
276  << "overriding pixfmt choice with gl-force-pixfmt("
277  << gl_force_pixfmt << ")\n";
278  _pfnum = gl_force_pixfmt;
279  _pfnum_properties = properties;
280  _pfnum_supports_pbuffer = true;
281  return;
282  }
283 
284  int best_pfnum = 0;
285  int best_quality = 0;
286  FrameBufferProperties best_prop;
287 
288  HDC hdc = GetDC(NULL);
289 
290  int max_pfnum = DescribePixelFormat(hdc, 1, 0, NULL);
291 
292  for (int pfnum = 0; pfnum<max_pfnum; ++pfnum) {
293  FrameBufferProperties pfprop;
294  get_properties(pfprop, hdc, pfnum);
295  int quality = pfprop.get_quality(properties);
296  if (quality > best_quality) {
297  best_pfnum = pfnum;
298  best_quality = quality;
299  best_prop = pfprop;
300  }
301  }
302 
303  ReleaseDC(NULL, hdc);
304 
305  _pfnum = best_pfnum;
306  _pfnum_supports_pbuffer = false;
307  _pfnum_properties = best_prop;
308  _pre_pfnum = _pfnum;
309  _pre_pfnum_properties = _pfnum_properties;
310 
311  if (best_quality == 0) {
312  wgldisplay_cat.error()
313  << "Could not find a usable pixel format.\n";
314  return;
315  }
316 
317  if (wgldisplay_cat.is_debug()) {
318  wgldisplay_cat.debug()
319  << "Preliminary pixfmt #" << _pfnum << " = "
320  << _pfnum_properties << "\n";
321  }
322 
323  //// See whether or not the wgl extensions are available.
324  //
325  // This routine is called before "reset". So the extensions
326  // list is empty. We need to create a twindow, make it current,
327  // fetch the extensions temporarily, get the few extensions
328  // we need, then clear the extensions list again in preparation
329  // for the reset.
330 
331  HDC twindow_dc = get_twindow_dc();
332  if (twindow_dc == 0) {
333  return;
334  }
335 
336  HGLRC twindow_ctx = wglCreateContext(twindow_dc);
337  if (twindow_ctx == 0) {
338  return;
339  }
340 
341  wglGraphicsPipe::wgl_make_current(twindow_dc, twindow_ctx, NULL);
342 
343  _extensions.clear();
344  save_extensions((const char *)GLP(GetString)(GL_EXTENSIONS));
345  get_extra_extensions();
346  _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
347  _supports_wgl_multisample = has_extension("WGL_ARB_multisample");
348  _extensions.clear();
349 
350  if (!_supports_pixel_format) {
351  wglDeleteContext(twindow_ctx);
352  return;
353  }
354 
355  _wglGetPixelFormatAttribivARB =
356  (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB");
357  _wglGetPixelFormatAttribfvARB =
358  (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribfvARB");
359  _wglChoosePixelFormatARB =
360  (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
361 
362  if (_wglGetPixelFormatAttribivARB == NULL ||
363  _wglGetPixelFormatAttribfvARB == NULL ||
364  _wglChoosePixelFormatARB == NULL) {
365  wgldisplay_cat.error()
366  << "Driver claims to support WGL_ARB_pixel_format extension, but does not define all functions.\n";
367  wglDeleteContext(twindow_ctx);
368  return;
369  }
370 
371  //// Use the wgl extensions to find a better format.
372  //
373 
374  static const int max_attrib_list = 64;
375  int iattrib_list[max_attrib_list];
376  float fattrib_list[max_attrib_list];
377  int ni = 0;
378  int nf = 0;
379 
380  iattrib_list[ni++] = WGL_SUPPORT_OPENGL_ARB;
381  iattrib_list[ni++] = true;
382  iattrib_list[ni++] = WGL_PIXEL_TYPE_ARB;
383  iattrib_list[ni++] = WGL_TYPE_RGBA_ARB;
384 
385  if (need_pbuffer) {
386  iattrib_list[ni++] = WGL_DRAW_TO_PBUFFER_ARB;
387  iattrib_list[ni++] = true;
388  if (_pfnum_properties.get_alpha_bits()) {
389  iattrib_list[ni++] = WGL_BIND_TO_TEXTURE_RGBA_ARB;
390  iattrib_list[ni++] = true;
391  } else {
392  iattrib_list[ni++] = WGL_BIND_TO_TEXTURE_RGB_ARB;
393  iattrib_list[ni++] = true;
394  }
395  }
396 
397  nassertv(ni < max_attrib_list && nf < max_attrib_list);
398  iattrib_list[ni] = 0;
399  fattrib_list[nf] = 0;
400 
401  static const int max_pformats = 1024;
402  int pformat[max_pformats];
403  memset(pformat, 0, sizeof(pformat));
404  int nformats = 0;
405 
406  if (!_wglChoosePixelFormatARB(twindow_dc, iattrib_list, fattrib_list,
407  max_pformats, pformat, (unsigned int *)&nformats)) {
408  nformats = 0;
409  }
410  nformats = min(nformats, max_pformats);
411 
412  if (wgldisplay_cat.is_debug()) {
413  wgldisplay_cat.debug()
414  << "Found " << nformats << " advanced formats: [";
415  for (int i = 0; i < nformats; i++) {
416  wgldisplay_cat.debug(false)
417  << " " << pformat[i];
418  }
419  wgldisplay_cat.debug(false)
420  << " ]\n";
421  }
422 
423  if (nformats > 0) {
424  if (need_pbuffer) {
425  best_quality = 0;
426  }
427 
428  for (int i = 0; i < nformats; i++) {
429  FrameBufferProperties pfprop;
430  if (get_properties_advanced(pfprop, twindow_dc, pformat[i])) {
431  int quality = pfprop.get_quality(properties);
432  if (quality > best_quality) {
433  best_pfnum = pformat[i];
434  best_quality = quality;
435  best_prop = pfprop;
436  }
437  }
438  }
439 
440  if (!properties.get_srgb_color()) {
441  best_prop.set_srgb_color(false);
442  }
443 
444  _pfnum = best_pfnum;
445  _pfnum_supports_pbuffer = need_pbuffer;
446  _pfnum_properties = best_prop;
447 
448  if (wgldisplay_cat.is_debug()) {
449  wgldisplay_cat.debug()
450  << "Selected advanced pixfmt #" << _pfnum << " = "
451  << _pfnum_properties << "\n";
452  }
453  }
454 
455  wglDeleteContext(twindow_ctx);
456  release_twindow();
457 }
458 
459 ////////////////////////////////////////////////////////////////////
460 // Function: wglGraphicsStateGuardian::reset
461 // Access: Public, Virtual
462 // Description: Resets all internal state as if the gsg were newly
463 // created.
464 ////////////////////////////////////////////////////////////////////
466 reset() {
467  GLGraphicsStateGuardian::reset();
468 
469  _supports_swap_control = has_extension("WGL_EXT_swap_control");
470 
471  if (_supports_swap_control) {
472  _wglSwapIntervalEXT =
473  (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
474  if (_wglSwapIntervalEXT == NULL) {
475  wgldisplay_cat.error()
476  << "Driver claims to support WGL_EXT_swap_control extension, but does not define all functions.\n";
477  _supports_swap_control = false;
478  }
479  }
480 
481  if (_supports_swap_control) {
482  // Set the video-sync setting up front, if we have the extension
483  // that supports it.
484  _wglSwapIntervalEXT(sync_video ? 1 : 0);
485  }
486 
487  _supports_pbuffer = has_extension("WGL_ARB_pbuffer");
488 
489  if (_supports_pbuffer) {
490  _wglCreatePbufferARB =
491  (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
492  _wglGetPbufferDCARB =
493  (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
494  _wglReleasePbufferDCARB =
495  (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
496  _wglDestroyPbufferARB =
497  (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
498  _wglQueryPbufferARB =
499  (PFNWGLQUERYPBUFFERARBPROC)wglGetProcAddress("wglQueryPbufferARB");
500 
501  if (_wglCreatePbufferARB == NULL ||
502  _wglGetPbufferDCARB == NULL ||
503  _wglReleasePbufferDCARB == NULL ||
504  _wglDestroyPbufferARB == NULL ||
505  _wglQueryPbufferARB == NULL) {
506  wgldisplay_cat.error()
507  << "Driver claims to support WGL_ARB_pbuffer extension, but does not define all functions.\n";
508  _supports_pbuffer = false;
509  }
510  }
511 
512  _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
513 
514  if (_supports_pixel_format) {
515  _wglGetPixelFormatAttribivARB =
516  (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB");
517  _wglGetPixelFormatAttribfvARB =
518  (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribfvARB");
519  _wglChoosePixelFormatARB =
520  (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
521 
522  if (_wglGetPixelFormatAttribivARB == NULL ||
523  _wglGetPixelFormatAttribfvARB == NULL ||
524  _wglChoosePixelFormatARB == NULL) {
525  wgldisplay_cat.error()
526  << "Driver claims to support WGL_ARB_pixel_format extension, but does not define all functions.\n";
527  _supports_pixel_format = false;
528  }
529  }
530 
531  _supports_wgl_multisample = has_extension("WGL_ARB_multisample");
532 
533  _supports_wgl_render_texture = has_extension("WGL_ARB_render_texture");
534 
535  if (_supports_wgl_render_texture) {
536  _wglBindTexImageARB =
537  (PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB");
538  _wglReleaseTexImageARB =
539  (PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress("wglReleaseTexImageARB");
540  _wglSetPbufferAttribARB =
541  (PFNWGLSETPBUFFERATTRIBARBPROC)wglGetProcAddress("wglSetPbufferAttribARB");
542  if (_wglBindTexImageARB == NULL ||
543  _wglReleaseTexImageARB == NULL ||
544  _wglSetPbufferAttribARB == NULL) {
545  wgldisplay_cat.error()
546  << "Driver claims to support WGL_ARB_render_texture, but does not define all functions.\n";
547  _supports_wgl_render_texture = false;
548  }
549  }
550 }
551 
552 ////////////////////////////////////////////////////////////////////
553 // Function: wglGraphicsStateGuardian::get_extra_extensions
554 // Access: Protected, Virtual
555 // Description: This may be redefined by a derived class (e.g. glx or
556 // wgl) to get whatever further extensions strings may
557 // be appropriate to that interface, in addition to the
558 // GL extension strings return by glGetString().
559 ////////////////////////////////////////////////////////////////////
560 void wglGraphicsStateGuardian::
561 get_extra_extensions() {
562  // This is a little bit tricky, since the query function is itself
563  // an extension.
564 
565  // Look for the ARB flavor first, which wants one parameter, the HDC
566  // of the drawing context.
567  PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB =
568  (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
569  if (wglGetExtensionsStringARB != NULL) {
570  HDC hdc = wglGetCurrentDC();
571  if (hdc != 0) {
572  save_extensions((const char *)wglGetExtensionsStringARB(hdc));
573  return;
574  }
575  }
576 
577  // If that failed, look for the EXT flavor, which wants no
578  // parameters.
579  PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT =
580  (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");
581  if (wglGetExtensionsStringEXT != NULL) {
582  save_extensions((const char *)wglGetExtensionsStringEXT());
583  }
584 }
585 
586 ////////////////////////////////////////////////////////////////////
587 // Function: wglGraphicsStateGuardian::do_get_extension_func
588 // Access: Public, Virtual
589 // Description: Returns the pointer to the GL extension function with
590 // the indicated name. It is the responsibility of the
591 // caller to ensure that the required extension is
592 // defined in the OpenGL runtime prior to calling this;
593 // it is an error to call this for a function that is
594 // not defined.
595 ////////////////////////////////////////////////////////////////////
596 void *wglGraphicsStateGuardian::
597 do_get_extension_func(const char *name) {
598  return (void*) wglGetProcAddress(name);
599 }
600 
601 ////////////////////////////////////////////////////////////////////
602 // Function: wglGraphicsStateGuardian::make_context
603 // Access: Private
604 // Description: Creates a suitable context for rendering into the
605 // given window. This should only be called from the
606 // draw thread.
607 ////////////////////////////////////////////////////////////////////
608 void wglGraphicsStateGuardian::
609 make_context(HDC hdc) {
610  // We should only call this once for a particular GSG.
611  nassertv(!_made_context);
612 
613  _made_context = true;
614 
615  // Attempt to create a context.
616  wglGraphicsPipe::_current_valid = false;
617  _context = wglCreateContext(hdc);
618 
619  if (_context == NULL) {
620  wgldisplay_cat.error()
621  << "Could not create GL context.\n";
622  _is_valid = false;
623  return;
624  }
625 
626  // Now share texture context with the indicated GSG.
627  if (_share_with != (wglGraphicsStateGuardian *)NULL) {
628  HGLRC share_context = _share_with->get_share_context();
629  if (share_context == NULL) {
630  // Whoops, the target context hasn't yet made its own context.
631  // In that case, it will share context with us.
632  _share_with->redirect_share_pool(this);
633 
634  } else {
635  if (!wglShareLists(share_context, _context)) {
636  wgldisplay_cat.error()
637  << "Could not share texture contexts between wglGraphicsStateGuardians.\n";
638  // Too bad we couldn't detect this error sooner. Now there's
639  // really no way to tell the application it's hosed.
640  _is_valid = false;
641 
642  } else {
643  _prepared_objects = _share_with->get_prepared_objects();
644  }
645  }
646 
647  _share_with = (wglGraphicsStateGuardian *)NULL;
648  }
649 }
650 
651 ////////////////////////////////////////////////////////////////////
652 // Function: wglGraphicsStateGuardian::get_share_context
653 // Access: Private
654 // Description: Returns a wgl context handle for the purpose of
655 // sharing texture context with this GSG. This will
656 // either be the GSG's own context handle, if it exists
657 // yet, or the context handle of some other GSG that
658 // this GSG is planning to share with. If this returns
659 // NULL, none of the GSG's in this share pool have yet
660 // created their context.
661 ////////////////////////////////////////////////////////////////////
662 HGLRC wglGraphicsStateGuardian::
663 get_share_context() const {
664  if (_made_context) {
665  return _context;
666  }
667  if (_share_with != (wglGraphicsStateGuardian *)NULL) {
668  return _share_with->get_share_context();
669  }
670  return NULL;
671 }
672 
673 ////////////////////////////////////////////////////////////////////
674 // Function: wglGraphicsStateGuardian::redirect_share_pool
675 // Access: Private
676 // Description: Directs the GSG (along with all GSG's it is planning
677 // to share a texture context with) to share texture
678 // context with the indicated GSG.
679 //
680 // This assumes that this GSG's context has not yet been
681 // created, and neither have any of the GSG's it is
682 // planning to share texture context with; but the
683 // graphics context for the indicated GSG has already
684 // been created.
685 ////////////////////////////////////////////////////////////////////
686 void wglGraphicsStateGuardian::
687 redirect_share_pool(wglGraphicsStateGuardian *share_with) {
688  nassertv(!_made_context);
689  if (_share_with != (wglGraphicsStateGuardian *)NULL) {
690  _share_with->redirect_share_pool(share_with);
691  } else {
692  _share_with = share_with;
693  }
694 }
695 
696 ////////////////////////////////////////////////////////////////////
697 // Function: wglGraphicsStateGuardian::make_twindow
698 // Access: Private
699 // Description: Creates an invisible window to associate with the GL
700 // context, even if we are not going to use it. This is
701 // necessary because in the Windows OpenGL API, we have
702 // to create window before we can create a GL
703 // context--even before we can ask about what GL
704 // extensions are available!
705 ////////////////////////////////////////////////////////////////////
706 bool wglGraphicsStateGuardian::
707 make_twindow() {
708  release_twindow();
709 
710  DWORD window_style = 0;
711 
712  register_twindow_class();
713  HINSTANCE hinstance = GetModuleHandle(NULL);
714  _twindow = CreateWindow(_twindow_class_name, "twindow", window_style,
715  0, 0, 1, 1, NULL, NULL, hinstance, 0);
716 
717  if (!_twindow) {
718  wgldisplay_cat.error()
719  << "CreateWindow() failed!" << endl;
720  return false;
721  }
722 
723  ShowWindow(_twindow, SW_HIDE);
724 
725  _twindow_dc = GetDC(_twindow);
726 
727  PIXELFORMATDESCRIPTOR pixelformat;
728  if (!SetPixelFormat(_twindow_dc, _pfnum, &pixelformat)) {
729  wgldisplay_cat.error()
730  << "SetPixelFormat(" << _pfnum << ") failed after window create\n";
731  release_twindow();
732  return false;
733  }
734 
735  return true;
736 }
737 
738 ////////////////////////////////////////////////////////////////////
739 // Function: wglGraphicsStateGuardian::release_twindow
740 // Access: Private
741 // Description: Closes and frees the resources associated with the
742 // temporary window created by a previous call to
743 // make_twindow().
744 ////////////////////////////////////////////////////////////////////
745 void wglGraphicsStateGuardian::
746 release_twindow() {
747  if (_twindow_dc) {
748  ReleaseDC(_twindow, _twindow_dc);
749  _twindow_dc = 0;
750  }
751  if (_twindow) {
752  DestroyWindow(_twindow);
753  _twindow = 0;
754  }
755 }
756 
757 ////////////////////////////////////////////////////////////////////
758 // Function: wglGraphicsStateGuardian::register_twindow_class
759 // Access: Private, Static
760 // Description: Registers a Window class for the twindow created by
761 // all wglGraphicsPipes. This only needs to be done
762 // once per session.
763 ////////////////////////////////////////////////////////////////////
764 void wglGraphicsStateGuardian::
765 register_twindow_class() {
766  if (_twindow_class_registered) {
767  return;
768  }
769 
770  WNDCLASS wc;
771 
772  HINSTANCE instance = GetModuleHandle(NULL);
773 
774  // Clear before filling in window structure!
775  ZeroMemory(&wc, sizeof(WNDCLASS));
776  wc.style = CS_OWNDC;
777  wc.lpfnWndProc = DefWindowProc;
778  wc.hInstance = instance;
779  wc.lpszClassName = _twindow_class_name;
780 
781  if (!RegisterClass(&wc)) {
782  wgldisplay_cat.error()
783  << "could not register window class!" << endl;
784  return;
785  }
786  _twindow_class_registered = true;
787 }
788 
789 #define GAMMA_1 (255.0 * 256.0)
790 
791 static bool _gamma_table_initialized = false;
792 static unsigned short _orignial_gamma_table [256 * 3];
793 
794 void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
795  int i;
796  double gamma_correction;
797 
798  if (gamma <= 0.0) {
799  // avoid divide by zero and negative exponents
800  gamma = 1.0;
801  }
802  gamma_correction = 1.0 / (double) gamma;
803 
804  for (i = 0; i < 256; i++) {
805  double r;
806  double g;
807  double b;
808 
809  if (original_red_table) {
810  r = (double) original_red_table [i] / GAMMA_1;
811  g = (double) original_green_table [i] / GAMMA_1;
812  b = (double) original_blue_table [i] / GAMMA_1;
813  }
814  else {
815  r = ((double) i / 255.0);
816  g = r;
817  b = r;
818  }
819 
820  r = pow (r, gamma_correction);
821  g = pow (g, gamma_correction);
822  b = pow (b, gamma_correction);
823 
824  if (r > 1.00) {
825  r = 1.0;
826  }
827  if (g > 1.00) {
828  g = 1.0;
829  }
830  if (b > 1.00) {
831  b = 1.0;
832  }
833 
834  r = r * GAMMA_1;
835  g = g * GAMMA_1;
836  b = b * GAMMA_1;
837 
838  red_table [i] = r;
839  green_table [i] = g;
840  blue_table [i] = b;
841  }
842 }
843 
844 ////////////////////////////////////////////////////////////////////
845 // Function: wglGraphicsStateGuardian::get_gamma_table
846 // Access: Public, Static
847 // Description: Static function for getting the original gamma.
848 ////////////////////////////////////////////////////////////////////
851  bool get;
852 
853  get = false;
854  if (_gamma_table_initialized == false) {
855  HDC hdc = GetDC(NULL);
856 
857  if (hdc) {
858  if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) {
859  _gamma_table_initialized = true;
860  get = true;
861  }
862 
863  ReleaseDC (NULL, hdc);
864  }
865  }
866 
867  return get;
868 }
869 
870 ////////////////////////////////////////////////////////////////////
871 // Function: wglGraphicsStateGuardian::static_set_gamma
872 // Access: Public, Static
873 // Description: Static function for setting gamma which is needed
874 // for atexit.
875 ////////////////////////////////////////////////////////////////////
877 static_set_gamma(bool restore, PN_stdfloat gamma) {
878  bool set;
879  HDC hdc = GetDC(NULL);
880 
881  set = false;
882  if (hdc) {
883  unsigned short ramp [256 * 3];
884 
885  if (restore && _gamma_table_initialized) {
886  _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
887  }
888  else {
889  _create_gamma_table (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]);
890  }
891 
892  if (SetDeviceGammaRamp (hdc, ramp)) {
893  set = true;
894  }
895 
896  ReleaseDC (NULL, hdc);
897  }
898 
899  return set;
900 }
901 
902 ////////////////////////////////////////////////////////////////////
903 // Function: wglGraphicsStateGuardian::set_gamma
904 // Access: Published
905 // Description: Non static version of setting gamma. Returns true
906 // on success.
907 ////////////////////////////////////////////////////////////////////
909 set_gamma(PN_stdfloat gamma) {
910  bool set;
911 
912  set = static_set_gamma(false, gamma);
913  if (set) {
914  _gamma = gamma;
915  }
916 
917  return set;
918 }
919 
920 ////////////////////////////////////////////////////////////////////
921 // Function: wglGraphicsStateGuardian::restore_gamma
922 // Access: Published
923 // Description: Restore original gamma.
924 ////////////////////////////////////////////////////////////////////
927  static_set_gamma(true, 1.0f);
928 }
929 
930 ////////////////////////////////////////////////////////////////////
931 // Function: wglGraphicsStateGuardian::atexit_function
932 // Access: Public, Static
933 // Description: This function is passed to the atexit function.
934 ////////////////////////////////////////////////////////////////////
937  static_set_gamma(true, 1.0);
938 }
void set_all_specified()
Marks all bits as having been specified.
HDC get_twindow_dc()
Returns the DC associated with the temporary, invisible window that was created with the gsg to query...
void clear()
Unsets all properties that have been specified so far, and resets the FrameBufferProperties structure...
bool set_gamma(PN_stdfloat gamma)
Non static version of setting gamma.
static bool get_gamma_table(void)
Static function for getting the original gamma.
void restore_gamma()
Restore original gamma.
static bool static_set_gamma(bool restore, PN_stdfloat gamma)
Static function for setting gamma which is needed for atexit.
bool get_properties_advanced(FrameBufferProperties &properties, HDC hdc, int pfnum)
Gets the FrameBufferProperties to match the indicated pixel format descriptor, using the WGL extensio...
bool fail_pfnum()
This is called by wglGraphicsWindow when it finds it cannot use the pfnum determined by the GSG...
A tiny specialization on GLGraphicsStateGuardian to add some wgl-specific information.
virtual void reset()
Resets all internal state as if the gsg were newly created.
static void atexit_function(void)
This function is passed to the atexit function.
void choose_pixel_format(const FrameBufferProperties &properties, bool need_pbuffer)
Selects a pixel format for all the windows and buffers that use this gsg.
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:58
void get_properties(FrameBufferProperties &properties, HDC hdc, int pfnum)
Gets the FrameBufferProperties to match the indicated pixel format descriptor.
bool has_value() const
Returns true if this variable has an explicit value, either from a prc file or locally set...
void set_rgba_bits(int r, int g, int b, int a)
Convenience method for setting the red, green, blue and alpha bits in one go.
void set_color_bits(int n)
Sets the number of requested color bits as a single number that represents the sum of the individual ...
This class is the main interface to controlling the render process.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
int get_quality(const FrameBufferProperties &reqs) const
Assumes that these properties are a description of a window.