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