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