Panda3D
osxGraphicsStateGuardian.cxx
1 ////////////////////////////////////////////////////////////////////
2 //
3 // PANDA 3D SOFTWARE
4 // Copyright (c) Carnegie Mellon University. All rights reserved.
5 //
6 // All use of this software is subject to the terms of the revised BSD
7 // license. You should have received a copy of this license along
8 // with this source code in a file named "LICENSE."
9 //
10 ////////////////////////////////////////////////////////////////////
11 
12 #include "osxGraphicsStateGuardian.h"
13 #include "osxGraphicsBuffer.h"
14 #include "string_utils.h"
15 #include "config_osxdisplay.h"
16 #include "depthWriteAttrib.h"
17 #include "depthTestAttrib.h"
18 #include "textureAttrib.h"
19 #include "pnmImage.h"
20 
21 #include <OpenGL/gl.h>
22 #import <mach-o/dyld.h>
23 
24 // This is generated data for the standard texture we use for drawing
25 // the resize box in the window corner.
26 #include "resize_box.rgb.c"
27 
28 TypeHandle osxGraphicsStateGuardian::_type_handle;
29 
30 ////////////////////////////////////////////////////////////////////
31 // Function: osxGraphicsStateGuardian::do_get_extension_func
32 // Access: Public, Virtual
33 // Description: Returns the pointer to the GL extension function with
34 // the indicated name. It is the responsibility of the
35 // caller to ensure that the required extension is
36 // defined in the OpenGL runtime prior to calling this;
37 // it is an error to call this for a function that is
38 // not defined.
39 ////////////////////////////////////////////////////////////////////
40 void *osxGraphicsStateGuardian::
41 do_get_extension_func(const char *name) {
42  string fullname = "_" + string(name);
43  NSSymbol symbol = NULL;
44 
45  if (NSIsSymbolNameDefined(fullname.c_str())) {
46  symbol = NSLookupAndBindSymbol(fullname.c_str());
47  }
48 
49  return symbol ? NSAddressOfSymbol(symbol) : NULL;
50 }
51 
52 ////////////////////////////////////////////////////////////////////
53 // Function: osxGraphicsStateGuardian::Constructor
54 // Access: Public
55 // Description:
56 ////////////////////////////////////////////////////////////////////
57 osxGraphicsStateGuardian::
58 osxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
59  osxGraphicsStateGuardian *share_with) :
60  GLGraphicsStateGuardian(engine, pipe),
61  _share_with(share_with),
62  _aglPixFmt(NULL),
63  _aglcontext(NULL)
64 {
65  _shared_buffer = 1011;
67 }
68 
69 ////////////////////////////////////////////////////////////////////
70 // Function: osxGraphicsStateGuardian::Destructor
71 // Access: Public
72 // Description:
73 ////////////////////////////////////////////////////////////////////
74 osxGraphicsStateGuardian::
75 ~osxGraphicsStateGuardian() {
76  if (_aglcontext != (AGLContext)NULL) {
77  aglSetCurrentContext(NULL);
78  aglDestroyContext(_aglcontext);
79  report_agl_error("aglDestroyContext");
80  _aglcontext = (AGLContext)NULL;
81  }
82 }
83 
84 ////////////////////////////////////////////////////////////////////
85 // Function: osxGraphicsStateGuardian::reset
86 // Access: Public, Virtual
87 // Description: Resets all internal state as if the gsg were newly
88 // created.
89 ////////////////////////////////////////////////////////////////////
91 {
92 /*
93  if(_aglcontext != (AGLContext)NULL)
94  {
95  aglDestroyContext(_aglcontext);
96  report_agl_error();
97  _aglcontext = (AGLContext)NULL;
98  }
99  */
100 
101  GLGraphicsStateGuardian::reset();
102 
103  if (_aglcontext != (AGLContext)NULL) {
104  // Apply the video-sync setting.
105  GLint value = sync_video ? 1 : 0;
106  aglSetInteger(_aglcontext, AGL_SWAP_INTERVAL, &value);
107  }
108 }
109 
110 ////////////////////////////////////////////////////////////////////
111 // Function: osxGraphicsStateGuardian::draw_resize_box
112 // Access: Public, Virtual
113 // Description: Draws an OSX-style resize icon in the bottom right
114 // corner of the current display region. This is
115 // normally done automatically at the end of each frame
116 // when the window is indicated as resizable, since the
117 // 3-D graphics overlay the normal, OS-drawn resize icon
118 // and the user won't be able see it.
119 ////////////////////////////////////////////////////////////////////
122  // This state is created, once, and never freed.
123  static CPT(RenderState) state;
124  if (state == (RenderState *)NULL) {
125  state = RenderState::make(TransparencyAttrib::make(TransparencyAttrib::M_alpha),
126  DepthWriteAttrib::make(DepthWriteAttrib::M_off),
127  DepthTestAttrib::make(DepthTestAttrib::M_none));
128 
129  // Get the default texture to apply to the resize box; it's
130  // compiled into the code.
131  string resize_box_string((const char *)resize_box, resize_box_len);
132  istringstream resize_box_strm(resize_box_string);
133  PNMImage resize_box_pnm;
134  if (resize_box_pnm.read(resize_box_strm, "resize_box.rgb")) {
135  PT(Texture) tex = new Texture;
136  tex->set_name("resize_box.rgb");
137  tex->load(resize_box_pnm);
138  tex->set_minfilter(SamplerState::FT_linear);
139  tex->set_magfilter(SamplerState::FT_linear);
140  state = state->add_attrib(TextureAttrib::make(tex));
141  }
142  }
143 
144  // Clear out the lens.
145  _projection_mat_inv = _projection_mat = TransformState::make_identity();
146  prepare_lens();
147 
148  // Set the state to our specific, known state for drawing the icon.
149  set_state_and_transform(state, TransformState::make_identity());
150 
151  // Now determine the inner corner of the quad, choosing a 15x15
152  // pixel square in the lower-right corner, computed from the
153  // viewport size.
154  PN_stdfloat inner_x = 1.0f - (15.0f * 2.0f / _viewport_width);
155  PN_stdfloat inner_y = (15.0f * 2.0f / _viewport_height) - 1.0f;
156 
157  // Draw the quad. We just use the slow, simple immediate mode calls
158  // here. It's just one quad, after all.
159  glBegin(GL_QUADS);
160 
161  glColor4f(1.0, 1.0, 1.0, 1.0);
162  glTexCoord2f(0.0, 0.0);
163  glVertex2f(inner_x, -1.0);
164 
165  glTexCoord2f(0.9375, 0.0);
166  glVertex2f(1.0, -1.0);
167 
168  glTexCoord2f(0.9375, 0.9375);
169  glVertex2f(1.0, inner_y);
170 
171  glTexCoord2f(0.0, 0.9375);
172  glVertex2f(inner_x, inner_y);
173 
174  glEnd();
175 }
176 
177 ////////////////////////////////////////////////////////////////////
178 // Function: osxGraphicsStateGuardian::build_gl
179 // Access: Public, Virtual
180 // Description: This function will build up a context for a gsg..
181 ////////////////////////////////////////////////////////////////////
183 build_gl(bool full_screen, bool pbuffer, FrameBufferProperties &fb_props) {
184  if (_aglcontext) {
185  describe_pixel_format(fb_props);
186  return noErr; // already built
187  }
188 
189  OSStatus err = noErr;
190 
191  GDHandle display = GetMainDevice();
192 
193  pvector<GLint> attrib;
194  if (!fb_props.get_indexed_color()) {
195  attrib.push_back(AGL_RGBA);
196  int color_bits = fb_props.get_color_bits();
197  int alpha_bits = fb_props.get_alpha_bits();
198  attrib.push_back(AGL_BUFFER_SIZE);
199  attrib.push_back(color_bits + alpha_bits);
200  attrib.push_back(AGL_PIXEL_SIZE);
201  attrib.push_back(color_bits);
202  attrib.push_back(AGL_RED_SIZE);
203  attrib.push_back(fb_props.get_red_bits());
204  attrib.push_back(AGL_GREEN_SIZE);
205  attrib.push_back(fb_props.get_green_bits());
206  attrib.push_back(AGL_BLUE_SIZE);
207  attrib.push_back(fb_props.get_blue_bits());
208  attrib.push_back(AGL_ALPHA_SIZE);
209  attrib.push_back(alpha_bits);
210  }
211  attrib.push_back(AGL_DEPTH_SIZE);
212  attrib.push_back(fb_props.get_depth_bits());
213  attrib.push_back(AGL_STENCIL_SIZE);
214  attrib.push_back(fb_props.get_stencil_bits());
215  if (fb_props.get_multisamples() != 0) {
216  attrib.push_back(AGL_MULTISAMPLE);
217  attrib.push_back(AGL_SAMPLE_BUFFERS_ARB);
218  attrib.push_back(1);
219  attrib.push_back(AGL_SAMPLES_ARB);
220  attrib.push_back(fb_props.get_multisamples());
221  }
222 
223  if (fb_props.is_stereo()) {
224  attrib.push_back(AGL_STEREO);
225  }
226 
227  if (!fb_props.is_single_buffered()) {
228  attrib.push_back(AGL_DOUBLEBUFFER);
229  }
230  if (full_screen) {
231  attrib.push_back(AGL_FULLSCREEN);
232  }
233  if (pbuffer) {
234  attrib.push_back(AGL_PBUFFER);
235  }
236 
237  if (fb_props.get_force_hardware()) {
238  attrib.push_back(AGL_ACCELERATED);
239  attrib.push_back(AGL_NO_RECOVERY);
240  }
241 
242  // Allow the system to choose the largest buffers requested that
243  // meets all our selections.
244  attrib.push_back(AGL_MAXIMUM_POLICY);
245 
246  // Terminate the list.
247  attrib.push_back(AGL_NONE);
248 
249  // build context
250  _aglcontext = NULL;
251  _aglPixFmt = aglChoosePixelFormat(&display, 1, &attrib[0]);
252  err = report_agl_error("aglChoosePixelFormat");
253  if (_aglPixFmt) {
254  if(_share_with == NULL) {
255  _aglcontext = aglCreateContext(_aglPixFmt, NULL);
256  } else {
257  _aglcontext = aglCreateContext(_aglPixFmt, ((osxGraphicsStateGuardian *)_share_with)->_aglcontext);
258  }
259  err = report_agl_error("aglCreateContext");
260 
261  if (_aglcontext == NULL) {
262  osxdisplay_cat.error()
263  << "osxGraphicsStateGuardian::build_gl Error Getting GL Context \n" ;
264  if(err == noErr) {
265  err = -1;
266  }
267  } else {
268  aglSetInteger(_aglcontext, AGL_BUFFER_NAME, &_shared_buffer);
269  err = report_agl_error("aglSetInteger AGL_BUFFER_NAME");
270  }
271 
272  } else {
273  osxdisplay_cat.error()
274  << "osxGraphicsStateGuardian::build_gl Error Getting Pixel Format\n" ;
275  osxdisplay_cat.error()
276  << fb_props << "\n";
277  if(err == noErr) {
278  err = -1;
279  }
280  }
281 
282  if (err == noErr) {
283  describe_pixel_format(fb_props);
284  }
285 
286  if (osxdisplay_cat.is_debug()) {
287  osxdisplay_cat.debug()
288  << "osxGraphicsStateGuardian::build_gl Returning :" << err << "\n";
289  osxdisplay_cat.debug()
290  << fb_props << "\n";
291  }
292 
293  return err;
294 }
295 
296 
297 ////////////////////////////////////////////////////////////////////
298 // Function: osxGraphicsStateGuardian::describe_pixel_format
299 // Access: Private
300 // Description: Fills in the fb_props member with the appropriate
301 // values according to the chosen pixel format.
302 ////////////////////////////////////////////////////////////////////
303 void osxGraphicsStateGuardian::
304 describe_pixel_format(FrameBufferProperties &fb_props) {
305  fb_props.clear();
306  GLint value;
307 
308  if (aglDescribePixelFormat(_aglPixFmt, AGL_RGBA, &value)) {
309  fb_props.set_indexed_color(!value);
310  fb_props.set_rgb_color(value);
311  }
312  if (aglDescribePixelFormat(_aglPixFmt, AGL_DEPTH_SIZE, &value)) {
313  fb_props.set_depth_bits(value);
314  }
315  int color_bits = 0;
316  if (aglDescribePixelFormat(_aglPixFmt, AGL_RED_SIZE, &value)) {
317  fb_props.set_red_bits(value);
318  color_bits += value;
319  }
320  if (aglDescribePixelFormat(_aglPixFmt, AGL_GREEN_SIZE, &value)) {
321  fb_props.set_green_bits(value);
322  color_bits += value;
323  }
324  if (aglDescribePixelFormat(_aglPixFmt, AGL_BLUE_SIZE, &value)) {
325  fb_props.set_blue_bits(value);
326  color_bits += value;
327  }
328  fb_props.set_color_bits(color_bits);
329  if (aglDescribePixelFormat(_aglPixFmt, AGL_ALPHA_SIZE, &value)) {
330  fb_props.set_alpha_bits(value);
331  }
332 
333  if (aglDescribePixelFormat(_aglPixFmt, AGL_STENCIL_SIZE, &value)) {
334  fb_props.set_stencil_bits(value);
335  }
336 
337  int accum_bits = 0;
338  if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_RED_SIZE, &value)) {
339  accum_bits += value;
340  }
341  if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_GREEN_SIZE, &value)) {
342  accum_bits += value;
343  }
344  if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_BLUE_SIZE, &value)) {
345  accum_bits += value;
346  }
347 
348  if (aglDescribePixelFormat(_aglPixFmt, AGL_SAMPLES_ARB, &value)) {
349  fb_props.set_multisamples(value);
350  }
351 
352  if (aglDescribePixelFormat(_aglPixFmt, AGL_DOUBLEBUFFER, &value)) {
353  if (value) {
354  fb_props.set_back_buffers(1);
355  } else {
356  fb_props.set_back_buffers(0);
357  }
358  }
359 
360  if (aglDescribePixelFormat(_aglPixFmt, AGL_STEREO, &value)) {
361  fb_props.set_stereo(value);
362  }
363 
364  // Until we query the renderer, we don't know whether it's hardware
365  // or software based, so set both flags to indicate we don't know.
366  fb_props.set_force_hardware(true);
367  fb_props.set_force_software(true);
368 
369  GLint ndevs;
370  AGLDevice *gdevs = aglDevicesOfPixelFormat(_aglPixFmt, &ndevs);
371  if (gdevs != (AGLDevice *)NULL) {
372  AGLRendererInfo rinfo = aglQueryRendererInfo(gdevs, ndevs);
373  if (rinfo != NULL) {
374  if (aglDescribeRenderer(rinfo, AGL_ACCELERATED, &value)) {
375  // Now we know whether it's hardware or software.
376  fb_props.set_force_hardware(value);
377  fb_props.set_force_software(!value);
378  }
379  if (aglDescribeRenderer(rinfo, AGL_VIDEO_MEMORY, &value)) {
380  osxdisplay_cat.debug()
381  << "Reported video memory is " << value << "\n";
382  }
383  if (aglDescribeRenderer(rinfo, AGL_TEXTURE_MEMORY, &value)) {
384  osxdisplay_cat.debug()
385  << "Reported texture memory is " << value << "\n";
386  }
387  }
388  }
389 }
390 
391 ////////////////////////////////////////////////////////////////////
392 // Function: osxGraphicsStateGuardian::get_gamma_table
393 // Access: Public, Static
394 // Description: Static function for getting the orig gamma tables
395 ////////////////////////////////////////////////////////////////////
398  CGDisplayRestoreColorSyncSettings();
399  _cgErr = CGGetDisplayTransferByTable( 0, 256, _gOriginalRedTable, _gOriginalGreenTable, _gOriginalBlueTable, &_sampleCount);
400 }
401 
402 ////////////////////////////////////////////////////////////////////
403 // Function: osxGraphicsStateGuardian::static_set_gamma
404 // Access: Public, Static
405 // Description: Static function for setting gamma which is needed
406 // for atexit.
407 ////////////////////////////////////////////////////////////////////
409 static_set_gamma(bool restore, PN_stdfloat gamma) {
410  bool set;
411 
412  set = false;
413 
414  if (restore) {
415  CGDisplayRestoreColorSyncSettings();
416  set = true;
417  return set;
418  }
419  // CGDisplayRestoreColorSyncSettings();
420 
421  // CGGammaValue gOriginalRedTable[ 256 ];
422  // CGGammaValue gOriginalGreenTable[ 256 ];
423  // CGGammaValue gOriginalBlueTable[ 256 ];
424 
425  // CGTableCount sampleCount;
426  // CGDisplayErr cgErr;
427 
428  // cgErr = CGGetDisplayTransferByTable( 0, 256, _gOriginalRedTable, _gOriginalGreenTable, _gOriginalBlueTable, &_sampleCount);
429 
430  CGGammaValue redTable[ 256 ];
431  CGGammaValue greenTable[ 256 ];
432  CGGammaValue blueTable[ 256 ];
433 
434  short j, i;
435  short y[3];
436 
437  for (j = 0; j < 3; j++) {
438  y[j] = 255;
439  }
440 
441  y[0] = 256 * gamma;
442  y[1] = 256 * gamma;
443  y[2] = 256 * gamma;
444 
445  for (i = 0; i < 256; i++) {
446  redTable[i] = _gOriginalRedTable[ i ] * (y[ 0 ] ) / 256;
447  greenTable[ i ] = _gOriginalGreenTable[ i ] * (y[ 1 ] ) / 256;
448  blueTable[ i ] = _gOriginalBlueTable[ i ] * (y[ 2 ] ) / 256;
449  }
450  _cgErr = CGSetDisplayTransferByTable( 0, 256, redTable, greenTable, blueTable);
451 
452  if (_cgErr == 0) {
453  set = true;
454  }
455 
456  return set;
457 }
458 
459 ////////////////////////////////////////////////////////////////////
460 // Function: osxGraphicsStateGuardian::set_gamma
461 // Access: Published
462 // Description: Non static version of setting gamma. Returns true
463 // on success.
464 ////////////////////////////////////////////////////////////////////
466 set_gamma(PN_stdfloat gamma) {
467  bool set;
468 
469  set = static_set_gamma(false, gamma);
470 
471  return set;
472 }
473 
474 ////////////////////////////////////////////////////////////////////
475 // Function: osxGraphicsStateGuardian::restore_gamma
476 // Access: Published
477 // Description: Restore original gamma.
478 ////////////////////////////////////////////////////////////////////
481  static_set_gamma(true, 1.0f);
482 }
483 
484 ////////////////////////////////////////////////////////////////////
485 // Function: osxGraphicsStateGuardian::atexit_function
486 // Access: Public, Static
487 // Description: This function is passed to the atexit function.
488 ////////////////////////////////////////////////////////////////////
491  static_set_gamma(true, 1.0);
492 }
493 
494 
bool set_gamma(PN_stdfloat gamma)
Non static version of setting gamma.
void clear()
Unsets all properties that have been specified so far, and resets the FrameBufferProperties structure...
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition: pnmImage.h:68
bool read(const Filename &filename, PNMFileType *type=NULL, bool report_unknown_type=true)
Reads the indicated image filename.
Definition: pnmImage.cxx:245
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
void draw_resize_box()
Draws an OSX-style resize icon in the bottom right corner of the current display region.
A tiny specialization on GLGraphicsStateGuardian to add some wgl-specific information.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
void atexit_function()
This function is passed to the atexit function.
bool static_set_gamma(bool restore, PN_stdfloat gamma)
Static function for setting gamma which is needed for atexit.
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:58
void restore_gamma()
Restore original gamma.
OSStatus build_gl(bool full_screen, bool pbuffer, FrameBufferProperties &fb_props)
This function will build up a context for a gsg.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
void set_color_bits(int n)
Sets the number of requested color bits as a single number that represents the sum of the individual ...
This class is the main interface to controlling the render process.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
virtual void reset()
Resets all internal state as if the gsg were newly created.
bool get_gamma_table()
Static function for getting the orig gamma tables.