Panda3D
|
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 }