Panda3D

osxGraphicsStateGuardian.cxx

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 
 All Classes Functions Variables Enumerations