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.h | 103 ++++ libs/cocos2d/Platforms/Mac/CCDirectorMac.m | 479 ++++++++++++++++++ libs/cocos2d/Platforms/Mac/CCEventDispatcher.h | 277 +++++++++++ libs/cocos2d/Platforms/Mac/CCEventDispatcher.m | 645 +++++++++++++++++++++++++ libs/cocos2d/Platforms/Mac/MacGLView.h | 89 ++++ libs/cocos2d/Platforms/Mac/MacGLView.m | 242 ++++++++++ libs/cocos2d/Platforms/Mac/MacWindow.h | 42 ++ libs/cocos2d/Platforms/Mac/MacWindow.m | 70 +++ 8 files changed, 1947 insertions(+) create mode 100755 libs/cocos2d/Platforms/Mac/CCDirectorMac.h create mode 100755 libs/cocos2d/Platforms/Mac/CCDirectorMac.m create mode 100755 libs/cocos2d/Platforms/Mac/CCEventDispatcher.h create mode 100755 libs/cocos2d/Platforms/Mac/CCEventDispatcher.m create mode 100755 libs/cocos2d/Platforms/Mac/MacGLView.h create mode 100755 libs/cocos2d/Platforms/Mac/MacGLView.m create mode 100755 libs/cocos2d/Platforms/Mac/MacWindow.h create mode 100755 libs/cocos2d/Platforms/Mac/MacWindow.m (limited to 'libs/cocos2d/Platforms/Mac') diff --git a/libs/cocos2d/Platforms/Mac/CCDirectorMac.h b/libs/cocos2d/Platforms/Mac/CCDirectorMac.h new file mode 100755 index 0000000..0d623b4 --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/CCDirectorMac.h @@ -0,0 +1,103 @@ +/* + * 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 "../../CCDirector.h" + +enum { + /// If the window is resized, it won't be autoscaled + kCCDirectorResize_NoScale, + /// If the window is resized, it will be autoscaled (default behavior) + kCCDirectorResize_AutoScale, +}; + +@interface CCDirector (MacExtension) +/** converts an NSEvent to GL coordinates */ +-(CGPoint) convertEventToGL:(NSEvent*)event; +@end + +/** Base class of Mac directors + @since v0.99.5 + */ +@interface CCDirectorMac : CCDirector +{ + BOOL isFullScreen_; + int resizeMode_; + CGPoint winOffset_; + CGSize originalWinSize_; + + NSWindow *fullScreenWindow_; + + // cache + NSWindow *windowGLView_; + NSView *superViewGLView_; + NSRect originalWinRect_; // Original size and position +} + +// whether or not the view is in fullscreen mode +@property (nonatomic, readonly) BOOL isFullScreen; + +// resize mode: with or without scaling +@property (nonatomic, readwrite) int resizeMode; + +@property (nonatomic, readwrite) CGSize originalWinSize; + +/** Sets the view in fullscreen or window mode */ +- (void) setFullScreen:(BOOL)fullscreen; + +/** Converts window size coordiantes to logical coordinates. + Useful only if resizeMode is kCCDirectorResize_Scale. + If resizeMode is kCCDirectorResize_NoScale, then no conversion will be done. +*/ +- (CGPoint) convertToLogicalCoordinates:(CGPoint)coordinates; +@end + + +/** DisplayLinkDirector is a Director that synchronizes timers with the refresh rate of the display. + * + * Features and Limitations: + * - Only available on 3.1+ + * - Scheduled timers & drawing are synchronizes with the refresh rate of the display + * - Only supports animation intervals of 1/60 1/30 & 1/15 + * + * It is the recommended Director if the SDK is 3.1 or newer + * + * @since v0.8.2 + */ +@interface CCDirectorDisplayLink : CCDirectorMac +{ + CVDisplayLinkRef displayLink; +} +@end + +#endif // __MAC_OS_X_VERSION_MAX_ALLOWED + 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 diff --git a/libs/cocos2d/Platforms/Mac/CCEventDispatcher.h b/libs/cocos2d/Platforms/Mac/CCEventDispatcher.h new file mode 100755 index 0000000..06889e8 --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/CCEventDispatcher.h @@ -0,0 +1,277 @@ +/* + * 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 "MacGLView.h" +#import "../../Support/uthash.h" // hack: uthash needs to be imported before utlist to prevent warning +#import "../../Support/utlist.h" +#import "../../ccConfig.h" + +#pragma mark - +#pragma mark CCMouseEventDelegate + +/** CCMouseEventDelegate protocol. + Implement it in your node to receive any of mouse events + */ +@protocol CCMouseEventDelegate +@optional + +// +// left +// +/** called when the "mouseDown" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccMouseDown:(NSEvent*)event; + +/** called when the "mouseDragged" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccMouseDragged:(NSEvent*)event; + +/** called when the "mouseMoved" event is received. + Return YES to avoid propagating the event to other delegates. + By default, "mouseMoved" is disabled. To enable it, send the "setAcceptsMouseMovedEvents:YES" message to the main window. + */ +-(BOOL) ccMouseMoved:(NSEvent*)event; + +/** called when the "mouseUp" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccMouseUp:(NSEvent*)event; + + +// +// right +// + +/** called when the "rightMouseDown" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccRightMouseDown:(NSEvent*)event; + +/** called when the "rightMouseDragged" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccRightMouseDragged:(NSEvent*)event; + +/** called when the "rightMouseUp" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccRightMouseUp:(NSEvent*)event; + +// +// other +// + +/** called when the "otherMouseDown" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccOtherMouseDown:(NSEvent*)event; + +/** called when the "otherMouseDragged" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccOtherMouseDragged:(NSEvent*)event; + +/** called when the "otherMouseUp" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccOtherMouseUp:(NSEvent*)event; + +// +// scroll wheel +// + +/** called when the "scrollWheel" event is received. + Return YES to avoid propagating the event to other delegates. + */ +- (BOOL)ccScrollWheel:(NSEvent *)theEvent; + + +// +// enter / exit +// + +/** called when the "mouseEntered" event is received. + Return YES to avoid propagating the event to other delegates. + */ +- (void)ccMouseEntered:(NSEvent *)theEvent; + +/** called when the "mouseExited" event is received. + Return YES to avoid propagating the event to other delegates. + */ +- (void)ccMouseExited:(NSEvent *)theEvent; + +@end + +#pragma mark - +#pragma mark CCKeyboardEventDelegate + +/** CCKeyboardEventDelegate protocol. + Implement it in your node to receive any of keyboard events + */ +@protocol CCKeyboardEventDelegate +@optional +/** called when the "keyUp" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccKeyUp:(NSEvent*)event; + +/** called when the "keyDown" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccKeyDown:(NSEvent*)event; +/** called when the "flagsChanged" event is received. + Return YES to avoid propagating the event to other delegates. + */ +-(BOOL) ccFlagsChanged:(NSEvent*)event; +@end + +#pragma mark - +#pragma mark CCTouchEventDelegate + +/** CCTouchEventDelegate protocol. + Implement it in your node to receive any of touch events + */ +@protocol CCTouchEventDelegate +@optional +/** called when the "touchesBegan" event is received. + Return YES to avoid propagating the event to other delegates. + */ +- (BOOL)ccTouchesBeganWithEvent:(NSEvent *)event; + +/** called when the "touchesMoved" event is received. + Return YES to avoid propagating the event to other delegates. + */ +- (BOOL)ccTouchesMovedWithEvent:(NSEvent *)event; + +/** called when the "touchesEnded" event is received. + Return YES to avoid propagating the event to other delegates. + */ +- (BOOL)ccTouchesEndedWithEvent:(NSEvent *)event; + +/** called when the "touchesCancelled" event is received. + Return YES to avoid propagating the event to other delegates. + */ +- (BOOL)ccTouchesCancelledWithEvent:(NSEvent *)event; + +@end + + +#pragma mark - +#pragma mark CCEventDispatcher + +struct _listEntry; + +/** CCEventDispatcher + + This is object is responsible for dispatching the events: + - Mouse events + - Keyboard events + - Touch events + + Only available on Mac + */ +@interface CCEventDispatcher : NSObject { + + BOOL dispatchEvents_; + + struct _listEntry *keyboardDelegates_; + struct _listEntry *mouseDelegates_; + struct _listEntry *touchDelegates_; +} + +@property (nonatomic, readwrite) BOOL dispatchEvents; + + +/** CCEventDispatcher singleton */ ++(CCEventDispatcher*) sharedDispatcher; + +#pragma mark CCEventDispatcher - Mouse + +/** Adds a mouse delegate to the dispatcher's list. + Delegates with a lower priority value will be called before higher priority values. + All the events will be propgated to all the delegates, unless the one delegate returns YES. + + IMPORTANT: The delegate will be retained. + */ +-(void) addMouseDelegate:(id) delegate priority:(NSInteger)priority; + +/** removes a mouse delegate */ +-(void) removeMouseDelegate:(id) delegate; + +/** Removes all mouse delegates, releasing all the delegates */ +-(void) removeAllMouseDelegates; + +#pragma mark CCEventDispatcher - Keyboard + +/** Adds a Keyboard delegate to the dispatcher's list. + Delegates with a lower priority value will be called before higher priority values. + All the events will be propgated to all the delegates, unless the one delegate returns YES. + + IMPORTANT: The delegate will be retained. + */ +-(void) addKeyboardDelegate:(id) delegate priority:(NSInteger)priority; + +/** removes a mouse delegate */ +-(void) removeKeyboardDelegate:(id) delegate; + +/** Removes all mouse delegates, releasing all the delegates */ +-(void) removeAllKeyboardDelegates; + +#pragma mark CCEventDispatcher - Touches + +/** Adds a Touch delegate to the dispatcher's list. + Delegates with a lower priority value will be called before higher priority values. + All the events will be propgated to all the delegates, unless the one delegate returns YES. + + IMPORTANT: The delegate will be retained. + */ +- (void)addTouchDelegate:(id)delegate priority:(NSInteger)priority; + +/** Removes a touch delegate */ +- (void)removeTouchDelegate:(id) delegate; + +/** Removes all touch delegates, releasing all the delegates */ +- (void)removeAllTouchDelegates; + +#pragma mark CCEventDispatcher - Dispatch Events + +#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD +-(void) dispatchQueuedEvents; +#endif + +@end + + +#endif // __MAC_OS_X_VERSION_MAX_ALLOWED diff --git a/libs/cocos2d/Platforms/Mac/CCEventDispatcher.m b/libs/cocos2d/Platforms/Mac/CCEventDispatcher.m new file mode 100755 index 0000000..1d1740e --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/CCEventDispatcher.m @@ -0,0 +1,645 @@ +/* + * 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 "CCEventDispatcher.h" +#import "../../ccConfig.h" + +static CCEventDispatcher *sharedDispatcher = nil; + +enum { + // mouse + kCCImplementsMouseDown = 1 << 0, + kCCImplementsMouseMoved = 1 << 1, + kCCImplementsMouseDragged = 1 << 2, + kCCImplementsMouseUp = 1 << 3, + kCCImplementsRightMouseDown = 1 << 4, + kCCImplementsRightMouseDragged = 1 << 5, + kCCImplementsRightMouseUp = 1 << 6, + kCCImplementsOtherMouseDown = 1 << 7, + kCCImplementsOtherMouseDragged = 1 << 8, + kCCImplementsOtherMouseUp = 1 << 9, + kCCImplementsScrollWheel = 1 << 10, + kCCImplementsMouseEntered = 1 << 11, + kCCImplementsMouseExited = 1 << 12, + + kCCImplementsTouchesBegan = 1 << 13, + kCCImplementsTouchesMoved = 1 << 14, + kCCImplementsTouchesEnded = 1 << 15, + kCCImplementsTouchesCancelled = 1 << 16, + + // keyboard + kCCImplementsKeyUp = 1 << 0, + kCCImplementsKeyDown = 1 << 1, + kCCImplementsFlagsChanged = 1 << 2, +}; + + +typedef struct _listEntry +{ + struct _listEntry *prev, *next; + id delegate; + NSInteger priority; + NSUInteger flags; +} tListEntry; + + +#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD + +#define QUEUE_EVENT_MAX 128 +struct _eventQueue { + SEL selector; + NSEvent *event; +}; + +static struct _eventQueue eventQueue[QUEUE_EVENT_MAX]; +static int eventQueueCount; + +#endif // CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD + + +@implementation CCEventDispatcher + +@synthesize dispatchEvents=dispatchEvents_; + + ++(CCEventDispatcher*) sharedDispatcher +{ + @synchronized(self) { + if (sharedDispatcher == nil) + sharedDispatcher = [[self alloc] init]; // assignment not done here + } + return sharedDispatcher; +} + ++(id) allocWithZone:(NSZone *)zone +{ + @synchronized(self) { + NSAssert(sharedDispatcher == nil, @"Attempted to allocate a second instance of a singleton."); + return [super allocWithZone:zone]; + } + return nil; // on subsequent allocation attempts return nil +} + +-(id) init +{ + if( (self = [super init]) ) + { + // events enabled by default + dispatchEvents_ = YES; + + // delegates + keyboardDelegates_ = NULL; + mouseDelegates_ = NULL; + touchDelegates_ = NULL; + +#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD + eventQueueCount = 0; +#endif + } + + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + +#pragma mark CCEventDispatcher - add / remove delegates + +-(void) addDelegate:(id)delegate priority:(NSInteger)priority flags:(NSUInteger)flags list:(tListEntry**)list +{ + tListEntry *listElement = malloc( sizeof(*listElement) ); + + listElement->delegate = [delegate retain]; + listElement->priority = priority; + listElement->flags = flags; + listElement->next = listElement->prev = NULL; + + // empty list ? + if( ! *list ) { + DL_APPEND( *list, listElement ); + + } else { + BOOL added = NO; + + for( tListEntry *elem = *list; elem ; elem = elem->next ) { + if( priority < elem->priority ) { + + if( elem == *list ) + DL_PREPEND(*list, listElement); + else { + listElement->next = elem; + listElement->prev = elem->prev; + + elem->prev->next = listElement; + elem->prev = listElement; + } + + added = YES; + break; + } + } + + // Not added? priority has the higher value. Append it. + if( !added ) + DL_APPEND(*list, listElement); + } +} + +-(void) removeDelegate:(id)delegate fromList:(tListEntry**)list +{ + tListEntry *entry, *tmp; + + // updates with priority < 0 + DL_FOREACH_SAFE( *list, entry, tmp ) { + if( entry->delegate == delegate ) { + DL_DELETE( *list, entry ); + [delegate release]; + free(entry); + break; + } + } +} + +-(void) removeAllDelegatesFromList:(tListEntry**)list +{ + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( *list, entry, tmp ) { + DL_DELETE( *list, entry ); + free(entry); + } +} + + +-(void) addMouseDelegate:(id) delegate priority:(NSInteger)priority +{ + NSUInteger flags = 0; + + flags |= ( [delegate respondsToSelector:@selector(ccMouseDown:)] ? kCCImplementsMouseDown : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccMouseDragged:)] ? kCCImplementsMouseDragged : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccMouseMoved:)] ? kCCImplementsMouseMoved : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccMouseUp:)] ? kCCImplementsMouseUp : 0 ); + + flags |= ( [delegate respondsToSelector:@selector(ccRightMouseDown:)] ? kCCImplementsRightMouseDown : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccRightMouseDragged:)] ? kCCImplementsRightMouseDragged : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccRightMouseUp:)] ? kCCImplementsRightMouseUp : 0 ); + + flags |= ( [delegate respondsToSelector:@selector(ccOtherMouseDown:)] ? kCCImplementsOtherMouseDown : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccOtherMouseDragged:)] ? kCCImplementsOtherMouseDragged : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccOtherMouseUp:)] ? kCCImplementsOtherMouseUp : 0 ); + + flags |= ( [delegate respondsToSelector:@selector(ccMouseEntered:)] ? kCCImplementsMouseEntered : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccMouseExited:)] ? kCCImplementsMouseExited : 0 ); + + flags |= ( [delegate respondsToSelector:@selector(ccScrollWheel:)] ? kCCImplementsScrollWheel : 0 ); + + [self addDelegate:delegate priority:priority flags:flags list:&mouseDelegates_]; +} + +-(void) removeMouseDelegate:(id) delegate +{ + [self removeDelegate:delegate fromList:&mouseDelegates_]; +} + +-(void) removeAllMouseDelegates +{ + [self removeAllDelegatesFromList:&mouseDelegates_]; +} + +-(void) addKeyboardDelegate:(id) delegate priority:(NSInteger)priority +{ + NSUInteger flags = 0; + + flags |= ( [delegate respondsToSelector:@selector(ccKeyUp:)] ? kCCImplementsKeyUp : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccKeyDown:)] ? kCCImplementsKeyDown : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccFlagsChanged:)] ? kCCImplementsFlagsChanged : 0 ); + + [self addDelegate:delegate priority:priority flags:flags list:&keyboardDelegates_]; +} + +-(void) removeKeyboardDelegate:(id) delegate +{ + [self removeDelegate:delegate fromList:&keyboardDelegates_]; +} + +-(void) removeAllKeyboardDelegates +{ + [self removeAllDelegatesFromList:&keyboardDelegates_]; +} + +-(void) addTouchDelegate:(id) delegate priority:(NSInteger)priority +{ + NSUInteger flags = 0; + + flags |= ( [delegate respondsToSelector:@selector(ccTouchesBeganWithEvent:)] ? kCCImplementsTouchesBegan : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccTouchesMovedWithEvent:)] ? kCCImplementsTouchesMoved : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccTouchesEndedWithEvent:)] ? kCCImplementsTouchesEnded : 0 ); + flags |= ( [delegate respondsToSelector:@selector(ccTouchesCancelledWithEvent:)] ? kCCImplementsTouchesCancelled : 0 ); + + [self addDelegate:delegate priority:priority flags:flags list:&touchDelegates_]; +} + +-(void) removeTouchDelegate:(id) delegate +{ + [self removeDelegate:delegate fromList:&touchDelegates_]; +} + +-(void) removeAllTouchDelegates +{ + [self removeAllDelegatesFromList:&touchDelegates_]; +} + + +#pragma mark CCEventDispatcher - Mouse events +// +// Mouse events +// + +// +// Left +// +- (void)mouseDown:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsMouseDown ) { + void *swallows = [entry->delegate performSelector:@selector(ccMouseDown:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)mouseMoved:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsMouseMoved ) { + void *swallows = [entry->delegate performSelector:@selector(ccMouseMoved:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)mouseDragged:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsMouseDragged ) { + void *swallows = [entry->delegate performSelector:@selector(ccMouseDragged:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)mouseUp:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsMouseUp ) { + void *swallows = [entry->delegate performSelector:@selector(ccMouseUp:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +// +// Mouse Right +// +- (void)rightMouseDown:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsRightMouseDown ) { + void *swallows = [entry->delegate performSelector:@selector(ccRightMouseDown:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)rightMouseDragged:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsRightMouseDragged ) { + void *swallows = [entry->delegate performSelector:@selector(ccRightMouseDragged:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)rightMouseUp:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsRightMouseUp ) { + void *swallows = [entry->delegate performSelector:@selector(ccRightMouseUp:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +// +// Mouse Other +// +- (void)otherMouseDown:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsOtherMouseDown ) { + void *swallows = [entry->delegate performSelector:@selector(ccOtherMouseDown:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)otherMouseDragged:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsOtherMouseDragged ) { + void *swallows = [entry->delegate performSelector:@selector(ccOtherMouseDragged:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)otherMouseUp:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsOtherMouseUp ) { + void *swallows = [entry->delegate performSelector:@selector(ccOtherMouseUp:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +// +// Scroll Wheel +// +- (void)scrollWheel:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsScrollWheel ) { + void *swallows = [entry->delegate performSelector:@selector(ccScrollWheel:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +// +// Mouse enter / exit +- (void)mouseExited:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsMouseEntered ) { + void *swallows = [entry->delegate performSelector:@selector(ccMouseEntered:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)mouseEntered:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( mouseDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsMouseExited) { + void *swallows = [entry->delegate performSelector:@selector(ccMouseExited:) withObject:event]; + if( swallows ) + break; + } + } + } +} + + +#pragma mark CCEventDispatcher - Keyboard events + +// Keyboard events +- (void)keyDown:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( keyboardDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsKeyDown ) { + void *swallows = [entry->delegate performSelector:@selector(ccKeyDown:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)keyUp:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( keyboardDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsKeyUp ) { + void *swallows = [entry->delegate performSelector:@selector(ccKeyUp:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)flagsChanged:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( keyboardDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsFlagsChanged ) { + void *swallows = [entry->delegate performSelector:@selector(ccFlagsChanged:) withObject:event]; + if( swallows ) + break; + } + } + } +} + + +#pragma mark CCEventDispatcher - Touch events + +- (void)touchesBeganWithEvent:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsTouchesBegan) { + void *swallows = [entry->delegate performSelector:@selector(ccTouchesBeganWithEvent:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)touchesMovedWithEvent:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsTouchesMoved) { + void *swallows = [entry->delegate performSelector:@selector(ccTouchesMovedWithEvent:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)touchesEndedWithEvent:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsTouchesEnded) { + void *swallows = [entry->delegate performSelector:@selector(ccTouchesEndedWithEvent:) withObject:event]; + if( swallows ) + break; + } + } + } +} + +- (void)touchesCancelledWithEvent:(NSEvent *)event +{ + if( dispatchEvents_ ) { + tListEntry *entry, *tmp; + + DL_FOREACH_SAFE( touchDelegates_, entry, tmp ) { + if ( entry->flags & kCCImplementsTouchesCancelled) { + void *swallows = [entry->delegate performSelector:@selector(ccTouchesCancelledWithEvent:) withObject:event]; + if( swallows ) + break; + } + } + } +} + + +#pragma mark CCEventDispatcher - queue events + +#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD +-(void) queueEvent:(NSEvent*)event selector:(SEL)selector +{ + NSAssert( eventQueueCount < QUEUE_EVENT_MAX, @"CCEventDispatcher: recompile. Increment QUEUE_EVENT_MAX value"); + + @synchronized (self) { + eventQueue[eventQueueCount].selector = selector; + eventQueue[eventQueueCount].event = [event copy]; + + eventQueueCount++; + } +} + +-(void) dispatchQueuedEvents +{ + @synchronized (self) { + for( int i=0; i < eventQueueCount; i++ ) { + SEL sel = eventQueue[i].selector; + NSEvent *event = eventQueue[i].event; + + [self performSelector:sel withObject:event]; + + [event release]; + } + + eventQueueCount = 0; + } +} +#endif // CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD + + +@end + +#endif // __MAC_OS_X_VERSION_MAX_ALLOWED diff --git a/libs/cocos2d/Platforms/Mac/MacGLView.h b/libs/cocos2d/Platforms/Mac/MacGLView.h new file mode 100755 index 0000000..8099273 --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/MacGLView.h @@ -0,0 +1,89 @@ +/* + * 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 "../../ccConfig.h" + +//PROTOCOLS: + +@protocol MacEventDelegate +// Mouse +- (void)mouseDown:(NSEvent *)theEvent; +- (void)mouseUp:(NSEvent *)theEvent; +- (void)mouseMoved:(NSEvent *)theEvent; +- (void)mouseDragged:(NSEvent *)theEvent; +- (void)rightMouseDown:(NSEvent*)event; +- (void)rightMouseDragged:(NSEvent*)event; +- (void)rightMouseUp:(NSEvent*)event; +- (void)otherMouseDown:(NSEvent*)event; +- (void)otherMouseDragged:(NSEvent*)event; +- (void)otherMouseUp:(NSEvent*)event; +- (void)scrollWheel:(NSEvent *)theEvent; +- (void)mouseEntered:(NSEvent *)theEvent; +- (void)mouseExited:(NSEvent *)theEvent; + + +// Keyboard +- (void)keyDown:(NSEvent *)theEvent; +- (void)keyUp:(NSEvent *)theEvent; +- (void)flagsChanged:(NSEvent *)theEvent; + +// Touches +- (void)touchesBeganWithEvent:(NSEvent *)event; +- (void)touchesMovedWithEvent:(NSEvent *)event; +- (void)touchesEndedWithEvent:(NSEvent *)event; +- (void)touchesCancelledWithEvent:(NSEvent *)event; + +#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD +- (void)queueEvent:(NSEvent*)event selector:(SEL)selector; +#endif + +@end + +/** MacGLView + + Only available for Mac OS X + */ +@interface MacGLView : NSOpenGLView { + id eventDelegate_; +} + +@property (nonatomic, readwrite, assign) id eventDelegate; + +// initializes the MacGLView with a frame rect and an OpenGL context +- (id) initWithFrame:(NSRect)frameRect shareContext:(NSOpenGLContext*)context; + +// private ++(void) load_; +@end + +#endif // __MAC_OS_X_VERSION_MAX_ALLOWED \ No newline at end of file diff --git a/libs/cocos2d/Platforms/Mac/MacGLView.m b/libs/cocos2d/Platforms/Mac/MacGLView.m new file mode 100755 index 0000000..a041dc8 --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/MacGLView.m @@ -0,0 +1,242 @@ +/* + * 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. + */ + +/* + * Idea of subclassing NSOpenGLView was taken from "TextureUpload" Apple's sample + */ + +// 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 "MacGLView.h" +#import + +#import "CCDirectorMac.h" +#import "../../ccConfig.h" + + +@implementation MacGLView + +@synthesize eventDelegate = eventDelegate_; + ++(void) load_ +{ + NSLog(@"%@ loaded", self); +} + +- (id) initWithFrame:(NSRect)frameRect +{ + self = [self initWithFrame:frameRect shareContext:nil]; + return self; +} + +- (id) initWithFrame:(NSRect)frameRect shareContext:(NSOpenGLContext*)context +{ + NSOpenGLPixelFormatAttribute attribs[] = + { + NSOpenGLPFAAccelerated, + NSOpenGLPFANoRecovery, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFADepthSize, 24, + + 0 + }; + + NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; + + if (!pixelFormat) + NSLog(@"No OpenGL pixel format"); + + if( (self = [super initWithFrame:frameRect pixelFormat:[pixelFormat autorelease]]) ) { + + if( context ) + [self setOpenGLContext:context]; + + // Synchronize buffer swaps with vertical refresh rate + GLint swapInt = 1; + [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; + +// GLint order = -1; +// [[self openGLContext] setValues:&order forParameter:NSOpenGLCPSurfaceOrder]; + + // event delegate + eventDelegate_ = nil; + } + + return self; +} + +- (void) reshape +{ + // 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([[self openGLContext] CGLContextObj]); + + NSRect rect = [self bounds]; + + CCDirector *director = [CCDirector sharedDirector]; + [director reshapeProjection: NSSizeToCGSize(rect.size) ]; + + // avoid flicker + [director drawScene]; +// [self setNeedsDisplay:YES]; + + CGLUnlockContext([[self openGLContext] CGLContextObj]); +} + +- (void) dealloc +{ + + [super dealloc]; +} + +#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD +#define DISPATCH_EVENT(__event__, __selector__) [eventDelegate_ queueEvent:__event__ selector:__selector__]; +#else +#define DISPATCH_EVENT(__event__, __selector__) \ + id obj = eventDelegate_; \ + [obj performSelector:__selector__ \ + onThread:[(CCDirectorMac*)[CCDirector sharedDirector] runningThread] \ + withObject:__event__ \ + waitUntilDone:NO]; +#endif + +#pragma mark MacGLView - Mouse events +- (void)mouseDown:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)mouseMoved:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)mouseDragged:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)mouseUp:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)rightMouseDown:(NSEvent *)theEvent { + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)rightMouseDragged:(NSEvent *)theEvent { + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)rightMouseUp:(NSEvent *)theEvent { + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)otherMouseDown:(NSEvent *)theEvent { + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)otherMouseDragged:(NSEvent *)theEvent { + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)otherMouseUp:(NSEvent *)theEvent { + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)mouseEntered:(NSEvent *)theEvent { + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)mouseExited:(NSEvent *)theEvent { + DISPATCH_EVENT(theEvent, _cmd); +} + +-(void) scrollWheel:(NSEvent *)theEvent { + DISPATCH_EVENT(theEvent, _cmd); +} + +#pragma mark MacGLView - Key events + +-(BOOL) becomeFirstResponder +{ + return YES; +} + +-(BOOL) acceptsFirstResponder +{ + return YES; +} + +-(BOOL) resignFirstResponder +{ + return YES; +} + +- (void)keyDown:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)keyUp:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)flagsChanged:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +#pragma mark MacGLView - Touch events +- (void)touchesBeganWithEvent:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)touchesMovedWithEvent:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)touchesEndedWithEvent:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +- (void)touchesCancelledWithEvent:(NSEvent *)theEvent +{ + DISPATCH_EVENT(theEvent, _cmd); +} + +@end + +#endif // __MAC_OS_X_VERSION_MAX_ALLOWED diff --git a/libs/cocos2d/Platforms/Mac/MacWindow.h b/libs/cocos2d/Platforms/Mac/MacWindow.h new file mode 100755 index 0000000..716fe9b --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/MacWindow.h @@ -0,0 +1,42 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2010 Ricardo Quesada + * + * 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 + + +@interface MacWindow : NSWindow +{ +} +- (id) initWithFrame:(NSRect)frame fullscreen:(BOOL)fullscreen; + +@end + + +#endif // __MAC_OS_X_VERSION_MAX_ALLOWED \ No newline at end of file diff --git a/libs/cocos2d/Platforms/Mac/MacWindow.m b/libs/cocos2d/Platforms/Mac/MacWindow.m new file mode 100755 index 0000000..28736a3 --- /dev/null +++ b/libs/cocos2d/Platforms/Mac/MacWindow.m @@ -0,0 +1,70 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2010 Ricardo Quesada + * + * 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 "MacWindow.h" + + +@implementation MacWindow + +- (id) initWithFrame:(NSRect)frame fullscreen:(BOOL)fullscreen +{ + int styleMask = fullscreen ? NSBackingStoreBuffered : ( NSTitledWindowMask | NSClosableWindowMask ); + self = [self initWithContentRect:frame + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:YES]; + + if (self != nil) + { + if(fullscreen) + { + [self setLevel:NSMainMenuWindowLevel+1]; + [self setHidesOnDeactivate:YES]; + [self setHasShadow:NO]; + } + + [self setAcceptsMouseMovedEvents:NO]; + [self setOpaque:YES]; + } + return self; +} + +- (BOOL) canBecomeKeyWindow +{ + return YES; +} + +- (BOOL) canBecomeMainWindow +{ + return YES; +} +@end + +#endif // __MAC_OS_X_VERSION_MAX_ALLOWED -- cgit 1.4.1