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