summary refs log tree commit diff stats
path: root/libs/cocos2d/Platforms/iOS/CCDirectorIOS.m
diff options
context:
space:
mode:
Diffstat (limited to 'libs/cocos2d/Platforms/iOS/CCDirectorIOS.m')
-rwxr-xr-xlibs/cocos2d/Platforms/iOS/CCDirectorIOS.m735
1 files changed, 735 insertions, 0 deletions
diff --git a/libs/cocos2d/Platforms/iOS/CCDirectorIOS.m b/libs/cocos2d/Platforms/iOS/CCDirectorIOS.m new file mode 100755 index 0000000..c483665 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/CCDirectorIOS.m
@@ -0,0 +1,735 @@
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
27// Only compile this code on iOS. These files should NOT be included on your Mac project.
28// But in case they are included, it won't be compiled.
29#import <Availability.h>
30#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
31
32#import <unistd.h>
33
34// cocos2d imports
35#import "CCDirectorIOS.h"
36#import "CCTouchDelegateProtocol.h"
37#import "CCTouchDispatcher.h"
38#import "../../CCScheduler.h"
39#import "../../CCActionManager.h"
40#import "../../CCTextureCache.h"
41#import "../../ccMacros.h"
42#import "../../CCScene.h"
43
44// support imports
45#import "glu.h"
46#import "../../Support/OpenGL_Internal.h"
47#import "../../Support/CGPointExtension.h"
48
49#import "CCLayer.h"
50
51#if CC_ENABLE_PROFILERS
52#import "../../Support/CCProfiling.h"
53#endif
54
55
56#pragma mark -
57#pragma mark Director - global variables (optimization)
58
59CGFloat __ccContentScaleFactor = 1;
60
61#pragma mark -
62#pragma mark Director iOS
63
64@interface CCDirector ()
65-(void) setNextScene;
66-(void) showFPS;
67-(void) calculateDeltaTime;
68@end
69
70@implementation CCDirector (iOSExtensionClassMethods)
71
72+(Class) defaultDirector
73{
74 return [CCDirectorTimer class];
75}
76
77+ (BOOL) setDirectorType:(ccDirectorType)type
78{
79 if( type == CCDirectorTypeDisplayLink ) {
80 NSString *reqSysVer = @"3.1";
81 NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
82
83 if([currSysVer compare:reqSysVer options:NSNumericSearch] == NSOrderedAscending)
84 return NO;
85 }
86 switch (type) {
87 case CCDirectorTypeNSTimer:
88 [CCDirectorTimer sharedDirector];
89 break;
90 case CCDirectorTypeDisplayLink:
91 [CCDirectorDisplayLink sharedDirector];
92 break;
93 case CCDirectorTypeMainLoop:
94 [CCDirectorFast sharedDirector];
95 break;
96 case CCDirectorTypeThreadMainLoop:
97 [CCDirectorFastThreaded sharedDirector];
98 break;
99 default:
100 NSAssert(NO,@"Unknown director type");
101 }
102
103 return YES;
104}
105
106@end
107
108
109
110#pragma mark -
111#pragma mark CCDirectorIOS
112
113@interface CCDirectorIOS ()
114-(void) updateContentScaleFactor;
115
116@end
117
118@implementation CCDirectorIOS
119
120- (id) init
121{
122 if( (self=[super init]) ) {
123
124 // portrait mode default
125 deviceOrientation_ = CCDeviceOrientationPortrait;
126
127 __ccContentScaleFactor = 1;
128 isContentScaleSupported_ = NO;
129
130 // running thread is main thread on iOS
131 runningThread_ = [NSThread currentThread];
132 }
133
134 return self;
135}
136
137- (void) dealloc
138{
139 [super dealloc];
140}
141
142//
143// Draw the Scene
144//
145- (void) drawScene
146{
147 /* calculate "global" dt */
148 [self calculateDeltaTime];
149
150 /* tick before glClear: issue #533 */
151 if( ! isPaused_ ) {
152 [[CCScheduler sharedScheduler] tick: dt];
153 }
154
155 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
156
157 /* to avoid flickr, nextScene MUST be here: after tick and before draw.
158 XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */
159 if( nextScene_ )
160 [self setNextScene];
161
162 glPushMatrix();
163
164 [self applyOrientation];
165
166 // By default enable VertexArray, ColorArray, TextureCoordArray and Texture2D
167 CC_ENABLE_DEFAULT_GL_STATES();
168
169 /* draw the scene */
170 [runningScene_ visit];
171
172 /* draw the notification node */
173 [notificationNode_ visit];
174
175 if( displayFPS_ )
176 [self showFPS];
177
178#if CC_ENABLE_PROFILERS
179 [self showProfilers];
180#endif
181
182 CC_DISABLE_DEFAULT_GL_STATES();
183
184 glPopMatrix();
185
186 [openGLView_ swapBuffers];
187}
188
189-(void) setProjection:(ccDirectorProjection)projection
190{
191 CGSize size = winSizeInPixels_;
192
193 switch (projection) {
194 case kCCDirectorProjection2D:
195 glViewport(0, 0, size.width, size.height);
196 glMatrixMode(GL_PROJECTION);
197 glLoadIdentity();
198 ccglOrtho(0, size.width, 0, size.height, -1024 * CC_CONTENT_SCALE_FACTOR(), 1024 * CC_CONTENT_SCALE_FACTOR());
199 glMatrixMode(GL_MODELVIEW);
200 glLoadIdentity();
201 break;
202
203 case kCCDirectorProjection3D:
204 {
205 float zeye = [self getZEye];
206
207 glViewport(0, 0, size.width, size.height);
208 glMatrixMode(GL_PROJECTION);
209 glLoadIdentity();
210// gluPerspective(60, (GLfloat)size.width/size.height, zeye-size.height/2, zeye+size.height/2 );
211 gluPerspective(60, (GLfloat)size.width/size.height, 0.5f, 1500);
212
213 glMatrixMode(GL_MODELVIEW);
214 glLoadIdentity();
215 gluLookAt( size.width/2, size.height/2, zeye,
216 size.width/2, size.height/2, 0,
217 0.0f, 1.0f, 0.0f);
218 break;
219 }
220
221 case kCCDirectorProjectionCustom:
222 if( projectionDelegate_ )
223 [projectionDelegate_ updateProjection];
224 break;
225
226 default:
227 CCLOG(@"cocos2d: Director: unrecognized projecgtion");
228 break;
229 }
230
231 projection_ = projection;
232}
233
234#pragma mark Director Integration with a UIKit view
235
236-(void) setOpenGLView:(EAGLView *)view
237{
238 if( view != openGLView_ ) {
239
240 [super setOpenGLView:view];
241
242 // set size
243 winSizeInPixels_ = CGSizeMake(winSizeInPoints_.width * __ccContentScaleFactor, winSizeInPoints_.height *__ccContentScaleFactor);
244
245 if( __ccContentScaleFactor != 1 )
246 [self updateContentScaleFactor];
247
248 CCTouchDispatcher *touchDispatcher = [CCTouchDispatcher sharedDispatcher];
249 [openGLView_ setTouchDelegate: touchDispatcher];
250 [touchDispatcher setDispatchEvents: YES];
251 }
252}
253
254#pragma mark Director - Retina Display
255
256-(CGFloat) contentScaleFactor
257{
258 return __ccContentScaleFactor;
259}
260
261-(void) setContentScaleFactor:(CGFloat)scaleFactor
262{
263 if( scaleFactor != __ccContentScaleFactor ) {
264
265 __ccContentScaleFactor = scaleFactor;
266 winSizeInPixels_ = CGSizeMake( winSizeInPoints_.width * scaleFactor, winSizeInPoints_.height * scaleFactor );
267
268 if( openGLView_ )
269 [self updateContentScaleFactor];
270
271 // update projection
272 [self setProjection:projection_];
273 }
274}
275
276-(void) updateContentScaleFactor
277{
278 // Based on code snippet from: http://developer.apple.com/iphone/prerelease/library/snippets/sp2010/sp28.html
279 if ([openGLView_ respondsToSelector:@selector(setContentScaleFactor:)])
280 {
281 [openGLView_ setContentScaleFactor: __ccContentScaleFactor];
282
283 isContentScaleSupported_ = YES;
284 }
285 else
286 CCLOG(@"cocos2d: 'setContentScaleFactor:' is not supported on this device");
287}
288
289-(BOOL) enableRetinaDisplay:(BOOL)enabled
290{
291 // Already enabled ?
292 if( enabled && __ccContentScaleFactor == 2 )
293 return YES;
294
295 // Already disabled
296 if( ! enabled && __ccContentScaleFactor == 1 )
297 return YES;
298
299 // setContentScaleFactor is not supported
300 if (! [openGLView_ respondsToSelector:@selector(setContentScaleFactor:)])
301 return NO;
302
303 // SD device
304 if ([[UIScreen mainScreen] scale] == 1.0)
305 return NO;
306
307 float newScale = enabled ? 2 : 1;
308 [self setContentScaleFactor:newScale];
309
310 return YES;
311}
312
313// overriden, don't call super
314-(void) reshapeProjection:(CGSize)size
315{
316 winSizeInPoints_ = [openGLView_ bounds].size;
317 winSizeInPixels_ = CGSizeMake(winSizeInPoints_.width * __ccContentScaleFactor, winSizeInPoints_.height *__ccContentScaleFactor);
318
319 [self setProjection:projection_];
320}
321
322#pragma mark Director Scene Landscape
323
324-(CGPoint)convertToGL:(CGPoint)uiPoint
325{
326 CGSize s = winSizeInPoints_;
327 float newY = s.height - uiPoint.y;
328 float newX = s.width - uiPoint.x;
329
330 CGPoint ret = CGPointZero;
331 switch ( deviceOrientation_) {
332 case CCDeviceOrientationPortrait:
333 ret = ccp( uiPoint.x, newY );
334 break;
335 case CCDeviceOrientationPortraitUpsideDown:
336 ret = ccp(newX, uiPoint.y);
337 break;
338 case CCDeviceOrientationLandscapeLeft:
339 ret.x = uiPoint.y;
340 ret.y = uiPoint.x;
341 break;
342 case CCDeviceOrientationLandscapeRight:
343 ret.x = newY;
344 ret.y = newX;
345 break;
346 }
347 return ret;
348}
349
350-(CGPoint)convertToUI:(CGPoint)glPoint
351{
352 CGSize winSize = winSizeInPoints_;
353 int oppositeX = winSize.width - glPoint.x;
354 int oppositeY = winSize.height - glPoint.y;
355 CGPoint uiPoint = CGPointZero;
356 switch ( deviceOrientation_) {
357 case CCDeviceOrientationPortrait:
358 uiPoint = ccp(glPoint.x, oppositeY);
359 break;
360 case CCDeviceOrientationPortraitUpsideDown:
361 uiPoint = ccp(oppositeX, glPoint.y);
362 break;
363 case CCDeviceOrientationLandscapeLeft:
364 uiPoint = ccp(glPoint.y, glPoint.x);
365 break;
366 case CCDeviceOrientationLandscapeRight:
367 // Can't use oppositeX/Y because x/y are flipped
368 uiPoint = ccp(winSize.width-glPoint.y, winSize.height-glPoint.x);
369 break;
370 }
371 return uiPoint;
372}
373
374// get the current size of the glview
375-(CGSize) winSize
376{
377 CGSize s = winSizeInPoints_;
378
379 if( deviceOrientation_ == CCDeviceOrientationLandscapeLeft || deviceOrientation_ == CCDeviceOrientationLandscapeRight ) {
380 // swap x,y in landscape mode
381 CGSize tmp = s;
382 s.width = tmp.height;
383 s.height = tmp.width;
384 }
385 return s;
386}
387
388-(CGSize) winSizeInPixels
389{
390 CGSize s = [self winSize];
391
392 s.width *= CC_CONTENT_SCALE_FACTOR();
393 s.height *= CC_CONTENT_SCALE_FACTOR();
394
395 return s;
396}
397
398-(ccDeviceOrientation) deviceOrientation
399{
400 return deviceOrientation_;
401}
402
403- (void) setDeviceOrientation:(ccDeviceOrientation) orientation
404{
405 if( deviceOrientation_ != orientation ) {
406 deviceOrientation_ = orientation;
407 switch( deviceOrientation_) {
408 case CCDeviceOrientationPortrait:
409 [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationPortrait animated:NO];
410 break;
411 case CCDeviceOrientationPortraitUpsideDown:
412 [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationPortraitUpsideDown animated:NO];
413 break;
414 case CCDeviceOrientationLandscapeLeft:
415 [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeRight animated:NO];
416 break;
417 case CCDeviceOrientationLandscapeRight:
418 [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeLeft animated:NO];
419 break;
420 default:
421 NSLog(@"Director: Unknown device orientation");
422 break;
423 }
424 }
425}
426
427-(void) applyOrientation
428{
429 CGSize s = winSizeInPixels_;
430 float w = s.width / 2;
431 float h = s.height / 2;
432
433 // XXX it's using hardcoded values.
434 // What if the the screen size changes in the future?
435 switch ( deviceOrientation_ ) {
436 case CCDeviceOrientationPortrait:
437 // nothing
438 break;
439 case CCDeviceOrientationPortraitUpsideDown:
440 // upside down
441 glTranslatef(w,h,0);
442 glRotatef(180,0,0,1);
443 glTranslatef(-w,-h,0);
444 break;
445 case CCDeviceOrientationLandscapeRight:
446 glTranslatef(w,h,0);
447 glRotatef(90,0,0,1);
448 glTranslatef(-h,-w,0);
449 break;
450 case CCDeviceOrientationLandscapeLeft:
451 glTranslatef(w,h,0);
452 glRotatef(-90,0,0,1);
453 glTranslatef(-h,-w,0);
454 break;
455 }
456}
457
458-(void) end
459{
460 // don't release the event handlers
461 // They are needed in case the director is run again
462 [[CCTouchDispatcher sharedDispatcher] removeAllDelegates];
463
464 [super end];
465}
466
467@end
468
469
470#pragma mark -
471#pragma mark Director TimerDirector
472
473@implementation CCDirectorTimer
474- (void)startAnimation
475{
476 NSAssert( animationTimer == nil, @"animationTimer must be nil. Calling startAnimation twice?");
477
478 if( gettimeofday( &lastUpdate_, NULL) != 0 ) {
479 CCLOG(@"cocos2d: Director: Error in gettimeofday");
480 }
481
482 animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval_ target:self selector:@selector(mainLoop) userInfo:nil repeats:YES];
483
484 //
485 // If you want to attach the opengl view into UIScrollView
486 // uncomment this line to prevent 'freezing'.
487 // It doesn't work on with the Fast Director
488 //
489 // [[NSRunLoop currentRunLoop] addTimer:animationTimer
490 // forMode:NSRunLoopCommonModes];
491}
492
493-(void) mainLoop
494{
495 [self drawScene];
496}
497
498- (void)stopAnimation
499{
500 [animationTimer invalidate];
501 animationTimer = nil;
502}
503
504- (void)setAnimationInterval:(NSTimeInterval)interval
505{
506 animationInterval_ = interval;
507
508 if(animationTimer) {
509 [self stopAnimation];
510 [self startAnimation];
511 }
512}
513
514-(void) dealloc
515{
516 [animationTimer release];
517 [super dealloc];
518}
519@end
520
521
522#pragma mark -
523#pragma mark Director DirectorFast
524
525@implementation CCDirectorFast
526
527- (id) init
528{
529 if(( self = [super init] )) {
530
531#if CC_DIRECTOR_DISPATCH_FAST_EVENTS
532 CCLOG(@"cocos2d: Fast Events enabled");
533#else
534 CCLOG(@"cocos2d: Fast Events disabled");
535#endif
536 isRunning = NO;
537
538 // XXX:
539 // XXX: Don't create any autorelease object before calling "fast director"
540 // XXX: else it will be leaked
541 // XXX:
542 autoreleasePool = [NSAutoreleasePool new];
543 }
544
545 return self;
546}
547
548- (void) startAnimation
549{
550 NSAssert( isRunning == NO, @"isRunning must be NO. Calling startAnimation twice?");
551
552 // XXX:
553 // XXX: release autorelease objects created
554 // XXX: between "use fast director" and "runWithScene"
555 // XXX:
556 [autoreleasePool release];
557 autoreleasePool = nil;
558
559 if ( gettimeofday( &lastUpdate_, NULL) != 0 ) {
560 CCLOG(@"cocos2d: Director: Error in gettimeofday");
561 }
562
563
564 isRunning = YES;
565
566 SEL selector = @selector(mainLoop);
567 NSMethodSignature* sig = [[[CCDirector sharedDirector] class]
568 instanceMethodSignatureForSelector:selector];
569 NSInvocation* invocation = [NSInvocation
570 invocationWithMethodSignature:sig];
571 [invocation setTarget:[CCDirector sharedDirector]];
572 [invocation setSelector:selector];
573 [invocation performSelectorOnMainThread:@selector(invokeWithTarget:)
574 withObject:[CCDirector sharedDirector] waitUntilDone:NO];
575
576// NSInvocationOperation *loopOperation = [[[NSInvocationOperation alloc]
577// initWithTarget:self selector:@selector(mainLoop) object:nil]
578// autorelease];
579//
580// [loopOperation performSelectorOnMainThread:@selector(start) withObject:nil
581// waitUntilDone:NO];
582}
583
584-(void) mainLoop
585{
586 while (isRunning) {
587
588 NSAutoreleasePool *loopPool = [NSAutoreleasePool new];
589
590#if CC_DIRECTOR_DISPATCH_FAST_EVENTS
591 while( CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.004f, FALSE) == kCFRunLoopRunHandledSource);
592#else
593 while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource);
594#endif
595
596 if (isPaused_) {
597 usleep(250000); // Sleep for a quarter of a second (250,000 microseconds) so that the framerate is 4 fps.
598 }
599
600 [self drawScene];
601
602#if CC_DIRECTOR_DISPATCH_FAST_EVENTS
603 while( CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.004f, FALSE) == kCFRunLoopRunHandledSource);
604#else
605 while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource);
606#endif
607
608 [loopPool release];
609 }
610}
611- (void) stopAnimation
612{
613 isRunning = NO;
614}
615
616- (void)setAnimationInterval:(NSTimeInterval)interval
617{
618 NSLog(@"FastDirectory doesn't support setAnimationInterval, yet");
619}
620@end
621
622#pragma mark -
623#pragma mark Director DirectorThreadedFast
624
625@implementation CCDirectorFastThreaded
626
627- (id) init
628{
629 if(( self = [super init] )) {
630 isRunning = NO;
631 }
632
633 return self;
634}
635
636- (void) startAnimation
637{
638 NSAssert( isRunning == NO, @"isRunning must be NO. Calling startAnimation twice?");
639
640 if ( gettimeofday( &lastUpdate_, NULL) != 0 ) {
641 CCLOG(@"cocos2d: ThreadedFastDirector: Error on gettimeofday");
642 }
643
644 isRunning = YES;
645
646 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(mainLoop) object:nil];
647 [thread start];
648 [thread release];
649}
650
651-(void) mainLoop
652{
653 while( ![[NSThread currentThread] isCancelled] ) {
654 if( isRunning )
655 [self performSelectorOnMainThread:@selector(drawScene) withObject:nil waitUntilDone:YES];
656
657 if (isPaused_) {
658 usleep(250000); // Sleep for a quarter of a second (250,000 microseconds) so that the framerate is 4 fps.
659 } else {
660// usleep(2000);
661 }
662 }
663}
664- (void) stopAnimation
665{
666 isRunning = NO;
667}
668
669- (void)setAnimationInterval:(NSTimeInterval)interval
670{
671 NSLog(@"FastDirector doesn't support setAnimationInterval, yet");
672}
673@end
674
675#pragma mark -
676#pragma mark DirectorDisplayLink
677
678// Allows building DisplayLinkDirector for pre-3.1 SDKS
679// without getting compiler warnings.
680@interface NSObject(CADisplayLink)
681+ (id) displayLinkWithTarget:(id)arg1 selector:(SEL)arg2;
682- (void) addToRunLoop:(id)arg1 forMode:(id)arg2;
683- (void) setFrameInterval:(int)interval;
684- (void) invalidate;
685@end
686
687@implementation CCDirectorDisplayLink
688
689- (void)setAnimationInterval:(NSTimeInterval)interval
690{
691 animationInterval_ = interval;
692 if(displayLink){
693 [self stopAnimation];
694 [self startAnimation];
695 }
696}
697
698- (void) startAnimation
699{
700 NSAssert( displayLink == nil, @"displayLink must be nil. Calling startAnimation twice?");
701
702 if ( gettimeofday( &lastUpdate_, NULL) != 0 ) {
703 CCLOG(@"cocos2d: DisplayLinkDirector: Error on gettimeofday");
704 }
705
706 // approximate frame rate
707 // assumes device refreshes at 60 fps
708 int frameInterval = (int) floor(animationInterval_ * 60.0f);
709
710 CCLOG(@"cocos2d: Frame interval: %d", frameInterval);
711
712 displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(mainLoop:)];
713 [displayLink setFrameInterval:frameInterval];
714 [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
715}
716
717-(void) mainLoop:(id)sender
718{
719 [self drawScene];
720}
721
722- (void) stopAnimation
723{
724 [displayLink invalidate];
725 displayLink = nil;
726}
727
728-(void) dealloc
729{
730 [displayLink release];
731 [super dealloc];
732}
733@end
734
735#endif // __IPHONE_OS_VERSION_MAX_ALLOWED