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