[1] | 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 | }
|
---|