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