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