diff options
Diffstat (limited to 'libs/cocos2d/Platforms/Mac/CCDirectorMac.m')
-rwxr-xr-x | libs/cocos2d/Platforms/Mac/CCDirectorMac.m | 479 |
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 | ||
331 | static 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 | ||