1 | /*
|
---|
2 | -----------------------------------------------------------------------------
|
---|
3 | This source file is part of OGRE
|
---|
4 | (Object-oriented Graphics Rendering Engine)
|
---|
5 | For the latest info, see http://www.ogre3d.org/
|
---|
6 |
|
---|
7 | Copyright (c) 2000-2006 Torus Knot Software Ltd
|
---|
8 | Also see acknowledgements in Readme.html
|
---|
9 |
|
---|
10 | This program is free software; you can redistribute it and/or modify it under
|
---|
11 | the terms of the GNU Lesser General Public License as published by the Free Software
|
---|
12 | Foundation; either version 2 of the License, or (at your option) any later
|
---|
13 | version.
|
---|
14 |
|
---|
15 | This program is distributed in the hope that it will be useful, but WITHOUT
|
---|
16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
---|
17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
---|
18 |
|
---|
19 | You should have received a copy of the GNU Lesser General Public License along with
|
---|
20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
---|
21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to
|
---|
22 | http://www.gnu.org/copyleft/lesser.txt.
|
---|
23 |
|
---|
24 | You may alternatively use this source under the terms of a specific version of
|
---|
25 | the OGRE Unrestricted License provided you have obtained such a license from
|
---|
26 | Torus Knot Software Ltd.
|
---|
27 | -----------------------------------------------------------------------------
|
---|
28 | */
|
---|
29 |
|
---|
30 | #include "OgreException.h"
|
---|
31 | #include "OgreLogManager.h"
|
---|
32 | #include "OgreStringConverter.h"
|
---|
33 | #include "OgreRoot.h"
|
---|
34 |
|
---|
35 | #include "OgreOSXGLSupport.h"
|
---|
36 | #include "OgreOSXCarbonWindow.h"
|
---|
37 | #include "OgreOSXCocoaWindow.h"
|
---|
38 |
|
---|
39 | #include "OgreGLTexture.h"
|
---|
40 | #include "OgreOSXRenderTexture.h"
|
---|
41 |
|
---|
42 | #include <OpenGL/OpenGL.h>
|
---|
43 | #include <mach-o/dyld.h>
|
---|
44 |
|
---|
45 | namespace Ogre {
|
---|
46 |
|
---|
47 | OSXGLSupport::OSXGLSupport() : mAPI(""), mContextType("")
|
---|
48 | {
|
---|
49 | }
|
---|
50 |
|
---|
51 | OSXGLSupport::~OSXGLSupport()
|
---|
52 | {
|
---|
53 | }
|
---|
54 |
|
---|
55 | void OSXGLSupport::addConfig( void )
|
---|
56 | {
|
---|
57 | ConfigOption optFullScreen;
|
---|
58 | ConfigOption optVideoMode;
|
---|
59 | ConfigOption optBitDepth;
|
---|
60 | ConfigOption optFSAA;
|
---|
61 | ConfigOption optRTTMode;
|
---|
62 |
|
---|
63 | // FS setting possiblities
|
---|
64 | optFullScreen.name = "Full Screen";
|
---|
65 | optFullScreen.possibleValues.push_back( "Yes" );
|
---|
66 | optFullScreen.possibleValues.push_back( "No" );
|
---|
67 | optFullScreen.currentValue = "No";
|
---|
68 | optFullScreen.immutable = false;
|
---|
69 |
|
---|
70 | optBitDepth.name = "Colour Depth";
|
---|
71 | optBitDepth.possibleValues.push_back( "32" );
|
---|
72 | optBitDepth.possibleValues.push_back( "16" );
|
---|
73 | optBitDepth.currentValue = "32";
|
---|
74 | optBitDepth.immutable = false;
|
---|
75 |
|
---|
76 | mOptions[ optFullScreen.name ] = optFullScreen;
|
---|
77 | mOptions[ optBitDepth.name ] = optBitDepth;
|
---|
78 |
|
---|
79 | CGLRendererInfoObj rend;
|
---|
80 | long nrend;
|
---|
81 | CGLQueryRendererInfo(CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay), &rend, &nrend);
|
---|
82 |
|
---|
83 | long maxSamples;
|
---|
84 | CGLDescribeRenderer(rend, 0, kCGLRPMaxSamples, &maxSamples);
|
---|
85 |
|
---|
86 | //FSAA possibilities
|
---|
87 | optFSAA.name = "FSAA";
|
---|
88 | optFSAA.possibleValues.push_back( "0" );
|
---|
89 |
|
---|
90 | switch( maxSamples )
|
---|
91 | {
|
---|
92 | case 6:
|
---|
93 | optFSAA.possibleValues.push_back( "2" );
|
---|
94 | optFSAA.possibleValues.push_back( "4" );
|
---|
95 | optFSAA.possibleValues.push_back( "6" );
|
---|
96 | break;
|
---|
97 | case 4:
|
---|
98 | optFSAA.possibleValues.push_back( "2" );
|
---|
99 | optFSAA.possibleValues.push_back( "4" );
|
---|
100 | break;
|
---|
101 | case 2:
|
---|
102 | optFSAA.possibleValues.push_back( "2" );
|
---|
103 | break;
|
---|
104 | default: break;
|
---|
105 | }
|
---|
106 |
|
---|
107 | optFSAA.currentValue = "0";
|
---|
108 | optFSAA.immutable = false;
|
---|
109 |
|
---|
110 | mOptions[ optFSAA.name ] = optFSAA;
|
---|
111 |
|
---|
112 | // Video mode possiblities
|
---|
113 | optVideoMode.name = "Video Mode";
|
---|
114 | optVideoMode.immutable = false;
|
---|
115 |
|
---|
116 | CFArrayRef displayModes = CGDisplayAvailableModes(CGMainDisplayID());
|
---|
117 | CFIndex numModes = CFArrayGetCount(displayModes);
|
---|
118 | CFMutableArrayRef goodModes = NULL;
|
---|
119 | goodModes = CFArrayCreateMutable(kCFAllocatorDefault, numModes, NULL);
|
---|
120 |
|
---|
121 | // Grab all the available display modes, then weed out duplicates...
|
---|
122 | for(int i = 0; i < numModes; ++i)
|
---|
123 | {
|
---|
124 | CFDictionaryRef modeInfo = (CFDictionaryRef)CFArrayGetValueAtIndex(displayModes, i);
|
---|
125 |
|
---|
126 | Boolean safeForHardware = _getDictionaryBoolean(modeInfo, kCGDisplayModeIsSafeForHardware);
|
---|
127 | Boolean stretched = _getDictionaryBoolean(modeInfo, kCGDisplayModeIsStretched);
|
---|
128 | Boolean skipped = false;
|
---|
129 |
|
---|
130 | if((safeForHardware) || (!stretched))
|
---|
131 | {
|
---|
132 | long width = _getDictionaryLong(modeInfo, kCGDisplayWidth);
|
---|
133 | long height = _getDictionaryLong(modeInfo, kCGDisplayHeight);
|
---|
134 |
|
---|
135 | for(int j = 0; j < CFArrayGetCount(goodModes); ++j)
|
---|
136 | {
|
---|
137 | CFDictionaryRef otherMode = (CFDictionaryRef)CFArrayGetValueAtIndex(goodModes, j);
|
---|
138 |
|
---|
139 | long otherWidth = _getDictionaryLong(otherMode, kCGDisplayWidth);
|
---|
140 | long otherHeight = _getDictionaryLong(otherMode, kCGDisplayHeight);
|
---|
141 |
|
---|
142 | // If we find a duplicate then skip this mode
|
---|
143 | if((otherWidth == width) && (otherHeight == height))
|
---|
144 | skipped = true;
|
---|
145 | }
|
---|
146 |
|
---|
147 | // This is a new mode, so add it to our goodModes array
|
---|
148 | if(!skipped)
|
---|
149 | CFArrayAppendValue(goodModes, modeInfo);
|
---|
150 | }
|
---|
151 | }
|
---|
152 |
|
---|
153 | // Sort the modes...
|
---|
154 | CFArraySortValues(goodModes, CFRangeMake(0, CFArrayGetCount(goodModes)),
|
---|
155 | (CFComparatorFunction)_compareModes, NULL);
|
---|
156 |
|
---|
157 | // Now pull the modes out and put them into optVideoModes
|
---|
158 | for(int i = 0; i < CFArrayGetCount(goodModes); ++i)
|
---|
159 | {
|
---|
160 | CFDictionaryRef resolution = (CFDictionaryRef)CFArrayGetValueAtIndex(goodModes, i);
|
---|
161 |
|
---|
162 | long fWidth = _getDictionaryLong(resolution, kCGDisplayWidth);
|
---|
163 | long fHeight = _getDictionaryLong(resolution, kCGDisplayHeight);
|
---|
164 |
|
---|
165 | String resoString = StringConverter::toString(fWidth) + " x " + StringConverter::toString(fHeight);
|
---|
166 | optVideoMode.possibleValues.push_back(resoString);
|
---|
167 |
|
---|
168 | //LogManager::getSingleton().logMessage( "Added resolution: " + resoString);
|
---|
169 | }
|
---|
170 |
|
---|
171 | optRTTMode.name = "RTT Preferred Mode";
|
---|
172 | optRTTMode.possibleValues.push_back( "FBO" );
|
---|
173 | optRTTMode.possibleValues.push_back( "PBuffer" );
|
---|
174 | optRTTMode.possibleValues.push_back( "Copy" );
|
---|
175 | optRTTMode.currentValue = "PBuffer";
|
---|
176 | optRTTMode.immutable = false;
|
---|
177 |
|
---|
178 |
|
---|
179 | mOptions[optFullScreen.name] = optFullScreen;
|
---|
180 | mOptions[optVideoMode.name] = optVideoMode;
|
---|
181 | mOptions[optFSAA.name] = optFSAA;
|
---|
182 | mOptions[optRTTMode.name] = optRTTMode;
|
---|
183 |
|
---|
184 | }
|
---|
185 |
|
---|
186 | String OSXGLSupport::validateConfig( void )
|
---|
187 | {
|
---|
188 | return String( "" );
|
---|
189 | }
|
---|
190 |
|
---|
191 | RenderWindow* OSXGLSupport::createWindow( bool autoCreateWindow, GLRenderSystem* renderSystem, const String& windowTitle )
|
---|
192 | {
|
---|
193 | if( autoCreateWindow )
|
---|
194 | {
|
---|
195 | ConfigOptionMap::iterator opt = mOptions.find( "Full Screen" );
|
---|
196 | if( opt == mOptions.end() )
|
---|
197 | OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR, "Can't find full screen options!", "OSXGLSupport::createWindow" );
|
---|
198 | bool fullscreen = ( opt->second.currentValue == "Yes" );
|
---|
199 |
|
---|
200 | opt = mOptions.find( "Video Mode" );
|
---|
201 | if( opt == mOptions.end() )
|
---|
202 | OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR, "Can't find video mode options!", "OSXGLSupport::createWindow" );
|
---|
203 | String val = opt->second.currentValue;
|
---|
204 | String::size_type pos = val.find( 'x' );
|
---|
205 | if( pos == String::npos )
|
---|
206 | OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR, "Invalid Video Mode provided", "OSXGLSupport::createWindow" );
|
---|
207 |
|
---|
208 | unsigned int w = StringConverter::parseUnsignedInt( val.substr( 0, pos ) );
|
---|
209 | unsigned int h = StringConverter::parseUnsignedInt( val.substr( pos + 1 ) );
|
---|
210 |
|
---|
211 | // Parse FSAA config
|
---|
212 | NameValuePairList winOptions;
|
---|
213 | winOptions[ "title" ] = windowTitle;
|
---|
214 | int fsaa_x_samples = 0;
|
---|
215 | opt = mOptions.find( "FSAA" );
|
---|
216 | if( opt != mOptions.end() )
|
---|
217 | {
|
---|
218 | winOptions[ "FSAA" ] = opt->second.currentValue;
|
---|
219 | }
|
---|
220 |
|
---|
221 | return renderSystem->createRenderWindow( windowTitle, w, h, fullscreen, &winOptions );
|
---|
222 | }
|
---|
223 | else
|
---|
224 | {
|
---|
225 | // XXX What is the else?
|
---|
226 | return NULL;
|
---|
227 | }
|
---|
228 | }
|
---|
229 |
|
---|
230 | RenderWindow* OSXGLSupport::newWindow( const String &name, unsigned int width, unsigned int height,
|
---|
231 | bool fullScreen, const NameValuePairList *miscParams )
|
---|
232 | {
|
---|
233 | // Does the user want Cocoa or Carbon, default to carbon...
|
---|
234 | mAPI = "carbon";
|
---|
235 | mContextType = "AGL";
|
---|
236 |
|
---|
237 | if(miscParams)
|
---|
238 | {
|
---|
239 | NameValuePairList::const_iterator opt = NULL;
|
---|
240 |
|
---|
241 | // First we must determine if this is a carbon or a cocoa window
|
---|
242 | // that we wish to create
|
---|
243 | opt = miscParams->find("macAPI");
|
---|
244 | if(opt != miscParams->end() && opt->second == "cocoa")
|
---|
245 | {
|
---|
246 | // Our user wants a cocoa compatable system
|
---|
247 | mAPI = "cocoa";
|
---|
248 | mContextType = "NSOpenGL";
|
---|
249 | }
|
---|
250 | }
|
---|
251 |
|
---|
252 | // Create the window, if cocoa return a cocoa window
|
---|
253 | if(mAPI == "cocoa")
|
---|
254 | {
|
---|
255 | LogManager::getSingleton().logMessage("Creating a Cocoa Compatible Render System");
|
---|
256 | OSXCocoaWindow* window = new OSXCocoaWindow();
|
---|
257 | window->create(name, width, height, fullScreen, miscParams);
|
---|
258 | return window;
|
---|
259 | }
|
---|
260 |
|
---|
261 | // Otherwise default to carbon
|
---|
262 | LogManager::getSingleton().logMessage("Creating a Carbon Compatible Render System");
|
---|
263 | OSXCarbonWindow* window = new OSXCarbonWindow();
|
---|
264 | window->create(name, width, height, fullScreen, miscParams);
|
---|
265 | return window;
|
---|
266 | }
|
---|
267 |
|
---|
268 | void OSXGLSupport::start()
|
---|
269 | {
|
---|
270 | LogManager::getSingleton().logMessage(
|
---|
271 | "*******************************************\n"
|
---|
272 | "*** Starting OSX OpenGL Subsystem ***\n"
|
---|
273 | "*******************************************");
|
---|
274 | }
|
---|
275 |
|
---|
276 | void OSXGLSupport::stop()
|
---|
277 | {
|
---|
278 | LogManager::getSingleton().logMessage(
|
---|
279 | "*******************************************\n"
|
---|
280 | "*** Stopping OSX OpenGL Subsystem ***\n"
|
---|
281 | "*******************************************");
|
---|
282 | }
|
---|
283 |
|
---|
284 | void* OSXGLSupport::getProcAddress( const char* name )
|
---|
285 | {
|
---|
286 | NSSymbol symbol;
|
---|
287 | char *symbolName;
|
---|
288 | // Prepend a '_' for the Unix C symbol mangling convention
|
---|
289 | symbolName = (char*)malloc (strlen (name) + 2);
|
---|
290 | strcpy(symbolName + 1, name);
|
---|
291 | symbolName[0] = '_';
|
---|
292 | symbol = NULL;
|
---|
293 | // TODO: dlopen calls, dyld
|
---|
294 | if (NSIsSymbolNameDefined (symbolName))
|
---|
295 | symbol = NSLookupAndBindSymbol (symbolName);
|
---|
296 | free (symbolName);
|
---|
297 | return symbol ? NSAddressOfSymbol (symbol) : NULL;
|
---|
298 | }
|
---|
299 |
|
---|
300 | void* OSXGLSupport::getProcAddress( const String& procname )
|
---|
301 | {
|
---|
302 | return getProcAddress( procname.c_str() );
|
---|
303 | }
|
---|
304 |
|
---|
305 | bool OSXGLSupport::supportsPBuffers()
|
---|
306 | {
|
---|
307 | return true;
|
---|
308 | }
|
---|
309 |
|
---|
310 | GLPBuffer* OSXGLSupport::createPBuffer(PixelComponentType format, size_t width, size_t height)
|
---|
311 | {
|
---|
312 | // if(mContextType == "NSOpenGL")
|
---|
313 | // return new OSXCocoaPBuffer(format, width, height);
|
---|
314 | // if(mContextType == "CGL")
|
---|
315 | // return new OSXCGLPBuffer(format, width, height);
|
---|
316 | // else
|
---|
317 | return new OSXPBuffer(format, width, height);
|
---|
318 | }
|
---|
319 |
|
---|
320 | CFComparisonResult OSXGLSupport::_compareModes (const void *val1, const void *val2, void *context)
|
---|
321 | {
|
---|
322 | // These are the values we will be interested in...
|
---|
323 | /*
|
---|
324 | _getDictionaryLong((mode), kCGDisplayWidth)
|
---|
325 | _getDictionaryLong((mode), kCGDisplayHeight)
|
---|
326 | _getDictionaryLong((mode), kCGDisplayRefreshRate)
|
---|
327 | _getDictionaryLong((mode), kCGDisplayBitsPerPixel)
|
---|
328 | _getDictionaryBoolean((mode), kCGDisplayModeIsSafeForHardware)
|
---|
329 | _getDictionaryBoolean((mode), kCGDisplayModeIsStretched)
|
---|
330 | */
|
---|
331 |
|
---|
332 | // CFArray comparison callback for sorting display modes.
|
---|
333 | #pragma unused(context)
|
---|
334 | CFDictionaryRef thisMode = (CFDictionaryRef)val1;
|
---|
335 | CFDictionaryRef otherMode = (CFDictionaryRef)val2;
|
---|
336 |
|
---|
337 | long width = _getDictionaryLong(thisMode, kCGDisplayWidth);
|
---|
338 | long otherWidth = _getDictionaryLong(otherMode, kCGDisplayWidth);
|
---|
339 |
|
---|
340 | long height = _getDictionaryLong(thisMode, kCGDisplayHeight);
|
---|
341 | long otherHeight = _getDictionaryLong(otherMode, kCGDisplayHeight);
|
---|
342 |
|
---|
343 | // sort modes in screen size order
|
---|
344 | if (width * height < otherWidth * otherHeight)
|
---|
345 | {
|
---|
346 | return kCFCompareLessThan;
|
---|
347 | }
|
---|
348 | else if (width * height > otherWidth * otherHeight)
|
---|
349 | {
|
---|
350 | return kCFCompareGreaterThan;
|
---|
351 | }
|
---|
352 |
|
---|
353 | // sort modes by bits per pixel
|
---|
354 | long bitsPerPixel = _getDictionaryLong(thisMode, kCGDisplayBitsPerPixel);
|
---|
355 | long otherBitsPerPixel = _getDictionaryLong(otherMode, kCGDisplayBitsPerPixel);
|
---|
356 |
|
---|
357 | if (bitsPerPixel < otherBitsPerPixel)
|
---|
358 | {
|
---|
359 | return kCFCompareLessThan;
|
---|
360 | }
|
---|
361 | else if (bitsPerPixel > otherBitsPerPixel)
|
---|
362 | {
|
---|
363 | return kCFCompareGreaterThan;
|
---|
364 | }
|
---|
365 |
|
---|
366 | // sort modes by refresh rate.
|
---|
367 | long refreshRate = _getDictionaryLong(thisMode, kCGDisplayRefreshRate);
|
---|
368 | long otherRefreshRate = _getDictionaryLong(otherMode, kCGDisplayRefreshRate);
|
---|
369 |
|
---|
370 | if (refreshRate < otherRefreshRate)
|
---|
371 | {
|
---|
372 | return kCFCompareLessThan;
|
---|
373 | }
|
---|
374 | else if (refreshRate > otherRefreshRate)
|
---|
375 | {
|
---|
376 | return kCFCompareGreaterThan;
|
---|
377 | }
|
---|
378 |
|
---|
379 | return kCFCompareEqualTo;
|
---|
380 | }
|
---|
381 |
|
---|
382 | Boolean OSXGLSupport::_getDictionaryBoolean(CFDictionaryRef dict, const void* key)
|
---|
383 | {
|
---|
384 | Boolean value = false;
|
---|
385 | CFBooleanRef boolRef;
|
---|
386 | boolRef = (CFBooleanRef)CFDictionaryGetValue(dict, key);
|
---|
387 |
|
---|
388 | if (boolRef != NULL)
|
---|
389 | value = CFBooleanGetValue(boolRef);
|
---|
390 |
|
---|
391 | return value;
|
---|
392 | }
|
---|
393 |
|
---|
394 | long OSXGLSupport::_getDictionaryLong(CFDictionaryRef dict, const void* key)
|
---|
395 | {
|
---|
396 | long value = 0;
|
---|
397 | CFNumberRef numRef;
|
---|
398 | numRef = (CFNumberRef)CFDictionaryGetValue(dict, key);
|
---|
399 |
|
---|
400 | if (numRef != NULL)
|
---|
401 | CFNumberGetValue(numRef, kCFNumberLongType, &value);
|
---|
402 |
|
---|
403 | return value;
|
---|
404 | }
|
---|
405 |
|
---|
406 |
|
---|
407 | }
|
---|