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 /**
 28  * resource type
 29  * @constant
 30  * @type Object
 31  */
 32 cc.RESOURCE_TYPE = {
 33     "IMAGE": ["png", "jpg", "bmp", "jpeg", "gif"],
 34     "SOUND": ["mp3", "ogg", "wav", "mp4", "m4a"],
 35     "XML": ["plist", "xml", "fnt", "tmx", "tsx"],
 36     "BINARY": ["ccbi"],
 37     "FONT": "FONT",
 38     "TEXT": ["txt", "vsh", "fsh", "json", "ExportJson"],
 39     "UNKNOW": []
 40 };
 41 
 42 /**
 43  * resource structure
 44  * @param resList
 45  * @param selector
 46  * @param target
 47  * @constructor
 48  */
 49 cc.ResData = function (resList, selector, target) {
 50     this.resList = resList || [];
 51     this.selector = selector;
 52     this.target = target;
 53     this.curNumber = 0;
 54     this.loadedNumber = 0;
 55     this.totalNumber = this.resList.length;
 56 };
 57 
 58 /**
 59  * A class to preload resources async
 60  * @class
 61  * @extends cc.Class
 62  */
 63 cc.Loader = cc.Class.extend(/** @lends cc.Loader# */{
 64     _curData: null,
 65     _resQueue: null,
 66     _isAsync: false,
 67     _scheduler: null,
 68     _running: false,
 69     _regisiterLoader: false,
 70 
 71     /**
 72      * Constructor
 73      */
 74     ctor: function () {
 75         this._scheduler = cc.Director.getInstance().getScheduler();
 76         this._resQueue = [];
 77     },
 78 
 79     /**
 80      * init with resources
 81      * @param {Array} resources
 82      * @param {Function|String} selector
 83      * @param {Object} target
 84      */
 85     initWithResources: function (resources, selector, target) {
 86         if (!resources) {
 87             cc.log("cocos2d:resources should not null");
 88             return;
 89         }
 90         var res = resources.concat([]);
 91         var data = new cc.ResData(res, selector, target);
 92         this._resQueue.push(data);
 93 
 94         if (!this._running) {
 95             this._running = true;
 96             this._curData = this._resQueue.shift();
 97             this._scheduler.scheduleUpdateForTarget(this);
 98         }
 99     },
100 
101     setAsync: function (isAsync) {
102         this._isAsync = isAsync;
103     },
104 
105     /**
106      * Callback when a resource file loaded.
107      */
108     onResLoaded: function (err) {
109         if(err != null){
110             cc.log("cocos2d:Failed loading resource: " + err);
111         }
112 
113         this._curData.loadedNumber++;
114     },
115 
116     /**
117      * Get loading percentage
118      * @return {Number}
119      * @example
120      * //example
121      * cc.log(cc.Loader.getInstance().getPercentage() + "%");
122      */
123     getPercentage: function () {
124         var percent = 0, curData = this._curData;
125         if (curData.totalNumber == 0) {
126             percent = 100;
127         }
128         else {
129             percent = (0 | (curData.loadedNumber / curData.totalNumber * 100));
130         }
131         return percent;
132     },
133 
134     /**
135      * release resources from a list
136      * @param resources
137      */
138     releaseResources: function (resources) {
139         if (resources && resources.length > 0) {
140             var sharedTextureCache = cc.TextureCache.getInstance(),
141                 sharedEngine = cc.AudioEngine ? cc.AudioEngine.getInstance() : null,
142                 sharedParser = cc.SAXParser.getInstance(),
143                 sharedFileUtils = cc.FileUtils.getInstance();
144 
145             var resInfo, path, type;
146             for (var i = 0; i < resources.length; i++) {
147                 resInfo = resources[i];
148                 path = typeof resInfo == "string" ? resInfo : resInfo.src;
149                 type = this._getResType(resInfo, path);
150 
151                 switch (type) {
152                     case "IMAGE":
153                         sharedTextureCache.removeTextureForKey(path);
154                         break;
155                     case "SOUND":
156                         if (!sharedEngine) throw "Can not find AudioEngine! Install it, please.";
157                         sharedEngine.unloadEffect(path);
158                         break;
159                     case "XML":
160                         sharedParser.unloadPlist(path);
161                         break;
162                     case "BINARY":
163                         sharedFileUtils.unloadBinaryFileData(path);
164                         break;
165                     case "TEXT":
166                         sharedFileUtils.unloadTextFileData(path);
167                         break;
168                     case "FONT":
169                         this._unregisterFaceFont(resInfo);
170                         break;
171                     default:
172                         throw "cocos2d:unknown filename extension: " + type;
173                         break;
174                 }
175             }
176         }
177     },
178 
179     update: function () {
180         if (this._isAsync) {
181             var frameRate = cc.Director.getInstance()._frameRate;
182             if (frameRate != null && frameRate < 20) {
183                 cc.log("cocos2d: frame rate less than 20 fps, skip frame.");
184                 return;
185             }
186         }
187 
188         var curData = this._curData;
189         if (curData && curData.curNumber < curData.totalNumber) {
190             this._loadRes();
191             curData.curNumber++;
192         }
193 
194         var percent = this.getPercentage();
195         if(percent >= 100){
196             this._complete();
197             if (this._resQueue.length > 0) {
198                 this._running = true;
199                 this._curData = this._resQueue.shift();
200             }
201             else{
202                 this._running = false;
203                 this._scheduler.unscheduleUpdateForTarget(this);
204             }
205         }
206     },
207 
208     _loadRes: function () {
209         var sharedTextureCache = cc.TextureCache.getInstance(),
210             sharedEngine = cc.AudioEngine ? cc.AudioEngine.getInstance() : null,
211             sharedParser = cc.SAXParser.getInstance(),
212             sharedFileUtils = cc.FileUtils.getInstance();
213 
214         var resInfo = this._curData.resList.shift(),
215             path = this._getResPath(resInfo),
216             type = this._getResType(resInfo, path);
217 
218         switch (type) {
219             case "IMAGE":
220                 sharedTextureCache.addImageAsync(path, this.onResLoaded, this);
221                 break;
222             case "SOUND":
223                 if (!sharedEngine) throw "Can not find AudioEngine! Install it, please.";
224                 sharedEngine.preloadSound(path, this.onResLoaded, this);
225                 break;
226             case "XML":
227                 sharedParser.preloadPlist(path, this.onResLoaded, this);
228                 break;
229             case "BINARY":
230                 sharedFileUtils.preloadBinaryFileData(path, this.onResLoaded, this);
231                 break;
232             case "TEXT" :
233                 sharedFileUtils.preloadTextFileData(path, this.onResLoaded, this);
234                 break;
235             case "FONT":
236                 this._registerFaceFont(resInfo, this.onResLoaded, this);
237                 break;
238             default:
239                 throw "cocos2d:unknown filename extension: " + type;
240                 break;
241         }
242     },
243 
244     _getResPath: function (resInfo) {
245         return typeof resInfo == "string" ? resInfo : resInfo.src;
246     },
247 
248     _getResType: function (resInfo, path) {
249         var isFont = resInfo.fontName;
250         if (isFont != null) {
251             return cc.RESOURCE_TYPE["FONT"];
252         }
253         else {
254             var ext = path.substring(path.lastIndexOf(".") + 1, path.length);
255             var index = ext.indexOf("?");
256             if (index > 0) ext = ext.substring(0, index);
257 
258             for (var resType in cc.RESOURCE_TYPE) {
259                 if (cc.RESOURCE_TYPE[resType].indexOf(ext) != -1) {
260                     return resType;
261                 }
262             }
263             return ext;
264         }
265     },
266 
267     _complete: function () {
268         cc.doCallback(this._curData.selector,this._curData.target);
269     },
270 
271     _registerFaceFont: function (fontRes,seletor,target) {
272         var srcArr = fontRes.src;
273         var fileUtils = cc.FileUtils.getInstance();
274         if (srcArr && srcArr.length > 0) {
275             var fontStyle = document.createElement("style");
276             fontStyle.type = "text/css";
277             document.body.appendChild(fontStyle);
278 
279             var fontStr = "@font-face { font-family:" + fontRes.fontName + "; src:";
280             for (var i = 0; i < srcArr.length; i++) {
281                 fontStr += "url('" + fileUtils.fullPathForFilename(encodeURI(srcArr[i].src)) + "') format('" + srcArr[i].type + "')";
282                 fontStr += (i == (srcArr.length - 1)) ? ";" : ",";
283             }
284             fontStyle.textContent += fontStr + "};";
285 
286             //preload
287             //<div style="font-family: PressStart;">.</div>
288             var preloadDiv = document.createElement("div");
289             preloadDiv.style.fontFamily = fontRes.fontName;
290             preloadDiv.innerHTML = ".";
291             preloadDiv.style.position = "absolute";
292             preloadDiv.style.left = "-100px";
293             preloadDiv.style.top = "-100px";
294             document.body.appendChild(preloadDiv);
295         }
296         cc.doCallback(seletor,target);
297     },
298 
299     _unregisterFaceFont: function (fontRes) {
300         //todo remove style
301     }
302 });
303 
304 /**
305  * Preload resources in the background
306  * @param {Array} resources
307  * @param {Function|String} selector
308  * @param {Object} target
309  * @return {cc.Loader}
310  * @example
311  * //example
312  * var g_mainmenu = [
313  *    {src:"res/hello.png"},
314  *    {src:"res/hello.plist"},
315  *
316  *    {src:"res/logo.png"},
317  *    {src:"res/btn.png"},
318  *
319  *    {src:"res/boom.mp3"},
320  * ]
321  *
322  * var g_level = [
323  *    {src:"res/level01.png"},
324  *    {src:"res/level02.png"},
325  *    {src:"res/level03.png"}
326  * ]
327  *
328  * //load a list of resources
329  * cc.Loader.preload(g_mainmenu, this.startGame, this);
330  *
331  * //load multi lists of resources
332  * cc.Loader.preload([g_mainmenu,g_level], this.startGame, this);
333  */
334 cc.Loader.preload = function (resources, selector, target) {
335     if (!this._instance) {
336         this._instance = new cc.Loader();
337     }
338     this._instance.initWithResources(resources, selector, target);
339     return this._instance;
340 };
341 
342 /**
343  * Preload resources async
344  * @param {Array} resources
345  * @param {Function|String} selector
346  * @param {Object} target
347  * @return {cc.Loader}
348  */
349 cc.Loader.preloadAsync = function (resources, selector, target) {
350     if (!this._instance) {
351         this._instance = new cc.Loader();
352     }
353     this._instance.setAsync(true);
354     this._instance.initWithResources(resources, selector, target);
355     return this._instance;
356 };
357 
358 /**
359  * Release the resources from a list
360  * @param {Array} resources
361  */
362 cc.Loader.purgeCachedData = function (resources) {
363     if (this._instance) {
364         this._instance.releaseResources(resources);
365     }
366 };
367 
368 /**
369  * Returns a shared instance of the loader
370  * @function
371  * @return {cc.Loader}
372  */
373 cc.Loader.getInstance = function () {
374     if (!this._instance) {
375         this._instance = new cc.Loader();
376     }
377     return this._instance;
378 };
379 
380 cc.Loader._instance = null;
381 
382 
383 /**
384  * Used to display the loading screen
385  * @class
386  * @extends cc.Scene
387  */
388 cc.LoaderScene = cc.Scene.extend(/** @lends cc.LoaderScene# */{
389     _logo: null,
390     _logoTexture: null,
391     _texture2d: null,
392     _bgLayer: null,
393     _label: null,
394     _winSize: null,
395 
396     /**
397      * Constructor
398      */
399     ctor: function () {
400         cc.Scene.prototype.ctor.call(this);
401         this._winSize = cc.Director.getInstance().getWinSize();
402     },
403     init: function () {
404         cc.Scene.prototype.init.call(this);
405 
406         //logo
407         var logoWidth = 160;
408         var logoHeight = 200;
409         var centerPos = cc.p(this._winSize.width / 2, this._winSize.height / 2);
410 
411         this._logoTexture = new Image();
412         var _this = this, handler;
413         this._logoTexture.addEventListener("load", handler = function () {
414             _this._initStage(centerPos);
415             this.removeEventListener('load', handler, false);
416         });
417         this._logoTexture.src = "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAlAAD/4QMpaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjAtYzA2MCA2MS4xMzQ3NzcsIDIwMTAvMDIvMTItMTc6MzI6MDAgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjM4MDBEMDY2QTU1MjExRTFBQTAzQjEzMUNFNzMxRkQwIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjM4MDBEMDY1QTU1MjExRTFBQTAzQjEzMUNFNzMxRkQwIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkU2RTk0OEM4OERCNDExRTE5NEUyRkE3M0M3QkE1NTlEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkU2RTk0OEM5OERCNDExRTE5NEUyRkE3M0M3QkE1NTlEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+/+4ADkFkb2JlAGTAAAAAAf/bAIQADQkJCQoJDQoKDRMMCwwTFhENDREW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";
418         this._logoTexture.width = logoWidth;
419         this._logoTexture.height = logoHeight;
420 
421         // bg
422         this._bgLayer = cc.LayerColor.create(cc.c4(32, 32, 32, 255));
423         this._bgLayer.setPosition(0, 0);
424         this.addChild(this._bgLayer, 0);
425 
426         //loading percent
427         this._label = cc.LabelTTF.create("Loading... 0%", "Arial", 14);
428         this._label.setColor(cc.c3(180, 180, 180));
429         this._label.setPosition(cc.pAdd(centerPos, cc.p(0, -logoHeight / 2 - 10)));
430         this._bgLayer.addChild(this._label, 10);
431     },
432 
433     _initStage: function (centerPos) {
434         this._texture2d = new cc.Texture2D();
435         this._texture2d.initWithElement(this._logoTexture);
436         this._texture2d.handleLoadedTexture();
437         this._logo = cc.Sprite.createWithTexture(this._texture2d);
438         this._logo.setScale(cc.CONTENT_SCALE_FACTOR());
439         this._logo.setPosition(centerPos);
440         this._bgLayer.addChild(this._logo, 10);
441     },
442 
443     onEnter: function () {
444         cc.Node.prototype.onEnter.call(this);
445         this.schedule(this._startLoading, 0.3);
446     },
447 
448     onExit: function () {
449         cc.Node.prototype.onExit.call(this);
450         var tmpStr = "Loading... 0%";
451         this._label.setString(tmpStr);
452     },
453 
454     /**
455      * init with resources
456      * @param {Array} resources
457      * @param {Function|String} selector
458      * @param {Object} target
459      */
460     initWithResources: function (resources, selector, target) {
461         this.resources = resources;
462         this.selector = selector;
463         this.target = target;
464     },
465 
466     _startLoading: function () {
467         this.unschedule(this._startLoading);
468         cc.Loader.preload(this.resources, this.selector, this.target);
469         this.schedule(this._updatePercent);
470     },
471 
472     _updatePercent: function () {
473         var percent = cc.Loader.getInstance().getPercentage();
474         var tmpStr = "Loading... " + percent + "%";
475         this._label.setString(tmpStr);
476 
477         if (percent >= 100)
478             this.unschedule(this._updatePercent);
479     }
480 });
481 
482 /**
483  * Preload multi scene resources.
484  * @param {Array} resources
485  * @param {Function|String} selector
486  * @param {Object} target
487  * @return {cc.LoaderScene}
488  * @example
489  * //example
490  * var g_mainmenu = [
491  *    {src:"res/hello.png"},
492  *    {src:"res/hello.plist"},
493  *
494  *    {src:"res/logo.png"},
495  *    {src:"res/btn.png"},
496  *
497  *    {src:"res/boom.mp3"},
498  * ]
499  *
500  * var g_level = [
501  *    {src:"res/level01.png"},
502  *    {src:"res/level02.png"},
503  *    {src:"res/level03.png"}
504  * ]
505  *
506  * //load a list of resources
507  * cc.LoaderScene.preload(g_mainmenu, this.startGame, this);
508  *
509  * //load multi lists of resources
510  * cc.LoaderScene.preload([g_mainmenu,g_level], this.startGame, this);
511  */
512 cc.LoaderScene.preload = function (resources, selector, target) {
513     if (!this._instance) {
514         this._instance = new cc.LoaderScene();
515         this._instance.init();
516     }
517 
518     this._instance.initWithResources(resources, selector, target);
519 
520     var director = cc.Director.getInstance();
521     if (director.getRunningScene()) {
522         director.replaceScene(this._instance);
523     } else {
524         director.runWithScene(this._instance);
525     }
526 
527     return this._instance;
528 };
529