Panda3D
|
00001 //////////////////////////////////////////////////////////////////// 00002 // 00003 // PANDA 3D SOFTWARE 00004 // Copyright (c) Carnegie Mellon University. All rights reserved. 00005 // 00006 // All use of this software is subject to the terms of the revised BSD 00007 // license. You should have received a copy of this license along 00008 // with this source code in a file named "LICENSE." 00009 // 00010 //////////////////////////////////////////////////////////////////// 00011 00012 #include "osxGraphicsStateGuardian.h" 00013 #include "osxGraphicsBuffer.h" 00014 #include "string_utils.h" 00015 #include "config_osxdisplay.h" 00016 #include "depthWriteAttrib.h" 00017 #include "depthTestAttrib.h" 00018 #include "textureAttrib.h" 00019 #include "pnmImage.h" 00020 00021 #include <OpenGL/gl.h> 00022 #import <mach-o/dyld.h> 00023 00024 // This is generated data for the standard texture we use for drawing 00025 // the resize box in the window corner. 00026 #include "resize_box.rgb.c" 00027 00028 TypeHandle osxGraphicsStateGuardian::_type_handle; 00029 00030 //////////////////////////////////////////////////////////////////// 00031 // Function: osxGraphicsStateGuardian::do_get_extension_func 00032 // Access: Public, Virtual 00033 // Description: Returns the pointer to the GL extension function with 00034 // the indicated name. It is the responsibility of the 00035 // caller to ensure that the required extension is 00036 // defined in the OpenGL runtime prior to calling this; 00037 // it is an error to call this for a function that is 00038 // not defined. 00039 //////////////////////////////////////////////////////////////////// 00040 void *osxGraphicsStateGuardian:: 00041 do_get_extension_func(const char *prefix, const char *name) { 00042 string fullname = "_" + string(prefix) + string(name); 00043 NSSymbol symbol = NULL; 00044 00045 if (NSIsSymbolNameDefined (fullname.c_str())) { 00046 symbol = NSLookupAndBindSymbol (fullname.c_str()); 00047 } 00048 00049 return symbol ? NSAddressOfSymbol(symbol) : NULL; 00050 } 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: osxGraphicsStateGuardian::Constructor 00054 // Access: Public 00055 // Description: 00056 //////////////////////////////////////////////////////////////////// 00057 osxGraphicsStateGuardian:: 00058 osxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe, 00059 osxGraphicsStateGuardian *share_with) : 00060 GLGraphicsStateGuardian(engine, pipe), 00061 _share_with(share_with), 00062 _aglPixFmt(NULL), 00063 _aglcontext(NULL) 00064 { 00065 _shared_buffer = 1011; 00066 get_gamma_table(); 00067 } 00068 00069 //////////////////////////////////////////////////////////////////// 00070 // Function: osxGraphicsStateGuardian::Destructor 00071 // Access: Public 00072 // Description: 00073 //////////////////////////////////////////////////////////////////// 00074 osxGraphicsStateGuardian:: 00075 ~osxGraphicsStateGuardian() { 00076 if (_aglcontext != (AGLContext)NULL) { 00077 aglSetCurrentContext(NULL); 00078 aglDestroyContext(_aglcontext); 00079 report_agl_error("aglDestroyContext"); 00080 _aglcontext = (AGLContext)NULL; 00081 } 00082 } 00083 00084 //////////////////////////////////////////////////////////////////// 00085 // Function: osxGraphicsStateGuardian::reset 00086 // Access: Public, Virtual 00087 // Description: Resets all internal state as if the gsg were newly 00088 // created. 00089 //////////////////////////////////////////////////////////////////// 00090 void osxGraphicsStateGuardian::reset() 00091 { 00092 /* 00093 if(_aglcontext != (AGLContext)NULL) 00094 { 00095 aglDestroyContext(_aglcontext); 00096 report_agl_error(); 00097 _aglcontext = (AGLContext)NULL; 00098 } 00099 */ 00100 00101 GLGraphicsStateGuardian::reset(); 00102 00103 if (_aglcontext != (AGLContext)NULL) { 00104 // Apply the video-sync setting. 00105 GLint value = sync_video ? 1 : 0; 00106 aglSetInteger(_aglcontext, AGL_SWAP_INTERVAL, &value); 00107 } 00108 } 00109 00110 //////////////////////////////////////////////////////////////////// 00111 // Function: osxGraphicsStateGuardian::draw_resize_box 00112 // Access: Public, Virtual 00113 // Description: Draws an OSX-style resize icon in the bottom right 00114 // corner of the current display region. This is 00115 // normally done automatically at the end of each frame 00116 // when the window is indicated as resizable, since the 00117 // 3-D graphics overlay the normal, OS-drawn resize icon 00118 // and the user won't be able see it. 00119 //////////////////////////////////////////////////////////////////// 00120 void osxGraphicsStateGuardian:: 00121 draw_resize_box() { 00122 // This state is created, once, and never freed. 00123 static CPT(RenderState) state; 00124 if (state == (RenderState *)NULL) { 00125 state = RenderState::make(TransparencyAttrib::make(TransparencyAttrib::M_alpha), 00126 DepthWriteAttrib::make(DepthWriteAttrib::M_off), 00127 DepthTestAttrib::make(DepthTestAttrib::M_none)); 00128 00129 // Get the default texture to apply to the resize box; it's 00130 // compiled into the code. 00131 string resize_box_string((const char *)resize_box, resize_box_len); 00132 istringstream resize_box_strm(resize_box_string); 00133 PNMImage resize_box_pnm; 00134 if (resize_box_pnm.read(resize_box_strm, "resize_box.rgb")) { 00135 PT(Texture) tex = new Texture; 00136 tex->set_name("resize_box.rgb"); 00137 tex->load(resize_box_pnm); 00138 tex->set_minfilter(Texture::FT_linear); 00139 tex->set_magfilter(Texture::FT_linear); 00140 state = state->add_attrib(TextureAttrib::make(tex)); 00141 } 00142 } 00143 00144 // Clear out the lens. 00145 _projection_mat_inv = _projection_mat = TransformState::make_identity(); 00146 prepare_lens(); 00147 00148 // Set the state to our specific, known state for drawing the icon. 00149 set_state_and_transform(state, TransformState::make_identity()); 00150 00151 // Now determine the inner corner of the quad, choosing a 15x15 00152 // pixel square in the lower-right corner, computed from the 00153 // viewport size. 00154 PN_stdfloat inner_x = 1.0f - (15.0f * 2.0f / _viewport_width); 00155 PN_stdfloat inner_y = (15.0f * 2.0f / _viewport_height) - 1.0f; 00156 00157 // Draw the quad. We just use the slow, simple immediate mode calls 00158 // here. It's just one quad, after all. 00159 glBegin(GL_QUADS); 00160 00161 glColor4f(1.0, 1.0, 1.0, 1.0); 00162 glTexCoord2f(0.0, 0.0); 00163 glVertex2f(inner_x, -1.0); 00164 00165 glTexCoord2f(0.9375, 0.0); 00166 glVertex2f(1.0, -1.0); 00167 00168 glTexCoord2f(0.9375, 0.9375); 00169 glVertex2f(1.0, inner_y); 00170 00171 glTexCoord2f(0.0, 0.9375); 00172 glVertex2f(inner_x, inner_y); 00173 00174 glEnd(); 00175 } 00176 00177 //////////////////////////////////////////////////////////////////// 00178 // Function: osxGraphicsStateGuardian::build_gl 00179 // Access: Public, Virtual 00180 // Description: This function will build up a context for a gsg.. 00181 //////////////////////////////////////////////////////////////////// 00182 OSStatus osxGraphicsStateGuardian:: 00183 build_gl(bool full_screen, bool pbuffer, FrameBufferProperties &fb_props) { 00184 if (_aglcontext) { 00185 describe_pixel_format(fb_props); 00186 return noErr; // already built 00187 } 00188 00189 OSStatus err = noErr; 00190 00191 GDHandle display = GetMainDevice(); 00192 00193 pvector<GLint> attrib; 00194 if (!fb_props.get_indexed_color()) { 00195 attrib.push_back(AGL_RGBA); 00196 int color_bits = fb_props.get_color_bits(); 00197 int alpha_bits = fb_props.get_alpha_bits(); 00198 attrib.push_back(AGL_BUFFER_SIZE); 00199 attrib.push_back(color_bits + alpha_bits); 00200 attrib.push_back(AGL_PIXEL_SIZE); 00201 attrib.push_back(color_bits); 00202 attrib.push_back(AGL_RED_SIZE); 00203 attrib.push_back(color_bits / 3); 00204 attrib.push_back(AGL_GREEN_SIZE); 00205 attrib.push_back(color_bits / 3); 00206 attrib.push_back(AGL_BLUE_SIZE); 00207 attrib.push_back(color_bits / 3); 00208 attrib.push_back(AGL_ALPHA_SIZE); 00209 attrib.push_back(alpha_bits); 00210 } 00211 attrib.push_back(AGL_DEPTH_SIZE); 00212 attrib.push_back(fb_props.get_depth_bits()); 00213 attrib.push_back(AGL_STENCIL_SIZE); 00214 attrib.push_back(fb_props.get_stencil_bits()); 00215 if (fb_props.get_multisamples() != 0) { 00216 attrib.push_back(AGL_MULTISAMPLE); 00217 attrib.push_back(AGL_SAMPLE_BUFFERS_ARB); 00218 attrib.push_back(1); 00219 attrib.push_back(AGL_SAMPLES_ARB); 00220 attrib.push_back(fb_props.get_multisamples()); 00221 } 00222 00223 if (fb_props.is_stereo()) { 00224 attrib.push_back(AGL_STEREO); 00225 } 00226 00227 if (!fb_props.is_single_buffered()) { 00228 attrib.push_back(AGL_DOUBLEBUFFER); 00229 } 00230 if (full_screen) { 00231 attrib.push_back(AGL_FULLSCREEN); 00232 } 00233 if (pbuffer) { 00234 attrib.push_back(AGL_PBUFFER); 00235 } 00236 00237 if (fb_props.get_force_hardware()) { 00238 attrib.push_back(AGL_ACCELERATED); 00239 attrib.push_back(AGL_NO_RECOVERY); 00240 } 00241 00242 // Allow the system to choose the largest buffers requested that 00243 // meets all our selections. 00244 attrib.push_back(AGL_MAXIMUM_POLICY); 00245 00246 // Terminate the list. 00247 attrib.push_back(AGL_NONE); 00248 00249 // build context 00250 _aglcontext = NULL; 00251 _aglPixFmt = aglChoosePixelFormat(&display, 1, &attrib[0]); 00252 err = report_agl_error("aglChoosePixelFormat"); 00253 if (_aglPixFmt) { 00254 if(_share_with == NULL) { 00255 _aglcontext = aglCreateContext(_aglPixFmt, NULL); 00256 } else { 00257 _aglcontext = aglCreateContext(_aglPixFmt, ((osxGraphicsStateGuardian *)_share_with)->_aglcontext); 00258 } 00259 err = report_agl_error("aglCreateContext"); 00260 00261 if (_aglcontext == NULL) { 00262 osxdisplay_cat.error() 00263 << "osxGraphicsStateGuardian::build_gl Error Getting GL Context \n" ; 00264 if(err == noErr) { 00265 err = -1; 00266 } 00267 } else { 00268 aglSetInteger(_aglcontext, AGL_BUFFER_NAME, &_shared_buffer); 00269 err = report_agl_error("aglSetInteger AGL_BUFFER_NAME"); 00270 } 00271 00272 } else { 00273 osxdisplay_cat.error() 00274 << "osxGraphicsStateGuardian::build_gl Error Getting Pixel Format\n" ; 00275 osxdisplay_cat.error() 00276 << fb_props << "\n"; 00277 if(err == noErr) { 00278 err = -1; 00279 } 00280 } 00281 00282 if (err == noErr) { 00283 describe_pixel_format(fb_props); 00284 } 00285 00286 if (osxdisplay_cat.is_debug()) { 00287 osxdisplay_cat.debug() 00288 << "osxGraphicsStateGuardian::build_gl Returning :" << err << "\n"; 00289 osxdisplay_cat.debug() 00290 << fb_props << "\n"; 00291 } 00292 00293 return err; 00294 } 00295 00296 00297 //////////////////////////////////////////////////////////////////// 00298 // Function: osxGraphicsStateGuardian::describe_pixel_format 00299 // Access: Private 00300 // Description: Fills in the fb_props member with the appropriate 00301 // values according to the chosen pixel format. 00302 //////////////////////////////////////////////////////////////////// 00303 void osxGraphicsStateGuardian:: 00304 describe_pixel_format(FrameBufferProperties &fb_props) { 00305 fb_props.clear(); 00306 GLint value; 00307 00308 if (aglDescribePixelFormat(_aglPixFmt, AGL_RGBA, &value)) { 00309 fb_props.set_indexed_color(!value); 00310 fb_props.set_rgb_color(value); 00311 } 00312 if (aglDescribePixelFormat(_aglPixFmt, AGL_DEPTH_SIZE, &value)) { 00313 fb_props.set_depth_bits(value); 00314 } 00315 int color_bits = 0; 00316 if (aglDescribePixelFormat(_aglPixFmt, AGL_RED_SIZE, &value)) { 00317 color_bits += value; 00318 } 00319 if (aglDescribePixelFormat(_aglPixFmt, AGL_GREEN_SIZE, &value)) { 00320 color_bits += value; 00321 } 00322 if (aglDescribePixelFormat(_aglPixFmt, AGL_BLUE_SIZE, &value)) { 00323 color_bits += value; 00324 } 00325 fb_props.set_color_bits(color_bits); 00326 if (aglDescribePixelFormat(_aglPixFmt, AGL_ALPHA_SIZE, &value)) { 00327 fb_props.set_alpha_bits(value); 00328 } 00329 00330 if (aglDescribePixelFormat(_aglPixFmt, AGL_STENCIL_SIZE, &value)) { 00331 fb_props.set_stencil_bits(value); 00332 } 00333 00334 int accum_bits = 0; 00335 if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_RED_SIZE, &value)) { 00336 accum_bits += value; 00337 } 00338 if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_GREEN_SIZE, &value)) { 00339 accum_bits += value; 00340 } 00341 if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_BLUE_SIZE, &value)) { 00342 accum_bits += value; 00343 } 00344 00345 if (aglDescribePixelFormat(_aglPixFmt, AGL_SAMPLES_ARB, &value)) { 00346 fb_props.set_multisamples(value); 00347 } 00348 00349 if (aglDescribePixelFormat(_aglPixFmt, AGL_DOUBLEBUFFER, &value)) { 00350 if (value) { 00351 fb_props.set_back_buffers(1); 00352 } else { 00353 fb_props.set_back_buffers(0); 00354 } 00355 } 00356 00357 if (aglDescribePixelFormat(_aglPixFmt, AGL_STEREO, &value)) { 00358 fb_props.set_stereo(value); 00359 } 00360 00361 // Until we query the renderer, we don't know whether it's hardware 00362 // or software based, so set both flags to indicate we don't know. 00363 fb_props.set_force_hardware(true); 00364 fb_props.set_force_software(true); 00365 00366 GLint ndevs; 00367 AGLDevice *gdevs = aglDevicesOfPixelFormat(_aglPixFmt, &ndevs); 00368 if (gdevs != (AGLDevice *)NULL) { 00369 AGLRendererInfo rinfo = aglQueryRendererInfo(gdevs, ndevs); 00370 if (rinfo != NULL) { 00371 if (aglDescribeRenderer(rinfo, AGL_ACCELERATED, &value)) { 00372 // Now we know whether it's hardware or software. 00373 fb_props.set_force_hardware(value); 00374 fb_props.set_force_software(!value); 00375 } 00376 if (aglDescribeRenderer(rinfo, AGL_VIDEO_MEMORY, &value)) { 00377 osxdisplay_cat.debug() 00378 << "Reported video memory is " << value << "\n"; 00379 } 00380 if (aglDescribeRenderer(rinfo, AGL_TEXTURE_MEMORY, &value)) { 00381 osxdisplay_cat.debug() 00382 << "Reported texture memory is " << value << "\n"; 00383 } 00384 } 00385 } 00386 } 00387 00388 //////////////////////////////////////////////////////////////////// 00389 // Function: osxGraphicsStateGuardian::get_gamma_table 00390 // Access: Public, Static 00391 // Description: Static function for getting the orig gamma tables 00392 //////////////////////////////////////////////////////////////////// 00393 bool osxGraphicsStateGuardian:: 00394 get_gamma_table() { 00395 CGDisplayRestoreColorSyncSettings(); 00396 _cgErr = CGGetDisplayTransferByTable( 0, 256, _gOriginalRedTable, _gOriginalGreenTable, _gOriginalBlueTable, &_sampleCount); 00397 } 00398 00399 //////////////////////////////////////////////////////////////////// 00400 // Function: osxGraphicsStateGuardian::static_set_gamma 00401 // Access: Public, Static 00402 // Description: Static function for setting gamma which is needed 00403 // for atexit. 00404 //////////////////////////////////////////////////////////////////// 00405 bool osxGraphicsStateGuardian:: 00406 static_set_gamma(bool restore, PN_stdfloat gamma) { 00407 bool set; 00408 00409 set = false; 00410 00411 if (restore) { 00412 CGDisplayRestoreColorSyncSettings(); 00413 set = true; 00414 return set; 00415 } 00416 // CGDisplayRestoreColorSyncSettings(); 00417 00418 // CGGammaValue gOriginalRedTable[ 256 ]; 00419 // CGGammaValue gOriginalGreenTable[ 256 ]; 00420 // CGGammaValue gOriginalBlueTable[ 256 ]; 00421 00422 // CGTableCount sampleCount; 00423 // CGDisplayErr cgErr; 00424 00425 // cgErr = CGGetDisplayTransferByTable( 0, 256, _gOriginalRedTable, _gOriginalGreenTable, _gOriginalBlueTable, &_sampleCount); 00426 00427 CGGammaValue redTable[ 256 ]; 00428 CGGammaValue greenTable[ 256 ]; 00429 CGGammaValue blueTable[ 256 ]; 00430 00431 short j, i; 00432 short y[3]; 00433 00434 for (j = 0; j < 3; j++) { 00435 y[j] = 255; 00436 } 00437 00438 y[0] = 256 * gamma; 00439 y[1] = 256 * gamma; 00440 y[2] = 256 * gamma; 00441 00442 for (i = 0; i < 256; i++) { 00443 redTable[i] = _gOriginalRedTable[ i ] * (y[ 0 ] ) / 256; 00444 greenTable[ i ] = _gOriginalGreenTable[ i ] * (y[ 1 ] ) / 256; 00445 blueTable[ i ] = _gOriginalBlueTable[ i ] * (y[ 2 ] ) / 256; 00446 } 00447 _cgErr = CGSetDisplayTransferByTable( 0, 256, redTable, greenTable, blueTable); 00448 00449 if (_cgErr == 0) { 00450 set = true; 00451 } 00452 00453 return set; 00454 } 00455 00456 //////////////////////////////////////////////////////////////////// 00457 // Function: osxGraphicsStateGuardian::set_gamma 00458 // Access: Published 00459 // Description: Non static version of setting gamma. Returns true 00460 // on success. 00461 //////////////////////////////////////////////////////////////////// 00462 bool osxGraphicsStateGuardian:: 00463 set_gamma(PN_stdfloat gamma) { 00464 bool set; 00465 00466 set = static_set_gamma(false, gamma); 00467 00468 return set; 00469 } 00470 00471 //////////////////////////////////////////////////////////////////// 00472 // Function: osxGraphicsStateGuardian::restore_gamma 00473 // Access: Published 00474 // Description: Restore original gamma. 00475 //////////////////////////////////////////////////////////////////// 00476 void osxGraphicsStateGuardian:: 00477 restore_gamma() { 00478 static_set_gamma(true, 1.0f); 00479 } 00480 00481 //////////////////////////////////////////////////////////////////// 00482 // Function: osxGraphicsStateGuardian::atexit_function 00483 // Access: Public, Static 00484 // Description: This function is passed to the atexit function. 00485 //////////////////////////////////////////////////////////////////// 00486 void osxGraphicsStateGuardian:: 00487 atexit_function() { 00488 static_set_gamma(true, 1.0); 00489 } 00490 00491