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