CCDirector.js 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313
  1. /****************************************************************************
  2. Copyright (c) 2010-2012 cocos2d-x.org
  3. Copyright (c) 2008-2010 Ricardo Quesada
  4. Copyright (c) 2011 Zynga Inc.
  5. http://www.cocos2d-x.org
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12. The above copyright notice and this permission notice shall be included in
  13. all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. THE SOFTWARE.
  21. ****************************************************************************/
  22. cc.g_NumberOfDraws = 0;
  23. //Possible OpenGL projections used by director
  24. /**
  25. * sets a 2D projection (orthogonal projection)
  26. * @constant
  27. * @type Number
  28. */
  29. cc.DIRECTOR_PROJECTION_2D = 0;
  30. /**
  31. * sets a 3D projection with a fovy=60, znear=0.5f and zfar=1500.
  32. * @constant
  33. * @type Number
  34. */
  35. cc.DIRECTOR_PROJECTION_3D = 1;
  36. /**
  37. * it calls "updateProjection" on the projection delegate.
  38. * @constant
  39. * @type Number
  40. */
  41. cc.DIRECTOR_PROJECTION_CUSTOM = 3;
  42. /**
  43. * Default projection is 3D projection
  44. * @constant
  45. * @type Number
  46. */
  47. cc.DIRECTOR_PROJECTION_DEFAULT = cc.DIRECTOR_PROJECTION_3D;
  48. //----------------------------------------------------------------------------------------------------------------------
  49. //Possible device orientations
  50. /**
  51. * Device oriented vertically, home button on the bottom (UIDeviceOrientationPortrait)
  52. * @constant
  53. * @type Number
  54. */
  55. cc.DEVICE_ORIENTATION_PORTRAIT = 0;
  56. /**
  57. * Device oriented horizontally, home button on the right (UIDeviceOrientationLandscapeLeft)
  58. * @constant
  59. * @type Number
  60. */
  61. cc.DEVICE_ORIENTATION_LANDSCAPE_LEFT = 1;
  62. /**
  63. * Device oriented vertically, home button on the top (UIDeviceOrientationPortraitUpsideDown)
  64. * @constant
  65. * @type Number
  66. */
  67. cc.DEVICE_ORIENTATION_PORTRAIT_UPSIDE_DOWN = 2;
  68. /**
  69. * Device oriented horizontally, home button on the left (UIDeviceOrientationLandscapeRight)
  70. * @constant
  71. * @type Number
  72. */
  73. cc.DEVICE_ORIENTATION_LANDSCAPE_RIGHT = 3;
  74. /**
  75. * In browsers, we only support 2 orientations by change window size.
  76. * @constant
  77. * @type Number
  78. */
  79. cc.DEVICE_MAX_ORIENTATIONS = 2;
  80. /**
  81. * OpenGL projection protocol
  82. * @class
  83. * @extends cc.Class
  84. */
  85. cc.DirectorDelegate = cc.Class.extend(/** @lends cc.DirectorDelegate# */{
  86. /**
  87. * Called by CCDirector when the projection is updated, and "custom" projection is used
  88. */
  89. updateProjection:function () {
  90. }
  91. });
  92. cc.GLToClipTransform = function (transformOut) {
  93. var projection = new cc.kmMat4();
  94. cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, projection);
  95. var modelview = new cc.kmMat4();
  96. cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, modelview);
  97. cc.kmMat4Multiply(transformOut, projection, modelview);
  98. };
  99. //----------------------------------------------------------------------------------------------------------------------
  100. /**
  101. * <p>
  102. * Class that creates and handle the main Window and manages how<br/>
  103. * and when to execute the Scenes.<br/>
  104. * <br/>
  105. * The cc.Director is also responsible for:<br/>
  106. * - initializing the OpenGL context<br/>
  107. * - setting the OpenGL pixel format (default on is RGB565)<br/>
  108. * - setting the OpenGL pixel format (default on is RGB565)<br/>
  109. * - setting the OpenGL buffer depth (default one is 0-bit)<br/>
  110. * - setting the projection (default one is 3D)<br/>
  111. * - setting the orientation (default one is Protrait)<br/>
  112. * <br/>
  113. * Since the cc.Director is a singleton, the standard way to use it is by calling:<br/>
  114. * - cc.Director.getInstance().methodName(); <br/>
  115. * <br/>
  116. * The CCDirector also sets the default OpenGL context:<br/>
  117. * - GL_TEXTURE_2D is enabled<br/>
  118. * - GL_VERTEX_ARRAY is enabled<br/>
  119. * - GL_COLOR_ARRAY is enabled<br/>
  120. * - GL_TEXTURE_COORD_ARRAY is enabled<br/>
  121. * </p>
  122. * @class
  123. * @extends cc.Class
  124. */
  125. cc.Director = cc.Class.extend(/** @lends cc.Director# */{
  126. //Variables
  127. _landscape:false,
  128. _nextDeltaTimeZero:false,
  129. _paused:false,
  130. _purgeDirecotorInNextLoop:false,
  131. _sendCleanupToScene:false,
  132. _animationInterval:0.0,
  133. _oldAnimationInterval:0.0,
  134. _projection:0,
  135. _accumDt:0.0,
  136. _contentScaleFactor:1.0,
  137. _displayStats:false,
  138. _deltaTime:0.0,
  139. _frameRate:0.0,
  140. _FPSLabel:null,
  141. _SPFLabel:null,
  142. _drawsLabel:null,
  143. _winSizeInPoints:null,
  144. _lastUpdate:null,
  145. _nextScene:null,
  146. _notificationNode:null,
  147. _openGLView:null,
  148. _scenesStack:null,
  149. _projectionDelegate:null,
  150. _runningScene:null,
  151. _frames:0,
  152. _totalFrames:0,
  153. _secondsPerFrame:0,
  154. _dirtyRegion:null,
  155. _scheduler:null,
  156. _actionManager:null,
  157. _touchDispatcher:null,
  158. _keyboardDispatcher:null,
  159. _accelerometer:null,
  160. _mouseDispatcher:null,
  161. _isBlur:false,
  162. /**
  163. * Constructor
  164. */
  165. ctor:function () {
  166. this._lastUpdate = Date.now();
  167. if (!cc.isAddedHiddenEvent) {
  168. var selfPointer = this;
  169. window.addEventListener("focus", function () {
  170. selfPointer._lastUpdate = Date.now();
  171. }, false);
  172. }
  173. },
  174. _resetLastUpdate:function () {
  175. this._lastUpdate = Date.now();
  176. },
  177. /**
  178. * initializes cc.Director
  179. * @return {Boolean}
  180. */
  181. init:function () {
  182. // scenes
  183. this._oldAnimationInterval = this._animationInterval = 1.0 / cc.defaultFPS;
  184. this._scenesStack = [];
  185. // Set default projection (3D)
  186. this._projection = cc.DIRECTOR_PROJECTION_DEFAULT;
  187. // projection delegate if "Custom" projection is used
  188. this._projectionDelegate = null;
  189. //FPS
  190. this._accumDt = 0;
  191. this._frameRate = 0;
  192. this._displayStats = false;//can remove
  193. this._totalFrames = this._frames = 0;
  194. this._lastUpdate = Date.now();
  195. //Paused?
  196. this._paused = false;
  197. //purge?
  198. this._purgeDirecotorInNextLoop = false;
  199. this._winSizeInPoints = cc.size(0, 0);
  200. this._openGLView = null;
  201. this._contentScaleFactor = 1.0;
  202. //scheduler
  203. this._scheduler = new cc.Scheduler();
  204. //action manager
  205. this._actionManager = new cc.ActionManager();
  206. this._scheduler.scheduleUpdateForTarget(this._actionManager, cc.PRIORITY_SYSTEM, false);
  207. //touchDispatcher
  208. if(cc.TouchDispatcher){
  209. this._touchDispatcher = new cc.TouchDispatcher();
  210. this._touchDispatcher.init();
  211. }
  212. //KeyboardDispatcher
  213. if(cc.KeyboardDispatcher)
  214. this._keyboardDispatcher = cc.KeyboardDispatcher.getInstance();
  215. //accelerometer
  216. if(cc.Accelerometer)
  217. this._accelerometer = new cc.Accelerometer();
  218. //MouseDispatcher
  219. if(cc.MouseDispatcher){
  220. this._mouseDispatcher = new cc.MouseDispatcher();
  221. this._mouseDispatcher.init();
  222. }
  223. return true;
  224. },
  225. /**
  226. * calculates delta time since last time it was called
  227. */
  228. calculateDeltaTime:function () {
  229. var now = Date.now();
  230. // new delta time.
  231. if (this._nextDeltaTimeZero) {
  232. this._deltaTime = 0;
  233. this._nextDeltaTimeZero = false;
  234. } else {
  235. this._deltaTime = (now - this._lastUpdate) / 1000;
  236. }
  237. if ((cc.COCOS2D_DEBUG > 0) && (this._deltaTime > 0.2))
  238. this._deltaTime = 1 / 60.0;
  239. this._lastUpdate = now;
  240. },
  241. /**
  242. * <p>
  243. * converts a UIKit coordinate to an OpenGL coordinate<br/>
  244. * Useful to convert (multi) touches coordinates to the current layout (portrait or landscape)
  245. * </p>
  246. * @param {cc.Point} uiPoint
  247. * @return {cc.Point}
  248. */
  249. convertToGL:function (uiPoint) {
  250. var transform = new cc.kmMat4();
  251. cc.GLToClipTransform(transform);
  252. var transformInv = new cc.kmMat4();
  253. cc.kmMat4Inverse(transformInv, transform);
  254. // Calculate z=0 using -> transform*[0, 0, 0, 1]/w
  255. var zClip = transform.mat[14] / transform.mat[15];
  256. var glSize = this._openGLView.getDesignResolutionSize();
  257. var clipCoord = new cc.kmVec3(2.0 * uiPoint.x / glSize.width - 1.0, 1.0 - 2.0 * uiPoint.y / glSize.height, zClip);
  258. var glCoord = new cc.kmVec3();
  259. cc.kmVec3TransformCoord(glCoord, clipCoord, transformInv);
  260. return cc.p(glCoord.x, glCoord.y);
  261. },
  262. /**
  263. * <p>converts an OpenGL coordinate to a UIKit coordinate<br/>
  264. * Useful to convert node points to window points for calls such as glScissor</p>
  265. * @param {cc.Point} glPoint
  266. * @return {cc.Point}
  267. */
  268. convertToUI:function (glPoint) {
  269. var transform = new cc.kmMat4();
  270. cc.GLToClipTransform(transform);
  271. var clipCoord = new cc.kmVec3();
  272. // Need to calculate the zero depth from the transform.
  273. var glCoord = new cc.kmVec3(glPoint.x, glPoint.y, 0.0);
  274. cc.kmVec3TransformCoord(clipCoord, glCoord, transform);
  275. var glSize = this._openGLView.getDesignResolutionSize();
  276. return cc.p(glSize.width * (clipCoord.x * 0.5 + 0.5), glSize.height * (-clipCoord.y * 0.5 + 0.5));
  277. },
  278. /**
  279. * Draw the scene. This method is called every frame. Don't call it manually.
  280. */
  281. drawScene: function() {
  282. // calculate "global" dt
  283. this.calculateDeltaTime();
  284. //tick before glClear: issue #533
  285. if (!this._paused)
  286. this._scheduler.update(this._deltaTime);
  287. this._clear();
  288. /* to avoid flickr, nextScene MUST be here: after tick and before draw.
  289. XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */
  290. if (this._nextScene) {
  291. this.setNextScene();
  292. }
  293. if (this._beforeVisitScene) this._beforeVisitScene();
  294. // draw the scene
  295. if (this._runningScene)
  296. this._runningScene.visit();
  297. // draw the notifications node
  298. if (this._notificationNode)
  299. this._notificationNode.visit();
  300. if (this._displayStats)
  301. this._showStats();
  302. if (this._afterVisitScene) this._afterVisitScene();
  303. this._totalFrames++;
  304. if (this._displayStats)
  305. this._calculateMPF();
  306. },
  307. _clearCanvas: function() {
  308. var viewport = this._openGLView.getViewPortRect();
  309. cc.renderContext.clearRect(-viewport.x, viewport.y, viewport.width, -viewport.height);
  310. },
  311. _clearWebGL: function() {
  312. var gl = cc.renderContext;
  313. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  314. },
  315. _beforeVisitScene: null,
  316. _afterVisitScene: null,
  317. _beforeVisitSceneWebGL: function() {
  318. cc.kmGLPushMatrix();
  319. },
  320. _afterVisitSceneWebGL: function() {
  321. cc.kmGLPopMatrix();
  322. },
  323. /**
  324. * end director
  325. */
  326. end:function () {
  327. this._purgeDirecotorInNextLoop = true;
  328. },
  329. /**
  330. * <p>get the size in pixels of the surface. It could be different than the screen size.<br/>
  331. * High-res devices might have a higher surface size than the screen size.<br/>
  332. * Only available when compiled using SDK >= 4.0.
  333. * </p>
  334. * @return {Number}
  335. */
  336. getContentScaleFactor:function () {
  337. return this._contentScaleFactor;
  338. },
  339. /**
  340. * <p>
  341. * This object will be visited after the main scene is visited.<br/>
  342. * This object MUST implement the "visit" selector.<br/>
  343. * Useful to hook a notification object, like CCNotifications (http://github.com/manucorporat/CCNotifications)
  344. * </p>
  345. * @return {cc.Node}
  346. */
  347. getNotificationNode:function () {
  348. return this._notificationNode;
  349. },
  350. /**
  351. * <p>
  352. * returns the size of the OpenGL view in points.<br/>
  353. * It takes into account any possible rotation (device orientation) of the window
  354. * </p>
  355. * @return {cc.Size}
  356. */
  357. getWinSize:function () {
  358. return cc.size(this._winSizeInPoints);
  359. },
  360. /**
  361. * <p>
  362. * returns the size of the OpenGL view in pixels.<br/>
  363. * It takes into account any possible rotation (device orientation) of the window.<br/>
  364. * On Mac winSize and winSizeInPixels return the same value.
  365. * </p>
  366. * @return {cc.Size}
  367. */
  368. getWinSizeInPixels:function () {
  369. return cc.size(this._winSizeInPoints.width * this._contentScaleFactor, this._winSizeInPoints.height * this._contentScaleFactor);
  370. },
  371. getVisibleSize:function () {
  372. if (this._openGLView) {
  373. return this._openGLView.getVisibleSize();
  374. } else {
  375. return this.getWinSize();
  376. }
  377. },
  378. getVisibleOrigin:function () {
  379. if (this._openGLView) {
  380. return this._openGLView.getVisibleOrigin();
  381. } else {
  382. return cc.POINT_ZERO;
  383. }
  384. },
  385. getZEye:function () {
  386. return (this._winSizeInPoints.height / 1.1566 );
  387. },
  388. /**
  389. * pause director
  390. */
  391. pause:function () {
  392. if (this._paused)
  393. return;
  394. this._oldAnimationInterval = this._animationInterval;
  395. // when paused, don't consume CPU
  396. this.setAnimationInterval(1 / 4.0);
  397. this._paused = true;
  398. },
  399. /**
  400. * <p>
  401. * Pops out a scene from the queue.<br/>
  402. * This scene will replace the running one.<br/>
  403. * The running scene will be deleted. If there are no more scenes in the stack the execution is terminated.<br/>
  404. * ONLY call it if there is a running scene.
  405. * </p>
  406. */
  407. popScene:function () {
  408. if(!this._runningScene)
  409. throw "running scene should not null";
  410. //this.addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height));
  411. this._scenesStack.pop();
  412. var c = this._scenesStack.length;
  413. if (c == 0)
  414. this.end();
  415. else {
  416. this._sendCleanupToScene = true;
  417. this._nextScene = this._scenesStack[c - 1];
  418. }
  419. },
  420. /**
  421. * Removes cached all cocos2d cached data. It will purge the CCTextureCache, CCSpriteFrameCache, CCLabelBMFont cache
  422. */
  423. purgeCachedData:function () {
  424. cc.LabelBMFont.purgeCachedData();
  425. //cc.TextureCache.getInstance().removeUnusedTextures();
  426. },
  427. /**
  428. * purge Director
  429. */
  430. purgeDirector:function () {
  431. //cleanup scheduler
  432. this.getScheduler().unscheduleAllCallbacks();
  433. // don't release the event handlers
  434. // They are needed in case the director is run again
  435. if(this._touchDispatcher)this._touchDispatcher.removeAllDelegates();
  436. if (this._runningScene) {
  437. this._runningScene.onExitTransitionDidStart();
  438. this._runningScene.onExit();
  439. this._runningScene.cleanup();
  440. }
  441. this._runningScene = null;
  442. this._nextScene = null;
  443. // remove all objects, but don't release it.
  444. // runWithScene might be executed after 'end'.
  445. this._scenesStack.length = 0;
  446. this.stopAnimation();
  447. // purge bitmap cache
  448. cc.LabelBMFont.purgeCachedData();
  449. // purge all managers
  450. cc.AnimationCache.purgeSharedAnimationCache();
  451. cc.SpriteFrameCache.purgeSharedSpriteFrameCache();
  452. cc.TextureCache.purgeSharedTextureCache();
  453. //CCShaderCache::purgeSharedShaderCache();
  454. //CCFileUtils::purgeFileUtils();
  455. //CCConfiguration::purgeConfiguration();
  456. //extension::CCNotificationCenter::purgeNotificationCenter();
  457. //extension::CCTextureWatcher::purgeTextureWatcher();
  458. //extension::CCNodeLoaderLibrary::purgeSharedCCNodeLoaderLibrary();
  459. //cc.UserDefault.purgeSharedUserDefault();
  460. //ccGLInvalidateStateCache();
  461. cc.CHECK_GL_ERROR_DEBUG();
  462. // OpenGL view
  463. //this._openGLView.end();
  464. //this._openGLView = null;
  465. },
  466. /**
  467. * <p>
  468. * Suspends the execution of the running scene, pushing it on the stack of suspended scenes.<br/>
  469. * The new scene will be executed.<br/>
  470. * Try to avoid big stacks of pushed scenes to reduce memory allocation.<br/>
  471. * ONLY call it if there is a running scene.
  472. * </p>
  473. * @param {cc.Scene} scene
  474. */
  475. pushScene:function (scene) {
  476. if(!scene)
  477. throw "the scene should not null";
  478. this._sendCleanupToScene = false;
  479. this._scenesStack.push(scene);
  480. this._nextScene = scene;
  481. },
  482. /**
  483. * Replaces the running scene with a new one. The running scene is terminated. ONLY call it if there is a running scene.
  484. * @param {cc.Scene} scene
  485. */
  486. replaceScene:function (scene) {
  487. if(!this._runningScene)
  488. throw "Use runWithScene: instead to start the director";
  489. if(!scene)
  490. throw "the scene should not be null";
  491. var i = this._scenesStack.length;
  492. if(i === 0){
  493. this._sendCleanupToScene = true;
  494. this._scenesStack[i] = scene;
  495. this._nextScene = scene;
  496. } else {
  497. this._sendCleanupToScene = true;
  498. this._scenesStack[i - 1] = scene;
  499. this._nextScene = scene;
  500. }
  501. },
  502. /**
  503. * resume director
  504. */
  505. resume:function () {
  506. if (!this._paused) {
  507. return;
  508. }
  509. this.setAnimationInterval(this._oldAnimationInterval);
  510. this._lastUpdate = Date.now();
  511. if (!this._lastUpdate) {
  512. cc.log("cocos2d: Director: Error in gettimeofday");
  513. }
  514. this._paused = false;
  515. this._deltaTime = 0;
  516. },
  517. /**
  518. * <p>
  519. * Enters the Director's main loop with the given Scene.<br/>
  520. * Call it to run only your FIRST scene.<br/>
  521. * Don't call it if there is already a running scene.
  522. * </p>
  523. * @param {cc.Scene} scene
  524. */
  525. runWithScene:function (scene) {
  526. if(!scene)
  527. throw "This command can only be used to start the CCDirector. There is already a scene present.";
  528. if(this._runningScene)
  529. throw "_runningScene should be null";
  530. this.pushScene(scene);
  531. this.startAnimation();
  532. },
  533. /**
  534. * enables/disables OpenGL alpha blending
  535. * @param {Boolean} on
  536. */
  537. setAlphaBlending:function (on) {
  538. if (on)
  539. cc.glBlendFunc(cc.BLEND_SRC, cc.BLEND_DST);
  540. else
  541. cc.glBlendFunc(cc.renderContext.ONE, cc.renderContext.ZERO);
  542. //cc.CHECK_GL_ERROR_DEBUG();
  543. },
  544. /**
  545. * <p>
  546. * The size in pixels of the surface. It could be different than the screen size.<br/>
  547. * High-res devices might have a higher surface size than the screen size.<br/>
  548. * Only available when compiled using SDK >= 4.0.
  549. * </p>
  550. * @param {Number} scaleFactor
  551. */
  552. setContentScaleFactor:function (scaleFactor) {
  553. if (scaleFactor != this._contentScaleFactor) {
  554. this._contentScaleFactor = scaleFactor;
  555. this._createStatsLabel();
  556. }
  557. },
  558. /**
  559. * enables/disables OpenGL depth test
  560. * @param {Boolean} on
  561. */
  562. setDepthTest:function (on) {
  563. if(cc.renderContextType === cc.CANVAS)
  564. return;
  565. var loc_gl= cc.renderContext;
  566. if (on) {
  567. loc_gl.clearDepth(1.0);
  568. loc_gl.enable(loc_gl.DEPTH_TEST);
  569. loc_gl.depthFunc(loc_gl.LEQUAL);
  570. //cc.renderContext.hint(cc.renderContext.PERSPECTIVE_CORRECTION_HINT, cc.renderContext.NICEST);
  571. } else {
  572. loc_gl.disable(loc_gl.DEPTH_TEST);
  573. }
  574. //cc.CHECK_GL_ERROR_DEBUG();
  575. },
  576. /**
  577. * sets the default values based on the CCConfiguration info
  578. */
  579. setDefaultValues:function(){
  580. },
  581. /**
  582. * sets the OpenGL default values
  583. */
  584. setGLDefaultValues:function () {
  585. this.setAlphaBlending(true);
  586. // XXX: Fix me, should enable/disable depth test according the depth format as cocos2d-iphone did
  587. // [self setDepthTest: view_.depthFormat];
  588. this.setDepthTest(false);
  589. this.setProjection(this._projection);
  590. // set other opengl default values
  591. cc.renderContext.clearColor(0.0, 0.0, 0.0, 1.0);
  592. },
  593. /**
  594. * set next delta time is zero
  595. * @param {Boolean} nextDeltaTimeZero
  596. */
  597. setNextDeltaTimeZero:function (nextDeltaTimeZero) {
  598. this._nextDeltaTimeZero = nextDeltaTimeZero;
  599. },
  600. /**
  601. * set next scene
  602. */
  603. setNextScene:function () {
  604. var runningIsTransition = false, newIsTransition = false;
  605. if(cc.TransitionScene){
  606. runningIsTransition = this._runningScene ? this._runningScene instanceof cc.TransitionScene : false;
  607. newIsTransition = this._nextScene ? this._nextScene instanceof cc.TransitionScene : false;
  608. }
  609. // If it is not a transition, call onExit/cleanup
  610. if (!newIsTransition) {
  611. var locRunningScene = this._runningScene;
  612. if (locRunningScene) {
  613. locRunningScene.onExitTransitionDidStart();
  614. locRunningScene.onExit();
  615. }
  616. // issue #709. the root node (scene) should receive the cleanup message too
  617. // otherwise it might be leaked.
  618. if (this._sendCleanupToScene && locRunningScene)
  619. locRunningScene.cleanup();
  620. }
  621. this._runningScene = this._nextScene;
  622. this._nextScene = null;
  623. if ((!runningIsTransition) && (this._runningScene != null)) {
  624. this._runningScene.onEnter();
  625. this._runningScene.onEnterTransitionDidFinish();
  626. }
  627. },
  628. /**
  629. * set Notification Node
  630. * @param {cc.Node} node
  631. */
  632. setNotificationNode:function (node) {
  633. this._notificationNode = node;
  634. },
  635. /**
  636. * CCDirector delegate. It shall implemente the CCDirectorDelegate protocol
  637. * @return {cc.DirectorDelegate}
  638. */
  639. getDelegate:function () {
  640. return this._projectionDelegate;
  641. },
  642. setDelegate:function (delegate) {
  643. this._projectionDelegate = delegate;
  644. },
  645. /**
  646. * Set the CCEGLView, where everything is rendered
  647. * @param {*} openGLView
  648. */
  649. setOpenGLView:function (openGLView) {
  650. // set size
  651. this._winSizeInPoints.width = cc.canvas.width; //this._openGLView.getDesignResolutionSize();
  652. this._winSizeInPoints.height = cc.canvas.height;
  653. this._openGLView = openGLView || cc.EGLView.getInstance();
  654. if (cc.renderContextType === cc.CANVAS)
  655. return;
  656. // Configuration. Gather GPU info
  657. var conf = cc.Configuration.getInstance();
  658. conf.gatherGPUInfo();
  659. conf.dumpInfo();
  660. // set size
  661. //this._winSizeInPoints = this._openGLView.getDesignResolutionSize();
  662. //this._winSizeInPixels = cc.size(this._winSizeInPoints.width * this._contentScaleFactor, this._winSizeInPoints.height * this._contentScaleFactor);
  663. //if (this._openGLView != openGLView) {
  664. // because EAGLView is not kind of CCObject
  665. this._createStatsLabel();
  666. //if (this._openGLView)
  667. this.setGLDefaultValues();
  668. /* if (this._contentScaleFactor != 1) {
  669. this.updateContentScaleFactor();
  670. }*/
  671. if(this._touchDispatcher)this._touchDispatcher.setDispatchEvents(true);
  672. //}
  673. },
  674. /**
  675. * Sets the glViewport
  676. */
  677. setViewport:function(){
  678. if(this._openGLView) {
  679. var locWinSizeInPoints = this._winSizeInPoints;
  680. this._openGLView.setViewPortInPoints(0,0, locWinSizeInPoints.width, locWinSizeInPoints.height);
  681. }
  682. },
  683. /**
  684. * Sets an OpenGL projection
  685. * @param {Number} projection
  686. */
  687. setProjection:function (projection) {
  688. var size = this._winSizeInPoints;
  689. if(cc.renderContextType === cc.WEBGL){
  690. this.setViewport();
  691. switch (projection) {
  692. case cc.DIRECTOR_PROJECTION_2D:
  693. cc.kmGLMatrixMode(cc.KM_GL_PROJECTION);
  694. cc.kmGLLoadIdentity();
  695. var orthoMatrix = new cc.kmMat4();
  696. cc.kmMat4OrthographicProjection(orthoMatrix, 0, size.width, 0, size.height, -1024, 1024);
  697. cc.kmGLMultMatrix(orthoMatrix);
  698. cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW);
  699. cc.kmGLLoadIdentity();
  700. break;
  701. case cc.DIRECTOR_PROJECTION_3D:
  702. var zeye = this.getZEye();
  703. var matrixPerspective = new cc.kmMat4(), matrixLookup = new cc.kmMat4();
  704. cc.kmGLMatrixMode(cc.KM_GL_PROJECTION);
  705. cc.kmGLLoadIdentity();
  706. // issue #1334
  707. cc.kmMat4PerspectiveProjection(matrixPerspective, 60, size.width / size.height, 0.1, zeye * 2);
  708. // kmMat4PerspectiveProjection( &matrixPerspective, 60, (GLfloat)size.width/size.height, 0.1f, 1500);
  709. cc.kmGLMultMatrix(matrixPerspective);
  710. cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW);
  711. cc.kmGLLoadIdentity();
  712. var eye = cc.kmVec3Fill(null, size.width / 2, size.height / 2, zeye);
  713. var center = cc.kmVec3Fill(null, size.width / 2, size.height / 2, 0.0);
  714. var up = cc.kmVec3Fill(null, 0.0, 1.0, 0.0);
  715. cc.kmMat4LookAt(matrixLookup, eye, center, up);
  716. cc.kmGLMultMatrix(matrixLookup);
  717. break;
  718. case cc.DIRECTOR_PROJECTION_CUSTOM:
  719. if (this._projectionDelegate)
  720. this._projectionDelegate.updateProjection();
  721. break;
  722. default:
  723. cc.log("cocos2d: Director: unrecognized projection");
  724. break;
  725. }
  726. this._projection = projection;
  727. cc.setProjectionMatrixDirty();
  728. return;
  729. }
  730. this._projection = projection;
  731. },
  732. /**
  733. * shows the FPS in the screen
  734. */
  735. _showStats: function () {
  736. this._frames++;
  737. this._accumDt += this._deltaTime;
  738. if (this._FPSLabel && this._SPFLabel && this._drawsLabel) {
  739. if (this._accumDt > cc.DIRECTOR_FPS_INTERVAL) {
  740. this._SPFLabel.setString(this._secondsPerFrame.toFixed(3));
  741. this._frameRate = this._frames / this._accumDt;
  742. this._frames = 0;
  743. this._accumDt = 0;
  744. this._FPSLabel.setString(this._frameRate.toFixed(1));
  745. this._drawsLabel.setString((0 | cc.g_NumberOfDraws).toString());
  746. }
  747. this._FPSLabel.visit();
  748. this._SPFLabel.visit();
  749. this._drawsLabel.visit();
  750. } else
  751. this._createStatsLabel();
  752. cc.g_NumberOfDraws = 0;
  753. },
  754. /**
  755. * <p>
  756. * Whether or not the replaced scene will receive the cleanup message.<br>
  757. * If the new scene is pushed, then the old scene won't receive the "cleanup" message.<br/>
  758. * If the new scene replaces the old one, the it will receive the "cleanup" message.
  759. * </p>
  760. * @return {Boolean}
  761. */
  762. isSendCleanupToScene:function () {
  763. return this._sendCleanupToScene;
  764. },
  765. /**
  766. * Get current running Scene. Director can only run one Scene at the time
  767. * @return {cc.Scene}
  768. */
  769. getRunningScene:function () {
  770. return this._runningScene;
  771. },
  772. /**
  773. * Get the FPS value
  774. * @return {Number}
  775. */
  776. getAnimationInterval:function () {
  777. return this._animationInterval;
  778. },
  779. /**
  780. * Whether or not to display the FPS on the bottom-left corner
  781. * @return {Boolean}
  782. */
  783. isDisplayStats:function () {
  784. return this._displayStats;
  785. },
  786. /**
  787. * Display the FPS on the bottom-left corner
  788. * @param {Boolean} displayStats
  789. */
  790. setDisplayStats:function (displayStats) {
  791. this._displayStats = displayStats;
  792. },
  793. /**
  794. * seconds per frame
  795. * @return {Number}
  796. */
  797. getSecondsPerFrame:function () {
  798. return this._secondsPerFrame;
  799. },
  800. /**
  801. * Get the CCEGLView, where everything is rendered
  802. * @return {*}
  803. */
  804. getOpenGLView:function () {
  805. return this._openGLView;
  806. },
  807. /**
  808. * is next delta time zero
  809. * @return {Boolean}
  810. */
  811. isNextDeltaTimeZero:function () {
  812. return this._nextDeltaTimeZero;
  813. },
  814. /**
  815. * Whether or not the Director is paused
  816. * @return {Boolean}
  817. */
  818. isPaused:function () {
  819. return this._paused;
  820. },
  821. /**
  822. * How many frames were called since the director started
  823. * @return {Number}
  824. */
  825. getTotalFrames:function () {
  826. return this._totalFrames;
  827. },
  828. /**
  829. * Sets an OpenGL projection
  830. * @return {Number}
  831. */
  832. getProjection:function () {
  833. return this._projection;
  834. },
  835. /**
  836. * <p>
  837. * Pops out all scenes from the queue until the root scene in the queue. <br/>
  838. * This scene will replace the running one. <br/>
  839. * Internally it will call `popToSceneStackLevel(1)`
  840. * </p>
  841. */
  842. popToRootScene:function () {
  843. this.popToSceneStackLevel(1);
  844. },
  845. /**
  846. * <p>
  847. * Pops out all scenes from the queue until it reaches `level`. <br/>
  848. * If level is 0, it will end the director. <br/>
  849. * If level is 1, it will pop all scenes until it reaches to root scene. <br/>
  850. * If level is <= than the current stack level, it won't do anything.
  851. * </p>
  852. * @param {Number} level
  853. */
  854. popToSceneStackLevel: function (level) {
  855. if(!this._runningScene)
  856. throw "A running Scene is needed";
  857. var locScenesStack = this._scenesStack;
  858. var c = locScenesStack.length;
  859. if (c == 0) {
  860. this.end();
  861. return;
  862. }
  863. // current level or lower -> nothing
  864. if (level > c)
  865. return;
  866. // pop stack until reaching desired level
  867. while (c > level) {
  868. var current = locScenesStack.pop();
  869. if (current.isRunning()) {
  870. current.onExitTransitionDidStart();
  871. current.onExit();
  872. }
  873. current.cleanup();
  874. c--;
  875. }
  876. this._nextScene = locScenesStack[locScenesStack.length - 1];
  877. this._sendCleanupToScene = false;
  878. },
  879. /**
  880. * (cc.Scheduler associated with this director)
  881. */
  882. getScheduler:function () {
  883. return this._scheduler;
  884. },
  885. setScheduler:function (scheduler) {
  886. if (this._scheduler != scheduler) {
  887. this._scheduler = scheduler;
  888. }
  889. },
  890. getActionManager:function () {
  891. return this._actionManager;
  892. },
  893. setActionManager:function (actionManager) {
  894. if (this._actionManager != actionManager) {
  895. this._actionManager = actionManager;
  896. }
  897. },
  898. getTouchDispatcher:function () {
  899. return this._touchDispatcher;
  900. },
  901. setTouchDispatcher:function (touchDispatcher) {
  902. if (this._touchDispatcher != touchDispatcher) {
  903. this._touchDispatcher = touchDispatcher;
  904. }
  905. },
  906. getKeyboardDispatcher:function () {
  907. if(!cc.KeyboardDispatcher)
  908. throw "cc.KeyboardDispatcher is undefined, maybe it has been removed from js loading list.";
  909. return this._keyboardDispatcher;
  910. },
  911. setKeyboardDispatcher:function (keyboardDispatcher) {
  912. if(!cc.KeyboardDispatcher)
  913. throw "cc.KeyboardDispatcher is undefined, maybe it has been removed from js loading list.";
  914. this._keyboardDispatcher = keyboardDispatcher;
  915. },
  916. getAccelerometer:function () {
  917. if(!cc.Accelerometer)
  918. throw "cc.Accelerometer is undefined, maybe it has been removed from js loading list.";
  919. return this._accelerometer;
  920. },
  921. setAccelerometer:function (accelerometer) {
  922. if(!cc.Accelerometer)
  923. throw "cc.Accelerometer is undefined, maybe it has been removed from js loading list.";
  924. if (this._accelerometer != accelerometer)
  925. this._accelerometer = accelerometer;
  926. },
  927. getDeltaTime:function(){
  928. return this._deltaTime;
  929. },
  930. getMouseDispatcher:function () {
  931. if(!cc.MouseDispatcher)
  932. throw "cc.MouseDispatcher is undefined, maybe it has been removed from js loading list.";
  933. return this._mouseDispatcher;
  934. },
  935. setMouseDispatcher:function (mouseDispatcher) {
  936. if(!cc.MouseDispatcher)
  937. throw "cc.MouseDispatcher is undefined, maybe it has been removed from js loading list.";
  938. if (this._mouseDispatcher != mouseDispatcher)
  939. this._mouseDispatcher = mouseDispatcher;
  940. },
  941. _createStatsLabel: null,
  942. _createStatsLabelForWebGL:function(){
  943. if(!cc.LabelAtlas)
  944. return this._createStatsLabelForCanvas();
  945. if((cc.Director._fpsImageLoaded == null) || (cc.Director._fpsImageLoaded == false))
  946. return;
  947. var texture = new cc.Texture2D();
  948. texture.initWithElement(cc.Director._fpsImage);
  949. texture.handleLoadedTexture();
  950. /*
  951. We want to use an image which is stored in the file named ccFPSImage.c
  952. for any design resolutions and all resource resolutions.
  953. To achieve this,
  954. Firstly, we need to ignore 'contentScaleFactor' in 'CCAtlasNode' and 'CCLabelAtlas'.
  955. So I added a new method called 'setIgnoreContentScaleFactor' for 'CCAtlasNode',
  956. this is not exposed to game developers, it's only used for displaying FPS now.
  957. Secondly, the size of this image is 480*320, to display the FPS label with correct size,
  958. a factor of design resolution ratio of 480x320 is also needed.
  959. */
  960. var factor = cc.EGLView.getInstance().getDesignResolutionSize().height / 320.0;
  961. if(factor === 0)
  962. factor = this._winSizeInPoints.height / 320.0;
  963. var tmpLabel = new cc.LabelAtlas();
  964. tmpLabel._setIgnoreContentScaleFactor(true);
  965. tmpLabel.initWithString("00.0", texture, 12, 32 , '.');
  966. tmpLabel.setScale(factor);
  967. this._FPSLabel = tmpLabel;
  968. tmpLabel = new cc.LabelAtlas();
  969. tmpLabel._setIgnoreContentScaleFactor(true);
  970. tmpLabel.initWithString("0.000", texture, 12, 32, '.');
  971. tmpLabel.setScale(factor);
  972. this._SPFLabel = tmpLabel;
  973. tmpLabel = new cc.LabelAtlas();
  974. tmpLabel._setIgnoreContentScaleFactor(true);
  975. tmpLabel.initWithString("000", texture, 12, 32, '.');
  976. tmpLabel.setScale(factor);
  977. this._drawsLabel = tmpLabel;
  978. var locStatsPosition = cc.DIRECTOR_STATS_POSITION;
  979. this._drawsLabel.setPosition(cc.pAdd(cc.p(0, 34 * factor), locStatsPosition));
  980. this._SPFLabel.setPosition(cc.pAdd(cc.p(0, 17 * factor), locStatsPosition));
  981. this._FPSLabel.setPosition(locStatsPosition);
  982. },
  983. _createStatsLabelForCanvas:function(){
  984. var fontSize = 0;
  985. if (this._winSizeInPoints.width > this._winSizeInPoints.height)
  986. fontSize = 0 | (this._winSizeInPoints.height / 320 * 24);
  987. else
  988. fontSize = 0 | (this._winSizeInPoints.width / 320 * 24);
  989. this._FPSLabel = cc.LabelTTF.create("000.0", "Arial", fontSize);
  990. this._SPFLabel = cc.LabelTTF.create("0.000", "Arial", fontSize);
  991. this._drawsLabel = cc.LabelTTF.create("0000", "Arial", fontSize);
  992. var locStatsPosition = cc.DIRECTOR_STATS_POSITION;
  993. var contentSize = this._drawsLabel.getContentSize();
  994. this._drawsLabel.setPosition(cc.pAdd(cc.p(contentSize.width / 2, contentSize.height * 5 / 2), locStatsPosition));
  995. contentSize = this._SPFLabel.getContentSize();
  996. this._SPFLabel.setPosition(cc.pAdd(cc.p(contentSize.width / 2, contentSize.height * 3 / 2), locStatsPosition));
  997. contentSize = this._FPSLabel.getContentSize();
  998. this._FPSLabel.setPosition(cc.pAdd(cc.p(contentSize.width / 2, contentSize.height / 2), locStatsPosition));
  999. },
  1000. _calculateMPF: function () {
  1001. var now = Date.now();
  1002. this._secondsPerFrame = (now - this._lastUpdate) / 1000;
  1003. }
  1004. });
  1005. if (cc.Browser.supportWebGL) {
  1006. cc.Director.prototype._clear = cc.Director.prototype._clearWebGL;
  1007. cc.Director.prototype._beforeVisitScene = cc.Director.prototype._beforeVisitSceneWebGL;
  1008. cc.Director.prototype._afterVisitScene = cc.Director.prototype._afterVisitSceneWebGL;
  1009. cc.Director.prototype._createStatsLabel = cc.Director.prototype._createStatsLabelForWebGL;
  1010. } else {
  1011. cc.Director.prototype._clear = cc.Director.prototype._clearCanvas;
  1012. cc.Director.prototype._createStatsLabel = cc.Director.prototype._createStatsLabelForCanvas;
  1013. }
  1014. /***************************************************
  1015. * implementation of DisplayLinkDirector
  1016. **************************************************/
  1017. // should we afford 4 types of director ??
  1018. // I think DisplayLinkDirector is enough
  1019. // so we now only support DisplayLinkDirector
  1020. /**
  1021. * <p>
  1022. * DisplayLinkDirector is a Director that synchronizes timers with the refresh rate of the display.<br/>
  1023. * Features and Limitations:<br/>
  1024. * - Scheduled timers & drawing are synchronizes with the refresh rate of the display<br/>
  1025. * - Only supports animation intervals of 1/60 1/30 & 1/15<br/>
  1026. * </p>
  1027. * @class
  1028. * @extends cc.Director
  1029. */
  1030. cc.DisplayLinkDirector = cc.Director.extend(/** @lends cc.DisplayLinkDirector# */{
  1031. invalid:false,
  1032. /**
  1033. * start Animation
  1034. */
  1035. startAnimation:function () {
  1036. this._nextDeltaTimeZero = true;
  1037. this.invalid = false;
  1038. cc.Application.getInstance().setAnimationInterval(this._animationInterval);
  1039. },
  1040. /**
  1041. * main loop of director
  1042. */
  1043. mainLoop:function () {
  1044. if (this._purgeDirecotorInNextLoop) {
  1045. this._purgeDirecotorInNextLoop = false;
  1046. this.purgeDirector();
  1047. }
  1048. else if (!this.invalid) {
  1049. this.drawScene();
  1050. }
  1051. },
  1052. /**
  1053. * stop animation
  1054. */
  1055. stopAnimation:function () {
  1056. this.invalid = true;
  1057. },
  1058. /**
  1059. * set Animation Interval
  1060. * @param {Number} value
  1061. */
  1062. setAnimationInterval:function (value) {
  1063. this._animationInterval = value;
  1064. if (!this.invalid) {
  1065. this.stopAnimation();
  1066. this.startAnimation();
  1067. }
  1068. }
  1069. });
  1070. cc.s_SharedDirector = null;
  1071. cc.firstUseDirector = true;
  1072. /**
  1073. * returns a shared instance of the director
  1074. * @function
  1075. * @return {cc.Director}
  1076. */
  1077. cc.Director.getInstance = function () {
  1078. if (cc.firstUseDirector) {
  1079. cc.firstUseDirector = false;
  1080. cc.s_SharedDirector = new cc.DisplayLinkDirector();
  1081. cc.s_SharedDirector.init();
  1082. cc.s_SharedDirector.setOpenGLView(cc.EGLView.getInstance());
  1083. }
  1084. return cc.s_SharedDirector;
  1085. };
  1086. Object.defineProperties(cc, {
  1087. windowSize: {
  1088. get: function () {
  1089. return cc.director.getWinSize();
  1090. },
  1091. enumerable: true
  1092. }
  1093. });
  1094. /**
  1095. * is director first run
  1096. * @type Boolean
  1097. */
  1098. cc.firstRun = true;
  1099. /**
  1100. * set default fps to 60
  1101. * @type Number
  1102. */
  1103. cc.defaultFPS = 60;
  1104. /*
  1105. window.onfocus = function () {
  1106. if (!cc.firstRun) {
  1107. cc.Director.getInstance().addRegionToDirtyRegion(cc.rect(0, 0, cc.canvas.width, cc.canvas.height));
  1108. }
  1109. };
  1110. */
  1111. cc.Director._fpsImage = new Image();
  1112. cc.Director._fpsImage.addEventListener("load", function () {
  1113. cc.Director._fpsImageLoaded = true;
  1114. });
  1115. cc.Director._fpsImage.src = "data:image/png;base64,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";