1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 cc.g_NumberOfDraws = 0; 28 29 //Possible OpenGL projections used by director 30 /** 31 * sets a 2D projection (orthogonal projection) 32 * @constant 33 * @type Number 34 */ 35 cc.DIRECTOR_PROJECTION_2D = 0; 36 37 /** 38 * sets a 3D projection with a fovy=60, znear=0.5f and zfar=1500. 39 * @constant 40 * @type Number 41 */ 42 cc.DIRECTOR_PROJECTION_3D = 1; 43 44 /** 45 * it calls "updateProjection" on the projection delegate. 46 * @constant 47 * @type Number 48 */ 49 cc.DIRECTOR_PROJECTION_CUSTOM = 3; 50 51 /** 52 * Detault projection is 3D projection 53 * @constant 54 * @type Number 55 */ 56 cc.DIRECTOR_PROJECTION_DEFAULT = cc.DIRECTOR_PROJECTION_3D; 57 58 //---------------------------------------------------------------------------------------------------------------------- 59 //Possible device orientations 60 /** 61 * Device oriented vertically, home button on the bottom (UIDeviceOrientationPortrait) 62 * @constant 63 * @type Number 64 */ 65 cc.DEVICE_ORIENTATION_PORTRAIT = 0; 66 67 /** 68 * Device oriented horizontally, home button on the right (UIDeviceOrientationLandscapeLeft) 69 * @constant 70 * @type Number 71 */ 72 cc.DEVICE_ORIENTATION_LANDSCAPE_LEFT = 1; 73 74 /** 75 * Device oriented vertically, home button on the top (UIDeviceOrientationPortraitUpsideDown) 76 * @constant 77 * @type Number 78 */ 79 cc.DEVICE_ORIENTATION_PORTRAIT_UPSIDE_DOWN = 2; 80 81 /** 82 * Device oriented horizontally, home button on the left (UIDeviceOrientationLandscapeRight) 83 * @constant 84 * @type Number 85 */ 86 cc.DEVICE_ORIENTATION_LANDSCAPE_RIGHT = 3; 87 88 /** 89 * In browsers, we only support 2 orientations by change window size. 90 * @constant 91 * @type Number 92 */ 93 cc.DEVICE_MAX_ORIENTATIONS = 2; 94 95 96 //---------------------------------------------------------------------------------------------------------------------- 97 98 /** 99 * <p> 100 * Class that creates and handle the main Window and manages how<br/> 101 * and when to execute the Scenes.<br/> 102 * <br/> 103 * The cc.Director is also responsible for:<br/> 104 * - initializing the OpenGL context<br/> 105 * - setting the OpenGL pixel format (default on is RGB565)<br/> 106 * - setting the OpenGL pixel format (default on is RGB565)<br/> 107 * - setting the OpenGL buffer depth (default one is 0-bit)<br/> 108 * - setting the projection (default one is 3D)<br/> 109 * - setting the orientation (default one is Protrait)<br/> 110 * <br/> 111 * Since the cc.Director is a singleton, the standard way to use it is by calling:<br/> 112 * - cc.Director.getInstance().methodName(); <br/> 113 * <br/> 114 * The CCDirector also sets the default OpenGL context:<br/> 115 * - GL_TEXTURE_2D is enabled<br/> 116 * - GL_VERTEX_ARRAY is enabled<br/> 117 * - GL_COLOR_ARRAY is enabled<br/> 118 * - GL_TEXTURE_COORD_ARRAY is enabled<br/> 119 * </p> 120 * @class 121 * @extends cc.Class 122 */ 123 cc.Director = cc.Class.extend(/** @lends cc.Director# */{ 124 //Variables 125 _isContentScaleSupported:false, 126 _landscape:false, 127 _nextDeltaTimeZero:false, 128 _paused:false, 129 _purgeDirecotorInNextLoop:false, 130 _sendCleanupToScene:false, 131 _animationInterval:0.0, 132 _oldAnimationInterval:0.0, 133 _projection:0, 134 _accumDt:0.0, 135 _contentScaleFactor:1.0, 136 137 _displayStats:false, 138 _deltaTime:0.0, 139 _frameRate:0.0, 140 141 _FPSLabel:null, 142 _SPFLabel:null, 143 _drawsLabel:null, 144 145 _winSizeInPixels:null, 146 _winSizeInPoints:null, 147 148 _lastUpdate:null, 149 _nextScene:null, 150 _notificationNode:null, 151 _openGLView:null, 152 _scenesStack:null, 153 _projectionDelegate:null, 154 _runningScene:null, 155 156 _frames:0, 157 _totalFrames:0, 158 _secondsPerFrame:0, 159 160 _dirtyRegion:null, 161 162 _scheduler:null, 163 _actionManager:null, 164 _touchDispatcher:null, 165 _keyboardDispatcher:null, 166 _accelerometer:null, 167 _mouseDispatcher:null, 168 169 _watcherFun:null, 170 _watcherSender:null, 171 172 _currTimeValue:null, 173 _isBlur:false, 174 175 /** 176 * Constructor 177 */ 178 ctor:function () { 179 this._currTimeValue = new cc.timeval(); 180 this._lastUpdate = new cc.timeval(); 181 if(!cc.isAddedHiddenEvent){ 182 var selfPointer = this; 183 window.addEventListener("focus",function(){ 184 selfPointer._lastUpdate = cc.Time.gettimeofdayCocos2d(selfPointer._lastUpdate); 185 }, false); 186 } 187 }, 188 189 _resetLastUpdate:function(){ 190 this._lastUpdate = cc.Time.gettimeofdayCocos2d(this._lastUpdate); 191 }, 192 193 /** 194 * initializes cc.Director 195 * @return {Boolean} 196 */ 197 init:function () { 198 // scenes 199 //TODO these are already set to null, so maybe we can remove them in the init? 200 this._runningScene = null; 201 this._nextScene = null; 202 this._notificationNode = null; 203 204 this._oldAnimationInterval = this._animationInterval = 1.0 / cc.defaultFPS; 205 this._scenesStack = []; 206 // Set default projection (3D) 207 this._projection = cc.DIRECTOR_PROJECTION_DEFAULT; 208 // projection delegate if "Custom" projection is used 209 this._projectionDelegate = null; 210 211 //FPS 212 this._accumDt = 0; 213 this._frameRate = 0; 214 this._displayStats = false;//can remove 215 this._totalFrames = this._frames = 0; 216 this._lastUpdate = new cc.timeval(); 217 218 //Paused? 219 this._paused = false; 220 221 //purge? 222 this._purgeDirecotorInNextLoop = false; 223 this._winSizeInPixels = this._winSizeInPoints = cc.size(cc.canvas.width, cc.canvas.height); 224 225 this._openGLView = null; 226 this._contentScaleFactor = 1.0; 227 this._isContentScaleSupported = false; 228 229 this._watcherFun = null; 230 this._watcherSender = null; 231 232 //scheduler 233 this._scheduler = new cc.Scheduler(); 234 //action manager 235 this._actionManager = new cc.ActionManager(); 236 this._scheduler.scheduleUpdateForTarget(this._actionManager, cc.PRIORITY_SYSTEM, false); 237 //touchDispatcher 238 this._touchDispatcher = new cc.TouchDispatcher(); 239 this._touchDispatcher.init(); 240 241 //KeyboardDispatcher 242 this._keyboardDispatcher = cc.KeyboardDispatcher.getInstance(); 243 244 //accelerometer 245 //this._accelerometer = new cc.Accelerometer(); 246 247 //MouseDispatcher 248 this._mouseDispatcher = new cc.MouseDispatcher(); 249 this._mouseDispatcher.init(); 250 251 return true; 252 }, 253 254 /** 255 * calculates delta time since last time it was called 256 */ 257 calculateDeltaTime:function () { 258 var now = cc.Time.gettimeofdayCocos2d(this._currTimeValue); 259 if (!now) { 260 cc.log("error in gettimeofday"); 261 this._deltaTime = 0; 262 return; 263 } 264 265 // new delta time. 266 if (this._nextDeltaTimeZero) { 267 this._deltaTime = 0; 268 this._nextDeltaTimeZero = false; 269 } else { 270 this._deltaTime = (now.tv_sec - this._lastUpdate.tv_sec) + (now.tv_usec - this._lastUpdate.tv_usec) / 1000000.0; 271 this._deltaTime = Math.max(0, this._deltaTime); 272 } 273 274 if (cc.DEBUG) { 275 if (this._deltaTime > 0.2) { 276 this._deltaTime = 1 / 60.0; 277 } 278 } 279 this._lastUpdate.tv_sec = now.tv_sec; 280 this._lastUpdate.tv_usec = now.tv_usec; 281 }, 282 283 /** 284 * <p> 285 * converts a UIKit coordinate to an OpenGL coordinate<br/> 286 * Useful to convert (multi) touches coordinates to the current layout (portrait or landscape) 287 * </p> 288 * @param {cc.Point} point 289 * @return {cc.Point} 290 */ 291 convertToGL:function (point) { 292 var newY = this._winSizeInPoints.height - point.y; 293 return cc.p(point.x, newY); 294 }, 295 296 /** 297 * <p>converts an OpenGL coordinate to a UIKit coordinate<br/> 298 * Useful to convert node points to window points for calls such as glScissor</p> 299 * @param {cc.Point} point 300 * @return {cc.Point} 301 */ 302 convertToUI:function (point) { 303 var oppositeY = this._winSizeInPoints.height - point.y; 304 return cc.p(point.x, oppositeY); 305 }, 306 307 //_fullRect:null, 308 /** 309 * Draw the scene. This method is called every frame. Don't call it manually. 310 */ 311 drawScene:function () { 312 // calculate "global" dt 313 this.calculateDeltaTime(); 314 315 //tick before glClear: issue #533 316 if (!this._paused) { 317 this._scheduler.update(this._deltaTime); 318 } 319 //this._fullRect = cc.rect(0, 0, cc.canvas.width, cc.canvas.height); 320 //cc.renderContext.clearRect(this._fullRect.origin.x, this._fullRect.origin.y, this._fullRect.size.width, -this._fullRect.size.height); 321 cc.renderContext.clearRect(0, 0, cc.canvas.width, -cc.canvas.height); 322 323 /* 324 var isSaveContext = false; 325 //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 326 327 if (this._dirtyRegion) { 328 //cc.renderContext.clearRect(0, 0, cc.canvas.width, -cc.canvas.height); 329 330 var fullRect = cc.rect(0, 0, cc.canvas.width, cc.canvas.height); 331 this._dirtyRegion = cc.Rect.CCRectIntersection(this._dirtyRegion, fullRect); 332 333 if(cc.Rect.CCRectEqualToRect(cc.RectZero(), this._dirtyRegion)){ 334 this._dirtyRegion = null; 335 }else{ 336 cc.renderContext.clearRect(0 | this._dirtyRegion.origin.x, -(0 | this._dirtyRegion.origin.y), 337 0 | this._dirtyRegion.size.width, -(0 | this._dirtyRegion.size.height)); 338 339 if(!cc.Rect.CCRectEqualToRect(fullRect, this._dirtyRegion)){ 340 isSaveContext = true; 341 cc.renderContext.save(); 342 cc.renderContext.beginPath(); 343 cc.renderContext.rect(0 | this._dirtyRegion.origin.x - 1, -(0 | this._dirtyRegion.origin.y - 1), 344 0 | this._dirtyRegion.size.width + 2, -(0 | this._dirtyRegion.size.height + 2)); 345 cc.renderContext.clip(); 346 cc.renderContext.closePath(); 347 } 348 } 349 } 350 */ 351 352 /* to avoid flickr, nextScene MUST be here: after tick and before draw. 353 XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */ 354 if (this._nextScene) { 355 this.setNextScene(); 356 } 357 358 //kmGLPushMatrix(); 359 360 // draw the scene 361 if (this._runningScene) { 362 //if (this._dirtyRegion) { 363 this._runningScene.visit(); 364 //} 365 } 366 367 /* 368 if (this._dirtyRegion) { 369 this._dirtyRegion = null; 370 if(isSaveContext){ 371 cc.renderContext.restore(); 372 } 373 } 374 */ 375 376 // draw the notifications node 377 if (this._notificationNode) { 378 this._notificationNode.visit(); 379 } 380 381 if (this._displayStats) { 382 this._showStats(); 383 } 384 385 if (this._watcherFun && this._watcherSender) { 386 this._watcherFun.call(this._watcherSender); 387 } 388 389 //TODO OpenGL 390 //kmGLPopMatrix(); 391 392 this._totalFrames++; 393 394 // swap buffers 395 if (this._openGLView) { 396 this._openGLView.swapBuffers(); 397 } 398 399 if (this._displayStats) { 400 this._calculateMPF(); 401 } 402 }, 403 404 addRegionToDirtyRegion:function (rect) { 405 if (!rect) 406 return; 407 408 if (!this._dirtyRegion) { 409 this._dirtyRegion = cc.rect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); 410 return; 411 } 412 this._dirtyRegion = cc.Rect.CCRectUnion(this._dirtyRegion, 413 cc.rect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)); 414 }, 415 416 rectIsInDirtyRegion:function (rect) { 417 if (!rect || !this._fullRect) 418 return false; 419 420 return cc.Rect.CCRectIntersectsRect(this._fullRect, rect); 421 }, 422 423 /** 424 * <p> 425 * Will enable Retina Display on devices that supports it. <br/> 426 * It will enable Retina Display on iPhone4 and iPod Touch 4.<br/> 427 * It will return YES, if it could enabled it, otherwise it will return NO.<br/> 428 * <br/> 429 * This is the recommened way to enable Retina Display. 430 * </p> 431 * @param {Boolean} enabled 432 * @return {Boolean} 433 */ 434 enableRetinaDisplay:function (enabled) { 435 // Already enabled? 436 if (enabled && this._contentScaleFactor == 2) { 437 return true; 438 } 439 440 // Already diabled? 441 if (!enabled && this._contentScaleFactor == 1) { 442 return false; 443 } 444 445 // setContentScaleFactor is not supported 446 if (!this._openGLView.canSetContentScaleFactor()) { 447 return false; 448 } 449 450 // SD device 451 if (this._openGLView.getMainScreenScale() == 1.0) { 452 return false; 453 } 454 455 var newScale = (enabled) ? 2 : 1; 456 this.setContentScaleFactor(newScale); 457 458 this._createStatsLabel(); 459 return true; 460 }, 461 462 /** 463 * end director 464 */ 465 end:function () { 466 this._purgeDirecotorInNextLoop = true; 467 }, 468 469 /** 470 * <p>get the size in pixels of the surface. It could be different than the screen size.<br/> 471 * High-res devices might have a higher surface size than the screen size.<br/> 472 * Only available when compiled using SDK >= 4.0. 473 * </p> 474 * @return {Number} 475 */ 476 getContentScaleFactor:function () { 477 return this._contentScaleFactor; 478 }, 479 480 /** 481 * <p> 482 * This object will be visited after the main scene is visited.<br/> 483 * This object MUST implement the "visit" selector.<br/> 484 * Useful to hook a notification object, like CCNotifications (http://github.com/manucorporat/CCNotifications) 485 * </p> 486 * @return {cc.Node} 487 */ 488 getNotificationNode:function () { 489 return this._notificationNode; 490 }, 491 492 /** 493 * <p> 494 * returns the size of the OpenGL view in points.<br/> 495 * It takes into account any possible rotation (device orientation) of the window 496 * </p> 497 * @return {cc.Size} 498 */ 499 getWinSize:function () { 500 return this._winSizeInPoints; 501 }, 502 503 /** 504 * <p> 505 * returns the size of the OpenGL view in pixels.<br/> 506 * It takes into account any possible rotation (device orientation) of the window.<br/> 507 * On Mac winSize and winSizeInPixels return the same value. 508 * </p> 509 * @return {cc.Size} 510 */ 511 getWinSizeInPixels:function () { 512 return this._winSizeInPixels; 513 }, 514 515 getZEye:function () { 516 return (this._winSizeInPixels.height / 1.1566 / cc.CONTENT_SCALE_FACTOR()); 517 }, 518 519 /** 520 * pause director 521 */ 522 pause:function () { 523 if (this._paused) { 524 return; 525 } 526 527 this._oldAnimationInterval = this._animationInterval; 528 // when paused, don't consume CPU 529 this.setAnimationInterval(1 / 4.0); 530 this._paused = true; 531 }, 532 533 /** 534 * <p> 535 * Pops out a scene from the queue.<br/> 536 * This scene will replace the running one.<br/> 537 * The running scene will be deleted. If there are no more scenes in the stack the execution is terminated.<br/> 538 * ONLY call it if there is a running scene. 539 * </p> 540 */ 541 popScene:function () { 542 cc.Assert(this._runningScene != null, "running scene should not null"); 543 544 //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height)); 545 546 this._scenesStack.pop(); 547 var c = this._scenesStack.length; 548 549 if (c == 0) { 550 this.end(); 551 } 552 else { 553 this._sendCleanupToScene = true; 554 this._nextScene = this._scenesStack[c - 1]; 555 } 556 }, 557 558 /** 559 * Removes cached all cocos2d cached data. It will purge the CCTextureCache, CCSpriteFrameCache, CCLabelBMFont cache 560 */ 561 purgeCachedData:function () { 562 cc.LabelBMFont.purgeCachedData(); 563 //cc.TextureCache.getInstance().removeUnusedTextures(); 564 }, 565 566 /** 567 * purge Director 568 */ 569 purgeDirector:function () { 570 // don't release the event handlers 571 // They are needed in case the director is run again 572 this._touchDispatcher.removeAllDelegates(); 573 574 if (this._runningScene) { 575 this._runningScene.onExit(); 576 this._runningScene.cleanup(); 577 } 578 579 this._runningScene = null; 580 this._nextScene = null; 581 582 // remove all objects, but don't release it. 583 // runWithScene might be executed after 'end'. 584 this._scenesStack = []; 585 586 this.stopAnimation(); 587 588 // purge bitmap cache 589 cc.LabelBMFont.purgeCachedData(); 590 591 // purge all managers 592 cc.AnimationCache.purgeSharedAnimationCache(); 593 cc.SpriteFrameCache.purgeSharedSpriteFrameCache(); 594 cc.TextureCache.purgeSharedTextureCache(); 595 596 //CCShaderCache::purgeSharedShaderCache(); 597 //CCFileUtils::purgeFileUtils(); 598 //CCConfiguration::purgeConfiguration(); 599 //extension::CCNotificationCenter::purgeNotificationCenter(); 600 //extension::CCTextureWatcher::purgeTextureWatcher(); 601 //extension::CCNodeLoaderLibrary::purgeSharedCCNodeLoaderLibrary(); 602 //cc.UserDefault.purgeSharedUserDefault(); 603 //ccGLInvalidateStateCache(); 604 605 //CHECK_GL_ERROR_DEBUG(); 606 607 // OpenGL view 608 this._openGLView.end(); 609 this._openGLView = null; 610 }, 611 612 /** 613 * <p> 614 * Suspends the execution of the running scene, pushing it on the stack of suspended scenes.<br/> 615 * The new scene will be executed.<br/> 616 * Try to avoid big stacks of pushed scenes to reduce memory allocation.<br/> 617 * ONLY call it if there is a running scene. 618 * </p> 619 * @param {cc.Scene} scene 620 */ 621 pushScene:function (scene) { 622 cc.Assert(scene, "the scene should not null"); 623 624 //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height)); 625 626 this._sendCleanupToScene = false; 627 628 this._scenesStack.push(scene); 629 this._nextScene = scene; 630 }, 631 632 /** 633 * Replaces the running scene with a new one. The running scene is terminated. ONLY call it if there is a running scene. 634 * @param {cc.Scene} scene 635 */ 636 replaceScene:function (scene) { 637 cc.Assert(scene != null, "the scene should not be null"); 638 639 //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height)); 640 var i = this._scenesStack.length; 641 642 this._sendCleanupToScene = true; 643 this._scenesStack[i - 1] = scene; 644 this._nextScene = scene; 645 }, 646 647 /** 648 * changes the projection size 649 * @param {cc.Size} newWindowSize 650 */ 651 reshapeProjection:function (newWindowSize) { 652 if (this._openGLView) { 653 this._winSizeInPoints = this._openGLView.getSize(); 654 this._winSizeInPixels = cc.size(this._winSizeInPoints.width * this._contentScaleFactor, 655 this._winSizeInPoints.height * this._contentScaleFactor); 656 657 this.setProjection(this._projection); 658 } 659 }, 660 661 /** 662 * resume director 663 */ 664 resume:function () { 665 if (!this._paused) { 666 return; 667 } 668 //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height)); 669 670 this.setAnimationInterval(this._oldAnimationInterval); 671 this._lastUpdate = cc.Time.gettimeofdayCocos2d(); 672 if (!this._lastUpdate) { 673 cc.log("cocos2d: Director: Error in gettimeofday"); 674 } 675 676 this._paused = false; 677 this._deltaTime = 0; 678 }, 679 680 /** 681 * <p> 682 * Enters the Director's main loop with the given Scene.<br/> 683 * Call it to run only your FIRST scene.<br/> 684 * Don't call it if there is already a running scene. 685 * </p> 686 * @param {cc.Scene} scene 687 */ 688 runWithScene:function (scene) { 689 cc.Assert(scene != null, "running scene should not be null"); 690 cc.Assert(this._runningScene == null, "_runningScene should be null"); 691 692 //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height)); 693 694 this.pushScene(scene); 695 this.startAnimation(); 696 }, 697 698 /** 699 * enables/disables OpenGL alpha blending 700 * @param {Boolean} on 701 */ 702 setAlphaBlending:function (on) { 703 if (on) { 704 //TODO OpenGL 705 //ccGLEnable(CC_GL_BLEND); 706 //ccGLBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); 707 } 708 else { 709 //glDisable(GL_BLEND); 710 } 711 //CHECK_GL_ERROR_DEBUG(); 712 }, 713 714 /** 715 * <p> 716 * The size in pixels of the surface. It could be different than the screen size.<br/> 717 * High-res devices might have a higher surface size than the screen size.<br/> 718 * Only available when compiled using SDK >= 4.0. 719 * </p> 720 * @param {Number} scaleFactor 721 */ 722 setContentScaleFactor:function (scaleFactor) { 723 if (scaleFactor != this._contentScaleFactor) { 724 this._contentScaleFactor = scaleFactor; 725 this._winSizeInPixels = cc.size(this._winSizeInPoints.width * scaleFactor, this._winSizeInPoints.height * scaleFactor); 726 727 if (this._openGLView) { 728 this.updateContentScaleFactor(); 729 } 730 731 // update projection 732 this.setProjection(this._projection); 733 } 734 }, 735 736 /** 737 * enables/disables OpenGL depth test 738 * @param {Boolean} on 739 */ 740 setDepthTest:function (on) { 741 if (on) { 742 /*TODO OpenGL Stuff 743 ccglClearDepth(1.0f); 744 glEnable(GL_DEPTH_TEST); 745 glDepthFunc(GL_LEQUAL); 746 // glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 747 } 748 else 749 { 750 glDisable(GL_DEPTH_TEST);*/ 751 } 752 //CHECK_GL_ERROR_DEBUG(); 753 }, 754 755 /** 756 * sets the OpenGL default values 757 */ 758 setGLDefaultValues:function () { 759 // This method SHOULD be called only after openGLView_ was initialized 760 cc.Assert(this._openGLView, "opengl view should not be null"); 761 762 this.setAlphaBlending(true); 763 this.setDepthTest(true); 764 this.setProjection(this._projection); 765 766 // set other opengl default values 767 //TODO OpenGl 768 //glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 769 }, 770 771 /** 772 * set next delta time is zero 773 * @param {Boolean} nextDeltaTimeZero 774 */ 775 setNextDeltaTimeZero:function (nextDeltaTimeZero) { 776 this._nextDeltaTimeZero = nextDeltaTimeZero; 777 }, 778 779 /** 780 * set next scene 781 */ 782 setNextScene:function () { 783 var runningIsTransition = this._runningScene ? this._runningScene instanceof cc.TransitionScene : false; 784 785 var newIsTransition = this._nextScene ? this._nextScene instanceof cc.TransitionScene : false; 786 787 // If it is not a transition, call onExit/cleanup 788 if (!newIsTransition) { 789 if (this._runningScene) { 790 this._runningScene.onExit(); 791 } 792 793 // issue #709. the root node (scene) should receive the cleanup message too 794 // otherwise it might be leaked. 795 if (this._sendCleanupToScene && this._runningScene) { 796 this._runningScene.cleanup(); 797 } 798 } 799 800 this._runningScene = this._nextScene; 801 802 this._nextScene = null; 803 if ((!runningIsTransition) && (this._runningScene != null)) { 804 this._runningScene.onEnter(); 805 this._runningScene.onEnterTransitionDidFinish(); 806 } 807 }, 808 809 /** 810 * set Notification Node 811 * @param {cc.Node} node 812 */ 813 setNotificationNode:function (node) { 814 this._notificationNode = node; 815 }, 816 817 /** 818 * Set the CCEGLView, where everything is rendered 819 * @param {*} openGLView 820 */ 821 setOpenGLView:function (openGLView) { 822 cc.Assert(openGLView, "opengl view should not be null"); 823 824 if (this._openGLView != openGLView) { 825 // because EAGLView is not kind of CCObject 826 delete this._openGLView; // [openGLView_ release] 827 this._openGLView = openGLView; 828 829 // set size 830 this._winSizeInPoints = this._openGLView.getSize(); 831 this._winSizeInPixels = cc.size(this._winSizeInPoints.width * this._contentScaleFactor, this._winSizeInPoints.height * this._contentScaleFactor); 832 833 this._createStatsLabel(); 834 835 if (this._openGLView) { 836 this.setGLDefaultValues(); 837 } 838 839 //CHECK_GL_ERROR_DEBUG(); 840 841 if (this._contentScaleFactor != 1) { 842 this.updateContentScaleFactor(); 843 } 844 845 this._openGLView.setTouchDelegate(this._touchDispatcher); 846 this._touchDispatcher.setDispatchEvents(true); 847 } 848 }, 849 850 /** 851 * Sets an OpenGL projection 852 * @param {Number} projection 853 */ 854 setProjection:function (projection) { 855 var size = this._winSizeInPixels; 856 var sizePoint = this._winSizeInPoints; 857 858 if (this._openGLView) { 859 this._openGLView.setViewPortInPoints(0, 0, sizePoint.width, sizePoint.height); 860 } 861 862 switch (projection) { 863 case cc.DIRECTOR_PROJECTION_2D: 864 //TODO OpenGL 865 /* kmGLMatrixMode(KM_GL_PROJECTION); 866 kmGLLoadIdentity(); 867 kmMat4 orthoMatrix; 868 kmMat4OrthographicProjection(&orthoMatrix, 0, size.width / CC_CONTENT_SCALE_FACTOR(), 0, size.height / CC_CONTENT_SCALE_FACTOR(), -1024, 1024 ); 869 kmGLMultMatrix(&orthoMatrix); 870 kmGLMatrixMode(KM_GL_MODELVIEW); 871 kmGLLoadIdentity();*/ 872 break; 873 case cc.DIRECTOR_PROJECTION_3D: 874 //TODO OpenGl 875 /* float zeye = this->getZEye(); 876 877 kmMat4 matrixPerspective, matrixLookup; 878 879 kmGLMatrixMode(KM_GL_PROJECTION); 880 kmGLLoadIdentity(); 881 882 // issue #1334 883 kmMat4PerspectiveProjection( &matrixPerspective, 60, (GLfloat)size.width/size.height, 0.1f, zeye*2); 884 // kmMat4PerspectiveProjection( &matrixPerspective, 60, (GLfloat)size.width/size.height, 0.1f, 1500); 885 886 kmGLMultMatrix(&matrixPerspective); 887 888 kmGLMatrixMode(KM_GL_MODELVIEW); 889 kmGLLoadIdentity(); 890 kmVec3 eye, center, up; 891 kmVec3Fill( &eye, sizePoint.width/2, sizePoint.height/2, zeye ); 892 kmVec3Fill( ¢er, sizePoint.width/2, sizePoint.height/2, 0.0f ); 893 kmVec3Fill( &up, 0.0f, 1.0f, 0.0f); 894 kmMat4LookAt(&matrixLookup, &eye, ¢er, &up); 895 kmGLMultMatrix(&matrixLookup);*/ 896 break; 897 case cc.DIRECTOR_PROJECTION_CUSTOM: 898 if (this._projectionDelegate) { 899 this._projectionDelegate.updateProjection(); 900 } 901 break; 902 903 default: 904 cc.log("cocos2d: Director: unrecognized projection"); 905 break; 906 } 907 908 this._projection = projection; 909 //ccSetProjectionMatrixDirty(); 910 }, 911 912 /** 913 * shows the FPS in the screen 914 */ 915 _showStats:function () { 916 this._frames++; 917 this._accumDt += this._deltaTime; 918 if (this._displayStats) { 919 if (this._FPSLabel && this._SPFLabel && this._drawsLabel) { 920 if (this._accumDt > cc.DIRECTOR_FPS_INTERVAL) { 921 this._SPFLabel.setString(this._secondsPerFrame.toFixed(3)); 922 923 this._frameRate = this._frames / this._accumDt; 924 this._frames = 0; 925 this._accumDt = 0; 926 927 this._FPSLabel.setString(this._frameRate.toFixed(1)); 928 this._drawsLabel.setString((0 | cc.g_NumberOfDraws).toString()); 929 } 930 this._FPSLabel.visit(); 931 this._SPFLabel.visit(); 932 this._drawsLabel.visit(); 933 } else { 934 this._createStatsLabel(); 935 } 936 } 937 cc.g_NumberOfDraws = 0; 938 }, 939 940 /** 941 * update content scale factor 942 */ 943 updateContentScaleFactor:function () { 944 // [openGLView responseToSelector:@selector(setContentScaleFactor)] 945 if (this._openGLView.canSetContentScaleFactor()) { 946 this._openGLView.setContentScaleFactor(this._contentScaleFactor); 947 this._isContentScaleSupported = true; 948 } 949 else { 950 cc.log("cocos2d: setContentScaleFactor:'is not supported on this device"); 951 } 952 }, 953 954 /** 955 * <p> 956 * Whether or not the replaced scene will receive the cleanup message.<br> 957 * If the new scene is pushed, then the old scene won't receive the "cleanup" message.<br/> 958 * If the new scene replaces the old one, the it will receive the "cleanup" message. 959 * </p> 960 * @return {Boolean} 961 */ 962 isSendCleanupToScene:function () { 963 return this._sendCleanupToScene; 964 }, 965 966 /** 967 * Get current running Scene. Director can only run one Scene at the time 968 * @return {cc.Scene} 969 */ 970 getRunningScene:function () { 971 return this._runningScene; 972 }, 973 974 /** 975 * Get the FPS value 976 * @return {Number} 977 */ 978 getAnimationInterval:function () { 979 return this._animationInterval; 980 }, 981 982 /** 983 * Whether or not to display the FPS on the bottom-left corner 984 * @return {Boolean} 985 */ 986 isDisplayStats:function () { 987 return this._displayStats; 988 }, 989 990 /** 991 * Display the FPS on the bottom-left corner 992 * @param displayFPS 993 */ 994 setDisplayStats:function (displayStats) { 995 this._displayStats = displayStats; 996 }, 997 998 /** 999 * seconds per frame 1000 */ 1001 getSecondsPerFrame:function () { 1002 return this._secondsPerFrame; 1003 }, 1004 1005 /** 1006 * Get the CCEGLView, where everything is rendered 1007 * @return {*} 1008 */ 1009 getOpenGLView:function () { 1010 return this._openGLView; 1011 }, 1012 1013 /** 1014 * is next delta time zero 1015 * @return {Boolean} 1016 */ 1017 isNextDeltaTimeZero:function () { 1018 return this._nextDeltaTimeZero; 1019 }, 1020 1021 /** 1022 * Whether or not the Director is paused 1023 * @return {Boolean} 1024 */ 1025 isPaused:function () { 1026 return this._paused; 1027 }, 1028 1029 /** 1030 * How many frames were called since the director started 1031 * @return {Number} 1032 */ 1033 getTotalFrames:function () { 1034 return this._totalFrames; 1035 }, 1036 1037 /** 1038 * Sets an OpenGL projection 1039 * @return {Number} 1040 */ 1041 getProjection:function () { 1042 return this._projection; 1043 }, 1044 1045 /** 1046 * <p> 1047 * Pops out all scenes from the queue until the root scene in the queue. <br/> 1048 * This scene will replace the running one. <br/> 1049 * The running scene will be deleted. If there are no more scenes in the stack the execution is terminated. <br/> 1050 * ONLY call it if there is a running scene. 1051 * </p> 1052 */ 1053 popToRootScene:function () { 1054 cc.Assert(this._runningScene != null, "A running Scene is needed"); 1055 var c = this._scenesStack.length; 1056 1057 if (c == 1) { 1058 this._scenesStack.pop(); 1059 this.end(); 1060 } else { 1061 while (c > 1) { 1062 var current = this._scenesStack.pop(); 1063 if (current.isRunning()) { 1064 current.onExit(); 1065 } 1066 current.cleanup(); 1067 c--; 1068 } 1069 this._nextScene = this._scenesStack[this._scenesStack.length - 1]; 1070 this._sendCleanupToScene = false; 1071 } 1072 }, 1073 1074 setWatcherCallbackFun:function (pSender, func) { 1075 this._watcherFun = func; 1076 this._watcherSender = pSender; 1077 }, 1078 1079 /** 1080 * (cc.Scheduler associated with this director) 1081 */ 1082 getScheduler:function () { 1083 return this._scheduler; 1084 }, 1085 1086 setScheduler:function (scheduler) { 1087 if (this._scheduler != scheduler) { 1088 this._scheduler = scheduler; 1089 } 1090 }, 1091 1092 getActionManager:function () { 1093 return this._actionManager; 1094 }, 1095 setActionManager:function (actionManager) { 1096 if (this._actionManager != actionManager) { 1097 this._actionManager = actionManager; 1098 } 1099 }, 1100 1101 getTouchDispatcher:function () { 1102 return this._touchDispatcher; 1103 }, 1104 setTouchDispatcher:function (touchDispatcher) { 1105 if (this._touchDispatcher != touchDispatcher) { 1106 this._touchDispatcher = touchDispatcher; 1107 } 1108 }, 1109 1110 getKeyboardDispatcher:function () { 1111 return this._keyboardDispatcher; 1112 }, 1113 setKeyboardDispatcher:function (keyboardDispatcher) { 1114 this._keyboardDispatcher = keyboardDispatcher; 1115 }, 1116 1117 getAccelerometer:function () { 1118 return this._accelerometer; 1119 }, 1120 setAccelerometer:function (accelerometer) { 1121 if (this._accelerometer != accelerometer) { 1122 this._accelerometer = accelerometer; 1123 } 1124 }, 1125 1126 getMouseDispatcher:function(){ 1127 return this._mouseDispatcher; 1128 }, 1129 1130 setMouseDispatcher:function( mouseDispatcher){ 1131 if(this._mouseDispatcher != mouseDispatcher) 1132 this._mouseDispatcher = mouseDispatcher; 1133 }, 1134 1135 _createStatsLabel:function () { 1136 this._FPSLabel = cc.LabelTTF.create("00.0", "Arial", 18, cc.size(60, 16), cc.TEXT_ALIGNMENT_RIGHT); 1137 this._SPFLabel = cc.LabelTTF.create("0.000", "Arial", 18, cc.size(60, 16), cc.TEXT_ALIGNMENT_RIGHT); 1138 this._drawsLabel = cc.LabelTTF.create("000", "Arial", 18, cc.size(60, 16), cc.TEXT_ALIGNMENT_RIGHT); 1139 1140 this._drawsLabel.setPosition(cc.pAdd(cc.p(20, 48), cc.DIRECTOR_STATS_POSITION)); 1141 this._SPFLabel.setPosition(cc.pAdd(cc.p(20, 30), cc.DIRECTOR_STATS_POSITION)); 1142 this._FPSLabel.setPosition(cc.pAdd(cc.p(20, 10), cc.DIRECTOR_STATS_POSITION)); 1143 }, 1144 1145 _calculateMPF:function () { 1146 var now = cc.Time.gettimeofdayCocos2d(); 1147 1148 this._secondsPerFrame = (now.tv_sec - this._lastUpdate.tv_sec) + (now.tv_usec - this._lastUpdate.tv_usec) / 1000000.0; 1149 } 1150 }); 1151 1152 1153 /*************************************************** 1154 * implementation of DisplayLinkDirector 1155 **************************************************/ 1156 // should we afford 4 types of director ?? 1157 // I think DisplayLinkDirector is enough 1158 // so we now only support DisplayLinkDirector 1159 /** 1160 * <p> 1161 * DisplayLinkDirector is a Director that synchronizes timers with the refresh rate of the display.<br/> 1162 * Features and Limitations:<br/> 1163 * - Scheduled timers & drawing are synchronizes with the refresh rate of the display<br/> 1164 * - Only supports animation intervals of 1/60 1/30 & 1/15<br/> 1165 * </p> 1166 * @class 1167 * @extends cc.Director 1168 */ 1169 cc.DisplayLinkDirector = cc.Director.extend(/** @lends cc.DisplayLinkDirector# */{ 1170 invalid:false, 1171 1172 /** 1173 * start Animation 1174 */ 1175 startAnimation:function () { 1176 this._lastUpdate = cc.Time.gettimeofdayCocos2d(); 1177 this.invalid = false; 1178 cc.Application.sharedApplication().setAnimationInterval(this._animationInterval); 1179 }, 1180 1181 /** 1182 * main loop of director 1183 */ 1184 mainLoop:function () { 1185 if (this._purgeDirecotorInNextLoop) { 1186 this._purgeDirecotorInNextLoop = false; 1187 this.purgeDirector(); 1188 } 1189 else if (!this.invalid) { 1190 this.drawScene(); 1191 } 1192 }, 1193 1194 /** 1195 * stop animation 1196 */ 1197 stopAnimation:function () { 1198 this.invalid = true; 1199 }, 1200 1201 /** 1202 * set Animation Interval 1203 * @param {Number} value 1204 */ 1205 setAnimationInterval:function (value) { 1206 this._animationInterval = value; 1207 if (!this.invalid) { 1208 this.stopAnimation(); 1209 this.startAnimation(); 1210 } 1211 } 1212 }); 1213 1214 cc.s_SharedDirector = null; 1215 1216 cc.firstUseDirector = true; 1217 1218 /** 1219 * returns a shared instance of the director 1220 * @function 1221 * @return {cc.Director} 1222 */ 1223 cc.Director.getInstance = function () { 1224 if (cc.firstUseDirector) { 1225 cc.firstUseDirector = false; 1226 cc.s_SharedDirector = new cc.DisplayLinkDirector(); 1227 cc.s_SharedDirector.init(); 1228 } 1229 return cc.s_SharedDirector; 1230 }; 1231 1232 /** 1233 * is director first run 1234 * @type Boolean 1235 */ 1236 cc.firstRun = true; 1237 1238 /** 1239 * set default fps to 60 1240 * @type Number 1241 */ 1242 cc.defaultFPS = 60; 1243 1244 /* 1245 window.onfocus = function () { 1246 if (!cc.firstRun) { 1247 cc.Director.getInstance().addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height)); 1248 } 1249 }; 1250 */ 1251 1252