Panda3D

wglGraphicsStateGuardian.cxx

00001 // Filename: wglGraphicsStateGuardian.cxx
00002 // Created by:  drose (27Jan03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "wglGraphicsStateGuardian.h"
00016 #include "wglGraphicsBuffer.h"
00017 #include "string_utils.h"
00018 
00019 TypeHandle wglGraphicsStateGuardian::_type_handle;
00020 
00021 const char * const wglGraphicsStateGuardian::_twindow_class_name = "wglGraphicsStateGuardian";
00022 bool wglGraphicsStateGuardian::_twindow_class_registered = false;
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: wglGraphicsStateGuardian::Constructor
00026 //       Access: Public
00027 //  Description:
00028 ////////////////////////////////////////////////////////////////////
00029 wglGraphicsStateGuardian::
00030 wglGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
00031                          wglGraphicsStateGuardian *share_with) : 
00032   GLGraphicsStateGuardian(engine, pipe),
00033   _share_with(share_with)
00034 {
00035   _made_context = false;
00036   _context = (HGLRC)NULL;
00037 
00038   _twindow = (HWND)0;
00039   _twindow_dc = (HDC)0;
00040 
00041   _pfnum = -1;
00042   _pfnum_supports_pbuffer = false;
00043   _pfnum_properties.clear();
00044   
00045   _supports_pbuffer = false;
00046   _supports_pixel_format = false;
00047   _supports_wgl_multisample = false;
00048   _supports_wgl_render_texture = false;
00049   
00050   get_gamma_table();
00051   atexit(atexit_function);
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: wglGraphicsStateGuardian::Destructor
00056 //       Access: Public
00057 //  Description:
00058 ////////////////////////////////////////////////////////////////////
00059 wglGraphicsStateGuardian::
00060 ~wglGraphicsStateGuardian() {
00061   release_twindow();
00062   if (_context != (HGLRC)NULL) {
00063     wglDeleteContext(_context);
00064     _context = (HGLRC)NULL;
00065   }
00066 }
00067 
00068 ////////////////////////////////////////////////////////////////////
00069 //     Function: wglGraphicsStateGuardian::fail_pfnum
00070 //       Access: Public
00071 //  Description: This is called by wglGraphicsWindow when it finds it
00072 //               cannot use the pfnum determined by the GSG.  Assuming
00073 //               this pfnum corresponds to an "advanced" frame buffer
00074 //               determined by wglChoosePixelFormatARB, this asks the
00075 //               GSG to swap out that pfnum for the earlier,
00076 //               "preliminary" pfnum determined via
00077 //               DescribePixelFormat().
00078 //
00079 //               This is a one-way operation.  Once called, you can
00080 //               never go back to the advanced pfnum.
00081 //
00082 //               This method returns true if a change was successfully
00083 //               made, or false if there was no second tier to fall
00084 //               back to.
00085 ////////////////////////////////////////////////////////////////////
00086 bool wglGraphicsStateGuardian::
00087 fail_pfnum() {
00088   if (_pfnum == _pre_pfnum) {
00089     return false;
00090   }
00091 
00092   _pfnum = _pre_pfnum;
00093   _pfnum_supports_pbuffer = false;
00094   _pfnum_properties = _pre_pfnum_properties;
00095   return true;
00096 }
00097 
00098 ////////////////////////////////////////////////////////////////////
00099 //     Function: wglGraphicsStateGuardian::get_properties
00100 //       Access: Private
00101 //  Description: Gets the FrameBufferProperties to match the
00102 //               indicated pixel format descriptor.
00103 ////////////////////////////////////////////////////////////////////
00104 void wglGraphicsStateGuardian::
00105 get_properties(FrameBufferProperties &properties, HDC hdc, int pfnum) {
00106   
00107   PIXELFORMATDESCRIPTOR pfd;
00108   ZeroMemory(&pfd,sizeof(PIXELFORMATDESCRIPTOR));
00109   pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
00110   pfd.nVersion = 1;
00111 
00112   DescribePixelFormat(hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
00113 
00114   properties.clear();
00115   properties.set_all_specified();
00116   
00117   if (((pfd.dwFlags & PFD_SUPPORT_OPENGL) == 0)||
00118       ((pfd.dwFlags & PFD_DRAW_TO_WINDOW) == 0)) {
00119     // Return without setting either RGB or Indexed Color.
00120     // This indicates a window that can't do anything at all.
00121     return;
00122   }
00123 
00124   if (pfd.iPixelType == PFD_TYPE_COLORINDEX) {
00125     properties.set_indexed_color(1);
00126   } else {
00127     properties.set_rgb_color(1);
00128   }
00129 
00130   int mode = 0;
00131   if (pfd.dwFlags & PFD_DOUBLEBUFFER) {
00132     properties.set_back_buffers(1);
00133   }
00134   if (pfd.dwFlags & PFD_STEREO) {
00135     properties.set_stereo(1);
00136   }
00137   if (pfd.dwFlags & PFD_GENERIC_FORMAT) {
00138     properties.set_force_software(1);
00139   } else {
00140     properties.set_force_hardware(1);
00141   }
00142   
00143   if (pfd.cColorBits != 0) {
00144     properties.set_color_bits(pfd.cColorBits);
00145   }
00146   if (pfd.cAlphaBits != 0) {
00147     properties.set_alpha_bits(pfd.cAlphaBits);
00148   }
00149   if (pfd.cDepthBits != 0) {
00150     properties.set_depth_bits(pfd.cDepthBits);
00151   }
00152   if (pfd.cStencilBits != 0) {
00153     properties.set_stencil_bits(pfd.cStencilBits);
00154   }
00155 
00156   // The basic API doesn't do accum or multisample.
00157 }
00158 
00159 ////////////////////////////////////////////////////////////////////
00160 //     Function: wglGraphicsStateGuardian::get_properties_advanced
00161 //       Access: Private
00162 //  Description: Gets the FrameBufferProperties to match the
00163 //               indicated pixel format descriptor, using the WGL
00164 //               extensions.
00165 ////////////////////////////////////////////////////////////////////
00166 bool wglGraphicsStateGuardian::
00167 get_properties_advanced(FrameBufferProperties &properties, 
00168                         HDC window_dc, int pfnum) {
00169   
00170   static const int max_attrib_list = 32;
00171   int iattrib_list[max_attrib_list];
00172   int ivalue_list[max_attrib_list];
00173   int ni = 0;
00174   
00175   int acceleration_i, pixel_type_i, double_buffer_i, stereo_i,
00176     color_bits_i, alpha_bits_i, accum_bits_i, depth_bits_i, 
00177     stencil_bits_i, multisamples_i;
00178   
00179   iattrib_list[acceleration_i = ni++] = WGL_ACCELERATION_ARB;
00180   iattrib_list[pixel_type_i = ni++] = WGL_PIXEL_TYPE_ARB;
00181   iattrib_list[double_buffer_i = ni++] = WGL_DOUBLE_BUFFER_ARB;
00182   iattrib_list[stereo_i = ni++] = WGL_STEREO_ARB;
00183   iattrib_list[color_bits_i = ni++] = WGL_COLOR_BITS_ARB;
00184   iattrib_list[alpha_bits_i = ni++] = WGL_ALPHA_BITS_ARB;
00185   iattrib_list[accum_bits_i = ni++] = WGL_ACCUM_BITS_ARB;
00186   iattrib_list[depth_bits_i = ni++] = WGL_DEPTH_BITS_ARB;
00187   iattrib_list[stencil_bits_i = ni++] = WGL_STENCIL_BITS_ARB;
00188   
00189   if (_supports_wgl_multisample) {
00190     iattrib_list[multisamples_i = ni++] = WGL_SAMPLES_ARB;
00191   }
00192   
00193   // Terminate the list.
00194   nassertr(ni <= max_attrib_list, false);
00195   
00196   if (!_wglGetPixelFormatAttribivARB(window_dc, pfnum, 0,
00197                                      ni, iattrib_list, ivalue_list)) {
00198     return false;
00199   }
00200   
00201   properties.clear();
00202   properties.set_all_specified();
00203 
00204   int frame_buffer_mode = 0;
00205   if (ivalue_list[acceleration_i] == WGL_NO_ACCELERATION_ARB) {
00206     properties.set_force_software(1);
00207   } else {
00208     properties.set_force_hardware(1);
00209   }
00210   
00211   if (ivalue_list[pixel_type_i] == WGL_TYPE_COLORINDEX_ARB) {
00212     properties.set_indexed_color(1);
00213   } else {
00214     properties.set_rgb_color(1);
00215   }
00216 
00217   if (ivalue_list[double_buffer_i]) {
00218     properties.set_back_buffers(1);
00219   }
00220   
00221   if (ivalue_list[stereo_i]) {
00222     properties.set_stereo(1);
00223   }
00224   
00225   if (ivalue_list[alpha_bits_i] != 0) {
00226     properties.set_alpha_bits(ivalue_list[alpha_bits_i]);
00227   }
00228 
00229   if (ivalue_list[accum_bits_i] != 0) {
00230     properties.set_accum_bits(ivalue_list[accum_bits_i]);
00231   }
00232   
00233   if (ivalue_list[depth_bits_i] != 0) {
00234     properties.set_depth_bits(ivalue_list[depth_bits_i]);
00235   }
00236 
00237   if (ivalue_list[stencil_bits_i] != 0) {
00238     properties.set_stencil_bits(ivalue_list[stencil_bits_i]);
00239   }
00240 
00241   if (_supports_wgl_multisample) {
00242     if (ivalue_list[multisamples_i] != 0) {
00243       properties.set_multisamples(ivalue_list[multisamples_i]);
00244     }
00245   }
00246   
00247   properties.set_color_bits(ivalue_list[color_bits_i]);
00248   
00249   return true;
00250 }
00251 
00252 ////////////////////////////////////////////////////////////////////
00253 //     Function: wglGraphicsStateGuardian::choose_pixel_format
00254 //       Access: Private
00255 //  Description: Selects a pixel format for all the windows and
00256 //               buffers that use this gsg.
00257 ////////////////////////////////////////////////////////////////////
00258 void wglGraphicsStateGuardian::
00259 choose_pixel_format(const FrameBufferProperties &properties,
00260                     bool need_pbuffer) {
00261 
00262   //// Choose best format available using DescribePixelFormat.
00263   //
00264   // In the process, we need a DC to examine the available
00265   // pixel formats.  We'll use the screen DC.
00266 
00267   if (gl_force_pixfmt.has_value()) {
00268     wgldisplay_cat.info()
00269       << "overriding pixfmt choice with gl-force-pixfmt(" 
00270       << gl_force_pixfmt << ")\n";
00271     _pfnum = gl_force_pixfmt;
00272     _pfnum_properties = properties;
00273     _pfnum_supports_pbuffer = true;
00274     return;
00275   }
00276   
00277   int  best_pfnum = 0;
00278   int  best_quality = 0;
00279   FrameBufferProperties best_prop;
00280   
00281   HDC hdc = GetDC(NULL);
00282 
00283   int max_pfnum = DescribePixelFormat(hdc, 1, 0, NULL);
00284   
00285   for (int pfnum = 0; pfnum<max_pfnum; ++pfnum) {
00286     FrameBufferProperties pfprop;
00287     get_properties(pfprop, hdc, pfnum);
00288     int quality = pfprop.get_quality(properties);
00289     if (quality > best_quality) {
00290       best_pfnum = pfnum;
00291       best_quality = quality;
00292       best_prop = pfprop;
00293     }
00294   }
00295   
00296   ReleaseDC(NULL, hdc);
00297 
00298   _pfnum = best_pfnum;
00299   _pfnum_supports_pbuffer = false;
00300   _pfnum_properties = best_prop;
00301   _pre_pfnum = _pfnum;
00302   _pre_pfnum_properties = _pfnum_properties;
00303   
00304   if (best_quality == 0) {
00305     wgldisplay_cat.error()
00306       << "Could not find a usable pixel format.\n";
00307     return;
00308   }
00309 
00310   if (wgldisplay_cat.is_debug()) {
00311     wgldisplay_cat.debug()
00312       << "Preliminary pixfmt #" << _pfnum << " = " 
00313       << _pfnum_properties << "\n";
00314   }
00315 
00316   //// See whether or not the wgl extensions are available.
00317   //
00318   // This routine is called before "reset".  So the extensions
00319   // list is empty.  We need to create a twindow, make it current,
00320   // fetch the extensions temporarily, get the few extensions
00321   // we need, then clear the extensions list again in preparation
00322   // for the reset.
00323   
00324   HDC twindow_dc = get_twindow_dc();
00325   if (twindow_dc == 0) {
00326     return;
00327   }
00328 
00329   HGLRC twindow_ctx = wglCreateContext(twindow_dc);
00330   if (twindow_ctx == 0) {
00331     return;
00332   }
00333 
00334   wglGraphicsPipe::wgl_make_current(twindow_dc, twindow_ctx, NULL);
00335 
00336   _extensions.clear();
00337   save_extensions((const char *)GLP(GetString)(GL_EXTENSIONS));
00338   get_extra_extensions();
00339   _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
00340   _supports_wgl_multisample = has_extension("WGL_ARB_multisample");
00341   _extensions.clear();
00342 
00343   if (!_supports_pixel_format) {
00344     wglDeleteContext(twindow_ctx);
00345     return;
00346   }
00347 
00348   _wglGetPixelFormatAttribivARB =
00349     (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB");
00350   _wglGetPixelFormatAttribfvARB =
00351     (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribfvARB");
00352   _wglChoosePixelFormatARB =
00353     (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
00354 
00355   if (_wglGetPixelFormatAttribivARB == NULL ||
00356       _wglGetPixelFormatAttribfvARB == NULL ||
00357       _wglChoosePixelFormatARB == NULL) {
00358     wgldisplay_cat.error()
00359       << "Driver claims to support WGL_ARB_pixel_format extension, but does not define all functions.\n";
00360     wglDeleteContext(twindow_ctx);
00361     return;
00362   }
00363 
00364   //// Use the wgl extensions to find a better format.
00365   //
00366   
00367   static const int max_attrib_list = 64;
00368   int iattrib_list[max_attrib_list];
00369   float fattrib_list[max_attrib_list];
00370   int ni = 0;
00371   int nf = 0;
00372   
00373   iattrib_list[ni++] = WGL_SUPPORT_OPENGL_ARB;
00374   iattrib_list[ni++] = true;
00375   iattrib_list[ni++] = WGL_PIXEL_TYPE_ARB;
00376   iattrib_list[ni++] = WGL_TYPE_RGBA_ARB;
00377 
00378   if (need_pbuffer) {
00379     iattrib_list[ni++] = WGL_DRAW_TO_PBUFFER_ARB;
00380     iattrib_list[ni++] = true;
00381     if (_pfnum_properties.get_alpha_bits()) {
00382       iattrib_list[ni++] = WGL_BIND_TO_TEXTURE_RGBA_ARB;
00383       iattrib_list[ni++] = true;
00384     } else {
00385       iattrib_list[ni++] = WGL_BIND_TO_TEXTURE_RGB_ARB;
00386       iattrib_list[ni++] = true;
00387     }
00388   }
00389 
00390   nassertv(ni < max_attrib_list && nf < max_attrib_list);
00391   iattrib_list[ni] = 0;
00392   fattrib_list[nf] = 0;
00393   
00394   static const int max_pformats = 1024;
00395   int pformat[max_pformats];
00396   memset(pformat, 0, sizeof(pformat));
00397   int nformats = 0;
00398   
00399   if (!_wglChoosePixelFormatARB(twindow_dc, iattrib_list, fattrib_list,
00400                                 max_pformats, pformat, (unsigned int *)&nformats)) {
00401     nformats = 0;
00402   }
00403   nformats = min(nformats, max_pformats);
00404   
00405   if (wgldisplay_cat.is_debug()) {
00406     wgldisplay_cat.debug()
00407       << "Found " << nformats << " advanced formats: [";
00408     for (int i = 0; i < nformats; i++) {
00409       wgldisplay_cat.debug(false)
00410         << " " << pformat[i];
00411     }
00412     wgldisplay_cat.debug(false)
00413       << " ]\n";
00414   }
00415   
00416   if (nformats > 0) {
00417     if (need_pbuffer) {
00418       best_quality = 0;
00419     }
00420 
00421     for (int i = 0; i < nformats; i++) {
00422       FrameBufferProperties pfprop;
00423       if (get_properties_advanced(pfprop, twindow_dc, pformat[i])) {
00424         int quality = pfprop.get_quality(properties);
00425         if (quality > best_quality) {
00426           best_pfnum = pformat[i];
00427           best_quality = quality;
00428           best_prop = pfprop;
00429         }
00430       }
00431     }
00432     
00433     _pfnum = best_pfnum;
00434     _pfnum_supports_pbuffer = need_pbuffer;
00435     _pfnum_properties = best_prop;
00436 
00437     if (wgldisplay_cat.is_debug()) {
00438       wgldisplay_cat.debug()
00439         << "Selected advanced pixfmt #" << _pfnum << " = " 
00440         << _pfnum_properties << "\n";
00441     }
00442   }
00443   
00444   wglDeleteContext(twindow_ctx);
00445   release_twindow();
00446 }
00447 
00448 ////////////////////////////////////////////////////////////////////
00449 //     Function: wglGraphicsStateGuardian::reset
00450 //       Access: Public, Virtual
00451 //  Description: Resets all internal state as if the gsg were newly
00452 //               created.
00453 ////////////////////////////////////////////////////////////////////
00454 void wglGraphicsStateGuardian::
00455 reset() {
00456   GLGraphicsStateGuardian::reset();
00457 
00458   _supports_swap_control = has_extension("WGL_EXT_swap_control");
00459 
00460   if (_supports_swap_control) {
00461     _wglSwapIntervalEXT = 
00462       (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
00463     if (_wglSwapIntervalEXT == NULL) {
00464       wgldisplay_cat.error()
00465         << "Driver claims to support WGL_EXT_swap_control extension, but does not define all functions.\n";
00466       _supports_swap_control = false;
00467     }
00468   }
00469 
00470   if (_supports_swap_control) {
00471     // Set the video-sync setting up front, if we have the extension
00472     // that supports it.
00473     _wglSwapIntervalEXT(sync_video ? 1 : 0);
00474   }
00475 
00476   _supports_pbuffer = has_extension("WGL_ARB_pbuffer");
00477 
00478   if (_supports_pbuffer) {
00479     _wglCreatePbufferARB = 
00480       (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
00481     _wglGetPbufferDCARB = 
00482       (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
00483     _wglReleasePbufferDCARB = 
00484       (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
00485     _wglDestroyPbufferARB = 
00486       (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
00487     _wglQueryPbufferARB = 
00488       (PFNWGLQUERYPBUFFERARBPROC)wglGetProcAddress("wglQueryPbufferARB");
00489     
00490     if (_wglCreatePbufferARB == NULL ||
00491         _wglGetPbufferDCARB == NULL ||
00492         _wglReleasePbufferDCARB == NULL ||
00493         _wglDestroyPbufferARB == NULL ||
00494         _wglQueryPbufferARB == NULL) {
00495       wgldisplay_cat.error()
00496         << "Driver claims to support WGL_ARB_pbuffer extension, but does not define all functions.\n";
00497       _supports_pbuffer = false;
00498     }
00499   }
00500 
00501   _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
00502 
00503   if (_supports_pixel_format) {
00504     _wglGetPixelFormatAttribivARB =
00505       (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB");
00506     _wglGetPixelFormatAttribfvARB =
00507       (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribfvARB");
00508     _wglChoosePixelFormatARB =
00509       (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
00510 
00511     if (_wglGetPixelFormatAttribivARB == NULL ||
00512         _wglGetPixelFormatAttribfvARB == NULL ||
00513         _wglChoosePixelFormatARB == NULL) {
00514       wgldisplay_cat.error()
00515         << "Driver claims to support WGL_ARB_pixel_format extension, but does not define all functions.\n";
00516       _supports_pixel_format = false;
00517     }
00518   }
00519 
00520   _supports_wgl_multisample = has_extension("WGL_ARB_multisample");
00521 
00522   _supports_wgl_render_texture = has_extension("WGL_ARB_render_texture");
00523 
00524   if (_supports_wgl_render_texture) {
00525     _wglBindTexImageARB = 
00526       (PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB");
00527     _wglReleaseTexImageARB = 
00528       (PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress("wglReleaseTexImageARB");
00529     _wglSetPbufferAttribARB = 
00530       (PFNWGLSETPBUFFERATTRIBARBPROC)wglGetProcAddress("wglSetPbufferAttribARB");
00531     if (_wglBindTexImageARB == NULL ||
00532         _wglReleaseTexImageARB == NULL ||
00533         _wglSetPbufferAttribARB == NULL) {
00534       wgldisplay_cat.error()
00535         << "Driver claims to support WGL_ARB_render_texture, but does not define all functions.\n";
00536       _supports_wgl_render_texture = false;
00537     }
00538   }
00539 }
00540 
00541 ////////////////////////////////////////////////////////////////////
00542 //     Function: wglGraphicsStateGuardian::get_extra_extensions
00543 //       Access: Protected, Virtual
00544 //  Description: This may be redefined by a derived class (e.g. glx or
00545 //               wgl) to get whatever further extensions strings may
00546 //               be appropriate to that interface, in addition to the
00547 //               GL extension strings return by glGetString().
00548 ////////////////////////////////////////////////////////////////////
00549 void wglGraphicsStateGuardian::
00550 get_extra_extensions() {
00551   // This is a little bit tricky, since the query function is itself
00552   // an extension.
00553 
00554   // Look for the ARB flavor first, which wants one parameter, the HDC
00555   // of the drawing context.
00556   PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 
00557     (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
00558   if (wglGetExtensionsStringARB != NULL) {
00559     HDC hdc = wglGetCurrentDC();
00560     if (hdc != 0) {
00561       save_extensions((const char *)wglGetExtensionsStringARB(hdc));
00562       return;
00563     }
00564   }
00565 
00566   // If that failed, look for the EXT flavor, which wants no
00567   // parameters.
00568   PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT = 
00569     (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");
00570   if (wglGetExtensionsStringEXT != NULL) {
00571     save_extensions((const char *)wglGetExtensionsStringEXT());
00572   }
00573 }
00574 
00575 ////////////////////////////////////////////////////////////////////
00576 //     Function: wglGraphicsStateGuardian::do_get_extension_func
00577 //       Access: Public, Virtual
00578 //  Description: Returns the pointer to the GL extension function with
00579 //               the indicated name.  It is the responsibility of the
00580 //               caller to ensure that the required extension is
00581 //               defined in the OpenGL runtime prior to calling this;
00582 //               it is an error to call this for a function that is
00583 //               not defined.
00584 ////////////////////////////////////////////////////////////////////
00585 void *wglGraphicsStateGuardian::
00586 do_get_extension_func(const char *prefix, const char *name) {
00587   string fullname = string(prefix) + string(name);
00588   return wglGetProcAddress(fullname.c_str());
00589 }
00590 
00591 
00592 ////////////////////////////////////////////////////////////////////
00593 //     Function: wglGraphicsStateGuardian::make_context
00594 //       Access: Private
00595 //  Description: Creates a suitable context for rendering into the
00596 //               given window.  This should only be called from the
00597 //               draw thread.
00598 ////////////////////////////////////////////////////////////////////
00599 void wglGraphicsStateGuardian::
00600 make_context(HDC hdc) {
00601   // We should only call this once for a particular GSG.
00602   nassertv(!_made_context);
00603 
00604   _made_context = true;
00605 
00606   // Attempt to create a context.
00607   wglGraphicsPipe::_current_valid = false;
00608   _context = wglCreateContext(hdc);
00609 
00610   if (_context == NULL) {
00611     wgldisplay_cat.error()
00612       << "Could not create GL context.\n";
00613     return;
00614   }
00615 
00616   // Now share texture context with the indicated GSG.
00617   if (_share_with != (wglGraphicsStateGuardian *)NULL) {
00618     HGLRC share_context = _share_with->get_share_context();
00619     if (share_context == NULL) {
00620       // Whoops, the target context hasn't yet made its own context.
00621       // In that case, it will share context with us.
00622       _share_with->redirect_share_pool(this);
00623 
00624     } else {
00625       if (!wglShareLists(share_context, _context)) {
00626         wgldisplay_cat.error()
00627           << "Could not share texture contexts between wglGraphicsStateGuardians.\n";
00628         // Too bad we couldn't detect this error sooner.  Now there's
00629         // really no way to tell the application it's hosed.
00630 
00631       } else {
00632         _prepared_objects = _share_with->get_prepared_objects();
00633       }
00634     }
00635 
00636     _share_with = (wglGraphicsStateGuardian *)NULL;
00637   }
00638 }
00639 
00640 ////////////////////////////////////////////////////////////////////
00641 //     Function: wglGraphicsStateGuardian::get_share_context
00642 //       Access: Private
00643 //  Description: Returns a wgl context handle for the purpose of
00644 //               sharing texture context with this GSG.  This will
00645 //               either be the GSG's own context handle, if it exists
00646 //               yet, or the context handle of some other GSG that
00647 //               this GSG is planning to share with.  If this returns
00648 //               NULL, none of the GSG's in this share pool have yet
00649 //               created their context.
00650 ////////////////////////////////////////////////////////////////////
00651 HGLRC wglGraphicsStateGuardian::
00652 get_share_context() const {
00653   if (_made_context) {
00654     return _context;
00655   }
00656   if (_share_with != (wglGraphicsStateGuardian *)NULL) {
00657     return _share_with->get_share_context();
00658   }
00659   return NULL;
00660 }
00661 
00662 ////////////////////////////////////////////////////////////////////
00663 //     Function: wglGraphicsStateGuardian::redirect_share_pool
00664 //       Access: Private
00665 //  Description: Directs the GSG (along with all GSG's it is planning
00666 //               to share a texture context with) to share texture
00667 //               context with the indicated GSG.
00668 //
00669 //               This assumes that this GSG's context has not yet been
00670 //               created, and neither have any of the GSG's it is
00671 //               planning to share texture context with; but the
00672 //               graphics context for the indicated GSG has already
00673 //               been created.
00674 ////////////////////////////////////////////////////////////////////
00675 void wglGraphicsStateGuardian::
00676 redirect_share_pool(wglGraphicsStateGuardian *share_with) {
00677   nassertv(!_made_context);
00678   if (_share_with != (wglGraphicsStateGuardian *)NULL) {
00679     _share_with->redirect_share_pool(share_with);
00680   } else {
00681     _share_with = share_with;
00682   }
00683 }
00684 
00685 ////////////////////////////////////////////////////////////////////
00686 //     Function: wglGraphicsStateGuardian::make_twindow
00687 //       Access: Private
00688 //  Description: Creates an invisible window to associate with the GL
00689 //               context, even if we are not going to use it.  This is
00690 //               necessary because in the Windows OpenGL API, we have
00691 //               to create window before we can create a GL
00692 //               context--even before we can ask about what GL
00693 //               extensions are available!
00694 ////////////////////////////////////////////////////////////////////
00695 bool wglGraphicsStateGuardian::
00696 make_twindow() {
00697   release_twindow();
00698 
00699   DWORD window_style = 0;
00700 
00701   register_twindow_class();
00702   HINSTANCE hinstance = GetModuleHandle(NULL);
00703   _twindow = CreateWindow(_twindow_class_name, "twindow", window_style, 
00704                           0, 0, 1, 1, NULL, NULL, hinstance, 0);
00705   
00706   if (!_twindow) {
00707     wgldisplay_cat.error()
00708       << "CreateWindow() failed!" << endl;
00709     return false;
00710   }
00711 
00712   ShowWindow(_twindow, SW_HIDE);
00713 
00714   _twindow_dc = GetDC(_twindow);
00715 
00716   PIXELFORMATDESCRIPTOR pixelformat;
00717   if (!SetPixelFormat(_twindow_dc, _pfnum, &pixelformat)) {
00718     wgldisplay_cat.error()
00719       << "SetPixelFormat(" << _pfnum << ") failed after window create\n";
00720     release_twindow();
00721     return false;
00722   }
00723 
00724   return true;
00725 }
00726 
00727 ////////////////////////////////////////////////////////////////////
00728 //     Function: wglGraphicsStateGuardian::release_twindow
00729 //       Access: Private
00730 //  Description: Closes and frees the resources associated with the
00731 //               temporary window created by a previous call to
00732 //               make_twindow().
00733 ////////////////////////////////////////////////////////////////////
00734 void wglGraphicsStateGuardian::
00735 release_twindow() {
00736   if (_twindow_dc) {
00737     ReleaseDC(_twindow, _twindow_dc);
00738     _twindow_dc = 0;
00739   }
00740   if (_twindow) {
00741     DestroyWindow(_twindow);
00742     _twindow = 0;
00743   }
00744 }
00745 
00746 ////////////////////////////////////////////////////////////////////
00747 //     Function: wglGraphicsStateGuardian::register_twindow_class
00748 //       Access: Private, Static
00749 //  Description: Registers a Window class for the twindow created by
00750 //               all wglGraphicsPipes.  This only needs to be done
00751 //               once per session.
00752 ////////////////////////////////////////////////////////////////////
00753 void wglGraphicsStateGuardian::
00754 register_twindow_class() {
00755   if (_twindow_class_registered) {
00756     return;
00757   }
00758 
00759   WNDCLASS wc;
00760 
00761   HINSTANCE instance = GetModuleHandle(NULL);
00762 
00763   // Clear before filling in window structure!
00764   ZeroMemory(&wc, sizeof(WNDCLASS));
00765   wc.style = CS_OWNDC;
00766   wc.lpfnWndProc = DefWindowProc;
00767   wc.hInstance = instance;
00768   wc.lpszClassName = _twindow_class_name;
00769   
00770   if (!RegisterClass(&wc)) {
00771     wgldisplay_cat.error()
00772       << "could not register window class!" << endl;
00773     return;
00774   }
00775   _twindow_class_registered = true;
00776 }
00777 
00778 #define GAMMA_1 (255.0 * 256.0)
00779 
00780 static bool _gamma_table_initialized = false;
00781 static unsigned short _orignial_gamma_table [256 * 3];
00782 
00783 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) {
00784   int i;
00785   double gamma_correction;
00786 
00787   if (gamma <= 0.0) {
00788     // avoid divide by zero and negative exponents
00789     gamma = 1.0;
00790   }
00791   gamma_correction = 1.0 / (double) gamma;    
00792   
00793   for (i = 0; i < 256; i++) {
00794     double r;
00795     double g;
00796     double b;
00797 
00798     if (original_red_table) {
00799       r = (double) original_red_table [i] / GAMMA_1;
00800       g = (double) original_green_table [i] / GAMMA_1;
00801       b = (double) original_blue_table [i] / GAMMA_1;
00802     }
00803     else {    
00804       r = ((double) i / 255.0);
00805       g = r;
00806       b = r;
00807     }    
00808 
00809     r = pow (r, gamma_correction);
00810     g = pow (g, gamma_correction);
00811     b = pow (b, gamma_correction);
00812 
00813     if (r > 1.00) {
00814       r = 1.0;
00815     }
00816     if (g > 1.00) {
00817       g = 1.0;
00818     }
00819     if (b > 1.00) {
00820       b = 1.0;
00821     }
00822 
00823     r = r * GAMMA_1;    
00824     g = g * GAMMA_1;    
00825     b = b * GAMMA_1;    
00826 
00827     red_table [i] = r;
00828     green_table [i] = g;
00829     blue_table [i] = b;
00830   }    
00831 }
00832 
00833 ////////////////////////////////////////////////////////////////////
00834 //     Function: wglGraphicsStateGuardian::get_gamma_table
00835 //       Access: Public, Static
00836 //  Description: Static function for getting the original gamma.
00837 ////////////////////////////////////////////////////////////////////
00838 bool wglGraphicsStateGuardian::
00839 get_gamma_table(void) {
00840   bool get;  
00841 
00842   get = false;
00843   if (_gamma_table_initialized == false) {
00844     HDC hdc = GetDC(NULL);
00845 
00846     if (hdc) {   
00847       if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) {
00848         _gamma_table_initialized = true;
00849         get = true;
00850       }
00851 
00852       ReleaseDC (NULL, hdc);
00853     }
00854   }
00855   
00856   return get;
00857 }
00858 
00859 ////////////////////////////////////////////////////////////////////
00860 //     Function: wglGraphicsStateGuardian::static_set_gamma
00861 //       Access: Public, Static
00862 //  Description: Static function for setting gamma which is needed 
00863 //               for atexit.
00864 ////////////////////////////////////////////////////////////////////
00865 bool wglGraphicsStateGuardian::
00866 static_set_gamma(bool restore, PN_stdfloat gamma) {
00867   bool set;  
00868   HDC hdc = GetDC(NULL);
00869 
00870   set = false;
00871   if (hdc) {   
00872     unsigned short ramp [256 * 3];
00873 
00874     if (restore && _gamma_table_initialized) {    
00875       _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
00876     }
00877     else {
00878       _create_gamma_table (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]);
00879     }
00880 
00881     if (SetDeviceGammaRamp (hdc, ramp)) {
00882       set = true;
00883     }
00884     
00885     ReleaseDC (NULL, hdc);
00886   }
00887 
00888   return set;
00889 }
00890 
00891 ////////////////////////////////////////////////////////////////////
00892 //     Function: wglGraphicsStateGuardian::set_gamma
00893 //       Access: Published
00894 //  Description: Non static version of setting gamma.  Returns true
00895 //               on success.
00896 ////////////////////////////////////////////////////////////////////
00897 bool wglGraphicsStateGuardian::
00898 set_gamma(PN_stdfloat gamma) {
00899   bool set;
00900 
00901   set = static_set_gamma(false, gamma);
00902   if (set) {
00903     _gamma = gamma;  
00904   }
00905 
00906   return set;
00907 }
00908 
00909 ////////////////////////////////////////////////////////////////////
00910 //     Function: wglGraphicsStateGuardian::restore_gamma
00911 //       Access: Published
00912 //  Description: Restore original gamma.
00913 ////////////////////////////////////////////////////////////////////
00914 void wglGraphicsStateGuardian::
00915 restore_gamma() {
00916   static_set_gamma(true, 1.0f);
00917 }
00918 
00919 ////////////////////////////////////////////////////////////////////
00920 //     Function: wglGraphicsStateGuardian::atexit_function
00921 //       Access: Public, Static
00922 //  Description: This function is passed to the atexit function.
00923 ////////////////////////////////////////////////////////////////////
00924 void wglGraphicsStateGuardian::
00925 atexit_function(void) {
00926   static_set_gamma(true, 1.0);
00927 }
 All Classes Functions Variables Enumerations