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