1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga 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 //Possible OpenGL projections used by director
 30 /**
 31  * sets a 2D projection (orthogonal projection)
 32  * @constant
 33  * @type Number
 34  */
 35 cc.DIRECTOR_PROJECTION_2D = 0;
 36 
 37 /**
 38  * sets a 3D projection with a fovy=60, znear=0.5f and zfar=1500.
 39  * @constant
 40  * @type Number
 41  */
 42 cc.DIRECTOR_PROJECTION_3D = 1;
 43 
 44 /**
 45  * it calls "updateProjection" on the projection delegate.
 46  * @constant
 47  * @type Number
 48  */
 49 cc.DIRECTOR_PROJECTION_CUSTOM = 3;
 50 
 51 /**
 52  * Detault projection is 3D projection
 53  * @constant
 54  * @type Number
 55  */
 56 cc.DIRECTOR_PROJECTION_DEFAULT = cc.DIRECTOR_PROJECTION_3D;
 57 
 58 //----------------------------------------------------------------------------------------------------------------------
 59 //Possible device orientations
 60 /**
 61  * Device oriented vertically, home button on the bottom (UIDeviceOrientationPortrait)
 62  * @constant
 63  * @type Number
 64  */
 65 cc.DEVICE_ORIENTATION_PORTRAIT = 0;
 66 
 67 /**
 68  * Device oriented horizontally, home button on the right (UIDeviceOrientationLandscapeLeft)
 69  * @constant
 70  * @type Number
 71  */
 72 cc.DEVICE_ORIENTATION_LANDSCAPE_LEFT = 1;
 73 
 74 /**
 75  * Device oriented vertically, home button on the top (UIDeviceOrientationPortraitUpsideDown)
 76  * @constant
 77  * @type Number
 78  */
 79 cc.DEVICE_ORIENTATION_PORTRAIT_UPSIDE_DOWN = 2;
 80 
 81 /**
 82  * Device oriented horizontally, home button on the left (UIDeviceOrientationLandscapeRight)
 83  * @constant
 84  * @type Number
 85  */
 86 cc.DEVICE_ORIENTATION_LANDSCAPE_RIGHT = 3;
 87 
 88 /**
 89  * In browsers, we only support 2 orientations by change window size.
 90  * @constant
 91  * @type Number
 92  */
 93 cc.DEVICE_MAX_ORIENTATIONS = 2;
 94 
 95 
 96 //----------------------------------------------------------------------------------------------------------------------
 97 
 98 /**
 99  * <p>
100  *    Class that creates and handle the main Window and manages how<br/>
101  *    and when to execute the Scenes.<br/>
102  *    <br/>
103  *    The cc.Director is also responsible for:<br/>
104  *      - initializing the OpenGL context<br/>
105  *      - setting the OpenGL pixel format (default on is RGB565)<br/>
106  *      - setting the OpenGL pixel format (default on is RGB565)<br/>
107  *      - setting the OpenGL buffer depth (default one is 0-bit)<br/>
108  *      - setting the projection (default one is 3D)<br/>
109  *      - setting the orientation (default one is Protrait)<br/>
110  *      <br/>
111  *    Since the cc.Director is a singleton, the standard way to use it is by calling:<br/>
112  *      - cc.Director.getInstance().methodName(); <br/>
113  *    <br/>
114  *    The CCDirector also sets the default OpenGL context:<br/>
115  *      - GL_TEXTURE_2D is enabled<br/>
116  *      - GL_VERTEX_ARRAY is enabled<br/>
117  *      - GL_COLOR_ARRAY is enabled<br/>
118  *      - GL_TEXTURE_COORD_ARRAY is enabled<br/>
119  * </p>
120  * @class
121  * @extends cc.Class
122  */
123 cc.Director = cc.Class.extend(/** @lends cc.Director# */{
124     //Variables
125     _isContentScaleSupported:false,
126     _landscape:false,
127     _nextDeltaTimeZero:false,
128     _paused:false,
129     _purgeDirecotorInNextLoop:false,
130     _sendCleanupToScene:false,
131     _animationInterval:0.0,
132     _oldAnimationInterval:0.0,
133     _projection:0,
134     _accumDt:0.0,
135     _contentScaleFactor:1.0,
136 
137     _displayStats:false,
138     _deltaTime:0.0,
139     _frameRate:0.0,
140 
141     _FPSLabel:null,
142     _SPFLabel:null,
143     _drawsLabel:null,
144 
145     _winSizeInPixels:null,
146     _winSizeInPoints:null,
147 
148     _lastUpdate:null,
149     _nextScene:null,
150     _notificationNode:null,
151     _openGLView:null,
152     _scenesStack:null,
153     _projectionDelegate:null,
154     _runningScene:null,
155 
156     _frames:0,
157     _totalFrames:0,
158     _secondsPerFrame:0,
159 
160     _dirtyRegion:null,
161 
162     _scheduler:null,
163     _actionManager:null,
164     _touchDispatcher:null,
165     _keyboardDispatcher:null,
166     _accelerometer:null,
167     _mouseDispatcher:null,
168 
169     _watcherFun:null,
170     _watcherSender:null,
171 
172     _currTimeValue:null,
173     _isBlur:false,
174 
175     /**
176      * Constructor
177      */
178     ctor:function () {
179         this._currTimeValue = new cc.timeval();
180         this._lastUpdate = new cc.timeval();
181         if(!cc.isAddedHiddenEvent){
182             var selfPointer = this;
183             window.addEventListener("focus",function(){
184                 selfPointer._lastUpdate = cc.Time.gettimeofdayCocos2d(selfPointer._lastUpdate);
185             }, false);
186         }
187     },
188 
189     _resetLastUpdate:function(){
190         this._lastUpdate = cc.Time.gettimeofdayCocos2d(this._lastUpdate);
191     },
192 
193     /**
194      * initializes cc.Director
195      * @return {Boolean}
196      */
197     init:function () {
198         // scenes
199         //TODO these are already set to null, so maybe we can remove them in the init?
200         this._runningScene = null;
201         this._nextScene = null;
202         this._notificationNode = null;
203 
204         this._oldAnimationInterval = this._animationInterval = 1.0 / cc.defaultFPS;
205         this._scenesStack = [];
206         // Set default projection (3D)
207         this._projection = cc.DIRECTOR_PROJECTION_DEFAULT;
208         // projection delegate if "Custom" projection is used
209         this._projectionDelegate = null;
210 
211         //FPS
212         this._accumDt = 0;
213         this._frameRate = 0;
214         this._displayStats = false;//can remove
215         this._totalFrames = this._frames = 0;
216         this._lastUpdate = new cc.timeval();
217 
218         //Paused?
219         this._paused = false;
220 
221         //purge?
222         this._purgeDirecotorInNextLoop = false;
223         this._winSizeInPixels = this._winSizeInPoints = cc.size(cc.canvas.width, cc.canvas.height);
224 
225         this._openGLView = null;
226         this._contentScaleFactor = 1.0;
227         this._isContentScaleSupported = false;
228 
229         this._watcherFun = null;
230         this._watcherSender = null;
231 
232         //scheduler
233         this._scheduler = new cc.Scheduler();
234         //action manager
235         this._actionManager = new cc.ActionManager();
236         this._scheduler.scheduleUpdateForTarget(this._actionManager, cc.PRIORITY_SYSTEM, false);
237         //touchDispatcher
238         this._touchDispatcher = new cc.TouchDispatcher();
239         this._touchDispatcher.init();
240 
241         //KeyboardDispatcher
242         this._keyboardDispatcher = cc.KeyboardDispatcher.getInstance();
243 
244         //accelerometer
245         //this._accelerometer = new cc.Accelerometer();
246 
247         //MouseDispatcher
248         this._mouseDispatcher = new cc.MouseDispatcher();
249         this._mouseDispatcher.init();
250 
251         return true;
252     },
253 
254     /**
255      * calculates delta time since last time it was called
256      */
257     calculateDeltaTime:function () {
258         var now = cc.Time.gettimeofdayCocos2d(this._currTimeValue);
259         if (!now) {
260             cc.log("error in gettimeofday");
261             this._deltaTime = 0;
262             return;
263         }
264 
265         // new delta time.
266         if (this._nextDeltaTimeZero) {
267             this._deltaTime = 0;
268             this._nextDeltaTimeZero = false;
269         } else {
270             this._deltaTime = (now.tv_sec - this._lastUpdate.tv_sec) + (now.tv_usec - this._lastUpdate.tv_usec) / 1000000.0;
271             this._deltaTime = Math.max(0, this._deltaTime);
272         }
273 
274         if (cc.DEBUG) {
275             if (this._deltaTime > 0.2) {
276                 this._deltaTime = 1 / 60.0;
277             }
278         }
279         this._lastUpdate.tv_sec = now.tv_sec;
280         this._lastUpdate.tv_usec = now.tv_usec;
281     },
282 
283     /**
284      * <p>
285      *     converts a UIKit coordinate to an OpenGL coordinate<br/>
286      *     Useful to convert (multi) touches coordinates to the current layout (portrait or landscape)
287      * </p>
288      * @param {cc.Point} point
289      * @return {cc.Point}
290      */
291     convertToGL:function (point) {
292         var newY = this._winSizeInPoints.height - point.y;
293         return cc.p(point.x, newY);
294     },
295 
296     /**
297      * <p>converts an OpenGL coordinate to a UIKit coordinate<br/>
298      * Useful to convert node points to window points for calls such as glScissor</p>
299      * @param {cc.Point} point
300      * @return {cc.Point}
301      */
302     convertToUI:function (point) {
303         var oppositeY = this._winSizeInPoints.height - point.y;
304         return cc.p(point.x, oppositeY);
305     },
306 
307     //_fullRect:null,
308     /**
309      *  Draw the scene. This method is called every frame. Don't call it manually.
310      */
311     drawScene:function () {
312         // calculate "global" dt
313         this.calculateDeltaTime();
314 
315         //tick before glClear: issue #533
316         if (!this._paused) {
317             this._scheduler.update(this._deltaTime);
318         }
319         //this._fullRect = cc.rect(0, 0, cc.canvas.width, cc.canvas.height);
320         //cc.renderContext.clearRect(this._fullRect.origin.x, this._fullRect.origin.y, this._fullRect.size.width, -this._fullRect.size.height);
321         cc.renderContext.clearRect(0, 0, cc.canvas.width, -cc.canvas.height);
322 
323         /*
324          var isSaveContext = false;
325          //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
326 
327          if (this._dirtyRegion) {
328          //cc.renderContext.clearRect(0, 0, cc.canvas.width, -cc.canvas.height);
329 
330          var fullRect = cc.rect(0, 0, cc.canvas.width, cc.canvas.height);
331          this._dirtyRegion = cc.Rect.CCRectIntersection(this._dirtyRegion, fullRect);
332 
333          if(cc.Rect.CCRectEqualToRect(cc.RectZero(), this._dirtyRegion)){
334          this._dirtyRegion = null;
335          }else{
336          cc.renderContext.clearRect(0 | this._dirtyRegion.origin.x, -(0 | this._dirtyRegion.origin.y),
337          0 | this._dirtyRegion.size.width, -(0 | this._dirtyRegion.size.height));
338 
339          if(!cc.Rect.CCRectEqualToRect(fullRect, this._dirtyRegion)){
340          isSaveContext = true;
341          cc.renderContext.save();
342          cc.renderContext.beginPath();
343          cc.renderContext.rect(0 | this._dirtyRegion.origin.x - 1, -(0 | this._dirtyRegion.origin.y - 1),
344          0 | this._dirtyRegion.size.width + 2, -(0 | this._dirtyRegion.size.height + 2));
345          cc.renderContext.clip();
346          cc.renderContext.closePath();
347          }
348          }
349          }
350          */
351 
352         /* to avoid flickr, nextScene MUST be here: after tick and before draw.
353          XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */
354         if (this._nextScene) {
355             this.setNextScene();
356         }
357 
358         //kmGLPushMatrix();
359 
360         // draw the scene
361         if (this._runningScene) {
362             //if (this._dirtyRegion) {
363             this._runningScene.visit();
364             //}
365         }
366 
367         /*
368          if (this._dirtyRegion) {
369          this._dirtyRegion = null;
370          if(isSaveContext){
371          cc.renderContext.restore();
372          }
373          }
374          */
375 
376         // draw the notifications node
377         if (this._notificationNode) {
378             this._notificationNode.visit();
379         }
380 
381         if (this._displayStats) {
382             this._showStats();
383         }
384 
385         if (this._watcherFun && this._watcherSender) {
386             this._watcherFun.call(this._watcherSender);
387         }
388 
389         //TODO OpenGL
390         //kmGLPopMatrix();
391 
392         this._totalFrames++;
393 
394         // swap buffers
395         if (this._openGLView) {
396             this._openGLView.swapBuffers();
397         }
398 
399         if (this._displayStats) {
400             this._calculateMPF();
401         }
402     },
403 
404     addRegionToDirtyRegion:function (rect) {
405         if (!rect)
406             return;
407 
408         if (!this._dirtyRegion) {
409             this._dirtyRegion = cc.rect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
410             return;
411         }
412         this._dirtyRegion = cc.Rect.CCRectUnion(this._dirtyRegion,
413             cc.rect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height));
414     },
415 
416     rectIsInDirtyRegion:function (rect) {
417         if (!rect || !this._fullRect)
418             return false;
419 
420         return cc.Rect.CCRectIntersectsRect(this._fullRect, rect);
421     },
422 
423     /**
424      * <p>
425      *   Will enable Retina Display on devices that supports it. <br/>
426      *   It will enable Retina Display on iPhone4 and iPod Touch 4.<br/>
427      *   It will return YES, if it could enabled it, otherwise it will return NO.<br/>
428      *   <br/>
429      *   This is the recommened way to enable Retina Display.
430      * </p>
431      * @param {Boolean} enabled
432      * @return {Boolean}
433      */
434     enableRetinaDisplay:function (enabled) {
435         // Already enabled?
436         if (enabled && this._contentScaleFactor == 2) {
437             return true;
438         }
439 
440         // Already diabled?
441         if (!enabled && this._contentScaleFactor == 1) {
442             return false;
443         }
444 
445         // setContentScaleFactor is not supported
446         if (!this._openGLView.canSetContentScaleFactor()) {
447             return false;
448         }
449 
450         // SD device
451         if (this._openGLView.getMainScreenScale() == 1.0) {
452             return false;
453         }
454 
455         var newScale = (enabled) ? 2 : 1;
456         this.setContentScaleFactor(newScale);
457 
458         this._createStatsLabel();
459         return true;
460     },
461 
462     /**
463      * end director
464      */
465     end:function () {
466         this._purgeDirecotorInNextLoop = true;
467     },
468 
469     /**
470      * <p>get the size in pixels of the surface. It could be different than the screen size.<br/>
471      *   High-res devices might have a higher surface size than the screen size.<br/>
472      *   Only available when compiled using SDK >= 4.0.
473      * </p>
474      * @return {Number}
475      */
476     getContentScaleFactor:function () {
477         return this._contentScaleFactor;
478     },
479 
480     /**
481      * <p>
482      *    This object will be visited after the main scene is visited.<br/>
483      *    This object MUST implement the "visit" selector.<br/>
484      *    Useful to hook a notification object, like CCNotifications (http://github.com/manucorporat/CCNotifications)
485      * </p>
486      * @return {cc.Node}
487      */
488     getNotificationNode:function () {
489         return this._notificationNode;
490     },
491 
492     /**
493      * <p>
494      *     returns the size of the OpenGL view in points.<br/>
495      *     It takes into account any possible rotation (device orientation) of the window
496      * </p>
497      * @return {cc.Size}
498      */
499     getWinSize:function () {
500         return this._winSizeInPoints;
501     },
502 
503     /**
504      * <p>
505      *   returns the size of the OpenGL view in pixels.<br/>
506      *   It takes into account any possible rotation (device orientation) of the window.<br/>
507      *   On Mac winSize and winSizeInPixels return the same value.
508      * </p>
509      * @return {cc.Size}
510      */
511     getWinSizeInPixels:function () {
512         return this._winSizeInPixels;
513     },
514 
515     getZEye:function () {
516         return (this._winSizeInPixels.height / 1.1566 / cc.CONTENT_SCALE_FACTOR());
517     },
518 
519     /**
520      * pause director
521      */
522     pause:function () {
523         if (this._paused) {
524             return;
525         }
526 
527         this._oldAnimationInterval = this._animationInterval;
528         // when paused, don't consume CPU
529         this.setAnimationInterval(1 / 4.0);
530         this._paused = true;
531     },
532 
533     /**
534      * <p>
535      *     Pops out a scene from the queue.<br/>
536      *     This scene will replace the running one.<br/>
537      *     The running scene will be deleted. If there are no more scenes in the stack the execution is terminated.<br/>
538      *     ONLY call it if there is a running scene.
539      * </p>
540      */
541     popScene:function () {
542         cc.Assert(this._runningScene != null, "running scene should not null");
543 
544         //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height));
545 
546         this._scenesStack.pop();
547         var c = this._scenesStack.length;
548 
549         if (c == 0) {
550             this.end();
551         }
552         else {
553             this._sendCleanupToScene = true;
554             this._nextScene = this._scenesStack[c - 1];
555         }
556     },
557 
558     /**
559      * Removes cached all cocos2d cached data. It will purge the CCTextureCache, CCSpriteFrameCache, CCLabelBMFont cache
560      */
561     purgeCachedData:function () {
562         cc.LabelBMFont.purgeCachedData();
563         //cc.TextureCache.getInstance().removeUnusedTextures();
564     },
565 
566     /**
567      * purge Director
568      */
569     purgeDirector:function () {
570         // don't release the event handlers
571         // They are needed in case the director is run again
572         this._touchDispatcher.removeAllDelegates();
573 
574         if (this._runningScene) {
575             this._runningScene.onExit();
576             this._runningScene.cleanup();
577         }
578 
579         this._runningScene = null;
580         this._nextScene = null;
581 
582         // remove all objects, but don't release it.
583         // runWithScene might be executed after 'end'.
584         this._scenesStack = [];
585 
586         this.stopAnimation();
587 
588         // purge bitmap cache
589         cc.LabelBMFont.purgeCachedData();
590 
591         // purge all managers
592         cc.AnimationCache.purgeSharedAnimationCache();
593         cc.SpriteFrameCache.purgeSharedSpriteFrameCache();
594         cc.TextureCache.purgeSharedTextureCache();
595 
596         //CCShaderCache::purgeSharedShaderCache();
597         //CCFileUtils::purgeFileUtils();
598         //CCConfiguration::purgeConfiguration();
599         //extension::CCNotificationCenter::purgeNotificationCenter();
600         //extension::CCTextureWatcher::purgeTextureWatcher();
601         //extension::CCNodeLoaderLibrary::purgeSharedCCNodeLoaderLibrary();
602         //cc.UserDefault.purgeSharedUserDefault();
603         //ccGLInvalidateStateCache();
604 
605         //CHECK_GL_ERROR_DEBUG();
606 
607         // OpenGL view
608         this._openGLView.end();
609         this._openGLView = null;
610     },
611 
612     /**
613      * <p>
614      *    Suspends the execution of the running scene, pushing it on the stack of suspended scenes.<br/>
615      *    The new scene will be executed.<br/>
616      *    Try to avoid big stacks of pushed scenes to reduce memory allocation.<br/>
617      *    ONLY call it if there is a running scene.
618      * </p>
619      * @param {cc.Scene} scene
620      */
621     pushScene:function (scene) {
622         cc.Assert(scene, "the scene should not null");
623 
624         //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height));
625 
626         this._sendCleanupToScene = false;
627 
628         this._scenesStack.push(scene);
629         this._nextScene = scene;
630     },
631 
632     /**
633      * Replaces the running scene with a new one. The running scene is terminated. ONLY call it if there is a running scene.
634      * @param {cc.Scene} scene
635      */
636     replaceScene:function (scene) {
637         cc.Assert(scene != null, "the scene should not be null");
638 
639         //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height));
640         var i = this._scenesStack.length;
641 
642         this._sendCleanupToScene = true;
643         this._scenesStack[i - 1] = scene;
644         this._nextScene = scene;
645     },
646 
647     /**
648      * changes the projection size
649      * @param {cc.Size} newWindowSize
650      */
651     reshapeProjection:function (newWindowSize) {
652         if (this._openGLView) {
653             this._winSizeInPoints = this._openGLView.getSize();
654             this._winSizeInPixels = cc.size(this._winSizeInPoints.width * this._contentScaleFactor,
655                 this._winSizeInPoints.height * this._contentScaleFactor);
656 
657             this.setProjection(this._projection);
658         }
659     },
660 
661     /**
662      * resume director
663      */
664     resume:function () {
665         if (!this._paused) {
666             return;
667         }
668         //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height));
669 
670         this.setAnimationInterval(this._oldAnimationInterval);
671         this._lastUpdate = cc.Time.gettimeofdayCocos2d();
672         if (!this._lastUpdate) {
673             cc.log("cocos2d: Director: Error in gettimeofday");
674         }
675 
676         this._paused = false;
677         this._deltaTime = 0;
678     },
679 
680     /**
681      * <p>
682      *    Enters the Director's main loop with the given Scene.<br/>
683      *    Call it to run only your FIRST scene.<br/>
684      *    Don't call it if there is already a running scene.
685      * </p>
686      * @param {cc.Scene} scene
687      */
688     runWithScene:function (scene) {
689         cc.Assert(scene != null, "running scene should not be null");
690         cc.Assert(this._runningScene == null, "_runningScene should be null");
691 
692         //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height));
693 
694         this.pushScene(scene);
695         this.startAnimation();
696     },
697 
698     /**
699      * enables/disables OpenGL alpha blending
700      * @param {Boolean} on
701      */
702     setAlphaBlending:function (on) {
703         if (on) {
704             //TODO OpenGL
705             //ccGLEnable(CC_GL_BLEND);
706             //ccGLBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
707         }
708         else {
709             //glDisable(GL_BLEND);
710         }
711         //CHECK_GL_ERROR_DEBUG();
712     },
713 
714     /**
715      * <p>
716      *   The size in pixels of the surface. It could be different than the screen size.<br/>
717      *   High-res devices might have a higher surface size than the screen size.<br/>
718      *   Only available when compiled using SDK >= 4.0.
719      * </p>
720      * @param {Number} scaleFactor
721      */
722     setContentScaleFactor:function (scaleFactor) {
723         if (scaleFactor != this._contentScaleFactor) {
724             this._contentScaleFactor = scaleFactor;
725             this._winSizeInPixels = cc.size(this._winSizeInPoints.width * scaleFactor, this._winSizeInPoints.height * scaleFactor);
726 
727             if (this._openGLView) {
728                 this.updateContentScaleFactor();
729             }
730 
731             // update projection
732             this.setProjection(this._projection);
733         }
734     },
735 
736     /**
737      * enables/disables OpenGL depth test
738      * @param {Boolean} on
739      */
740     setDepthTest:function (on) {
741         if (on) {
742             /*TODO OpenGL Stuff
743              ccglClearDepth(1.0f);
744              glEnable(GL_DEPTH_TEST);
745              glDepthFunc(GL_LEQUAL);
746              //        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
747              }
748              else
749              {
750              glDisable(GL_DEPTH_TEST);*/
751         }
752         //CHECK_GL_ERROR_DEBUG();
753     },
754 
755     /**
756      * sets the OpenGL default values
757      */
758     setGLDefaultValues:function () {
759         // This method SHOULD be called only after openGLView_ was initialized
760         cc.Assert(this._openGLView, "opengl view should not be null");
761 
762         this.setAlphaBlending(true);
763         this.setDepthTest(true);
764         this.setProjection(this._projection);
765 
766         // set other opengl default values
767         //TODO OpenGl
768         //glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
769     },
770 
771     /**
772      * set next delta time is zero
773      * @param {Boolean} nextDeltaTimeZero
774      */
775     setNextDeltaTimeZero:function (nextDeltaTimeZero) {
776         this._nextDeltaTimeZero = nextDeltaTimeZero;
777     },
778 
779     /**
780      * set next scene
781      */
782     setNextScene:function () {
783         var runningIsTransition = this._runningScene ? this._runningScene instanceof cc.TransitionScene : false;
784 
785         var newIsTransition = this._nextScene ? this._nextScene instanceof cc.TransitionScene : false;
786 
787         // If it is not a transition, call onExit/cleanup
788         if (!newIsTransition) {
789             if (this._runningScene) {
790                 this._runningScene.onExit();
791             }
792 
793             // issue #709. the root node (scene) should receive the cleanup message too
794             // otherwise it might be leaked.
795             if (this._sendCleanupToScene && this._runningScene) {
796                 this._runningScene.cleanup();
797             }
798         }
799 
800         this._runningScene = this._nextScene;
801 
802         this._nextScene = null;
803         if ((!runningIsTransition) && (this._runningScene != null)) {
804             this._runningScene.onEnter();
805             this._runningScene.onEnterTransitionDidFinish();
806         }
807     },
808 
809     /**
810      * set Notification Node
811      * @param {cc.Node} node
812      */
813     setNotificationNode:function (node) {
814         this._notificationNode = node;
815     },
816 
817     /**
818      * Set the CCEGLView, where everything is rendered
819      * @param {*} openGLView
820      */
821     setOpenGLView:function (openGLView) {
822         cc.Assert(openGLView, "opengl view should not be null");
823 
824         if (this._openGLView != openGLView) {
825             // because EAGLView is not kind of CCObject
826             delete this._openGLView; // [openGLView_ release]
827             this._openGLView = openGLView;
828 
829             // set size
830             this._winSizeInPoints = this._openGLView.getSize();
831             this._winSizeInPixels = cc.size(this._winSizeInPoints.width * this._contentScaleFactor, this._winSizeInPoints.height * this._contentScaleFactor);
832 
833             this._createStatsLabel();
834 
835             if (this._openGLView) {
836                 this.setGLDefaultValues();
837             }
838 
839             //CHECK_GL_ERROR_DEBUG();
840 
841             if (this._contentScaleFactor != 1) {
842                 this.updateContentScaleFactor();
843             }
844 
845             this._openGLView.setTouchDelegate(this._touchDispatcher);
846             this._touchDispatcher.setDispatchEvents(true);
847         }
848     },
849 
850     /**
851      * Sets an OpenGL projection
852      * @param {Number} projection
853      */
854     setProjection:function (projection) {
855         var size = this._winSizeInPixels;
856         var sizePoint = this._winSizeInPoints;
857 
858         if (this._openGLView) {
859             this._openGLView.setViewPortInPoints(0, 0, sizePoint.width, sizePoint.height);
860         }
861 
862         switch (projection) {
863             case cc.DIRECTOR_PROJECTION_2D:
864                 //TODO OpenGL
865                 /* kmGLMatrixMode(KM_GL_PROJECTION);
866                  kmGLLoadIdentity();
867                  kmMat4 orthoMatrix;
868                  kmMat4OrthographicProjection(&orthoMatrix, 0, size.width / CC_CONTENT_SCALE_FACTOR(), 0, size.height / CC_CONTENT_SCALE_FACTOR(), -1024, 1024 );
869                  kmGLMultMatrix(&orthoMatrix);
870                  kmGLMatrixMode(KM_GL_MODELVIEW);
871                  kmGLLoadIdentity();*/
872                 break;
873             case cc.DIRECTOR_PROJECTION_3D:
874                 //TODO OpenGl
875                 /* float zeye = this->getZEye();
876 
877                  kmMat4 matrixPerspective, matrixLookup;
878 
879                  kmGLMatrixMode(KM_GL_PROJECTION);
880                  kmGLLoadIdentity();
881 
882                  // issue #1334
883                  kmMat4PerspectiveProjection( &matrixPerspective, 60, (GLfloat)size.width/size.height, 0.1f, zeye*2);
884                  // kmMat4PerspectiveProjection( &matrixPerspective, 60, (GLfloat)size.width/size.height, 0.1f, 1500);
885 
886                  kmGLMultMatrix(&matrixPerspective);
887 
888                  kmGLMatrixMode(KM_GL_MODELVIEW);
889                  kmGLLoadIdentity();
890                  kmVec3 eye, center, up;
891                  kmVec3Fill( &eye, sizePoint.width/2, sizePoint.height/2, zeye );
892                  kmVec3Fill( ¢er, sizePoint.width/2, sizePoint.height/2, 0.0f );
893                  kmVec3Fill( &up, 0.0f, 1.0f, 0.0f);
894                  kmMat4LookAt(&matrixLookup, &eye, ¢er, &up);
895                  kmGLMultMatrix(&matrixLookup);*/
896                 break;
897             case cc.DIRECTOR_PROJECTION_CUSTOM:
898                 if (this._projectionDelegate) {
899                     this._projectionDelegate.updateProjection();
900                 }
901                 break;
902 
903             default:
904                 cc.log("cocos2d: Director: unrecognized projection");
905                 break;
906         }
907 
908         this._projection = projection;
909         //ccSetProjectionMatrixDirty();
910     },
911 
912     /**
913      * shows the FPS in the screen
914      */
915     _showStats:function () {
916         this._frames++;
917         this._accumDt += this._deltaTime;
918         if (this._displayStats) {
919             if (this._FPSLabel && this._SPFLabel && this._drawsLabel) {
920                 if (this._accumDt > cc.DIRECTOR_FPS_INTERVAL) {
921                     this._SPFLabel.setString(this._secondsPerFrame.toFixed(3));
922 
923                     this._frameRate = this._frames / this._accumDt;
924                     this._frames = 0;
925                     this._accumDt = 0;
926 
927                     this._FPSLabel.setString(this._frameRate.toFixed(1));
928                     this._drawsLabel.setString((0 | cc.g_NumberOfDraws).toString());
929                 }
930                 this._FPSLabel.visit();
931                 this._SPFLabel.visit();
932                 this._drawsLabel.visit();
933             } else {
934                 this._createStatsLabel();
935             }
936         }
937         cc.g_NumberOfDraws = 0;
938     },
939 
940     /**
941      * update content scale factor
942      */
943     updateContentScaleFactor:function () {
944         // [openGLView responseToSelector:@selector(setContentScaleFactor)]
945         if (this._openGLView.canSetContentScaleFactor()) {
946             this._openGLView.setContentScaleFactor(this._contentScaleFactor);
947             this._isContentScaleSupported = true;
948         }
949         else {
950             cc.log("cocos2d: setContentScaleFactor:'is not supported on this device");
951         }
952     },
953 
954     /**
955      * <p>
956      *    Whether or not the replaced scene will receive the cleanup message.<br>
957      *    If the new scene is pushed, then the old scene won't receive the "cleanup" message.<br/>
958      *    If the new scene replaces the old one, the it will receive the "cleanup" message.
959      * </p>
960      * @return {Boolean}
961      */
962     isSendCleanupToScene:function () {
963         return this._sendCleanupToScene;
964     },
965 
966     /**
967      * Get current running Scene. Director can only run one Scene at the time
968      * @return {cc.Scene}
969      */
970     getRunningScene:function () {
971         return this._runningScene;
972     },
973 
974     /**
975      * Get the FPS value
976      * @return {Number}
977      */
978     getAnimationInterval:function () {
979         return this._animationInterval;
980     },
981 
982     /**
983      * Whether or not to display the FPS on the bottom-left corner
984      * @return {Boolean}
985      */
986     isDisplayStats:function () {
987         return this._displayStats;
988     },
989 
990     /**
991      * Display the FPS on the bottom-left corner
992      * @param displayFPS
993      */
994     setDisplayStats:function (displayStats) {
995         this._displayStats = displayStats;
996     },
997 
998     /**
999      * seconds per frame
1000      */
1001     getSecondsPerFrame:function () {
1002         return this._secondsPerFrame;
1003     },
1004 
1005     /**
1006      *  Get the CCEGLView, where everything is rendered
1007      * @return {*}
1008      */
1009     getOpenGLView:function () {
1010         return this._openGLView;
1011     },
1012 
1013     /**
1014      * is next delta time zero
1015      * @return {Boolean}
1016      */
1017     isNextDeltaTimeZero:function () {
1018         return this._nextDeltaTimeZero;
1019     },
1020 
1021     /**
1022      * Whether or not the Director is paused
1023      * @return {Boolean}
1024      */
1025     isPaused:function () {
1026         return this._paused;
1027     },
1028 
1029     /**
1030      * How many frames were called since the director started
1031      * @return {Number}
1032      */
1033     getTotalFrames:function () {
1034         return this._totalFrames;
1035     },
1036 
1037     /**
1038      * Sets an OpenGL projection
1039      * @return {Number}
1040      */
1041     getProjection:function () {
1042         return this._projection;
1043     },
1044 
1045     /**
1046      * <p>
1047      *     Pops out all scenes from the queue until the root scene in the queue. <br/>
1048      *     This scene will replace the running one.  <br/>
1049      *     The running scene will be deleted. If there are no more scenes in the stack the execution is terminated. <br/>
1050      *     ONLY call it if there is a running scene.
1051      * </p>
1052      */
1053     popToRootScene:function () {
1054         cc.Assert(this._runningScene != null, "A running Scene is needed");
1055         var c = this._scenesStack.length;
1056 
1057         if (c == 1) {
1058             this._scenesStack.pop();
1059             this.end();
1060         } else {
1061             while (c > 1) {
1062                 var current = this._scenesStack.pop();
1063                 if (current.isRunning()) {
1064                     current.onExit();
1065                 }
1066                 current.cleanup();
1067                 c--;
1068             }
1069             this._nextScene = this._scenesStack[this._scenesStack.length - 1];
1070             this._sendCleanupToScene = false;
1071         }
1072     },
1073 
1074     setWatcherCallbackFun:function (pSender, func) {
1075         this._watcherFun = func;
1076         this._watcherSender = pSender;
1077     },
1078 
1079     /**
1080      * (cc.Scheduler associated with this director)
1081      */
1082     getScheduler:function () {
1083         return this._scheduler;
1084     },
1085 
1086     setScheduler:function (scheduler) {
1087         if (this._scheduler != scheduler) {
1088             this._scheduler = scheduler;
1089         }
1090     },
1091 
1092     getActionManager:function () {
1093         return this._actionManager;
1094     },
1095     setActionManager:function (actionManager) {
1096         if (this._actionManager != actionManager) {
1097             this._actionManager = actionManager;
1098         }
1099     },
1100 
1101     getTouchDispatcher:function () {
1102         return this._touchDispatcher;
1103     },
1104     setTouchDispatcher:function (touchDispatcher) {
1105         if (this._touchDispatcher != touchDispatcher) {
1106             this._touchDispatcher = touchDispatcher;
1107         }
1108     },
1109 
1110     getKeyboardDispatcher:function () {
1111         return this._keyboardDispatcher;
1112     },
1113     setKeyboardDispatcher:function (keyboardDispatcher) {
1114         this._keyboardDispatcher = keyboardDispatcher;
1115     },
1116 
1117     getAccelerometer:function () {
1118         return this._accelerometer;
1119     },
1120     setAccelerometer:function (accelerometer) {
1121         if (this._accelerometer != accelerometer) {
1122             this._accelerometer = accelerometer;
1123         }
1124     },
1125 
1126     getMouseDispatcher:function(){
1127        return this._mouseDispatcher;
1128     },
1129 
1130     setMouseDispatcher:function( mouseDispatcher){
1131         if(this._mouseDispatcher != mouseDispatcher)
1132             this._mouseDispatcher = mouseDispatcher;
1133     },
1134 
1135     _createStatsLabel:function () {
1136         this._FPSLabel = cc.LabelTTF.create("00.0", "Arial", 18, cc.size(60, 16), cc.TEXT_ALIGNMENT_RIGHT);
1137         this._SPFLabel = cc.LabelTTF.create("0.000", "Arial", 18, cc.size(60, 16), cc.TEXT_ALIGNMENT_RIGHT);
1138         this._drawsLabel = cc.LabelTTF.create("000", "Arial", 18, cc.size(60, 16), cc.TEXT_ALIGNMENT_RIGHT);
1139 
1140         this._drawsLabel.setPosition(cc.pAdd(cc.p(20, 48), cc.DIRECTOR_STATS_POSITION));
1141         this._SPFLabel.setPosition(cc.pAdd(cc.p(20, 30), cc.DIRECTOR_STATS_POSITION));
1142         this._FPSLabel.setPosition(cc.pAdd(cc.p(20, 10), cc.DIRECTOR_STATS_POSITION));
1143     },
1144 
1145     _calculateMPF:function () {
1146         var now = cc.Time.gettimeofdayCocos2d();
1147 
1148         this._secondsPerFrame = (now.tv_sec - this._lastUpdate.tv_sec) + (now.tv_usec - this._lastUpdate.tv_usec) / 1000000.0;
1149     }
1150 });
1151 
1152 
1153 /***************************************************
1154  * implementation of DisplayLinkDirector
1155  **************************************************/
1156 // should we afford 4 types of director ??
1157 // I think DisplayLinkDirector is enough
1158 // so we now only support DisplayLinkDirector
1159 /**
1160  * <p>
1161  *   DisplayLinkDirector is a Director that synchronizes timers with the refresh rate of the display.<br/>
1162  *   Features and Limitations:<br/>
1163  *      - Scheduled timers & drawing are synchronizes with the refresh rate of the display<br/>
1164  *      - Only supports animation intervals of 1/60 1/30 & 1/15<br/>
1165  * </p>
1166  * @class
1167  * @extends cc.Director
1168  */
1169 cc.DisplayLinkDirector = cc.Director.extend(/** @lends cc.DisplayLinkDirector# */{
1170     invalid:false,
1171 
1172     /**
1173      * start Animation
1174      */
1175     startAnimation:function () {
1176         this._lastUpdate = cc.Time.gettimeofdayCocos2d();
1177         this.invalid = false;
1178         cc.Application.sharedApplication().setAnimationInterval(this._animationInterval);
1179     },
1180 
1181     /**
1182      * main loop of director
1183      */
1184     mainLoop:function () {
1185         if (this._purgeDirecotorInNextLoop) {
1186             this._purgeDirecotorInNextLoop = false;
1187             this.purgeDirector();
1188         }
1189         else if (!this.invalid) {
1190             this.drawScene();
1191         }
1192     },
1193 
1194     /**
1195      * stop animation
1196      */
1197     stopAnimation:function () {
1198         this.invalid = true;
1199     },
1200 
1201     /**
1202      * set Animation Interval
1203      * @param {Number} value
1204      */
1205     setAnimationInterval:function (value) {
1206         this._animationInterval = value;
1207         if (!this.invalid) {
1208             this.stopAnimation();
1209             this.startAnimation();
1210         }
1211     }
1212 });
1213 
1214 cc.s_SharedDirector = null;
1215 
1216 cc.firstUseDirector = true;
1217 
1218 /**
1219  * returns a shared instance of the director
1220  * @function
1221  * @return {cc.Director}
1222  */
1223 cc.Director.getInstance = function () {
1224     if (cc.firstUseDirector) {
1225         cc.firstUseDirector = false;
1226         cc.s_SharedDirector = new cc.DisplayLinkDirector();
1227         cc.s_SharedDirector.init();
1228     }
1229     return cc.s_SharedDirector;
1230 };
1231 
1232 /**
1233  * is director first run
1234  * @type Boolean
1235  */
1236 cc.firstRun = true;
1237 
1238 /**
1239  * set default fps to 60
1240  * @type Number
1241  */
1242 cc.defaultFPS = 60;
1243 
1244 /*
1245  window.onfocus = function () {
1246  if (!cc.firstRun) {
1247  cc.Director.getInstance().addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height));
1248  }
1249  };
1250  */
1251 
1252