1 /**************************************************************************** 2 Copyright (c) 2008-2010 Ricardo Quesada 3 Copyright (c) 2011-2012 cocos2d-x.org 4 Copyright (c) 2013-2014 Chukong Technologies Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 /** 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(cc._LogInfos.textureCache_dumpCachedTextureInfo_2, 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 cb && cb.call(target); 331 return tex; 332 } 333 334 if (!cc.loader.getRes(url)) { 335 if (cc.loader._checkIsImageURL(url)) { 336 cc.loader.load(url, function (err) { 337 cb && cb.call(target); 338 }); 339 } else { 340 cc.loader.cache[url] = cc.loader.loadImg(url, function (err, img) { 341 if (err) 342 return cb ? cb(err) : err; 343 cc.textureCache.handleLoadedTexture(url); 344 cb && cb(null, img); 345 }); 346 } 347 } 348 349 tex = locTexs[url] = new cc.Texture2D(); 350 tex.url = url; 351 return tex; 352 }; 353 354 _p = null; 355 356 } else { 357 cc.assert(typeof cc._tmp.WebGLTextureCache === "function", cc._LogInfos.MissingFile, "TexturesWebGL.js"); 358 cc._tmp.WebGLTextureCache(); 359 delete cc._tmp.WebGLTextureCache; 360 }