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  * @namespace The global cache for cc.Texture2D
 29  */
 30 cc.textureCache = /** @lends cc.textureCache# */{
 31     _textures: {},
 32     _textureColorsCache: {},
 33     _textureKeySeq: (0 | Math.random() * 1000),
 34 
 35     _loadedTexturesBefore: {},
 36 
 37     //handleLoadedTexture move to Canvas/WebGL
 38 
 39     _initializingRenderer: function () {
 40         var selPath;
 41         //init texture from _loadedTexturesBefore
 42         var locLoadedTexturesBefore = this._loadedTexturesBefore, locTextures = this._textures;
 43         for (selPath in locLoadedTexturesBefore) {
 44             var tex2d = locLoadedTexturesBefore[selPath];
 45             tex2d.handleLoadedTexture();
 46             locTextures[selPath] = tex2d;
 47         }
 48         this._loadedTexturesBefore = {};
 49     },
 50 
 51     /**
 52      * <p>
 53      *     Returns a Texture2D object given an PVR filename                                                              <br/>
 54      *     If the file image was not previously loaded, it will create a new CCTexture2D                                 <br/>
 55      *     object and it will return it. Otherwise it will return a reference of a previously loaded image              <br/>
 56      *     note: AddPVRTCImage does not support on HTML5
 57      * </p>
 58      * @param {String} filename
 59      * @return {cc.Texture2D}
 60      */
 61     addPVRTCImage: function (filename) {
 62         cc.log(cc._LogInfos.textureCache_addPVRTCImage);
 63     },
 64 
 65     /**
 66      * <p>
 67      *     Returns a Texture2D object given an ETC filename                                                               <br/>
 68      *     If the file image was not previously loaded, it will create a new CCTexture2D                                  <br/>
 69      *     object and it will return it. Otherwise it will return a reference of a previously loaded image                <br/>
 70      *    note:addETCImage does not support on HTML5
 71      * </p>
 72      * @param {String} filename
 73      * @return {cc.Texture2D}
 74      */
 75     addETCImage: function (filename) {
 76         cc.log(cc._LogInfos.textureCache_addETCImage);
 77     },
 78 
 79     /**
 80      * Description
 81      * @return {String}
 82      */
 83     description: function () {
 84         return "<TextureCache | Number of textures = " + this._textures.length + ">";
 85     },
 86 
 87     /**
 88      * Returns an already created texture. Returns null if the texture doesn't exist.
 89      * @param {String} textureKeyName
 90      * @return {cc.Texture2D|Null}
 91      * @example
 92      * //example
 93      * var key = cc.textureCache.textureForKey("hello.png");
 94      */
 95     textureForKey: function (textureKeyName) {
 96         return this._textures[textureKeyName] || this._textures[cc.loader._aliases[textureKeyName]];
 97     },
 98 
 99     /**
100      * @param {Image} texture
101      * @return {String|Null}
102      * @example
103      * //example
104      * var key = cc.textureCache.getKeyByTexture(texture);
105      */
106     getKeyByTexture: function (texture) {
107         for (var key in this._textures) {
108             if (this._textures[key] == texture) {
109                 return key;
110             }
111         }
112         return null;
113     },
114 
115     _generalTextureKey: function () {
116         this._textureKeySeq++;
117         return "_textureKey_" + this._textureKeySeq;
118     },
119 
120     /**
121      * @param {Image} texture
122      * @return {Array}
123      * @example
124      * //example
125      * var cacheTextureForColor = cc.textureCache.getTextureColors(texture);
126      */
127     getTextureColors: function (texture) {
128         var key = this.getKeyByTexture(texture);
129         if (!key) {
130             if (texture instanceof HTMLImageElement)
131                 key = texture.src;
132             else
133                 key = this._generalTextureKey();
134         }
135 
136         if (!this._textureColorsCache[key])
137             this._textureColorsCache[key] = cc.generateTextureCacheForColor(texture);
138         return this._textureColorsCache[key];
139     },
140 
141     /**
142      * <p>Returns a Texture2D object given an PVR filename<br />
143      * If the file image was not previously loaded, it will create a new Texture2D<br />
144      *  object and it will return it. Otherwise it will return a reference of a previously loaded image </p>
145      * @param {String} path
146      * @return {cc.Texture2D}
147      */
148     addPVRImage: function (path) {
149         cc.log(cc._LogInfos.textureCache_addPVRImage);
150     },
151 
152     /**
153      * <p>Purges the dictionary of loaded textures. <br />
154      * Call this method if you receive the "Memory Warning"  <br />
155      * In the short term: it will free some resources preventing your app from being killed  <br />
156      * In the medium term: it will allocate more resources <br />
157      * In the long term: it will be the same</p>
158      * @example
159      * //example
160      * cc.textureCache.removeAllTextures();
161      */
162     removeAllTextures: function () {
163         var locTextures = this._textures;
164         for (var selKey in locTextures) {
165             if (locTextures[selKey])
166                 locTextures[selKey].releaseTexture();
167         }
168         this._textures = {};
169     },
170 
171     /**
172      * Deletes a texture from the cache given a texture
173      * @param {Image} texture
174      * @example
175      * //example
176      * cc.textureCache.removeTexture(texture);
177      */
178     removeTexture: function (texture) {
179         if (!texture)
180             return;
181 
182         var locTextures = this._textures;
183         for (var selKey in locTextures) {
184             if (locTextures[selKey] == texture) {
185                 locTextures[selKey].releaseTexture();
186                 delete(locTextures[selKey]);
187             }
188         }
189     },
190 
191     /**
192      * Deletes a texture from the cache given a its key name
193      * @param {String} textureKeyName
194      * @example
195      * //example
196      * cc.textureCache.removeTexture("hello.png");
197      */
198     removeTextureForKey: function (textureKeyName) {
199         if (textureKeyName == null)
200             return;
201         if (this._textures[textureKeyName])
202             delete(this._textures[textureKeyName]);
203     },
204 
205     //addImage move to Canvas/WebGL
206 
207     /**
208      *  Cache the image data
209      * @param {String} path
210      * @param {Image|HTMLImageElement|HTMLCanvasElement} texture
211      */
212     cacheImage: function (path, texture) {
213         if (texture instanceof  cc.Texture2D) {
214             this._textures[path] = texture;
215             return;
216         }
217         var texture2d = new cc.Texture2D();
218         texture2d.initWithElement(texture);
219         texture2d.handleLoadedTexture();
220         this._textures[path] = texture2d;
221     },
222 
223     /**
224      * <p>Returns a Texture2D object given an UIImage image<br />
225      * If the image was not previously loaded, it will create a new Texture2D object and it will return it.<br />
226      * Otherwise it will return a reference of a previously loaded image<br />
227      * The "key" parameter will be used as the "key" for the cache.<br />
228      * If "key" is null, then a new texture will be created each time.</p>
229      * @param {HTMLImageElement|HTMLCanvasElement} image
230      * @param {String} key
231      * @return {cc.Texture2D}
232      */
233     addUIImage: function (image, key) {
234 
235         cc.assert(image, cc._LogInfos.textureCache_addUIImage_2);
236 
237         if (key) {
238             if (this._textures[key])
239                 return this._textures[key];
240         }
241 
242         // prevents overloading the autorelease pool
243         var texture = new cc.Texture2D();
244         texture.initWithImage(image);
245         if ((key != null) && (texture != null))
246             this._textures[key] = texture;
247         else
248             cc.log(cc._LogInfos.textureCache_addUIImage);
249         return texture;
250     },
251 
252     /**
253      * <p>Output to cc.log the current contents of this TextureCache <br />
254      * This will attempt to calculate the size of each texture, and the total texture memory in use. </p>
255      */
256     dumpCachedTextureInfo: function () {
257         var count = 0;
258         var totalBytes = 0, locTextures = this._textures;
259 
260         for (var key in locTextures) {
261             var selTexture = locTextures[key];
262             count++;
263             if (selTexture.getHtmlElementObj() instanceof  HTMLImageElement)
264                 cc.log(cc._LogInfos.textureCache_dumpCachedTextureInfo, key, selTexture.getHtmlElementObj().src, selTexture.pixelsWidth, selTexture.pixelsHeight);
265             else {
266                 cc.log(cc._LogInfos.textureCache_dumpCachedTextureInfo_2, key, selTexture.pixelsWidth, selTexture.pixelsHeight);
267             }
268             totalBytes += selTexture.pixelsWidth * selTexture.pixelsHeight * 4;
269         }
270 
271         var locTextureColorsCache = this._textureColorsCache;
272         for (key in locTextureColorsCache) {
273             var selCanvasColorsArr = locTextureColorsCache[key];
274             for (var selCanvasKey in selCanvasColorsArr) {
275                 var selCanvas = selCanvasColorsArr[selCanvasKey];
276                 count++;
277                 cc.log("cocos2d: '%s' id= HTMLCanvasElement %s x %s", key, selCanvas.width, selCanvas.height);
278                 totalBytes += selCanvas.width * selCanvas.height * 4;
279             }
280 
281         }
282         cc.log(cc._LogInfos.textureCache_dumpCachedTextureInfo_3, count, totalBytes / 1024, (totalBytes / (1024.0 * 1024.0)).toFixed(2));
283     },
284 
285     _clear: function () {
286         this._textures = {};
287         this._textureColorsCache = {};
288         this._textureKeySeq = (0 | Math.random() * 1000);
289         this._loadedTexturesBefore = {};
290     }
291 };
292 
293 if (cc._renderType === cc._RENDER_TYPE_CANVAS) {
294 
295     var _p = cc.textureCache;
296 
297     _p.handleLoadedTexture = function (url) {
298         var locTexs = this._textures;
299         //remove judge
300         var tex = locTexs[url];
301         if (!tex) {
302             tex = locTexs[url] = new cc.Texture2D();
303             tex.url = url;
304         }
305         tex.handleLoadedTexture();
306     };
307 
308     /**
309      * <p>Returns a Texture2D object given an file image <br />
310      * If the file image was not previously loaded, it will create a new Texture2D <br />
311      *  object and it will return it. It will use the filename as a key.<br />
312      * Otherwise it will return a reference of a previously loaded image. <br />
313      * Supported image extensions: .png, .jpg, .gif</p>
314      * @param {String} url
315      * @param {Function} cb
316      * @param {Object} target
317      * @return {cc.Texture2D}
318      * @example
319      * //example
320      * cc.textureCache.addImage("hello.png");
321      */
322     _p.addImage = function (url, cb, target) {
323 
324         cc.assert(url, cc._LogInfos.Texture2D_addImage);
325 
326         var locTexs = this._textures;
327         //remove judge
328         var tex = locTexs[url] || locTexs[cc.loader._aliases[url]];
329         if (tex) {
330             if (cb)
331                 cb.call(target);
332             return tex;
333         }
334 
335         if (!cc.loader.getRes(url)) {
336             if (cc.loader._checkIsImageURL(url)) {
337                 cc.loader.load(url, function (err) {
338                     if (cb)
339                         cb.call(target);
340                 });
341             } else {
342                 cc.loader.cache[url] = cc.loader.loadImg(url, function (err, img) {
343                     if (err)
344                         return cb(err);
345                     cc.textureCache.handleLoadedTexture(url);
346                     cb(null, img);
347                 });
348             }
349         }
350 
351         tex = locTexs[url] = new cc.Texture2D();
352         tex.url = url;
353         return tex;
354     };
355 
356     _p = null;
357 
358 } else {
359     _tmp.WebGLTextureCache();
360     delete _tmp.WebGLTextureCache;
361 }