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