1 /**************************************************************************** 2 Copyright (c) 2008-2010 Ricardo Quesada 3 Copyright (c) 2011-2012 cocos2d-x.org 4 Copyright (c) 2013-2014 Chukong Technologies 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 cc.GLToClipTransform = function (transformOut) { 30 var projection = new cc.kmMat4(); 31 cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, projection); 32 33 var modelview = new cc.kmMat4(); 34 cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, modelview); 35 36 cc.kmMat4Multiply(transformOut, projection, modelview); 37 }; 38 //---------------------------------------------------------------------------------------------------------------------- 39 40 /** 41 * <p> 42 * ATTENTION: USE cc.director INSTEAD OF cc.Director.<br/> 43 * cc.director is a singleton object which manage your game's logic flow.<br/> 44 * Since the cc.director is a singleton, you don't need to call any constructor or create functions,<br/> 45 * the standard way to use it is by calling:<br/> 46 * - cc.director.methodName(); <br/> 47 * 48 * It creates and handle the main Window and manages how and when to execute the Scenes.<br/> 49 * <br/> 50 * The cc.director is also responsible for:<br/> 51 * - initializing the OpenGL context<br/> 52 * - setting the OpenGL pixel format (default on is RGB565)<br/> 53 * - setting the OpenGL pixel format (default on is RGB565)<br/> 54 * - setting the OpenGL buffer depth (default one is 0-bit)<br/> 55 * - setting the projection (default one is 3D)<br/> 56 * - setting the orientation (default one is Portrait)<br/> 57 * <br/> 58 * <br/> 59 * The cc.director also sets the default OpenGL context:<br/> 60 * - GL_TEXTURE_2D is enabled<br/> 61 * - GL_VERTEX_ARRAY is enabled<br/> 62 * - GL_COLOR_ARRAY is enabled<br/> 63 * - GL_TEXTURE_COORD_ARRAY is enabled<br/> 64 * </p> 65 * <p> 66 * cc.director also synchronizes timers with the refresh rate of the display.<br/> 67 * Features and Limitations:<br/> 68 * - Scheduled timers & drawing are synchronizes with the refresh rate of the display<br/> 69 * - Only supports animation intervals of 1/60 1/30 & 1/15<br/> 70 * </p> 71 * @class 72 * @name cc.Director 73 */ 74 cc.Director = cc.Class.extend(/** @lends cc.Director# */{ 75 //Variables 76 _landscape: false, 77 _nextDeltaTimeZero: false, 78 _paused: false, 79 _purgeDirectorInNextLoop: false, 80 _sendCleanupToScene: false, 81 _animationInterval: 0.0, 82 _oldAnimationInterval: 0.0, 83 _projection: 0, 84 _accumDt: 0.0, 85 _contentScaleFactor: 1.0, 86 87 _displayStats: false, 88 _deltaTime: 0.0, 89 _frameRate: 0.0, 90 91 _FPSLabel: null, 92 _SPFLabel: null, 93 _drawsLabel: null, 94 95 _winSizeInPoints: null, 96 97 _lastUpdate: null, 98 _nextScene: null, 99 _notificationNode: null, 100 _openGLView: null, 101 _scenesStack: null, 102 _projectionDelegate: null, 103 _runningScene: null, 104 105 _frames: 0, 106 _totalFrames: 0, 107 _secondsPerFrame: 0, 108 109 _dirtyRegion: null, 110 111 _scheduler: null, 112 _actionManager: null, 113 _eventProjectionChanged: null, 114 _eventAfterDraw: null, 115 _eventAfterVisit: null, 116 _eventAfterUpdate: null, 117 118 ctor: function () { 119 var self = this; 120 self._lastUpdate = Date.now(); 121 cc.eventManager.addCustomListener(cc.game.EVENT_SHOW, function () { 122 self._lastUpdate = Date.now(); 123 }); 124 }, 125 126 init: function () { 127 // scenes 128 this._oldAnimationInterval = this._animationInterval = 1.0 / cc.defaultFPS; 129 this._scenesStack = []; 130 // Set default projection (3D) 131 this._projection = cc.Director.PROJECTION_DEFAULT; 132 // projection delegate if "Custom" projection is used 133 this._projectionDelegate = null; 134 135 //FPS 136 this._accumDt = 0; 137 this._frameRate = 0; 138 this._displayStats = false;//can remove 139 this._totalFrames = this._frames = 0; 140 this._lastUpdate = Date.now(); 141 142 //Paused? 143 this._paused = false; 144 145 //purge? 146 this._purgeDirectorInNextLoop = false; 147 148 this._winSizeInPoints = cc.size(0, 0); 149 150 this._openGLView = null; 151 this._contentScaleFactor = 1.0; 152 153 //scheduler 154 this._scheduler = new cc.Scheduler(); 155 //action manager 156 this._actionManager = cc.ActionManager ? new cc.ActionManager() : null; 157 this._scheduler.scheduleUpdateForTarget(this._actionManager, cc.Scheduler.PRIORITY_SYSTEM, false); 158 159 this._eventAfterDraw = new cc.EventCustom(cc.Director.EVENT_AFTER_DRAW); 160 this._eventAfterDraw.setUserData(this); 161 this._eventAfterVisit = new cc.EventCustom(cc.Director.EVENT_AFTER_VISIT); 162 this._eventAfterVisit.setUserData(this); 163 this._eventAfterUpdate = new cc.EventCustom(cc.Director.EVENT_AFTER_UPDATE); 164 this._eventAfterUpdate.setUserData(this); 165 this._eventProjectionChanged = new cc.EventCustom(cc.Director.EVENT_PROJECTION_CHANGED); 166 this._eventProjectionChanged.setUserData(this); 167 168 return true; 169 }, 170 171 /** 172 * calculates delta time since last time it was called 173 */ 174 calculateDeltaTime: function () { 175 var now = Date.now(); 176 177 // new delta time. 178 if (this._nextDeltaTimeZero) { 179 this._deltaTime = 0; 180 this._nextDeltaTimeZero = false; 181 } else { 182 this._deltaTime = (now - this._lastUpdate) / 1000; 183 } 184 185 if ((cc.game.config[cc.game.CONFIG_KEY.debugMode] > 0) && (this._deltaTime > 0.2)) 186 this._deltaTime = 1 / 60.0; 187 188 this._lastUpdate = now; 189 }, 190 191 /** 192 * Converts a view coordinate to an WebGL coordinate<br/> 193 * Useful to convert (multi) touches coordinates to the current layout (portrait or landscape)<br/> 194 * Implementation can be found in CCDirectorWebGL 195 * @function 196 * @param {cc.Point} uiPoint 197 * @return {cc.Point} 198 */ 199 convertToGL: null, 200 201 /** 202 * Converts an WebGL coordinate to a view coordinate<br/> 203 * Useful to convert node points to window points for calls such as glScissor<br/> 204 * Implementation can be found in CCDirectorWebGL 205 * @function 206 * @param {cc.Point} glPoint 207 * @return {cc.Point} 208 */ 209 convertToUI: null, 210 211 /** 212 * Draw the scene. This method is called every frame. Don't call it manually. 213 */ 214 drawScene: function () { 215 var renderer = cc.renderer; 216 // calculate "global" dt 217 this.calculateDeltaTime(); 218 219 //tick before glClear: issue #533 220 if (!this._paused) { 221 this._scheduler.update(this._deltaTime); 222 cc.eventManager.dispatchEvent(this._eventAfterUpdate); 223 } 224 225 this._clear(); 226 227 /* to avoid flickr, nextScene MUST be here: after tick and before draw. 228 XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */ 229 if (this._nextScene) { 230 this.setNextScene(); 231 } 232 233 if (this._beforeVisitScene) 234 this._beforeVisitScene(); 235 236 // draw the scene 237 if (this._runningScene) { 238 if (renderer.childrenOrderDirty === true) { 239 cc.renderer.clearRenderCommands(); 240 this._runningScene._renderCmd._curLevel = 0; //level start from 0; 241 this._runningScene.visit(); 242 renderer.resetFlag(); 243 } else if (renderer.transformDirty() === true) 244 renderer.transform(); 245 246 cc.eventManager.dispatchEvent(this._eventAfterVisit); 247 } 248 249 // draw the notifications node 250 if (this._notificationNode) 251 this._notificationNode.visit(); 252 253 if (this._displayStats) 254 this._showStats(); 255 256 if (this._afterVisitScene) 257 this._afterVisitScene(); 258 259 renderer.rendering(cc._renderContext); 260 cc.eventManager.dispatchEvent(this._eventAfterDraw); 261 this._totalFrames++; 262 263 if (this._displayStats) 264 this._calculateMPF(); 265 }, 266 267 _beforeVisitScene: null, 268 _afterVisitScene: null, 269 270 /** 271 * End the life of director in the next frame 272 */ 273 end: function () { 274 this._purgeDirectorInNextLoop = true; 275 }, 276 277 /** 278 * Returns the size in pixels of the surface. It could be different than the screen size.<br/> 279 * High-res devices might have a higher surface size than the screen size. 280 * @return {Number} 281 */ 282 getContentScaleFactor: function () { 283 return this._contentScaleFactor; 284 }, 285 286 /** 287 * This object will be visited after the main scene is visited.<br/> 288 * This object MUST implement the "visit" selector.<br/> 289 * Useful to hook a notification object 290 * @return {cc.Node} 291 */ 292 getNotificationNode: function () { 293 return this._notificationNode; 294 }, 295 296 /** 297 * Returns the size of the WebGL view in points.<br/> 298 * It takes into account any possible rotation (device orientation) of the window 299 * @return {cc.Size} 300 */ 301 getWinSize: function () { 302 return cc.size(this._winSizeInPoints); 303 }, 304 305 /** 306 * Returns the size of the OpenGL view in pixels.<br/> 307 * It takes into account any possible rotation (device orientation) of the window.<br/> 308 * On Mac winSize and winSizeInPixels return the same value. 309 * @return {cc.Size} 310 */ 311 getWinSizeInPixels: function () { 312 return cc.size(this._winSizeInPoints.width * this._contentScaleFactor, this._winSizeInPoints.height * this._contentScaleFactor); 313 }, 314 315 /** 316 * getVisibleSize/getVisibleOrigin move to CCDirectorWebGL/CCDirectorCanvas 317 * getZEye move to CCDirectorWebGL 318 */ 319 320 /** 321 * Returns the visible size of the running scene 322 * @function 323 * @return {cc.Size} 324 */ 325 getVisibleSize: null, 326 327 /** 328 * Returns the visible origin of the running scene 329 * @function 330 * @return {cc.Point} 331 */ 332 getVisibleOrigin: null, 333 334 /** 335 * Returns the z eye, only available in WebGL mode 336 * @function 337 * @return {Number} 338 */ 339 getZEye: null, 340 341 /** 342 * Pause the director's ticker 343 */ 344 pause: function () { 345 if (this._paused) 346 return; 347 348 this._oldAnimationInterval = this._animationInterval; 349 // when paused, don't consume CPU 350 this.setAnimationInterval(1 / 4.0); 351 this._paused = true; 352 }, 353 354 /** 355 * Pops out a scene from the queue.<br/> 356 * This scene will replace the running one.<br/> 357 * The running scene will be deleted. If there are no more scenes in the stack the execution is terminated.<br/> 358 * ONLY call it if there is a running scene. 359 */ 360 popScene: function () { 361 362 cc.assert(this._runningScene, cc._LogInfos.Director_popScene); 363 364 this._scenesStack.pop(); 365 var c = this._scenesStack.length; 366 367 if (c == 0) 368 this.end(); 369 else { 370 this._sendCleanupToScene = true; 371 this._nextScene = this._scenesStack[c - 1]; 372 } 373 }, 374 375 /** 376 * Removes cached all cocos2d cached data. It will purge the cc.textureCache, cc.spriteFrameCache, cc.animationCache 377 */ 378 purgeCachedData: function () { 379 cc.animationCache._clear(); 380 cc.spriteFrameCache._clear(); 381 cc.textureCache._clear(); 382 }, 383 384 /** 385 * Purge the cc.director itself, including unschedule all schedule, remove all event listeners, clean up and exit the running scene, stops all animations, clear cached data. 386 */ 387 purgeDirector: function () { 388 //cleanup scheduler 389 this.getScheduler().unscheduleAllCallbacks(); 390 391 // Disable event dispatching 392 if (cc.eventManager) 393 cc.eventManager.setEnabled(false); 394 395 // don't release the event handlers 396 // They are needed in case the director is run again 397 398 if (this._runningScene) { 399 this._runningScene.onExitTransitionDidStart(); 400 this._runningScene.onExit(); 401 this._runningScene.cleanup(); 402 } 403 404 this._runningScene = null; 405 this._nextScene = null; 406 407 // remove all objects, but don't release it. 408 // runScene might be executed after 'end'. 409 this._scenesStack.length = 0; 410 411 this.stopAnimation(); 412 413 // Clear all caches 414 this.purgeCachedData(); 415 416 cc.checkGLErrorDebug(); 417 }, 418 419 /** 420 * Suspends the execution of the running scene, pushing it on the stack of suspended scenes.<br/> 421 * The new scene will be executed.<br/> 422 * Try to avoid big stacks of pushed scenes to reduce memory allocation.<br/> 423 * ONLY call it if there is a running scene. 424 * @param {cc.Scene} scene 425 */ 426 pushScene: function (scene) { 427 428 cc.assert(scene, cc._LogInfos.Director_pushScene); 429 430 this._sendCleanupToScene = false; 431 432 this._scenesStack.push(scene); 433 this._nextScene = scene; 434 }, 435 436 /** 437 * Run a scene. Replaces the running scene with a new one or enter the first scene. 438 * @param {cc.Scene} scene 439 */ 440 runScene: function (scene) { 441 442 cc.assert(scene, cc._LogInfos.Director_pushScene); 443 444 if (!this._runningScene) { 445 //start scene 446 this.pushScene(scene); 447 this.startAnimation(); 448 } else { 449 //replace scene 450 var i = this._scenesStack.length; 451 if (i === 0) { 452 this._sendCleanupToScene = true; 453 this._scenesStack[i] = scene; 454 this._nextScene = scene; 455 } else { 456 this._sendCleanupToScene = true; 457 this._scenesStack[i - 1] = scene; 458 this._nextScene = scene; 459 } 460 } 461 }, 462 463 /** 464 * Resume director after pause, if the current scene is not paused, nothing will happen. 465 */ 466 resume: function () { 467 if (!this._paused) { 468 return; 469 } 470 471 this.setAnimationInterval(this._oldAnimationInterval); 472 this._lastUpdate = Date.now(); 473 if (!this._lastUpdate) { 474 cc.log(cc._LogInfos.Director_resume); 475 } 476 477 this._paused = false; 478 this._deltaTime = 0; 479 }, 480 481 /** 482 * The size in pixels of the surface. It could be different than the screen size.<br/> 483 * High-res devices might have a higher surface size than the screen size. 484 * @param {Number} scaleFactor 485 */ 486 setContentScaleFactor: function (scaleFactor) { 487 if (scaleFactor != this._contentScaleFactor) { 488 this._contentScaleFactor = scaleFactor; 489 this._createStatsLabel(); 490 } 491 }, 492 493 /** 494 * Enables or disables WebGL depth test.<br/> 495 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js 496 * @function 497 * @param {Boolean} on 498 */ 499 setDepthTest: null, 500 501 /** 502 * Sets the default values based on the CCConfiguration info 503 */ 504 setDefaultValues: function () { 505 506 }, 507 508 /** 509 * Sets whether next delta time equals to zero 510 * @param {Boolean} nextDeltaTimeZero 511 */ 512 setNextDeltaTimeZero: function (nextDeltaTimeZero) { 513 this._nextDeltaTimeZero = nextDeltaTimeZero; 514 }, 515 516 /** 517 * Starts the registered next scene 518 */ 519 setNextScene: function () { 520 var runningIsTransition = false, newIsTransition = false; 521 if (cc.TransitionScene) { 522 runningIsTransition = this._runningScene ? this._runningScene instanceof cc.TransitionScene : false; 523 newIsTransition = this._nextScene ? this._nextScene instanceof cc.TransitionScene : false; 524 } 525 526 // If it is not a transition, call onExit/cleanup 527 if (!newIsTransition) { 528 var locRunningScene = this._runningScene; 529 if (locRunningScene) { 530 locRunningScene.onExitTransitionDidStart(); 531 locRunningScene.onExit(); 532 } 533 534 // issue #709. the root node (scene) should receive the cleanup message too 535 // otherwise it might be leaked. 536 if (this._sendCleanupToScene && locRunningScene) 537 locRunningScene.cleanup(); 538 } 539 540 this._runningScene = this._nextScene; 541 cc.renderer.childrenOrderDirty = true; 542 543 this._nextScene = null; 544 if ((!runningIsTransition) && (this._runningScene != null)) { 545 this._runningScene.onEnter(); 546 this._runningScene.onEnterTransitionDidFinish(); 547 } 548 }, 549 550 /** 551 * Sets Notification Node 552 * @param {cc.Node} node 553 */ 554 setNotificationNode: function (node) { 555 this._notificationNode = node; 556 }, 557 558 /** 559 * Returns the cc.director delegate. 560 * @return {cc.DirectorDelegate} 561 */ 562 getDelegate: function () { 563 return this._projectionDelegate; 564 }, 565 566 /** 567 * Sets the cc.director delegate. It shall implement the CCDirectorDelegate protocol 568 * @return {cc.DirectorDelegate} 569 */ 570 setDelegate: function (delegate) { 571 this._projectionDelegate = delegate; 572 }, 573 574 /** 575 * Sets the view, where everything is rendered, do not call this function.<br/> 576 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 577 * @function 578 * @param {cc.view} openGLView 579 */ 580 setOpenGLView: null, 581 582 /** 583 * Sets an OpenGL projection.<br/> 584 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 585 * @function 586 * @param {Number} projection 587 */ 588 setProjection: null, 589 590 /** 591 * Update the view port.<br/> 592 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 593 * @function 594 */ 595 setViewport: null, 596 597 /** 598 * Get the CCEGLView, where everything is rendered.<br/> 599 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 600 * @function 601 * @return {cc.view} 602 */ 603 getOpenGLView: null, 604 605 /** 606 * Sets an OpenGL projection.<br/> 607 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 608 * @function 609 * @return {Number} 610 */ 611 getProjection: null, 612 613 /** 614 * Enables/disables OpenGL alpha blending.<br/> 615 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 616 * @function 617 * @param {Boolean} on 618 */ 619 setAlphaBlending: null, 620 621 _showStats: function () { 622 this._frames++; 623 this._accumDt += this._deltaTime; 624 if (this._FPSLabel && this._SPFLabel && this._drawsLabel) { 625 if (this._accumDt > cc.DIRECTOR_FPS_INTERVAL) { 626 this._SPFLabel.string = this._secondsPerFrame.toFixed(3); 627 628 this._frameRate = this._frames / this._accumDt; 629 this._frames = 0; 630 this._accumDt = 0; 631 632 this._FPSLabel.string = this._frameRate.toFixed(1); 633 this._drawsLabel.string = (0 | cc.g_NumberOfDraws).toString(); 634 } 635 this._FPSLabel.visit(); 636 this._SPFLabel.visit(); 637 this._drawsLabel.visit(); 638 } else 639 this._createStatsLabel(); 640 cc.g_NumberOfDraws = 0; 641 }, 642 643 /** 644 * Returns whether or not the replaced scene will receive the cleanup message.<br> 645 * If the new scene is pushed, then the old scene won't receive the "cleanup" message.<br/> 646 * If the new scene replaces the old one, the it will receive the "cleanup" message. 647 * @return {Boolean} 648 */ 649 isSendCleanupToScene: function () { 650 return this._sendCleanupToScene; 651 }, 652 653 /** 654 * Returns current running Scene. Director can only run one Scene at the time 655 * @return {cc.Scene} 656 */ 657 getRunningScene: function () { 658 return this._runningScene; 659 }, 660 661 /** 662 * Returns the FPS value 663 * @return {Number} 664 */ 665 getAnimationInterval: function () { 666 return this._animationInterval; 667 }, 668 669 /** 670 * Returns whether or not to display the FPS informations 671 * @return {Boolean} 672 */ 673 isDisplayStats: function () { 674 return this._displayStats; 675 }, 676 677 /** 678 * Sets whether display the FPS on the bottom-left corner 679 * @param {Boolean} displayStats 680 */ 681 setDisplayStats: function (displayStats) { 682 this._displayStats = displayStats; 683 }, 684 685 /** 686 * Returns seconds per frame 687 * @return {Number} 688 */ 689 getSecondsPerFrame: function () { 690 return this._secondsPerFrame; 691 }, 692 693 /** 694 * Returns whether next delta time equals to zero 695 * @return {Boolean} 696 */ 697 isNextDeltaTimeZero: function () { 698 return this._nextDeltaTimeZero; 699 }, 700 701 /** 702 * Returns whether or not the Director is paused 703 * @return {Boolean} 704 */ 705 isPaused: function () { 706 return this._paused; 707 }, 708 709 /** 710 * Returns how many frames were called since the director started 711 * @return {Number} 712 */ 713 getTotalFrames: function () { 714 return this._totalFrames; 715 }, 716 717 /** 718 * Pops out all scenes from the queue until the root scene in the queue. <br/> 719 * This scene will replace the running one. <br/> 720 * Internally it will call "popToSceneStackLevel(1)" 721 */ 722 popToRootScene: function () { 723 this.popToSceneStackLevel(1); 724 }, 725 726 /** 727 * Pops out all scenes from the queue until it reaches "level". <br/> 728 * If level is 0, it will end the director. <br/> 729 * If level is 1, it will pop all scenes until it reaches to root scene. <br/> 730 * If level is <= than the current stack level, it won't do anything. 731 * @param {Number} level 732 */ 733 popToSceneStackLevel: function (level) { 734 cc.assert(this._runningScene, cc._LogInfos.Director_popToSceneStackLevel_2); 735 736 var locScenesStack = this._scenesStack; 737 var c = locScenesStack.length; 738 739 if (c == 0) { 740 this.end(); 741 return; 742 } 743 // current level or lower -> nothing 744 if (level > c) 745 return; 746 747 // pop stack until reaching desired level 748 while (c > level) { 749 var current = locScenesStack.pop(); 750 if (current.running) { 751 current.onExitTransitionDidStart(); 752 current.onExit(); 753 } 754 current.cleanup(); 755 c--; 756 } 757 this._nextScene = locScenesStack[locScenesStack.length - 1]; 758 this._sendCleanupToScene = false; 759 }, 760 761 /** 762 * Returns the cc.Scheduler associated with this director 763 * @return {cc.Scheduler} 764 */ 765 getScheduler: function () { 766 return this._scheduler; 767 }, 768 769 /** 770 * Sets the cc.Scheduler associated with this director 771 * @param {cc.Scheduler} scheduler 772 */ 773 setScheduler: function (scheduler) { 774 if (this._scheduler != scheduler) { 775 this._scheduler = scheduler; 776 } 777 }, 778 779 /** 780 * Returns the cc.ActionManager associated with this director 781 * @return {cc.ActionManager} 782 */ 783 getActionManager: function () { 784 return this._actionManager; 785 }, 786 /** 787 * Sets the cc.ActionManager associated with this director 788 * @param {cc.ActionManager} actionManager 789 */ 790 setActionManager: function (actionManager) { 791 if (this._actionManager != actionManager) { 792 this._actionManager = actionManager; 793 } 794 }, 795 796 /** 797 * Returns the delta time since last frame 798 * @return {Number} 799 */ 800 getDeltaTime: function () { 801 return this._deltaTime; 802 }, 803 804 _createStatsLabel: null, 805 806 _calculateMPF: function () { 807 var now = Date.now(); 808 this._secondsPerFrame = (now - this._lastUpdate) / 1000; 809 } 810 }); 811 812 /** 813 * The event projection changed of cc.Director 814 * @constant 815 * @type {string} 816 * @example 817 * cc.eventManager.addCustomListener(cc.Director.EVENT_PROJECTION_CHANGED, function(event) { 818 * cc.log("Projection changed."); 819 * }); 820 */ 821 cc.Director.EVENT_PROJECTION_CHANGED = "director_projection_changed"; 822 823 /** 824 * The event after draw of cc.Director 825 * @constant 826 * @type {string} 827 * @example 828 * cc.eventManager.addCustomListener(cc.Director.EVENT_AFTER_DRAW, function(event) { 829 * cc.log("after draw event."); 830 * }); 831 */ 832 cc.Director.EVENT_AFTER_DRAW = "director_after_draw"; 833 834 /** 835 * The event after visit of cc.Director 836 * @constant 837 * @type {string} 838 * @example 839 * cc.eventManager.addCustomListener(cc.Director.EVENT_AFTER_VISIT, function(event) { 840 * cc.log("after visit event."); 841 * }); 842 */ 843 cc.Director.EVENT_AFTER_VISIT = "director_after_visit"; 844 845 /** 846 * The event after update of cc.Director 847 * @constant 848 * @type {string} 849 * @example 850 * cc.eventManager.addCustomListener(cc.Director.EVENT_AFTER_UPDATE, function(event) { 851 * cc.log("after update event."); 852 * }); 853 */ 854 cc.Director.EVENT_AFTER_UPDATE = "director_after_update"; 855 856 /*************************************************** 857 * implementation of DisplayLinkDirector 858 **************************************************/ 859 cc.DisplayLinkDirector = cc.Director.extend(/** @lends cc.Director# */{ 860 invalid: false, 861 862 /** 863 * Starts Animation 864 */ 865 startAnimation: function () { 866 this._nextDeltaTimeZero = true; 867 this.invalid = false; 868 }, 869 870 /** 871 * Run main loop of director 872 */ 873 mainLoop: function () { 874 if (this._purgeDirectorInNextLoop) { 875 this._purgeDirectorInNextLoop = false; 876 this.purgeDirector(); 877 } 878 else if (!this.invalid) { 879 this.drawScene(); 880 } 881 }, 882 883 /** 884 * Stops animation 885 */ 886 stopAnimation: function () { 887 this.invalid = true; 888 }, 889 890 /** 891 * Sets animation interval 892 * @param {Number} value the animation interval desired 893 */ 894 setAnimationInterval: function (value) { 895 this._animationInterval = value; 896 if (!this.invalid) { 897 this.stopAnimation(); 898 this.startAnimation(); 899 } 900 } 901 }); 902 903 cc.Director.sharedDirector = null; 904 cc.Director.firstUseDirector = true; 905 906 cc.Director._getInstance = function () { 907 if (cc.Director.firstUseDirector) { 908 cc.Director.firstUseDirector = false; 909 cc.Director.sharedDirector = new cc.DisplayLinkDirector(); 910 cc.Director.sharedDirector.init(); 911 } 912 return cc.Director.sharedDirector; 913 }; 914 915 /** 916 * Default fps is 60 917 * @type {Number} 918 */ 919 cc.defaultFPS = 60; 920 921 //Possible OpenGL projections used by director 922 /** 923 * Constant for 2D projection (orthogonal projection) 924 * @constant 925 * @type {Number} 926 */ 927 cc.Director.PROJECTION_2D = 0; 928 929 /** 930 * Constant for 3D projection with a fovy=60, znear=0.5f and zfar=1500. 931 * @constant 932 * @type {Number} 933 */ 934 cc.Director.PROJECTION_3D = 1; 935 936 /** 937 * Constant for custom projection, if cc.Director's projection set to it, it calls "updateProjection" on the projection delegate. 938 * @constant 939 * @type {Number} 940 */ 941 cc.Director.PROJECTION_CUSTOM = 3; 942 943 /** 944 * Constant for default projection of cc.Director, default projection is 3D projection 945 * @constant 946 * @type {Number} 947 */ 948 cc.Director.PROJECTION_DEFAULT = cc.Director.PROJECTION_3D; 949 950 if (cc._renderType === cc._RENDER_TYPE_CANVAS) { 951 952 var _p = cc.Director.prototype; 953 954 _p.setProjection = function (projection) { 955 this._projection = projection; 956 cc.eventManager.dispatchEvent(this._eventProjectionChanged); 957 }; 958 959 _p.setDepthTest = function () { 960 }; 961 962 _p.setOpenGLView = function (openGLView) { 963 // set size 964 this._winSizeInPoints.width = cc._canvas.width; //this._openGLView.getDesignResolutionSize(); 965 this._winSizeInPoints.height = cc._canvas.height; 966 this._openGLView = openGLView || cc.view; 967 if (cc.eventManager) 968 cc.eventManager.setEnabled(true); 969 }; 970 971 _p._clear = function () { 972 var viewport = this._openGLView.getViewPortRect(); 973 var context = cc._renderContext.getContext(); 974 context.setTransform(1,0,0,1, 0, 0); 975 context.clearRect(-viewport.x, viewport.y, viewport.width, viewport.height); 976 }; 977 978 _p._createStatsLabel = function () { 979 var _t = this; 980 var fontSize = 0; 981 if (_t._winSizeInPoints.width > _t._winSizeInPoints.height) 982 fontSize = 0 | (_t._winSizeInPoints.height / 320 * 24); 983 else 984 fontSize = 0 | (_t._winSizeInPoints.width / 320 * 24); 985 986 _t._FPSLabel = new cc.LabelTTF("000.0", "Arial", fontSize); 987 _t._SPFLabel = new cc.LabelTTF("0.000", "Arial", fontSize); 988 _t._drawsLabel = new cc.LabelTTF("0000", "Arial", fontSize); 989 990 var locStatsPosition = cc.DIRECTOR_STATS_POSITION; 991 _t._drawsLabel.setPosition(_t._drawsLabel.width / 2 + locStatsPosition.x, _t._drawsLabel.height * 5 / 2 + locStatsPosition.y); 992 _t._SPFLabel.setPosition(_t._SPFLabel.width / 2 + locStatsPosition.x, _t._SPFLabel.height * 3 / 2 + locStatsPosition.y); 993 _t._FPSLabel.setPosition(_t._FPSLabel.width / 2 + locStatsPosition.x, _t._FPSLabel.height / 2 + locStatsPosition.y); 994 }; 995 996 _p.getVisibleSize = function () { 997 //if (this._openGLView) { 998 //return this._openGLView.getVisibleSize(); 999 //} else { 1000 return this.getWinSize(); 1001 //} 1002 }; 1003 1004 _p.getVisibleOrigin = function () { 1005 //if (this._openGLView) { 1006 //return this._openGLView.getVisibleOrigin(); 1007 //} else { 1008 return cc.p(0, 0); 1009 //} 1010 }; 1011 } else { 1012 cc.Director._fpsImage = new Image(); 1013 cc._addEventListener(cc.Director._fpsImage, "load", function () { 1014 cc.Director._fpsImageLoaded = true; 1015 }); 1016 if (cc._fpsImage) { 1017 cc.Director._fpsImage.src = cc._fpsImage; 1018 } 1019 }