/libs/cocos2d/CCDirector.m

http://github.com/kstenerud/ObjectAL-for-iPhone · Objective C · 1231 lines · 848 code · 247 blank · 136 comment · 99 complexity · 20723224fb727a6a029fd0ce3d842d12 MD5 · raw file

  1. /*
  2. * cocos2d for iPhone: http://www.cocos2d-iphone.org
  3. *
  4. * Copyright (c) 2008-2010 Ricardo Quesada
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. /* Idea of decoupling Window from Director taken from OC3D project: http://code.google.com/p/oc3d/
  25. */
  26. #import <unistd.h>
  27. // cocos2d imports
  28. #import "CCDirector.h"
  29. #import "CCTouchDelegateProtocol.h"
  30. #import "CCCamera.h"
  31. #import "CCScheduler.h"
  32. #import "CCActionManager.h"
  33. #import "CCTextureCache.h"
  34. #import "CCLabelAtlas.h"
  35. #import "ccMacros.h"
  36. #import "ccExceptions.h"
  37. #import "CCTransition.h"
  38. #import "CCScene.h"
  39. #import "CCTouchDispatcher.h"
  40. #import "CCSpriteFrameCache.h"
  41. #import "CCTexture2D.h"
  42. #import "CCBitmapFontAtlas.h"
  43. // support imports
  44. #import "Support/glu.h"
  45. #import "Support/OpenGL_Internal.h"
  46. #import "Support/CGPointExtension.h"
  47. #import "CCLayer.h"
  48. #if CC_ENABLE_PROFILERS
  49. #import "Support/CCProfiling.h"
  50. #endif
  51. #define kDefaultFPS 60.0 // 60 frames per second
  52. extern NSString * cocos2dVersion(void);
  53. @interface CCDirector (Private)
  54. -(BOOL)isOpenGLAttached;
  55. -(BOOL)initOpenGLViewWithView:(UIView *)view withFrame:(CGRect)rect;
  56. -(void) preMainLoop;
  57. -(void) setNextScene;
  58. // shows the FPS in the screen
  59. -(void) showFPS;
  60. // calculates delta time since last time it was called
  61. -(void) calculateDeltaTime;
  62. -(void) updateContentScaleFactor;
  63. #if CC_ENABLE_PROFILERS
  64. - (void) showProfilers;
  65. #endif
  66. @end
  67. @implementation CCDirector
  68. @synthesize animationInterval=animationInterval_;
  69. @synthesize runningScene = runningScene_;
  70. @synthesize displayFPS = displayFPS_;
  71. @synthesize pixelFormat=pixelFormat_;
  72. @synthesize nextDeltaTimeZero=nextDeltaTimeZero_;
  73. @synthesize deviceOrientation=deviceOrientation_;
  74. @synthesize isPaused=isPaused_;
  75. @synthesize sendCleanupToScene=sendCleanupToScene_;
  76. //
  77. // singleton stuff
  78. //
  79. static CCDirector *_sharedDirector = nil;
  80. + (CCDirector *)sharedDirector
  81. {
  82. if (!_sharedDirector) {
  83. //
  84. // Default Director is TimerDirector
  85. //
  86. if( [ [CCDirector class] isEqual:[self class]] )
  87. _sharedDirector = [[CCTimerDirector alloc] init];
  88. else
  89. _sharedDirector = [[self alloc] init];
  90. }
  91. return _sharedDirector;
  92. }
  93. + (void) purgeSharedDirector
  94. {
  95. [_sharedDirector release];
  96. }
  97. + (BOOL) setDirectorType:(ccDirectorType)type
  98. {
  99. NSAssert(_sharedDirector==nil, @"A Director was alloced. setDirectorType must be the first call to Director");
  100. if( type == CCDirectorTypeDisplayLink ) {
  101. NSString *reqSysVer = @"3.1";
  102. NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
  103. if([currSysVer compare:reqSysVer options:NSNumericSearch] == NSOrderedAscending)
  104. return NO;
  105. }
  106. switch (type) {
  107. case CCDirectorTypeNSTimer:
  108. [CCTimerDirector sharedDirector];
  109. break;
  110. case CCDirectorTypeDisplayLink:
  111. [CCDisplayLinkDirector sharedDirector];
  112. break;
  113. case CCDirectorTypeMainLoop:
  114. [CCFastDirector sharedDirector];
  115. break;
  116. case CCDirectorTypeThreadMainLoop:
  117. [CCThreadedFastDirector sharedDirector];
  118. break;
  119. default:
  120. NSAssert(NO,@"Unknown director type");
  121. }
  122. return YES;
  123. }
  124. +(id)alloc
  125. {
  126. NSAssert(_sharedDirector == nil, @"Attempted to allocate a second instance of a singleton.");
  127. return [super alloc];
  128. }
  129. - (id) init
  130. {
  131. CCLOG(@"cocos2d: %@", cocos2dVersion() );
  132. if( (self=[super init]) ) {
  133. CCLOG(@"cocos2d: Using Director Type:%@", [self class]);
  134. // default values
  135. pixelFormat_ = kCCPixelFormatDefault;
  136. depthBufferFormat_ = 0;
  137. // scenes
  138. runningScene_ = nil;
  139. nextScene_ = nil;
  140. oldAnimationInterval_ = animationInterval_ = 1.0 / kDefaultFPS;
  141. scenesStack_ = [[NSMutableArray alloc] initWithCapacity:10];
  142. // landscape
  143. deviceOrientation_ = CCDeviceOrientationPortrait;
  144. // FPS
  145. displayFPS_ = NO;
  146. frames_ = 0;
  147. // paused ?
  148. isPaused_ = NO;
  149. contentScaleFactor_ = 1;
  150. screenSize_ = surfaceSize_ = CGSizeZero;
  151. isContentScaleSupported_ = NO;
  152. }
  153. return self;
  154. }
  155. - (void) dealloc
  156. {
  157. CCLOGINFO(@"cocos2d: deallocing %@", self);
  158. #if CC_DIRECTOR_FAST_FPS
  159. [FPSLabel_ release];
  160. #endif
  161. [runningScene_ release];
  162. [scenesStack_ release];
  163. _sharedDirector = nil;
  164. [super dealloc];
  165. }
  166. -(void) setGLDefaultValues
  167. {
  168. // This method SHOULD be called only after openGLView_ was initialized
  169. NSAssert( openGLView_, @"openGLView_ must be initialized");
  170. [self setAlphaBlending: YES];
  171. [self setDepthTest: YES];
  172. [self setProjection: kCCDirectorProjectionDefault];
  173. // set other opengl default values
  174. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  175. #if CC_DIRECTOR_FAST_FPS
  176. if (!FPSLabel_) {
  177. CCTexture2DPixelFormat currentFormat = [CCTexture2D defaultAlphaPixelFormat];
  178. [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA4444];
  179. FPSLabel_ = [[CCLabelAtlas labelAtlasWithString:@"00.0" charMapFile:@"fps_images.png" itemWidth:16 itemHeight:24 startCharMap:'.'] retain];
  180. [CCTexture2D setDefaultAlphaPixelFormat:currentFormat];
  181. }
  182. #endif // CC_DIRECTOR_FAST_FPS
  183. }
  184. //
  185. // Draw the Scene
  186. //
  187. - (void) drawScene
  188. {
  189. /* calculate "global" dt */
  190. [self calculateDeltaTime];
  191. /* tick before glClear: issue #533 */
  192. if( ! isPaused_ ) {
  193. [[CCScheduler sharedScheduler] tick: dt];
  194. }
  195. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  196. /* to avoid flickr, nextScene MUST be here: after tick and before draw.
  197. XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */
  198. if( nextScene_ )
  199. [self setNextScene];
  200. glPushMatrix();
  201. [self applyOrientation];
  202. // By default enable VertexArray, ColorArray, TextureCoordArray and Texture2D
  203. CC_ENABLE_DEFAULT_GL_STATES();
  204. /* draw the scene */
  205. [runningScene_ visit];
  206. if( displayFPS_ )
  207. [self showFPS];
  208. #if CC_ENABLE_PROFILERS
  209. [self showProfilers];
  210. #endif
  211. CC_DISABLE_DEFAULT_GL_STATES();
  212. glPopMatrix();
  213. /* swap buffers */
  214. [openGLView_ swapBuffers];
  215. }
  216. -(void) calculateDeltaTime
  217. {
  218. struct timeval now;
  219. if( gettimeofday( &now, NULL) != 0 ) {
  220. CCLOG(@"cocos2d: error in gettimeofday");
  221. dt = 0;
  222. return;
  223. }
  224. // new delta time
  225. if( nextDeltaTimeZero_ ) {
  226. dt = 0;
  227. nextDeltaTimeZero_ = NO;
  228. } else {
  229. dt = (now.tv_sec - lastUpdate_.tv_sec) + (now.tv_usec - lastUpdate_.tv_usec) / 1000000.0f;
  230. dt = MAX(0,dt);
  231. }
  232. lastUpdate_ = now;
  233. }
  234. #pragma mark Director Scene iPhone Specific
  235. -(void) setPixelFormat: (tPixelFormat) format
  236. {
  237. NSAssert( ! [self isOpenGLAttached], @"Can't change the pixel format after the director was initialized" );
  238. pixelFormat_ = format;
  239. }
  240. -(void) setDepthBufferFormat: (tDepthBufferFormat) format
  241. {
  242. NSAssert( ! [self isOpenGLAttached], @"Can't change the depth buffer format after the director was initialized");
  243. depthBufferFormat_ = format;
  244. }
  245. #pragma mark Director - Memory Helper
  246. -(void) purgeCachedData
  247. {
  248. [CCBitmapFontAtlas purgeCachedData];
  249. [CCTextureCache purgeSharedTextureCache];
  250. }
  251. #pragma mark Director - Scene OpenGL Helper
  252. -(ccDirectorProjection) projection
  253. {
  254. return projection_;
  255. }
  256. -(float) getZEye
  257. {
  258. return ( surfaceSize_.height / 1.1566f );
  259. }
  260. -(void) setProjection:(ccDirectorProjection)projection
  261. {
  262. CGSize size = surfaceSize_;
  263. switch (projection) {
  264. case kCCDirectorProjection2D:
  265. glViewport(0, 0, size.width, size.height);
  266. glMatrixMode(GL_PROJECTION);
  267. glLoadIdentity();
  268. glOrthof(0, size.width, 0, size.height, -1024, 1024);
  269. glMatrixMode(GL_MODELVIEW);
  270. glLoadIdentity();
  271. break;
  272. case kCCDirectorProjection3D:
  273. glViewport(0, 0, size.width, size.height);
  274. glMatrixMode(GL_PROJECTION);
  275. glLoadIdentity();
  276. gluPerspective(60, (GLfloat)size.width/size.height, 0.5f, 1500.0f);
  277. glMatrixMode(GL_MODELVIEW);
  278. glLoadIdentity();
  279. gluLookAt( size.width/2, size.height/2, [self getZEye],
  280. size.width/2, size.height/2, 0,
  281. 0.0f, 1.0f, 0.0f);
  282. break;
  283. case kCCDirectorProjectionCustom:
  284. // if custom, ignore it. The user is resposible for setting the correct projection
  285. break;
  286. default:
  287. CCLOG(@"cocos2d: Director: unrecognized projecgtion");
  288. break;
  289. }
  290. projection_ = projection;
  291. }
  292. - (void) setAlphaBlending: (BOOL) on
  293. {
  294. if (on) {
  295. glEnable(GL_BLEND);
  296. glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
  297. } else
  298. glDisable(GL_BLEND);
  299. }
  300. - (void) setDepthTest: (BOOL) on
  301. {
  302. if (on) {
  303. glClearDepthf(1.0f);
  304. glEnable(GL_DEPTH_TEST);
  305. glDepthFunc(GL_LEQUAL);
  306. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  307. } else
  308. glDisable( GL_DEPTH_TEST );
  309. }
  310. #pragma mark Director Integration with a UIKit view
  311. // is the view currently attached
  312. -(BOOL)isOpenGLAttached
  313. {
  314. return ([openGLView_ superview]!=nil);
  315. }
  316. // detach or attach to a view or a window
  317. -(BOOL)detach
  318. {
  319. NSAssert([self isOpenGLAttached], @"FATAL: Director: Can't detach the OpenGL View, because it is not attached. Attach it first.");
  320. // remove from the superview
  321. [openGLView_ removeFromSuperview];
  322. NSAssert(![self isOpenGLAttached], @"FATAL: Director: Can't detach the OpenGL View, it is still attached to the superview.");
  323. return YES;
  324. }
  325. // XXX: Deprecated method
  326. -(BOOL)attachInWindow:(UIWindow *)window
  327. {
  328. if([self initOpenGLViewWithView:window withFrame:[window bounds]])
  329. {
  330. return YES;
  331. }
  332. return NO;
  333. }
  334. // XXX: Deprecated method
  335. -(BOOL)attachInView:(UIView *)view
  336. {
  337. if([self initOpenGLViewWithView:view withFrame:[view bounds]])
  338. {
  339. return YES;
  340. }
  341. return NO;
  342. }
  343. // XXX: Deprecated method
  344. -(BOOL)attachInView:(UIView *)view withFrame:(CGRect)frame
  345. {
  346. if([self initOpenGLViewWithView:view withFrame:frame])
  347. {
  348. return YES;
  349. }
  350. return NO;
  351. }
  352. // XXX: Deprecated method
  353. -(BOOL)initOpenGLViewWithView:(UIView *)view withFrame:(CGRect)rect
  354. {
  355. NSAssert( ! [self isOpenGLAttached], @"FATAL: Can't re-attach the OpenGL View, because it is already attached. Detach it first");
  356. // check if the view is not initialized
  357. if(!openGLView_)
  358. {
  359. // define the pixel format
  360. NSString *pFormat = nil;
  361. GLuint depthFormat = 0;
  362. if(pixelFormat_==kCCPixelFormatRGBA8888)
  363. pFormat = kEAGLColorFormatRGBA8;
  364. else if(pixelFormat_== kCCPixelFormatRGB565)
  365. pFormat = kEAGLColorFormatRGB565;
  366. else {
  367. CCLOG(@"cocos2d: Director: Unknown pixel format.");
  368. }
  369. if(depthBufferFormat_ == kCCDepthBuffer16)
  370. depthFormat = GL_DEPTH_COMPONENT16_OES;
  371. else if(depthBufferFormat_ == kCCDepthBuffer24)
  372. depthFormat = GL_DEPTH_COMPONENT24_OES;
  373. else if(depthBufferFormat_ == kCCDepthBufferNone)
  374. depthFormat = 0;
  375. else {
  376. CCLOG(@"cocos2d: Director: Unknown buffer depth.");
  377. }
  378. // alloc and init the opengl view
  379. openGLView_ = [[EAGLView alloc] initWithFrame:rect pixelFormat:pFormat depthFormat:depthFormat preserveBackbuffer:NO];
  380. // check if the view was alloced and initialized
  381. NSAssert( openGLView_, @"FATAL: Could not alloc and init the OpenGL view. ");
  382. // opaque by default (faster)
  383. openGLView_.opaque = YES;
  384. }
  385. else
  386. {
  387. // set the (new) frame of the glview
  388. [openGLView_ setFrame:rect];
  389. }
  390. screenSize_ = rect.size;
  391. surfaceSize_ = CGSizeMake(screenSize_.width * contentScaleFactor_, screenSize_.height * contentScaleFactor_);
  392. // set the touch delegate of the glview to self
  393. [openGLView_ setTouchDelegate: [CCTouchDispatcher sharedDispatcher]];
  394. // check if the superview has touchs enabled and enable it in our view
  395. if([view isUserInteractionEnabled])
  396. {
  397. [openGLView_ setUserInteractionEnabled:YES];
  398. [[CCTouchDispatcher sharedDispatcher] setDispatchEvents: YES];
  399. }
  400. else
  401. {
  402. [openGLView_ setUserInteractionEnabled:NO];
  403. [[CCTouchDispatcher sharedDispatcher] setDispatchEvents: NO];
  404. }
  405. // check if multi touches are enabled and set them
  406. if([view isMultipleTouchEnabled])
  407. {
  408. [openGLView_ setMultipleTouchEnabled:YES];
  409. }
  410. else
  411. {
  412. [openGLView_ setMultipleTouchEnabled:NO];
  413. }
  414. // add the glview to his (new) superview
  415. [view addSubview:openGLView_];
  416. NSAssert( [self isOpenGLAttached], @"FATAL: Director: Could not attach OpenGL view");
  417. [self setGLDefaultValues];
  418. return YES;
  419. }
  420. -(EAGLView*) openGLView
  421. {
  422. return openGLView_;
  423. }
  424. -(void) setOpenGLView:(EAGLView *)view
  425. {
  426. NSAssert( view, @"EAGView must be non-nil");
  427. if( view != openGLView_ ) {
  428. [openGLView_ release];
  429. openGLView_ = [view retain];
  430. // set size
  431. screenSize_ = [view bounds].size;
  432. surfaceSize_ = CGSizeMake(screenSize_.width * contentScaleFactor_, screenSize_.height *contentScaleFactor_);
  433. if( contentScaleFactor_ != 1 )
  434. [self updateContentScaleFactor];
  435. CCTouchDispatcher *touchDispatcher = [CCTouchDispatcher sharedDispatcher];
  436. [openGLView_ setTouchDelegate: touchDispatcher];
  437. [touchDispatcher setDispatchEvents: YES];
  438. [self setGLDefaultValues];
  439. }
  440. }
  441. -(void) updateContentScaleFactor
  442. {
  443. // Based on code snippet from: http://developer.apple.com/iphone/prerelease/library/snippets/sp2010/sp28.html
  444. if ([openGLView_ respondsToSelector:@selector(setContentScaleFactor:)])
  445. {
  446. // XXX: To avoid compile warning when using Xcode 3.2.2
  447. // Version 1.0 will only support Xcode 3.2.3 or newer
  448. typedef void (*CC_CONTENT_SCALE)(id, SEL, float);
  449. SEL selector = @selector(setContentScaleFactor:);
  450. CC_CONTENT_SCALE method = (CC_CONTENT_SCALE) [openGLView_ methodForSelector:selector];
  451. method(openGLView_,selector, contentScaleFactor_);
  452. // [openGLView_ setContentScaleFactor: contentScaleFactor_];
  453. isContentScaleSupported_ = YES;
  454. }
  455. else
  456. {
  457. CCLOG(@"cocos2d: WARNING: calling setContentScaleFactor on iOS < 4. Using fallback mechanism");
  458. /* on pre-4.0 iOS, use bounds/transform */
  459. openGLView_.bounds = CGRectMake(0, 0,
  460. openGLView_.bounds.size.width * contentScaleFactor_,
  461. openGLView_.bounds.size.height * contentScaleFactor_);
  462. openGLView_.transform = CGAffineTransformScale(openGLView_.transform, 1 / contentScaleFactor_, 1 / contentScaleFactor_);
  463. isContentScaleSupported_ = NO;
  464. }
  465. }
  466. -(void) recalculateProjectionAndEAGLViewSize
  467. {
  468. screenSize_ = [openGLView_ bounds].size;
  469. surfaceSize_ = CGSizeMake(screenSize_.width * contentScaleFactor_, screenSize_.height *contentScaleFactor_);
  470. [self setProjection:projection_];
  471. }
  472. #pragma mark Director Scene Landscape
  473. -(CGPoint)convertToGL:(CGPoint)uiPoint
  474. {
  475. CGSize s = screenSize_;
  476. float newY = s.height - uiPoint.y;
  477. float newX = s.width - uiPoint.x;
  478. CGPoint ret = CGPointZero;
  479. switch ( deviceOrientation_) {
  480. case CCDeviceOrientationPortrait:
  481. ret = ccp( uiPoint.x, newY );
  482. break;
  483. case CCDeviceOrientationPortraitUpsideDown:
  484. ret = ccp(newX, uiPoint.y);
  485. break;
  486. case CCDeviceOrientationLandscapeLeft:
  487. ret.x = uiPoint.y;
  488. ret.y = uiPoint.x;
  489. break;
  490. case CCDeviceOrientationLandscapeRight:
  491. ret.x = newY;
  492. ret.y = newX;
  493. break;
  494. }
  495. if( contentScaleFactor_ != 1 && isContentScaleSupported_ )
  496. ret = ccpMult(ret, contentScaleFactor_);
  497. return ret;
  498. }
  499. -(CGPoint)convertToUI:(CGPoint)glPoint
  500. {
  501. CGSize winSize = surfaceSize_;
  502. int oppositeX = winSize.width - glPoint.x;
  503. int oppositeY = winSize.height - glPoint.y;
  504. CGPoint uiPoint = CGPointZero;
  505. switch ( deviceOrientation_) {
  506. case CCDeviceOrientationPortrait:
  507. uiPoint = ccp(glPoint.x, oppositeY);
  508. break;
  509. case CCDeviceOrientationPortraitUpsideDown:
  510. uiPoint = ccp(oppositeX, glPoint.y);
  511. break;
  512. case CCDeviceOrientationLandscapeLeft:
  513. uiPoint = ccp(glPoint.y, glPoint.x);
  514. break;
  515. case CCDeviceOrientationLandscapeRight:
  516. // Can't use oppositeX/Y because x/y are flipped
  517. uiPoint = ccp(winSize.width-glPoint.y, winSize.height-glPoint.x);
  518. break;
  519. }
  520. uiPoint = ccpMult(uiPoint, 1/contentScaleFactor_);
  521. return uiPoint;
  522. }
  523. // get the current size of the glview
  524. -(CGSize)winSize
  525. {
  526. CGSize s = surfaceSize_;
  527. if( deviceOrientation_ == CCDeviceOrientationLandscapeLeft || deviceOrientation_ == CCDeviceOrientationLandscapeRight ) {
  528. // swap x,y in landscape mode
  529. CGSize tmp = s;
  530. s.width = tmp.height;
  531. s.height = tmp.width;
  532. }
  533. return s;
  534. }
  535. // return the current frame size
  536. -(CGSize)displaySize
  537. {
  538. return surfaceSize_;
  539. }
  540. - (void) setDeviceOrientation:(ccDeviceOrientation) orientation
  541. {
  542. if( deviceOrientation_ != orientation ) {
  543. deviceOrientation_ = orientation;
  544. switch( deviceOrientation_) {
  545. case CCDeviceOrientationPortrait:
  546. [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationPortrait animated:NO];
  547. break;
  548. case CCDeviceOrientationPortraitUpsideDown:
  549. [[UIApplication sharedApplication] setStatusBarOrientation: UIDeviceOrientationPortraitUpsideDown animated:NO];
  550. break;
  551. case CCDeviceOrientationLandscapeLeft:
  552. [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeRight animated:NO];
  553. break;
  554. case CCDeviceOrientationLandscapeRight:
  555. [[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeLeft animated:NO];
  556. break;
  557. default:
  558. NSLog(@"Director: Unknown device orientation");
  559. break;
  560. }
  561. }
  562. }
  563. -(void) applyOrientation
  564. {
  565. CGSize s = surfaceSize_;
  566. float w = s.width / 2;
  567. float h = s.height / 2;
  568. // XXX it's using hardcoded values.
  569. // What if the the screen size changes in the future?
  570. switch ( deviceOrientation_ ) {
  571. case CCDeviceOrientationPortrait:
  572. // nothing
  573. break;
  574. case CCDeviceOrientationPortraitUpsideDown:
  575. // upside down
  576. glTranslatef(w,h,0);
  577. glRotatef(180,0,0,1);
  578. glTranslatef(-w,-h,0);
  579. break;
  580. case CCDeviceOrientationLandscapeRight:
  581. glTranslatef(w,h,0);
  582. glRotatef(90,0,0,1);
  583. glTranslatef(-h,-w,0);
  584. break;
  585. case CCDeviceOrientationLandscapeLeft:
  586. glTranslatef(w,h,0);
  587. glRotatef(-90,0,0,1);
  588. glTranslatef(-h,-w,0);
  589. break;
  590. }
  591. }
  592. #pragma mark Director Scene Management
  593. - (void)runWithScene:(CCScene*) scene
  594. {
  595. NSAssert( scene != nil, @"Argument must be non-nil");
  596. NSAssert( runningScene_ == nil, @"You can't run an scene if another Scene is running. Use replaceScene or pushScene instead");
  597. [self pushScene:scene];
  598. [self startAnimation];
  599. }
  600. -(void) replaceScene: (CCScene*) scene
  601. {
  602. NSAssert( scene != nil, @"Argument must be non-nil");
  603. NSUInteger index = [scenesStack_ count];
  604. sendCleanupToScene_ = YES;
  605. [scenesStack_ replaceObjectAtIndex:index-1 withObject:scene];
  606. nextScene_ = scene; // nextScene_ is a weak ref
  607. }
  608. - (void) pushScene: (CCScene*) scene
  609. {
  610. NSAssert( scene != nil, @"Argument must be non-nil");
  611. sendCleanupToScene_ = NO;
  612. [scenesStack_ addObject: scene];
  613. nextScene_ = scene; // nextScene_ is a weak ref
  614. }
  615. -(void) popScene
  616. {
  617. NSAssert( runningScene_ != nil, @"A running Scene is needed");
  618. [scenesStack_ removeLastObject];
  619. NSUInteger c = [scenesStack_ count];
  620. if( c == 0 ) {
  621. [self end];
  622. } else {
  623. nextScene_ = [scenesStack_ objectAtIndex:c-1];
  624. }
  625. }
  626. -(void) end
  627. {
  628. [runningScene_ onExit];
  629. [runningScene_ cleanup];
  630. [runningScene_ release];
  631. runningScene_ = nil;
  632. nextScene_ = nil;
  633. // remove all objects, but don't release it.
  634. // runWithScene might be executed after 'end'.
  635. [scenesStack_ removeAllObjects];
  636. // don't release the event handlers
  637. // They are needed in case the director is run again
  638. [[CCTouchDispatcher sharedDispatcher] removeAllDelegates];
  639. [self stopAnimation];
  640. #if CC_DIRECTOR_FAST_FPS
  641. [FPSLabel_ release];
  642. FPSLabel_ = nil;
  643. #endif
  644. // Purge bitmap cache
  645. [CCBitmapFontAtlas purgeCachedData];
  646. // Purge all managers
  647. [CCSpriteFrameCache purgeSharedSpriteFrameCache];
  648. [CCScheduler purgeSharedScheduler];
  649. [CCActionManager purgeSharedManager];
  650. [CCTextureCache purgeSharedTextureCache];
  651. // OpenGL view
  652. // Since the director doesn't attach the openglview to the window
  653. // it shouldn't remove it from the window too.
  654. // [openGLView_ removeFromSuperview];
  655. [openGLView_ release];
  656. openGLView_ = nil;
  657. }
  658. -(void) setNextScene
  659. {
  660. Class transClass = [CCTransitionScene class];
  661. BOOL runningIsTransition = [runningScene_ isKindOfClass:transClass];
  662. BOOL newIsTransition = [nextScene_ isKindOfClass:transClass];
  663. // If it is not a transition, call onExit/cleanup
  664. if( ! newIsTransition ) {
  665. [runningScene_ onExit];
  666. // issue #709. the root node (scene) should receive the cleanup message too
  667. // otherwise it might be leaked.
  668. if( sendCleanupToScene_)
  669. [runningScene_ cleanup];
  670. }
  671. [runningScene_ release];
  672. runningScene_ = [nextScene_ retain];
  673. nextScene_ = nil;
  674. if( ! runningIsTransition ) {
  675. [runningScene_ onEnter];
  676. [runningScene_ onEnterTransitionDidFinish];
  677. }
  678. }
  679. -(void) pause
  680. {
  681. if( isPaused_ )
  682. return;
  683. oldAnimationInterval_ = animationInterval_;
  684. // when paused, don't consume CPU
  685. [self setAnimationInterval:1/4.0];
  686. isPaused_ = YES;
  687. }
  688. -(void) resume
  689. {
  690. if( ! isPaused_ )
  691. return;
  692. [self setAnimationInterval: oldAnimationInterval_];
  693. if( gettimeofday( &lastUpdate_, NULL) != 0 ) {
  694. CCLOG(@"cocos2d: Director: Error in gettimeofday");
  695. }
  696. isPaused_ = NO;
  697. dt = 0;
  698. }
  699. - (void)startAnimation
  700. {
  701. CCLOG(@"cocos2d: Director#startAnimation. Override me");
  702. }
  703. - (void)stopAnimation
  704. {
  705. CCLOG(@"cocos2d: Director#stopAnimation. Override me");
  706. }
  707. - (void)setAnimationInterval:(NSTimeInterval)interval
  708. {
  709. CCLOG(@"cocos2d: Director#setAnimationInterval. Override me");
  710. }
  711. #if CC_DIRECTOR_FAST_FPS
  712. // display the FPS using a LabelAtlas
  713. // updates the FPS every frame
  714. -(void) showFPS
  715. {
  716. frames_++;
  717. accumDt_ += dt;
  718. if ( accumDt_ > CC_DIRECTOR_FPS_INTERVAL) {
  719. frameRate_ = frames_/accumDt_;
  720. frames_ = 0;
  721. accumDt_ = 0;
  722. // sprintf(format,"%.1f",frameRate);
  723. // [FPSLabel setCString:format];
  724. NSString *str = [[NSString alloc] initWithFormat:@"%.1f", frameRate_];
  725. [FPSLabel_ setString:str];
  726. [str release];
  727. }
  728. [FPSLabel_ draw];
  729. }
  730. #else
  731. // display the FPS using a manually generated Texture (very slow)
  732. // updates the FPS 3 times per second aprox.
  733. -(void) showFPS
  734. {
  735. frames++;
  736. accumDt += dt;
  737. if ( accumDt > CC_DIRECTOR_FPS_INTERVAL) {
  738. frameRate = frames/accumDt;
  739. frames = 0;
  740. accumDt = 0;
  741. }
  742. NSString *str = [NSString stringWithFormat:@"%.2f",frameRate];
  743. CCTexture2D *texture = [[CCTexture2D alloc] initWithString:str dimensions:CGSizeMake(100,30) alignment:UITextAlignmentLeft fontName:@"Arial" fontSize:24];
  744. // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
  745. // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY
  746. // Unneeded states: GL_COLOR_ARRAY
  747. glDisableClientState(GL_COLOR_ARRAY);
  748. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  749. glColor4ub(224,224,244,200);
  750. [texture drawAtPoint: ccp(5,2)];
  751. [texture release];
  752. glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
  753. // restore default GL state
  754. glEnableClientState(GL_COLOR_ARRAY);
  755. }
  756. #endif
  757. #if CC_ENABLE_PROFILERS
  758. - (void) showProfilers {
  759. accumDtForProfiler_ += dt;
  760. if (accumDtForProfiler_ > 1.0f) {
  761. accumDtForProfiler_ = 0;
  762. [[CCProfiler sharedProfiler] displayTimers];
  763. }
  764. }
  765. #endif
  766. -(CGFloat) contentScaleFactor
  767. {
  768. return contentScaleFactor_;
  769. }
  770. -(void) setContentScaleFactor:(CGFloat)scaleFactor
  771. {
  772. if( scaleFactor != contentScaleFactor_ ) {
  773. contentScaleFactor_ = scaleFactor;
  774. surfaceSize_ = CGSizeMake( screenSize_.width * scaleFactor, screenSize_.height * scaleFactor );
  775. if( openGLView_ )
  776. [self updateContentScaleFactor];
  777. // update projection
  778. [self setProjection:projection_];
  779. }
  780. }
  781. @end
  782. #pragma mark -
  783. #pragma mark Director TimerDirector
  784. @implementation CCTimerDirector
  785. - (void)startAnimation
  786. {
  787. NSAssert( animationTimer == nil, @"animationTimer must be nil. Calling startAnimation twice?");
  788. if( gettimeofday( &lastUpdate_, NULL) != 0 ) {
  789. CCLOG(@"cocos2d: Director: Error in gettimeofday");
  790. }
  791. animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval_ target:self selector:@selector(drawScene) userInfo:nil repeats:YES];
  792. //
  793. // If you want to attach the opengl view into UIScrollView
  794. // uncomment this line to prevent 'freezing'.
  795. // It doesn't work on with the Fast Director
  796. //
  797. // [[NSRunLoop currentRunLoop] addTimer:animationTimer
  798. // forMode:NSRunLoopCommonModes];
  799. }
  800. - (void)stopAnimation
  801. {
  802. [animationTimer invalidate];
  803. animationTimer = nil;
  804. }
  805. - (void)setAnimationInterval:(NSTimeInterval)interval
  806. {
  807. animationInterval_ = interval;
  808. if(animationTimer) {
  809. [self stopAnimation];
  810. [self startAnimation];
  811. }
  812. }
  813. -(void) dealloc
  814. {
  815. [animationTimer release];
  816. [super dealloc];
  817. }
  818. @end
  819. #pragma mark -
  820. #pragma mark Director FastDirector
  821. @implementation CCFastDirector
  822. - (id) init
  823. {
  824. if(( self = [super init] )) {
  825. #if CC_DIRECTOR_DISPATCH_FAST_EVENTS
  826. CCLOG(@"cocos2d: Fast Events enabled");
  827. #else
  828. CCLOG(@"cocos2d: Fast Events disabled");
  829. #endif
  830. isRunning = NO;
  831. // XXX:
  832. // XXX: Don't create any autorelease object before calling "fast director"
  833. // XXX: else it will be leaked
  834. // XXX:
  835. autoreleasePool = [NSAutoreleasePool new];
  836. }
  837. return self;
  838. }
  839. - (void) startAnimation
  840. {
  841. // XXX:
  842. // XXX: release autorelease objects created
  843. // XXX: between "use fast director" and "runWithScene"
  844. // XXX:
  845. [autoreleasePool release];
  846. autoreleasePool = nil;
  847. if ( gettimeofday( &lastUpdate_, NULL) != 0 ) {
  848. CCLOG(@"cocos2d: Director: Error in gettimeofday");
  849. }
  850. isRunning = YES;
  851. SEL selector = @selector(preMainLoop);
  852. NSMethodSignature* sig = [[[CCDirector sharedDirector] class]
  853. instanceMethodSignatureForSelector:selector];
  854. NSInvocation* invocation = [NSInvocation
  855. invocationWithMethodSignature:sig];
  856. [invocation setTarget:[CCDirector sharedDirector]];
  857. [invocation setSelector:selector];
  858. [invocation performSelectorOnMainThread:@selector(invokeWithTarget:)
  859. withObject:[CCDirector sharedDirector] waitUntilDone:NO];
  860. // NSInvocationOperation *loopOperation = [[[NSInvocationOperation alloc]
  861. // initWithTarget:self selector:@selector(preMainLoop) object:nil]
  862. // autorelease];
  863. //
  864. // [loopOperation performSelectorOnMainThread:@selector(start) withObject:nil
  865. // waitUntilDone:NO];
  866. }
  867. -(void) preMainLoop
  868. {
  869. while (isRunning) {
  870. NSAutoreleasePool *loopPool = [NSAutoreleasePool new];
  871. #if CC_DIRECTOR_DISPATCH_FAST_EVENTS
  872. while( CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.004f, FALSE) == kCFRunLoopRunHandledSource);
  873. #else
  874. while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource);
  875. #endif
  876. if (isPaused_) {
  877. usleep(250000); // Sleep for a quarter of a second (250,000 microseconds) so that the framerate is 4 fps.
  878. }
  879. [self drawScene];
  880. #if CC_DIRECTOR_DISPATCH_FAST_EVENTS
  881. while( CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.004f, FALSE) == kCFRunLoopRunHandledSource);
  882. #else
  883. while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource);
  884. #endif
  885. [loopPool release];
  886. }
  887. }
  888. - (void) stopAnimation
  889. {
  890. isRunning = NO;
  891. }
  892. - (void)setAnimationInterval:(NSTimeInterval)interval
  893. {
  894. NSLog(@"FastDirectory doesn't support setAnimationInterval, yet");
  895. }
  896. @end
  897. #pragma mark -
  898. #pragma mark Director ThreadedFastDirector
  899. @implementation CCThreadedFastDirector
  900. - (id) init
  901. {
  902. if(( self = [super init] )) {
  903. isRunning = NO;
  904. }
  905. return self;
  906. }
  907. - (void) startAnimation
  908. {
  909. if ( gettimeofday( &lastUpdate_, NULL) != 0 ) {
  910. CCLOG(@"cocos2d: ThreadedFastDirector: Error on gettimeofday");
  911. }
  912. isRunning = YES;
  913. NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(preMainLoop) object:nil];
  914. [thread start];
  915. [thread release];
  916. }
  917. -(void) preMainLoop
  918. {
  919. while( ![[NSThread currentThread] isCancelled] ) {
  920. if( isRunning )
  921. [self performSelectorOnMainThread:@selector(drawScene) withObject:nil waitUntilDone:YES];
  922. if (isPaused_) {
  923. usleep(250000); // Sleep for a quarter of a second (250,000 microseconds) so that the framerate is 4 fps.
  924. } else {
  925. // usleep(2000);
  926. }
  927. }
  928. }
  929. - (void) stopAnimation
  930. {
  931. isRunning = NO;
  932. }
  933. - (void)setAnimationInterval:(NSTimeInterval)interval
  934. {
  935. NSLog(@"FastDirector doesn't support setAnimationInterval, yet");
  936. }
  937. @end
  938. #pragma mark -
  939. #pragma mark DisplayLinkDirector
  940. // Allows building DisplayLinkDirector for pre-3.1 SDKS
  941. // without getting compiler warnings.
  942. @interface NSObject(CADisplayLink)
  943. + (id) displayLinkWithTarget:(id)arg1 selector:(SEL)arg2;
  944. - (void) addToRunLoop:(id)arg1 forMode:(id)arg2;
  945. - (void) setFrameInterval:(int)interval;
  946. - (void) invalidate;
  947. @end
  948. @implementation CCDisplayLinkDirector
  949. - (void)setAnimationInterval:(NSTimeInterval)interval
  950. {
  951. animationInterval_ = interval;
  952. if(displayLink){
  953. [self stopAnimation];
  954. [self startAnimation];
  955. }
  956. }
  957. - (void) startAnimation
  958. {
  959. if ( gettimeofday( &lastUpdate_, NULL) != 0 ) {
  960. CCLOG(@"cocos2d: DisplayLinkDirector: Error on gettimeofday");
  961. }
  962. // approximate frame rate
  963. // assumes device refreshes at 60 fps
  964. int frameInterval = (int) floor(animationInterval_ * 60.0f);
  965. CCLOG(@"cocos2d: Frame interval: %d", frameInterval);
  966. displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(preMainLoop:)];
  967. [displayLink setFrameInterval:frameInterval];
  968. [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  969. }
  970. -(void) preMainLoop:(id)sender
  971. {
  972. [self drawScene];
  973. }
  974. - (void) stopAnimation
  975. {
  976. [displayLink invalidate];
  977. displayLink = nil;
  978. }
  979. -(void) dealloc
  980. {
  981. [displayLink release];
  982. [super dealloc];
  983. }
  984. @end