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