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