PageRenderTime 156ms CodeModel.GetById 13ms app.highlight 134ms RepoModel.GetById 1ms app.codeStats 1ms

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