summary refs log tree commit diff stats
path: root/libs/cocos2d/Platforms/Mac/CCDirectorMac.m
diff options
context:
space:
mode:
Diffstat (limited to 'libs/cocos2d/Platforms/Mac/CCDirectorMac.m')
-rwxr-xr-xlibs/cocos2d/Platforms/Mac/CCDirectorMac.m479
1 files changed, 479 insertions, 0 deletions
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 @@
1/*
2 * cocos2d for iPhone: http://www.cocos2d-iphone.org
3 *
4 * Copyright (c) 2010 Ricardo Quesada
5 * Copyright (c) 2011 Zynga Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26// Only compile this code on Mac. These files should not be included on your iOS project.
27// But in case they are included, it won't be compiled.
28#import <Availability.h>
29#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
30#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
31
32#import <sys/time.h>
33
34#import "CCDirectorMac.h"
35#import "CCEventDispatcher.h"
36#import "MacGLView.h"
37
38#import "../../CCNode.h"
39#import "../../CCScheduler.h"
40#import "../../ccMacros.h"
41
42#pragma mark -
43#pragma mark Director Mac extensions
44
45
46@interface CCDirector ()
47-(void) setNextScene;
48-(void) showFPS;
49-(void) calculateDeltaTime;
50@end
51
52@implementation CCDirector (MacExtension)
53-(CGPoint) convertEventToGL:(NSEvent*)event
54{
55 NSPoint point = [openGLView_ convertPoint:[event locationInWindow] fromView:nil];
56 CGPoint p = NSPointToCGPoint(point);
57
58 return [(CCDirectorMac*)self convertToLogicalCoordinates:p];
59}
60
61@end
62
63#pragma mark -
64#pragma mark Director Mac
65
66@implementation CCDirectorMac
67
68@synthesize isFullScreen = isFullScreen_;
69@synthesize originalWinSize = originalWinSize_;
70
71-(id) init
72{
73 if( (self = [super init]) ) {
74 isFullScreen_ = NO;
75 resizeMode_ = kCCDirectorResize_AutoScale;
76
77 originalWinSize_ = CGSizeZero;
78 fullScreenWindow_ = nil;
79 windowGLView_ = nil;
80 winOffset_ = CGPointZero;
81 }
82
83 return self;
84}
85
86- (void) dealloc
87{
88 [superViewGLView_ release];
89 [fullScreenWindow_ release];
90 [windowGLView_ release];
91 [super dealloc];
92}
93
94//
95// setFullScreen code taken from GLFullScreen example by Apple
96//
97- (void) setFullScreen:(BOOL)fullscreen
98{
99 // Mac OS X 10.6 and later offer a simplified mechanism to create full-screen contexts
100#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5
101
102 if (isFullScreen_ == fullscreen) return;
103
104 if( fullscreen ) {
105 originalWinRect_ = [openGLView_ frame];
106
107 // Cache normal window and superview of openGLView
108 if(!windowGLView_)
109 windowGLView_ = [[openGLView_ window] retain];
110
111 [superViewGLView_ release];
112 superViewGLView_ = [[openGLView_ superview] retain];
113
114
115 // Get screen size
116 NSRect displayRect = [[NSScreen mainScreen] frame];
117
118 // Create a screen-sized window on the display you want to take over
119 fullScreenWindow_ = [[MacWindow alloc] initWithFrame:displayRect fullscreen:YES];
120
121 // Remove glView from window
122 [openGLView_ removeFromSuperview];
123
124 // Set new frame
125 [openGLView_ setFrame:displayRect];
126
127 // Attach glView to fullscreen window
128 [fullScreenWindow_ setContentView:openGLView_];
129
130 // Show the fullscreen window
131 [fullScreenWindow_ makeKeyAndOrderFront:self];
132 [fullScreenWindow_ makeMainWindow];
133
134 } else {
135
136 // Remove glView from fullscreen window
137 [openGLView_ removeFromSuperview];
138
139 // Release fullscreen window
140 [fullScreenWindow_ release];
141 fullScreenWindow_ = nil;
142
143 // Attach glView to superview
144 [superViewGLView_ addSubview:openGLView_];
145
146 // Set new frame
147 [openGLView_ setFrame:originalWinRect_];
148
149 // Show the window
150 [windowGLView_ makeKeyAndOrderFront:self];
151 [windowGLView_ makeMainWindow];
152 }
153 isFullScreen_ = fullscreen;
154
155 [openGLView_ retain]; // Retain +1
156
157 // re-configure glView
158 [self setOpenGLView:openGLView_];
159
160 [openGLView_ release]; // Retain -1
161
162 [openGLView_ setNeedsDisplay:YES];
163#else
164#error Full screen is not supported for Mac OS 10.5 or older yet
165#error If you don't want FullScreen support, you can safely remove these 2 lines
166#endif
167}
168
169-(void) setOpenGLView:(MacGLView *)view
170{
171 [super setOpenGLView:view];
172
173 // cache the NSWindow and NSOpenGLView created from the NIB
174 if( !isFullScreen_ && CGSizeEqualToSize(originalWinSize_, CGSizeZero))
175 {
176 originalWinSize_ = winSizeInPixels_;
177 }
178}
179
180-(int) resizeMode
181{
182 return resizeMode_;
183}
184
185-(void) setResizeMode:(int)mode
186{
187 if( mode != resizeMode_ ) {
188
189 resizeMode_ = mode;
190
191 [self setProjection:projection_];
192 [openGLView_ setNeedsDisplay: YES];
193 }
194}
195
196-(void) setProjection:(ccDirectorProjection)projection
197{
198 CGSize size = winSizeInPixels_;
199
200 CGPoint offset = CGPointZero;
201 float widthAspect = size.width;
202 float heightAspect = size.height;
203
204
205 if( resizeMode_ == kCCDirectorResize_AutoScale && ! CGSizeEqualToSize(originalWinSize_, CGSizeZero ) ) {
206
207 size = originalWinSize_;
208
209 float aspect = originalWinSize_.width / originalWinSize_.height;
210 widthAspect = winSizeInPixels_.width;
211 heightAspect = winSizeInPixels_.width / aspect;
212
213 if( heightAspect > winSizeInPixels_.height ) {
214 widthAspect = winSizeInPixels_.height * aspect;
215 heightAspect = winSizeInPixels_.height;
216 }
217
218 winOffset_.x = (winSizeInPixels_.width - widthAspect) / 2;
219 winOffset_.y = (winSizeInPixels_.height - heightAspect) / 2;
220
221 offset = winOffset_;
222
223 }
224
225 switch (projection) {
226 case kCCDirectorProjection2D:
227 glViewport(offset.x, offset.y, widthAspect, heightAspect);
228 glMatrixMode(GL_PROJECTION);
229 glLoadIdentity();
230 ccglOrtho(0, size.width, 0, size.height, -1024, 1024);
231 glMatrixMode(GL_MODELVIEW);
232 glLoadIdentity();
233 break;
234
235 case kCCDirectorProjection3D:
236 glViewport(offset.x, offset.y, widthAspect, heightAspect);
237 glMatrixMode(GL_PROJECTION);
238 glLoadIdentity();
239 gluPerspective(60, (GLfloat)widthAspect/heightAspect, 0.1f, 1500.0f);
240
241 glMatrixMode(GL_MODELVIEW);
242 glLoadIdentity();
243
244 float eyeZ = size.height * [self getZEye] / winSizeInPixels_.height;
245
246 gluLookAt( size.width/2, size.height/2, eyeZ,
247 size.width/2, size.height/2, 0,
248 0.0f, 1.0f, 0.0f);
249 break;
250
251 case kCCDirectorProjectionCustom:
252 if( projectionDelegate_ )
253 [projectionDelegate_ updateProjection];
254 break;
255
256 default:
257 CCLOG(@"cocos2d: Director: unrecognized projecgtion");
258 break;
259 }
260
261 projection_ = projection;
262}
263
264// If scaling is supported, then it should always return the original size
265// otherwise it should return the "real" size.
266-(CGSize) winSize
267{
268 if( resizeMode_ == kCCDirectorResize_AutoScale )
269 return originalWinSize_;
270
271 return winSizeInPixels_;
272}
273
274-(CGSize) winSizeInPixels
275{
276 return [self winSize];
277}
278
279- (CGPoint) convertToLogicalCoordinates:(CGPoint)coords
280{
281 CGPoint ret;
282
283 if( resizeMode_ == kCCDirectorResize_NoScale )
284 ret = coords;
285
286 else {
287
288 float x_diff = originalWinSize_.width / (winSizeInPixels_.width - winOffset_.x * 2);
289 float y_diff = originalWinSize_.height / (winSizeInPixels_.height - winOffset_.y * 2);
290
291 float adjust_x = (winSizeInPixels_.width * x_diff - originalWinSize_.width ) / 2;
292 float adjust_y = (winSizeInPixels_.height * y_diff - originalWinSize_.height ) / 2;
293
294 ret = CGPointMake( (x_diff * coords.x) - adjust_x, ( y_diff * coords.y ) - adjust_y );
295 }
296
297 return ret;
298}
299@end
300
301
302#pragma mark -
303#pragma mark DirectorDisplayLink
304
305
306@implementation CCDirectorDisplayLink
307
308- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime
309{
310#if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
311 if( ! runningThread_ )
312 runningThread_ = [NSThread currentThread];
313
314 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
315
316 [self drawScene];
317 [[CCEventDispatcher sharedDispatcher] dispatchQueuedEvents];
318
319 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:nil];
320
321 [pool release];
322
323#else
324 [self performSelector:@selector(drawScene) onThread:runningThread_ withObject:nil waitUntilDone:YES];
325#endif
326
327 return kCVReturnSuccess;
328}
329
330// This is the renderer output callback function
331static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
332{
333 CVReturn result = [(CCDirectorDisplayLink*)displayLinkContext getFrameForTime:outputTime];
334 return result;
335}
336
337- (void) startAnimation
338{
339#if ! CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
340 runningThread_ = [[NSThread alloc] initWithTarget:self selector:@selector(mainLoop) object:nil];
341 [runningThread_ start];
342#endif
343
344 gettimeofday( &lastUpdate_, NULL);
345
346 // Create a display link capable of being used with all active displays
347 CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
348
349 // Set the renderer output callback function
350 CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, self);
351
352 // Set the display link for the current renderer
353 CGLContextObj cglContext = [[openGLView_ openGLContext] CGLContextObj];
354 CGLPixelFormatObj cglPixelFormat = [[openGLView_ pixelFormat] CGLPixelFormatObj];
355 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
356
357 // Activate the display link
358 CVDisplayLinkStart(displayLink);
359}
360
361- (void) stopAnimation
362{
363 if( displayLink ) {
364 CVDisplayLinkStop(displayLink);
365 CVDisplayLinkRelease(displayLink);
366 displayLink = NULL;
367
368#if ! CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
369 [runningThread_ cancel];
370 [runningThread_ release];
371 runningThread_ = nil;
372#endif
373 }
374}
375
376-(void) dealloc
377{
378 if( displayLink ) {
379 CVDisplayLinkStop(displayLink);
380 CVDisplayLinkRelease(displayLink);
381 }
382 [super dealloc];
383}
384
385//
386// Mac Director has its own thread
387//
388-(void) mainLoop
389{
390 while( ![[NSThread currentThread] isCancelled] ) {
391 // There is no autorelease pool when this method is called because it will be called from a background thread
392 // It's important to create one or you will leak objects
393 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
394
395 [[NSRunLoop currentRunLoop] run];
396
397 [pool release];
398 }
399}
400
401//
402// Draw the Scene
403//
404- (void) drawScene
405{
406 // We draw on a secondary thread through the display link
407 // When resizing the view, -reshape is called automatically on the main thread
408 // Add a mutex around to avoid the threads accessing the context simultaneously when resizing
409 CGLLockContext([[openGLView_ openGLContext] CGLContextObj]);
410 [[openGLView_ openGLContext] makeCurrentContext];
411
412 /* calculate "global" dt */
413 [self calculateDeltaTime];
414
415 /* tick before glClear: issue #533 */
416 if( ! isPaused_ ) {
417 [[CCScheduler sharedScheduler] tick: dt];
418 }
419
420 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
421
422 /* to avoid flickr, nextScene MUST be here: after tick and before draw.
423 XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */
424 if( nextScene_ )
425 [self setNextScene];
426
427 glPushMatrix();
428
429
430 // By default enable VertexArray, ColorArray, TextureCoordArray and Texture2D
431 CC_ENABLE_DEFAULT_GL_STATES();
432
433 /* draw the scene */
434 [runningScene_ visit];
435
436 /* draw the notification node */
437 [notificationNode_ visit];
438
439 if( displayFPS_ )
440 [self showFPS];
441
442#if CC_ENABLE_PROFILERS
443 [self showProfilers];
444#endif
445
446 CC_DISABLE_DEFAULT_GL_STATES();
447
448 glPopMatrix();
449
450 [[openGLView_ openGLContext] flushBuffer];
451 CGLUnlockContext([[openGLView_ openGLContext] CGLContextObj]);
452}
453
454// set the event dispatcher
455-(void) setOpenGLView:(MacGLView *)view
456{
457 if( view != openGLView_ ) {
458
459 [super setOpenGLView:view];
460
461 CCEventDispatcher *eventDispatcher = [CCEventDispatcher sharedDispatcher];
462 [openGLView_ setEventDelegate: eventDispatcher];
463 [eventDispatcher setDispatchEvents: YES];
464
465 // Enable Touches. Default no.
466 [view setAcceptsTouchEvents:NO];
467// [view setAcceptsTouchEvents:YES];
468
469
470 // Synchronize buffer swaps with vertical refresh rate
471 [[view openGLContext] makeCurrentContext];
472 GLint swapInt = 1;
473 [[view openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
474 }
475}
476
477@end
478
479#endif // __MAC_OS_X_VERSION_MAX_ALLOWED