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 // Apply the video-sync setting. 00104 GLint value = sync_video ? 1 : 0; 00105 aglSetInteger(_aglcontext, AGL_SWAP_INTERVAL, &value); 00106 } 00107 00108 //////////////////////////////////////////////////////////////////// 00109 // Function: osxGraphicsStateGuardian::draw_resize_box 00110 // Access: Public, Virtual 00111 // Description: Draws an OSX-style resize icon in the bottom right 00112 // corner of the current display region. This is 00113 // normally done automatically at the end of each frame 00114 // when the window is indicated as resizable, since the 00115 // 3-D graphics overlay the normal, OS-drawn resize icon 00116 // and the user won't be able see it. 00117 //////////////////////////////////////////////////////////////////// 00118 void osxGraphicsStateGuardian:: 00119 draw_resize_box() { 00120 // This state is created, once, and never freed. 00121 static CPT(RenderState) state; 00122 if (state == (RenderState *)NULL) { 00123 state = RenderState::make(TransparencyAttrib::make(TransparencyAttrib::M_alpha), 00124 DepthWriteAttrib::make(DepthWriteAttrib::M_off), 00125 DepthTestAttrib::make(DepthTestAttrib::M_none)); 00126 00127 // Get the default texture to apply to the resize box; it's 00128 // compiled into the code. 00129 string resize_box_string((const char *)resize_box, resize_box_len); 00130 istringstream resize_box_strm(resize_box_string); 00131 PNMImage resize_box_pnm; 00132 if (resize_box_pnm.read(resize_box_strm, "resize_box.rgb")) { 00133 PT(Texture) tex = new Texture; 00134 tex->set_name("resize_box.rgb"); 00135 tex->load(resize_box_pnm); 00136 tex->set_minfilter(Texture::FT_linear); 00137 tex->set_magfilter(Texture::FT_linear); 00138 state = state->add_attrib(TextureAttrib::make(tex)); 00139 } 00140 } 00141 00142 // Clear out the lens. 00143 _projection_mat_inv = _projection_mat = TransformState::make_identity(); 00144 prepare_lens(); 00145 00146 // Set the state to our specific, known state for drawing the icon. 00147 set_state_and_transform(state, TransformState::make_identity()); 00148 00149 // Now determine the inner corner of the quad, choosing a 15x15 00150 // pixel square in the lower-right corner, computed from the 00151 // viewport size. 00152 float inner_x = 1.0f - (15.0f * 2.0f / _viewport_width); 00153 float inner_y = (15.0f * 2.0f / _viewport_height) - 1.0f; 00154 00155 // Draw the quad. We just use the slow, simple immediate mode calls 00156 // here. It's just one quad, after all. 00157 glBegin(GL_QUADS); 00158 00159 glColor4f(1.0, 1.0, 1.0, 1.0); 00160 glTexCoord2f(0.0, 0.0); 00161 glVertex2f(inner_x, -1.0); 00162 00163 glTexCoord2f(0.9375, 0.0); 00164 glVertex2f(1.0, -1.0); 00165 00166 glTexCoord2f(0.9375, 0.9375); 00167 glVertex2f(1.0, inner_y); 00168 00169 glTexCoord2f(0.0, 0.9375); 00170 glVertex2f(inner_x, inner_y); 00171 00172 glEnd(); 00173 } 00174 00175 //////////////////////////////////////////////////////////////////// 00176 // Function: osxGraphicsStateGuardian::build_gl 00177 // Access: Public, Virtual 00178 // Description: This function will build up a context for a gsg.. 00179 //////////////////////////////////////////////////////////////////// 00180 OSStatus osxGraphicsStateGuardian:: 00181 build_gl(bool full_screen, bool pbuffer, FrameBufferProperties &fb_props) { 00182 if (_aglcontext) { 00183 describe_pixel_format(fb_props); 00184 return noErr; // already built 00185 } 00186 00187 OSStatus err = noErr; 00188 00189 GDHandle display = GetMainDevice(); 00190 00191 pvector<GLint> attrib; 00192 if (!fb_props.get_indexed_color()) { 00193 attrib.push_back(AGL_RGBA); 00194 int color_bits = fb_props.get_color_bits(); 00195 int alpha_bits = fb_props.get_alpha_bits(); 00196 attrib.push_back(AGL_BUFFER_SIZE); 00197 attrib.push_back(color_bits + alpha_bits); 00198 attrib.push_back(AGL_PIXEL_SIZE); 00199 attrib.push_back(color_bits); 00200 attrib.push_back(AGL_RED_SIZE); 00201 attrib.push_back(color_bits / 3); 00202 attrib.push_back(AGL_GREEN_SIZE); 00203 attrib.push_back(color_bits / 3); 00204 attrib.push_back(AGL_BLUE_SIZE); 00205 attrib.push_back(color_bits / 3); 00206 attrib.push_back(AGL_ALPHA_SIZE); 00207 attrib.push_back(alpha_bits); 00208 } 00209 attrib.push_back(AGL_DEPTH_SIZE); 00210 attrib.push_back(fb_props.get_depth_bits()); 00211 attrib.push_back(AGL_STENCIL_SIZE); 00212 attrib.push_back(fb_props.get_stencil_bits()); 00213 if (fb_props.get_multisamples() != 0) { 00214 attrib.push_back(AGL_MULTISAMPLE); 00215 attrib.push_back(AGL_SAMPLE_BUFFERS_ARB); 00216 attrib.push_back(1); 00217 attrib.push_back(AGL_SAMPLES_ARB); 00218 attrib.push_back(fb_props.get_multisamples()); 00219 } 00220 00221 if (fb_props.is_stereo()) { 00222 attrib.push_back(AGL_STEREO); 00223 } 00224 00225 if (!fb_props.is_single_buffered()) { 00226 attrib.push_back(AGL_DOUBLEBUFFER); 00227 } 00228 if (full_screen) { 00229 attrib.push_back(AGL_FULLSCREEN); 00230 } 00231 if (pbuffer) { 00232 attrib.push_back(AGL_PBUFFER); 00233 } 00234 00235 if (fb_props.get_force_hardware()) { 00236 attrib.push_back(AGL_ACCELERATED); 00237 attrib.push_back(AGL_NO_RECOVERY); 00238 } 00239 00240 // Allow the system to choose the largest buffers requested that 00241 // meets all our selections. 00242 attrib.push_back(AGL_MAXIMUM_POLICY); 00243 00244 // Terminate the list. 00245 attrib.push_back(AGL_NONE); 00246 00247 // build context 00248 _aglcontext = NULL; 00249 _aglPixFmt = aglChoosePixelFormat(&display, 1, &attrib[0]); 00250 err = report_agl_error("aglChoosePixelFormat"); 00251 if (_aglPixFmt) { 00252 if(_share_with == NULL) { 00253 _aglcontext = aglCreateContext(_aglPixFmt, NULL); 00254 } else { 00255 _aglcontext = aglCreateContext(_aglPixFmt, ((osxGraphicsStateGuardian *)_share_with)->_aglcontext); 00256 } 00257 err = report_agl_error("aglCreateContext"); 00258 00259 if (_aglcontext == NULL) { 00260 osxdisplay_cat.error() 00261 << "osxGraphicsStateGuardian::build_gl Error Getting GL Context \n" ; 00262 if(err == noErr) { 00263 err = -1; 00264 } 00265 } else { 00266 aglSetInteger(_aglcontext, AGL_BUFFER_NAME, &_shared_buffer); 00267 err = report_agl_error("aglSetInteger AGL_BUFFER_NAME"); 00268 } 00269 00270 } else { 00271 osxdisplay_cat.error() 00272 << "osxGraphicsStateGuardian::build_gl Error Getting Pixel Format\n" ; 00273 osxdisplay_cat.error() 00274 << fb_props << "\n"; 00275 if(err == noErr) { 00276 err = -1; 00277 } 00278 } 00279 00280 if (err == noErr) { 00281 describe_pixel_format(fb_props); 00282 } 00283 00284 if (osxdisplay_cat.is_debug()) { 00285 osxdisplay_cat.debug() 00286 << "osxGraphicsStateGuardian::build_gl Returning :" << err << "\n"; 00287 osxdisplay_cat.debug() 00288 << fb_props << "\n"; 00289 } 00290 00291 return err; 00292 } 00293 00294 00295 //////////////////////////////////////////////////////////////////// 00296 // Function: osxGraphicsStateGuardian::describe_pixel_format 00297 // Access: Private 00298 // Description: Fills in the fb_props member with the appropriate 00299 // values according to the chosen pixel format. 00300 //////////////////////////////////////////////////////////////////// 00301 void osxGraphicsStateGuardian:: 00302 describe_pixel_format(FrameBufferProperties &fb_props) { 00303 fb_props.clear(); 00304 GLint value; 00305 00306 if (aglDescribePixelFormat(_aglPixFmt, AGL_RGBA, &value)) { 00307 fb_props.set_indexed_color(!value); 00308 fb_props.set_rgb_color(value); 00309 } 00310 if (aglDescribePixelFormat(_aglPixFmt, AGL_DEPTH_SIZE, &value)) { 00311 fb_props.set_depth_bits(value); 00312 } 00313 int color_bits = 0; 00314 if (aglDescribePixelFormat(_aglPixFmt, AGL_RED_SIZE, &value)) { 00315 color_bits += value; 00316 } 00317 if (aglDescribePixelFormat(_aglPixFmt, AGL_GREEN_SIZE, &value)) { 00318 color_bits += value; 00319 } 00320 if (aglDescribePixelFormat(_aglPixFmt, AGL_BLUE_SIZE, &value)) { 00321 color_bits += value; 00322 } 00323 fb_props.set_color_bits(color_bits); 00324 if (aglDescribePixelFormat(_aglPixFmt, AGL_ALPHA_SIZE, &value)) { 00325 fb_props.set_alpha_bits(value); 00326 } 00327 00328 if (aglDescribePixelFormat(_aglPixFmt, AGL_STENCIL_SIZE, &value)) { 00329 fb_props.set_stencil_bits(value); 00330 } 00331 00332 int accum_bits = 0; 00333 if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_RED_SIZE, &value)) { 00334 accum_bits += value; 00335 } 00336 if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_GREEN_SIZE, &value)) { 00337 accum_bits += value; 00338 } 00339 if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_BLUE_SIZE, &value)) { 00340 accum_bits += value; 00341 } 00342 00343 if (aglDescribePixelFormat(_aglPixFmt, AGL_SAMPLES_ARB, &value)) { 00344 fb_props.set_multisamples(value); 00345 } 00346 00347 if (aglDescribePixelFormat(_aglPixFmt, AGL_DOUBLEBUFFER, &value)) { 00348 if (value) { 00349 fb_props.set_back_buffers(1); 00350 } else { 00351 fb_props.set_back_buffers(0); 00352 } 00353 } 00354 00355 if (aglDescribePixelFormat(_aglPixFmt, AGL_STEREO, &value)) { 00356 fb_props.set_stereo(value); 00357 } 00358 00359 // Until we query the renderer, we don't know whether it's hardware 00360 // or software based, so set both flags to indicate we don't know. 00361 fb_props.set_force_hardware(true); 00362 fb_props.set_force_software(true); 00363 00364 GLint ndevs; 00365 AGLDevice *gdevs = aglDevicesOfPixelFormat(_aglPixFmt, &ndevs); 00366 if (gdevs != (AGLDevice *)NULL) { 00367 AGLRendererInfo rinfo = aglQueryRendererInfo(gdevs, ndevs); 00368 if (rinfo != NULL) { 00369 if (aglDescribeRenderer(rinfo, AGL_ACCELERATED, &value)) { 00370 // Now we know whether it's hardware or software. 00371 fb_props.set_force_hardware(value); 00372 fb_props.set_force_software(!value); 00373 } 00374 if (aglDescribeRenderer(rinfo, AGL_VIDEO_MEMORY, &value)) { 00375 osxdisplay_cat.debug() 00376 << "Reported video memory is " << value << "\n"; 00377 } 00378 if (aglDescribeRenderer(rinfo, AGL_TEXTURE_MEMORY, &value)) { 00379 osxdisplay_cat.debug() 00380 << "Reported texture memory is " << value << "\n"; 00381 } 00382 } 00383 } 00384 } 00385 00386 //////////////////////////////////////////////////////////////////// 00387 // Function: osxGraphicsStateGuardian::get_gamma_table 00388 // Access: Public, Static 00389 // Description: Static function for getting the orig gamma tables 00390 //////////////////////////////////////////////////////////////////// 00391 bool osxGraphicsStateGuardian:: 00392 get_gamma_table() { 00393 CGDisplayRestoreColorSyncSettings(); 00394 _cgErr = CGGetDisplayTransferByTable( 0, 256, _gOriginalRedTable, _gOriginalGreenTable, _gOriginalBlueTable, &_sampleCount); 00395 } 00396 00397 //////////////////////////////////////////////////////////////////// 00398 // Function: osxGraphicsStateGuardian::static_set_gamma 00399 // Access: Public, Static 00400 // Description: Static function for setting gamma which is needed 00401 // for atexit. 00402 //////////////////////////////////////////////////////////////////// 00403 bool osxGraphicsStateGuardian:: 00404 static_set_gamma(bool restore, float gamma) { 00405 bool set; 00406 00407 set = false; 00408 00409 if (restore) { 00410 CGDisplayRestoreColorSyncSettings(); 00411 set = true; 00412 return set; 00413 } 00414 // CGDisplayRestoreColorSyncSettings(); 00415 00416 // CGGammaValue gOriginalRedTable[ 256 ]; 00417 // CGGammaValue gOriginalGreenTable[ 256 ]; 00418 // CGGammaValue gOriginalBlueTable[ 256 ]; 00419 00420 // CGTableCount sampleCount; 00421 // CGDisplayErr cgErr; 00422 00423 // cgErr = CGGetDisplayTransferByTable( 0, 256, _gOriginalRedTable, _gOriginalGreenTable, _gOriginalBlueTable, &_sampleCount); 00424 00425 CGGammaValue redTable[ 256 ]; 00426 CGGammaValue greenTable[ 256 ]; 00427 CGGammaValue blueTable[ 256 ]; 00428 00429 short j, i; 00430 short y[3]; 00431 00432 for (j = 0; j < 3; j++) { 00433 y[j] = 255; 00434 } 00435 00436 y[0] = 256 * gamma; 00437 y[1] = 256 * gamma; 00438 y[2] = 256 * gamma; 00439 00440 for (i = 0; i < 256; i++) { 00441 redTable[i] = _gOriginalRedTable[ i ] * (y[ 0 ] ) / 256; 00442 greenTable[ i ] = _gOriginalGreenTable[ i ] * (y[ 1 ] ) / 256; 00443 blueTable[ i ] = _gOriginalBlueTable[ i ] * (y[ 2 ] ) / 256; 00444 } 00445 _cgErr = CGSetDisplayTransferByTable( 0, 256, redTable, greenTable, blueTable); 00446 00447 if (_cgErr == 0) { 00448 set = true; 00449 } 00450 00451 return set; 00452 } 00453 00454 //////////////////////////////////////////////////////////////////// 00455 // Function: osxGraphicsStateGuardian::set_gamma 00456 // Access: Published 00457 // Description: Non static version of setting gamma. Returns true 00458 // on success. 00459 //////////////////////////////////////////////////////////////////// 00460 bool osxGraphicsStateGuardian:: 00461 set_gamma(float gamma) { 00462 bool set; 00463 00464 set = static_set_gamma(false, gamma); 00465 00466 return set; 00467 } 00468 00469 //////////////////////////////////////////////////////////////////// 00470 // Function: osxGraphicsStateGuardian::restore_gamma 00471 // Access: Published 00472 // Description: Restore original gamma. 00473 //////////////////////////////////////////////////////////////////// 00474 void osxGraphicsStateGuardian:: 00475 restore_gamma() { 00476 static_set_gamma(true, 1.0f); 00477 } 00478 00479 //////////////////////////////////////////////////////////////////// 00480 // Function: osxGraphicsStateGuardian::atexit_function 00481 // Access: Public, Static 00482 // Description: This function is passed to the atexit function. 00483 //////////////////////////////////////////////////////////////////// 00484 void osxGraphicsStateGuardian:: 00485 atexit_function() { 00486 static_set_gamma(true, 1.0); 00487 } 00488 00489