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