From 9cd57b731ab1c666d4a1cb725538fdc137763d12 Mon Sep 17 00:00:00 2001 From: Starla Insigna Date: Sat, 30 Jul 2011 11:19:14 -0400 Subject: Initial commit (version 0.2.1) --- libs/cocos2d/Platforms/Mac/CCDirectorMac.m | 479 +++++++++++++++++++++++++++++ 1 file changed, 479 insertions(+) create mode 100755 libs/cocos2d/Platforms/Mac/CCDirectorMac.m (limited to 'libs/cocos2d/Platforms/Mac/CCDirectorMac.m') diff --git a/libs/cocos2d/Platforms/Mac/CCDirectorMac.m b/libs/cocos2d/Platforms/Mac/CCDirectorMac.m new file mode 100755 index 0000000..477081e --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/CCDirectorMac.m @@ -0,0 +1,479 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2010 Ricardo Quesada + * Copyright (c) 2011 Zynga Inc. + * + * 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. + */ + +// Only compile this code on Mac. These files should not be included on your iOS project. +// But in case they are included, it won't be compiled. +#import +#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED +#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) + +#import + +#import "CCDirectorMac.h" +#import "CCEventDispatcher.h" +#import "MacGLView.h" + +#import "../../CCNode.h" +#import "../../CCScheduler.h" +#import "../../ccMacros.h" + +#pragma mark - +#pragma mark Director Mac extensions + + +@interface CCDirector () +-(void) setNextScene; +-(void) showFPS; +-(void) calculateDeltaTime; +@end + +@implementation CCDirector (MacExtension) +-(CGPoint) convertEventToGL:(NSEvent*)event +{ + NSPoint point = [openGLView_ convertPoint:[event locationInWindow] fromView:nil]; + CGPoint p = NSPointToCGPoint(point); + + return [(CCDirectorMac*)self convertToLogicalCoordinates:p]; +} + +@end + +#pragma mark - +#pragma mark Director Mac + +@implementation CCDirectorMac + +@synthesize isFullScreen = isFullScreen_; +@synthesize originalWinSize = originalWinSize_; + +-(id) init +{ + if( (self = [super init]) ) { + isFullScreen_ = NO; + resizeMode_ = kCCDirectorResize_AutoScale; + + originalWinSize_ = CGSizeZero; + fullScreenWindow_ = nil; + windowGLView_ = nil; + winOffset_ = CGPointZero; + } + + return self; +} + +- (void) dealloc +{ + [superViewGLView_ release]; + [fullScreenWindow_ release]; + [windowGLView_ release]; + [super dealloc]; +} + +// +// setFullScreen code taken from GLFullScreen example by Apple +// +- (void) setFullScreen:(BOOL)fullscreen +{ + // Mac OS X 10.6 and later offer a simplified mechanism to create full-screen contexts +#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5 + + if (isFullScreen_ == fullscreen) return; + + if( fullscreen ) { + originalWinRect_ = [openGLView_ frame]; + + // Cache normal window and superview of openGLView + if(!windowGLView_) + windowGLView_ = [[openGLView_ window] retain]; + + [superViewGLView_ release]; + superViewGLView_ = [[openGLView_ superview] retain]; + + + // Get screen size + NSRect displayRect = [[NSScreen mainScreen] frame]; + + // Create a screen-sized window on the display you want to take over + fullScreenWindow_ = [[MacWindow alloc] initWithFrame:displayRect fullscreen:YES]; + + // Remove glView from window + [openGLView_ removeFromSuperview]; + + // Set new frame + [openGLView_ setFrame:displayRect]; + + // Attach glView to fullscreen window + [fullScreenWindow_ setContentView:openGLView_]; + + // Show the fullscreen window + [fullScreenWindow_ makeKeyAndOrderFront:self]; + [fullScreenWindow_ makeMainWindow]; + + } else { + + // Remove glView from fullscreen window + [openGLView_ removeFromSuperview]; + + // Release fullscreen window + [fullScreenWindow_ release]; + fullScreenWindow_ = nil; + + // Attach glView to superview + [superViewGLView_ addSubview:openGLView_]; + + // Set new frame + [openGLView_ setFrame:originalWinRect_]; + + // Show the window + [windowGLView_ makeKeyAndOrderFront:self]; + [windowGLView_ makeMainWindow]; + } + isFullScreen_ = fullscreen; + + [openGLView_ retain]; // Retain +1 + + // re-configure glView + [self setOpenGLView:openGLView_]; + + [openGLView_ release]; // Retain -1 + + [openGLView_ setNeedsDisplay:YES]; +#else +#error Full screen is not supported for Mac OS 10.5 or older yet +#error If you don't want FullScreen support, you can safely remove these 2 lines +#endif +} + +-(void) setOpenGLView:(MacGLView *)view +{ + [super setOpenGLView:view]; + + // cache the NSWindow and NSOpenGLView created from the NIB + if( !isFullScreen_ && CGSizeEqualToSize(originalWinSize_, CGSizeZero)) + { + originalWinSize_ = winSizeInPixels_; + } +} + +-(int) resizeMode +{ + return resizeMode_; +} + +-(void) setResizeMode:(int)mode +{ + if( mode != resizeMode_ ) { + + resizeMode_ = mode; + + [self setProjection:projection_]; + [openGLView_ setNeedsDisplay: YES]; + } +} + +-(void) setProjection:(ccDirectorProjection)projection +{ + CGSize size = winSizeInPixels_; + + CGPoint offset = CGPointZero; + float widthAspect = size.width; + float heightAspect = size.height; + + + if( resizeMode_ == kCCDirectorResize_AutoScale && ! CGSizeEqualToSize(originalWinSize_, CGSizeZero ) ) { + + size = originalWinSize_; + + float aspect = originalWinSize_.width / originalWinSize_.height; + widthAspect = winSizeInPixels_.width; + heightAspect = winSizeInPixels_.width / aspect; + + if( heightAspect > winSizeInPixels_.height ) { + widthAspect = winSizeInPixels_.height * aspect; + heightAspect = winSizeInPixels_.height; + } + + winOffset_.x = (winSizeInPixels_.width - widthAspect) / 2; + winOffset_.y = (winSizeInPixels_.height - heightAspect) / 2; + + offset = winOffset_; + + } + + switch (projection) { + case kCCDirectorProjection2D: + glViewport(offset.x, offset.y, widthAspect, heightAspect); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + ccglOrtho(0, size.width, 0, size.height, -1024, 1024); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + break; + + case kCCDirectorProjection3D: + glViewport(offset.x, offset.y, widthAspect, heightAspect); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60, (GLfloat)widthAspect/heightAspect, 0.1f, 1500.0f); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + float eyeZ = size.height * [self getZEye] / winSizeInPixels_.height; + + gluLookAt( size.width/2, size.height/2, eyeZ, + size.width/2, size.height/2, 0, + 0.0f, 1.0f, 0.0f); + break; + + case kCCDirectorProjectionCustom: + if( projectionDelegate_ ) + [projectionDelegate_ updateProjection]; + break; + + default: + CCLOG(@"cocos2d: Director: unrecognized projecgtion"); + break; + } + + projection_ = projection; +} + +// If scaling is supported, then it should always return the original size +// otherwise it should return the "real" size. +-(CGSize) winSize +{ + if( resizeMode_ == kCCDirectorResize_AutoScale ) + return originalWinSize_; + + return winSizeInPixels_; +} + +-(CGSize) winSizeInPixels +{ + return [self winSize]; +} + +- (CGPoint) convertToLogicalCoordinates:(CGPoint)coords +{ + CGPoint ret; + + if( resizeMode_ == kCCDirectorResize_NoScale ) + ret = coords; + + else { + + float x_diff = originalWinSize_.width / (winSizeInPixels_.width - winOffset_.x * 2); + float y_diff = originalWinSize_.height / (winSizeInPixels_.height - winOffset_.y * 2); + + float adjust_x = (winSizeInPixels_.width * x_diff - originalWinSize_.width ) / 2; + float adjust_y = (winSizeInPixels_.height * y_diff - originalWinSize_.height ) / 2; + + ret = CGPointMake( (x_diff * coords.x) - adjust_x, ( y_diff * coords.y ) - adjust_y ); + } + + return ret; +} +@end + + +#pragma mark - +#pragma mark DirectorDisplayLink + + +@implementation CCDirectorDisplayLink + +- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime +{ +#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD + if( ! runningThread_ ) + runningThread_ = [NSThread currentThread]; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [self drawScene]; + [[CCEventDispatcher sharedDispatcher] dispatchQueuedEvents]; + + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:nil]; + + [pool release]; + +#else + [self performSelector:@selector(drawScene) onThread:runningThread_ withObject:nil waitUntilDone:YES]; +#endif + + return kCVReturnSuccess; +} + +// This is the renderer output callback function +static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) +{ + CVReturn result = [(CCDirectorDisplayLink*)displayLinkContext getFrameForTime:outputTime]; + return result; +} + +- (void) startAnimation +{ +#if ! CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD + runningThread_ = [[NSThread alloc] initWithTarget:self selector:@selector(mainLoop) object:nil]; + [runningThread_ start]; +#endif + + gettimeofday( &lastUpdate_, NULL); + + // Create a display link capable of being used with all active displays + CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); + + // Set the renderer output callback function + CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, self); + + // Set the display link for the current renderer + CGLContextObj cglContext = [[openGLView_ openGLContext] CGLContextObj]; + CGLPixelFormatObj cglPixelFormat = [[openGLView_ pixelFormat] CGLPixelFormatObj]; + CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat); + + // Activate the display link + CVDisplayLinkStart(displayLink); +} + +- (void) stopAnimation +{ + if( displayLink ) { + CVDisplayLinkStop(displayLink); + CVDisplayLinkRelease(displayLink); + displayLink = NULL; + +#if ! CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD + [runningThread_ cancel]; + [runningThread_ release]; + runningThread_ = nil; +#endif + } +} + +-(void) dealloc +{ + if( displayLink ) { + CVDisplayLinkStop(displayLink); + CVDisplayLinkRelease(displayLink); + } + [super dealloc]; +} + +// +// Mac Director has its own thread +// +-(void) mainLoop +{ + while( ![[NSThread currentThread] isCancelled] ) { + // There is no autorelease pool when this method is called because it will be called from a background thread + // It's important to create one or you will leak objects + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [[NSRunLoop currentRunLoop] run]; + + [pool release]; + } +} + +// +// Draw the Scene +// +- (void) drawScene +{ + // We draw on a secondary thread through the display link + // When resizing the view, -reshape is called automatically on the main thread + // Add a mutex around to avoid the threads accessing the context simultaneously when resizing + CGLLockContext([[openGLView_ openGLContext] CGLContextObj]); + [[openGLView_ openGLContext] makeCurrentContext]; + + /* calculate "global" dt */ + [self calculateDeltaTime]; + + /* tick before glClear: issue #533 */ + if( ! isPaused_ ) { + [[CCScheduler sharedScheduler] tick: dt]; + } + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + /* to avoid flickr, nextScene MUST be here: after tick and before draw. + XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */ + if( nextScene_ ) + [self setNextScene]; + + glPushMatrix(); + + + // By default enable VertexArray, ColorArray, TextureCoordArray and Texture2D + CC_ENABLE_DEFAULT_GL_STATES(); + + /* draw the scene */ + [runningScene_ visit]; + + /* draw the notification node */ + [notificationNode_ visit]; + + if( displayFPS_ ) + [self showFPS]; + +#if CC_ENABLE_PROFILERS + [self showProfilers]; +#endif + + CC_DISABLE_DEFAULT_GL_STATES(); + + glPopMatrix(); + + [[openGLView_ openGLContext] flushBuffer]; + CGLUnlockContext([[openGLView_ openGLContext] CGLContextObj]); +} + +// set the event dispatcher +-(void) setOpenGLView:(MacGLView *)view +{ + if( view != openGLView_ ) { + + [super setOpenGLView:view]; + + CCEventDispatcher *eventDispatcher = [CCEventDispatcher sharedDispatcher]; + [openGLView_ setEventDelegate: eventDispatcher]; + [eventDispatcher setDispatchEvents: YES]; + + // Enable Touches. Default no. + [view setAcceptsTouchEvents:NO]; +// [view setAcceptsTouchEvents:YES]; + + + // Synchronize buffer swaps with vertical refresh rate + [[view openGLContext] makeCurrentContext]; + GLint swapInt = 1; + [[view openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; + } +} + +@end + +#endif // __MAC_OS_X_VERSION_MAX_ALLOWED -- cgit 1.4.1