| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- /*
- -----------------------------------------------------------------------------
- This source file is part of OGRE
- (Object-oriented Graphics Rendering Engine)
- For the latest info, see http://www.ogre3d.org
- Copyright (c) 2000-2011 Torus Knot Software Ltd
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- -----------------------------------------------------------------------------
- */
- // 64-bit Mac OS X doesn't support Carbon UI API
- #ifndef __LP64__
- #include "CmOSXCarbonWindow.h"
- #include "CmGLRenderSystem.h"
- #include "CmWindowEventUtilities.h"
- namespace CamelotEngine
- {
- //-------------------------------------------------------------------------------------------------//
- OSXCarbonWindow::OSXCarbonWindow() : mWindow(NULL), mEventHandlerRef(NULL), mView(NULL), mAGLContext(NULL), mAGLPixelFormat(NULL),
- mWindowTitle(""), mCGLContext(NULL), mCarbonContext(NULL), mActive(false), mClosed(false), mCreated(false), mHasResized(false),
- mIsExternal(false), mVisible(false)
- {
- mIsFullScreen = false;
- mContext = NULL;
- mColourDepth = 32;
- }
- //-------------------------------------------------------------------------------------------------//
- OSXCarbonWindow::~OSXCarbonWindow()
- {
- destroy();
- }
- //-------------------------------------------------------------------------------------------------//
- void OSXCarbonWindow::create( const String& name, unsigned int width, unsigned int height,
- bool fullScreen, const NameValuePairList *miscParams )
- {
- bool hasDepthBuffer = false;
- String title = name;
- size_t fsaa_samples = 0;
- int left = 0;
- int top = 0;
- int depth = 32;
- if( miscParams )
- {
- NameValuePairList::const_iterator opt(NULL);
-
- // Full screen anti aliasing
- opt = miscParams->find( "FSAA" );
- if( opt != miscParams->end() )
- fsaa_samples = StringConverter::parseUnsignedInt( opt->second );
- opt = miscParams->find( "left" );
- if( opt != miscParams->end() )
- left = StringConverter::parseUnsignedInt( opt->second );
- opt = miscParams->find( "top" );
- if( opt != miscParams->end() )
- top = StringConverter::parseUnsignedInt( opt->second );
- opt = miscParams->find( "title" );
- if( opt != miscParams->end() )
- title = opt->second;
- opt = miscParams->find( "depthBuffer" );
- if( opt != miscParams->end() )
- hasDepthBuffer = StringConverter::parseBool( opt->second );
-
- opt = miscParams->find( "colourDepth" );
- if( opt != miscParams->end() )
- depth = StringConverter::parseUnsignedInt( opt->second );
- opt = miscParams->find( "Full Screen" );
- if( opt != miscParams->end() )
- fullScreen = StringConverter::parseBool( opt->second );
- }
-
- mName = name;
- mWidth = width;
- mHeight = height;
- mColourDepth = depth;
- mFSAA = fsaa_samples;
- mIsFullScreen = fullScreen;
- if(fullScreen)
- {
- setFullscreen(fullScreen, width, height);
- }
- else
- {
- createAGLContext(fsaa_samples, depth);
- NameValuePairList::const_iterator opt(NULL);
- if(miscParams)
- opt = miscParams->find("externalWindowHandle");
- if(!miscParams || opt == miscParams->end())
- createNewWindow(width, height, title.c_str());
- else
- createWindowFromExternal((HIViewRef)StringConverter::parseUnsignedLong(opt->second));
- // Set the drawable, and current context
- // If you do this last, there is a moment before the rendering window pops-up
- // This could go once inside each case above, before the window is displayed,
- // if desired.
- #if defined(MAC_OS_X_VERSION_10_4) && MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
- aglSetDrawable(mAGLContext, GetWindowPort(mWindow));
- #else
- aglSetWindowRef(mAGLContext, mWindow);
- #endif
- aglSetCurrentContext(mAGLContext);
- // Give a copy of our context to the render system
- if(!mCarbonContext)
- {
- mCarbonContext = OGRE_NEW OSXCarbonContext(mAGLContext, mAGLPixelFormat);
- mContext = mCarbonContext;
- }
- }
-
- mActive = true;
- mClosed = false;
- mCreated = true;
- }
- void OSXCarbonWindow::createAGLContext(size_t fsaa_samples, int depth)
- {
- if(!mAGLContext)
- {
- int i = 0;
- GLint attribs[ 20 ];
-
- attribs[ i++ ] = AGL_NO_RECOVERY;
- attribs[ i++ ] = GL_TRUE;
- attribs[ i++ ] = AGL_ACCELERATED;
- attribs[ i++ ] = GL_TRUE;
- attribs[ i++ ] = AGL_RGBA;
- attribs[ i++ ] = AGL_DOUBLEBUFFER;
- attribs[ i++ ] = AGL_ALPHA_SIZE;
- attribs[ i++ ] = 8;
- attribs[ i++ ] = AGL_STENCIL_SIZE;
- attribs[ i++ ] = 8;
- attribs[ i++ ] = AGL_DEPTH_SIZE;
- attribs[ i++ ] = depth;
-
- if(fsaa_samples > 1)
- {
- attribs[ i++ ] = AGL_MULTISAMPLE;
- attribs[ i++ ] = AGL_SAMPLE_BUFFERS_ARB;
- attribs[ i++ ] = 1;
- attribs[ i++ ] = AGL_SAMPLES_ARB;
- attribs[ i++ ] = fsaa_samples;
- }
-
- attribs[ i++ ] = AGL_NONE;
-
- mAGLPixelFormat = aglChoosePixelFormat( NULL, 0, attribs );
- if(!mAGLPixelFormat)
- {
- OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
- "Unable to create a valid pixel format with selected attributes.",
- "OSXCarbonWindow::createAGLContext" );
- }
-
- // Create the AGLContext from our pixel format
- // Share it with main
- GLRenderSystem *rs = static_cast<GLRenderSystem*>(Root::getSingleton().getRenderSystem());
- OSXContext* mainContext = static_cast<OSXContext*>( rs->_getMainContext() );
- if(mainContext == 0 || !(mainContext->getContextType() == "AGL"))
- {
- mAGLContext = aglCreateContext(mAGLPixelFormat, NULL);
- }
- else
- {
- OSXCarbonContext* context = static_cast<OSXCarbonContext*>( rs->_getMainContext() );
- mAGLContext = aglCreateContext(mAGLPixelFormat, context->getContext());
- }
- }
- }
- void OSXCarbonWindow::createNewWindow(unsigned int width, unsigned int height, String title)
- {
- if(!mWindow)
- {
- // Create the window rect in global coords
- ::Rect windowRect;
- windowRect.left = 0;
- windowRect.top = 0;
- windowRect.right = width;
- windowRect.bottom = height;
-
- // Set the default attributes for the window
- WindowAttributes windowAttrs = kWindowStandardDocumentAttributes; // default: "resize"
- windowAttrs |= kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowHideOnFullScreenAttribute | kWindowNoShadowAttribute;
- // Create the window
- CreateNewWindow(kDocumentWindowClass, windowAttrs, &windowRect, &mWindow);
- // Color the window background black
- SetThemeWindowBackground(mWindow, kThemeBrushBlack, true);
-
- // Set the title of our window
- CFStringRef titleRef = CFStringCreateWithCString( kCFAllocatorDefault, title.c_str(), kCFStringEncodingASCII );
- SetWindowTitleWithCFString( mWindow, titleRef );
- mWindowTitle = title;
-
- // Center our window on the screen
- RepositionWindow( mWindow, NULL, kWindowCenterOnMainScreen );
-
- // Get our view
- HIViewFindByID( HIViewGetRoot( mWindow ), kHIViewWindowContentID, &mView );
-
- // Set up our UPP for Window Events
- EventTypeSpec eventSpecs[] = {
- {kEventClassWindow, kEventWindowActivated},
- {kEventClassWindow, kEventWindowDeactivated},
- {kEventClassWindow, kEventWindowShown},
- {kEventClassWindow, kEventWindowHidden},
- {kEventClassWindow, kEventWindowDragCompleted},
- {kEventClassWindow, kEventWindowBoundsChanged},
- {kEventClassWindow, kEventWindowExpanded},
- {kEventClassWindow, kEventWindowCollapsed},
- {kEventClassWindow, kEventWindowClosed},
- {kEventClassWindow, kEventWindowClose}
- };
- EventHandlerUPP handlerUPP = NewEventHandlerUPP(WindowEventUtilities::_CarbonWindowHandler);
-
- // Install the standard event handler for the window
- EventTargetRef target = GetWindowEventTarget(mWindow);
- InstallStandardEventHandler(target);
-
- // We also need to install the WindowEvent Handler, we pass along the window with our requests
- InstallEventHandler(target, handlerUPP, 10, eventSpecs, (void*)this, &mEventHandlerRef);
- }
- HIRect winBounds = CGRectZero;
- HIViewRef root = HIViewGetRoot(HIViewGetWindow(mView));
- HIViewGetBounds(root, &winBounds);
- HIRect viewBounds = CGRectZero;
- HIViewGetBounds(mView, &viewBounds);
- // Display and select our window
- ShowWindow(mWindow);
- SelectWindow(mWindow);
-
- // Add our window to the window event listener class
- WindowEventUtilities::_addRenderWindow(this);
- }
-
- void OSXCarbonWindow::createWindowFromExternal(HIViewRef viewRef)
- {
- // TODO: The Control is going to report the incorrect location with a
- // Metalic / Textured window. The default windows work just fine.
-
- // First get the HIViewRef / ControlRef
- mView = viewRef;
- mWindow = GetControlOwner(mView);
- // Lets try hiding the HIView
- //HIViewSetVisible(mView, false);
- // Get the rect bounds
- ::Rect ctrlBounds;
- GetControlBounds(mView, &ctrlBounds);
- GLint bufferRect[4];
-
- bufferRect[0] = ctrlBounds.left; // left edge
- bufferRect[1] = ctrlBounds.bottom; // bottom edge
- bufferRect[2] = ctrlBounds.right - ctrlBounds.left; // width of buffer rect
- bufferRect[3] = ctrlBounds.bottom - ctrlBounds.top; // height of buffer rect
-
- aglSetInteger(mAGLContext, AGL_BUFFER_RECT, bufferRect);
- aglEnable(mAGLContext, AGL_BUFFER_RECT);
-
- mIsExternal = true;
- }
-
- //-------------------------------------------------------------------------------------------------//
- void OSXCarbonWindow::destroy(void)
- {
- if(!mCreated)
- return;
- if(mIsFullScreen)
- {
- // Handle fullscreen destruction
- destroyCGLFullscreen();
- }
- else
- {
- // Handle windowed destruction
-
- // Destroy the Ogre context
- if(mCGLContext)
- {
- OGRE_DELETE mCGLContext;
- mCGLContext = NULL;
- }
-
- if(mCarbonContext)
- {
- OGRE_DELETE mCarbonContext;
- mCarbonContext = NULL;
- }
- if(mContext)
- {
- // mContext is a reference to either the AGL or CGL context, already deleted.
- // Just clear the variable
- mContext = NULL;
- }
- if(!mIsExternal)
- {
- // Remove the window from the Window listener
- WindowEventUtilities::_removeRenderWindow( this );
-
- // Remove our event handler
- if(mEventHandlerRef)
- RemoveEventHandler(mEventHandlerRef);
- }
- if(mAGLContext)
- aglDestroyContext(mAGLContext);
-
- if(mWindow)
- DisposeWindow(mWindow);
- }
- mActive = false;
- mClosed = true;
- mCreated = false;
- }
-
- //-------------------------------------------------------------------------------------------------//
- bool OSXCarbonWindow::isActive() const
- {
- return mActive;
- }
-
- //-------------------------------------------------------------------------------------------------//
- bool OSXCarbonWindow::isClosed() const
- {
- return mClosed;
- }
-
- //-------------------------------------------------------------------------------------------------//
- void OSXCarbonWindow::reposition(int left, int top)
- {
- if(mWindow)
- MoveWindow(mWindow, left, top, true);
- }
-
- //-------------------------------------------------------------------------------------------------//
- void OSXCarbonWindow::resize(unsigned int width, unsigned int height)
- {
- if(!mWindow)
- return;
-
- // Check if the window size really changed
- if(mWidth == width && mHeight == height)
- return;
- mWidth = width;
- mHeight = height;
- if (mIsExternal)
- {
- HIRect viewBounds = CGRectZero, winBounds = CGRectZero;
- HIViewGetBounds(mView, &viewBounds);
- HIViewRef root = HIViewGetRoot(HIViewGetWindow(mView));
- HIViewGetBounds(root, &winBounds);
- HIViewConvertRect(&viewBounds, mView, root);
- mLeft = viewBounds.origin.x;
- mTop = winBounds.size.height - (viewBounds.origin.y + viewBounds.size.height);
-
- // Set the AGL buffer rectangle (i.e. the bounds that we will use)
- GLint bufferRect[4];
- bufferRect[0] = mLeft; // 0 = left edge
- bufferRect[1] = mTop; // 0 = bottom edge
- bufferRect[2] = mWidth; // width of buffer rect
- bufferRect[3] = mHeight; // height of buffer rect
- aglSetInteger(mAGLContext, AGL_BUFFER_RECT, bufferRect);
- for (ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); ++it)
- {
- (*it).second->_updateDimensions();
- }
- }
- else
- {
- SizeWindow(mWindow, width, height, true);
- }
- }
-
- void OSXCarbonWindow::setVisible( bool visible )
- {
- mVisible = visible;
- if(mIsExternal && !visible) {
- GLint bufferRect[4] = {0, 0, 0, 0};
- aglSetInteger(mAGLContext, AGL_BUFFER_RECT, bufferRect);
- }
- }
-
- bool OSXCarbonWindow::isVisible( void ) const
- {
- return mVisible;
- }
-
- //-------------------------------------------------------------------------------------------------//
- void OSXCarbonWindow::windowHasResized()
- {
- mHasResized = true;
-
- // Ensure the context is current
- if(!mIsFullScreen)
- aglSwapBuffers(mAGLContext);
- else
- swapCGLBuffers();
- }
-
- //-------------------------------------------------------------------------------------------------//
- void OSXCarbonWindow::windowResized()
- {
- // Ensure the context is current
- if(!mIsFullScreen)
- {
- // Determine the AGL_BUFFER_RECT for the view. The coordinate
- // system for this rectangle is relative to the owning window, with
- // the origin at the bottom left corner and the y-axis inverted.
- HIRect newFrame = CGRectMake(mLeft, mTop+22, mWidth, mHeight);
- HIRect viewBounds = CGRectZero, winBounds = CGRectZero;
- SizeWindow(mWindow, mWidth, mHeight, true);
- HIViewSetFrame(mView, &newFrame);
- HIViewGetBounds(mView, &viewBounds);
- HIViewRef root = HIViewGetRoot(HIViewGetWindow(mView));
- HIViewGetBounds(root, &winBounds);
- HIViewConvertRect(&viewBounds, mView, root);
- // Set the AGL buffer rectangle (i.e. the bounds that we will use)
- GLint bufferRect[4];
- bufferRect[0] = viewBounds.origin.x; // 0 = left edge
- bufferRect[1] = winBounds.size.height - (viewBounds.origin.y + viewBounds.size.height); // 0 = bottom edge
- bufferRect[2] = viewBounds.size.width; // width of buffer rect
- bufferRect[3] = viewBounds.size.height; // height of buffer rect
- aglSetInteger(mAGLContext, AGL_BUFFER_RECT, bufferRect);
- aglEnable(mAGLContext, AGL_BUFFER_RECT);
- aglUpdateContext(mAGLContext);
- mLeft = viewBounds.origin.x;
- mTop = bufferRect[1];
- }
- else
- {
- swapCGLBuffers();
- }
-
- for (ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); ++it)
- {
- (*it).second->_updateDimensions();
- }
- }
-
- //-------------------------------------------------------------------------------------------------//
- void OSXCarbonWindow::windowMovedOrResized()
- {
- // External windows will call this method.
- if(mView != NULL)
- {
- // Determine the AGL_BUFFER_RECT for the view. The coordinate
- // system for this rectangle is relative to the owning window, with
- // the origin at the bottom left corner and the y-axis inverted.
-
- // Also, when leaving fullscreen, the display properties are not guaranteed to be
- // the same as when we were windowed previously. So resize the window and views back
- // to their original dimensions.
- HIRect newFrame = CGRectMake(mLeft, mTop+22, mWidth, mHeight);
- HIRect viewBounds = CGRectZero, winBounds = CGRectZero;
- SizeWindow(mWindow, mWidth, mHeight, true);
- HIViewSetFrame(mView, &newFrame);
- HIViewGetBounds(mView, &viewBounds);
- HIViewRef root = HIViewGetRoot(HIViewGetWindow(mView));
- HIViewGetBounds(root, &winBounds);
- HIViewConvertRect(&viewBounds, mView, root);
- // Set the AGL buffer rectangle (i.e. the bounds that we will use)
- GLint bufferRect[4];
- bufferRect[0] = viewBounds.origin.x; // 0 = left edge
- bufferRect[1] = winBounds.size.height - (viewBounds.origin.y + viewBounds.size.height); // 0 = bottom edge
- bufferRect[2] = viewBounds.size.width; // width of buffer rect
- bufferRect[3] = viewBounds.size.height; // height of buffer rect
-
- aglSetInteger(mAGLContext, AGL_BUFFER_RECT, bufferRect);
- aglEnable(mAGLContext, AGL_BUFFER_RECT);
- aglUpdateContext(mAGLContext);
-
- mLeft = viewBounds.origin.x;
- mTop = bufferRect[1];
- }
-
- for (ViewportList::iterator it = mViewportList.begin(); it != mViewportList.end(); ++it)
- {
- (*it).second->_updateDimensions();
- }
- }
-
- //-------------------------------------------------------------------------------------------------//
- void OSXCarbonWindow::swapBuffers( bool waitForVSync )
- {
- if(!mIsFullScreen)
- {
- if(mAGLContext != aglGetCurrentContext())
- aglSetCurrentContext(mAGLContext);
-
- aglSwapBuffers(mAGLContext);
- }
- else
- {
- swapCGLBuffers();
- }
-
- if(mHasResized)
- {
- windowResized();
- mHasResized = false;
- }
- }
- //-------------------------------------------------------------------------------------------------//
- void OSXCarbonWindow::getCustomAttribute( const String& name, void* pData )
- {
- if( name == "GLCONTEXT" )
- {
- *static_cast<OSXContext**>(pData) = mContext;
- return;
- }
- else if( name == "WINDOW" )
- {
- if(mIsFullScreen)
- {
- // A fullscreen application uses CGL and thus has no window.
- pData = 0;
- return;
- }
- else
- {
- *static_cast<WindowRef*>(pData) = mWindow;
- }
- return;
- }
- }
-
- void OSXCarbonWindow::setFullscreen(bool fullScreen, unsigned int width, unsigned int height)
- {
- if (mIsFullScreen != fullScreen || width != mWidth || height != mHeight)
- {
- // Set the full screen flag
- mIsFullScreen = fullScreen;
- createAGLContext(mFSAA, mColourDepth);
- if (mIsFullScreen)
- {
- GLRenderSystem *rs = static_cast<GLRenderSystem*>(Root::getSingleton().getRenderSystem());
- CGLContextObj share = NULL;
- aglGetCGLContext(mAGLContext, (void**)&share);
- // Create the CGL context object if it doesn't already exist, sharing the AGL context.
- if(!mCGLContext)
- {
- void *cglPixFormat;
- aglGetCGLPixelFormat(mAGLPixelFormat, (void **)&cglPixFormat);
- mCGLContext = OGRE_NEW OSXCGLContext(mCGLContextObj, (CGLPixelFormatObj) cglPixFormat);
- }
- // Create the context, keeping the current colour depth and FSAA settings
- createCGLFullscreen(width, height, getColourDepth(), getFSAA(), share);
- rs->_switchContext(mContext);
- // Hide the Carbon window
- HideWindow(mWindow);
- // And tell the rendersystem to stop rendering to it too
- WindowEventUtilities::_removeRenderWindow(this);
- }
- else
- {
- // Create a new AGL context and pixel format if necessary
- createAGLContext(mFSAA, mColourDepth);
- // Create a window if we haven't already, existence check is done within the functions
- if(!mWindow)
- {
- if(mIsExternal)
- createWindowFromExternal(mView);
- else
- createNewWindow(width, height, mWindowTitle);
- }
- // Destroy the current CGL context, we will create a new one when/if we go back to full screen
- destroyCGLFullscreen();
- // Set the drawable, and current context
- // If you do this last, there is a moment before the rendering window pops-up
- #if defined(MAC_OS_X_VERSION_10_4) && MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
- aglSetDrawable(mAGLContext, GetWindowPort(mWindow));
- #else
- aglSetWindowRef(mAGLContext, mWindow);
- #endif
- aglSetCurrentContext(mAGLContext);
- if(!mCarbonContext)
- {
- mCarbonContext = OGRE_NEW OSXCarbonContext(mAGLContext, mAGLPixelFormat);
- }
-
- GLRenderSystem *rs = static_cast<GLRenderSystem*>(Root::getSingleton().getRenderSystem());
- mContext = mCarbonContext;
- rs->_switchContext(mContext);
- WindowEventUtilities::_addRenderWindow(this);
- ShowWindow(mWindow);
- SelectWindow(mWindow);
- RepositionWindow(mWindow, NULL, kWindowCenterOnMainScreen);
- }
- mWidth = width;
- mHeight = height;
- }
- }
- }
- #endif // __LP64__
|