BasomtiKombucha Posted August 27, 2014 Share Posted August 27, 2014 Hi!So here's something that has been bothering me for a while...Can we somehow "unload" textures/texture atlases/assets? I'm working on a game that has multiple levels. At the start of each level, I preload all of the assets the level requires using the AssetLoader. So at the start of the first level I have something like:loader = new PIXI.AssetLoader(["level1_assets.json"]);loader.onComplete = startLevelloader.load();While at the start of the second level I have something like:loader = new PIXI.AssetLoader(["level2_assets.json"]);loader.onComplete = startLevelloader.load();The point is, once the first level is over, I will never again need the texture atlas used to store its assets (resp. "level1_assets.json"). So there's no need for it to linger in my precious GPU memory anymore! Can I somehow dispose of it? Quote Link to comment Share on other sites More sharing options...
hubert Posted August 27, 2014 Share Posted August 27, 2014 Once a assetLoader loads a texture it stores it in PIXI.Texture element so as far as i know you can do this: Removing a texture - texture.destroy(true) I remember that there were some issues regarding the base texture, but I thing that all is fixed already! I hope this helps. http://www.sevenative.com Quote Link to comment Share on other sites More sharing options...
BasomtiKombucha Posted August 28, 2014 Author Share Posted August 28, 2014 Thanks for the reply! You're probably pushing me on the right track, but I still don't fully understand Could you be more specific? AssetLoader.load() returns void, not an instance of a Texture element - so I can't justvar myTexture = loader.load();But I need to call the Texture.destroy() on something - probably some instance of the 'Texture' object, right?So how do I store an asset I loaded through loader into a 'Texture' variable? TLDR; my problem is that I don't know what should I call the "texture.destroy(true)" on :/ Quote Link to comment Share on other sites More sharing options...
hubert Posted August 28, 2014 Share Posted August 28, 2014 Sure! As documentation states all loaded textures are added to textureCache If you console.log(PIXI.TextureCache) it will list all of your textures inside the cache. In order to remove the texture from cache you have to put this simple line of code THIS IS IT!!!!!!!PIXI.TextureCache['assets/images/hud/hud_bench.png'].destroy(true);The true argument states that you want to remove the baseTexture as well. So if you console log in pixi js 1.6.0 dev this (line of code 13360)PIXI.BaseTexture.prototype.destroy = function(){ if(this.imageUrl) { console.log(this.imageUrl); console.log('Base texture destroy: ', PIXI.BaseTextureCache[this.imageUrl]); console.log('Texture cache destroy: ', PIXI.TextureCache[this.imageUrl]); delete PIXI.BaseTextureCache[this.imageUrl]; delete PIXI.TextureCache[this.imageUrl]; console.log('Base texture destroy: ', PIXI.BaseTextureCache[this.imageUrl]); console.log('Texture cache destroy: ', PIXI.TextureCache[this.imageUrl]); this.imageUrl = null; this.source.src = null; } else if (this.source && this.source._pixiId) { delete PIXI.BaseTextureCache[this.source._pixiId]; } this.source = null; PIXI.texturesToDestroy.push(this);};You'll get at first the reference to the texture in cache and the base texture that I am removing and the second ones will return typeof 'undefined'. Additionally in the __proto__ property you'll see the before mentioned method destroy (not the one shown in the code above this is called with the true arguemnt). BUT BE AWARE THAT IF YOUR CODE CALLS THE SAME TEXTURE AS WELL BUT WITHOUT THE ASSET LOADER THE TEXTURE WILL BE READDED INTO THE TextureCache AND WILL HAVE A NEW BaseTexture. So in other words calling this code somewhere else after destroying your texture will add it back!var hud_benchTexture = new PIXI.Texture.fromImage('assets/images/hud/hud_bench.png');Under the hood pixi js uses good old delete statement like this:delete PIXI.BaseTextureCache['assets/images/hud/hud_bench.png'];delete PIXI.TextureCache['assets/images/hud/hud_bench.png'];DO NOT DO IT BY YOURSELF IN THE CODE, SINCE PIXI IS ALSO CLEANING SOME OTHER THINGS, IT CAN FREEZE YOUR APP IN CASE OF webGL context (that happened to me... yup... I was lazy about the documentation! ) IF THIS IS THE ANSWER TO YOUR QUESTION PLEASE MARK IT AS 'THE ANSWER'!!! p.s. this is the bug with the base texture that i have mentioned - http://www.html5gamedevs.com/topic/2182-pixi-web-app-slows-down-after-loading-20mb-of-images-on-ipad-mini2/, (corrections made by Peg Digital were added to the official pixi code)and this is a very good article about delete in javascript - http://perfectionkills.com/understanding-delete/ http://www.sevenative.com Quote Link to comment Share on other sites More sharing options...
BasomtiKombucha Posted August 29, 2014 Author Share Posted August 29, 2014 Thanks! Yep, I guess it'll to do so I'll mark it as 'the answer' very soon But before that, if I may ask just one more thing: what is the difference between: PIXI.TextureCache['image.png'].destroy(true);andPIXI.Texture.removeTextureFromCache('image.png');? My problem is that instead of using the standard pixi.js, I'm using its Dart port (https://github.com/FedeOmoto/pixi) and the port does not seem to have the TextureCache class anywhere I can get (actually, I can't even find it in the official pixi.js documentation (http://www.goodboydigital.com/pixijs/docs/) perhaps it's out of date?) Also the difference between Texture and BaseTexture is mystery to me, why do we need them both? Quote Link to comment Share on other sites More sharing options...
hubert Posted August 29, 2014 Share Posted August 29, 2014 This is how pixi does it. Texture.removeTextureFromCachePIXI.Texture.removeTextureFromCache = function(id){ var texture = PIXI.TextureCache[id]; delete PIXI.TextureCache[id]; delete PIXI.BaseTextureCache[id]; return texture;};And this is is Texture.destroy()PIXI.Texture.prototype.destroy = function(destroyBase){ if (destroyBase) this.baseTexture.destroy(); this.valid = false;};Practically removing the texture from cache will not influence the textures already loaded. If you'll remove baseTexture the sprites created from texture will leave a blank (black) space. as fr where your texture cache is in dart port..... drum roll! IT IS HERETexture._cache[frameId]; And this is the equivalent of dart destroy method:void destroy([bool destroyBase = false]) { if (destroyBase) baseTexture.destroy(); _valid = false; } IF YOU WANT TO DESTROY A TEXTURE IN DART PORT YOU HAVE TO :Texture._cache[frameId].destroy(); // remove from cacheTexture._cache[frameId].destroy(true); // remove from cache and remove the base textureAs for what is the baseTexture used for ... I think that they use it for a technique called prerendering... BUT I AM NOT SURE. I DON'T WANT TO STEER YOU INTO THE WRONG DIRECTION! http://www.sevenative.com Quote Link to comment Share on other sites More sharing options...
Sebi Posted August 29, 2014 Share Posted August 29, 2014 The baseTexture is the image that you have loaded. A Texture is just a frame of that image. E.g. you have a Spritesheet 100x100 pixel (baseTexture), with 4 Textures (4x 50x50 frames) PIXI.TextureCache['image.png'].destroy(true); That line destroys the baseTexture + the frame for that baseTexture (afaik not all other frames that use that baseTexture) PIXI.Texture.removeTextureFromCache('image.png'); I'd assume that this one only destroys the frame, but you have to look that up. In short: If you want to unload the image file, you have to destroy the baseTexture. Detroying frames alone will not unload the image. Quote Link to comment Share on other sites More sharing options...
BasomtiKombucha Posted August 30, 2014 Author Share Posted August 30, 2014 Hubert: It's not that simple with the Texture._cache[frameId]; _ underscore works somehow like a 'private' keyword in dart and there is no getter for the "_cache"Still, you probably had to dig in the Dart Pixi source to get that piece of code for me and I appreciate that! It seems that the problem is unsolvable without modifying the library source. I'll write to its author and see what he thinks about it Sebastian: That was well explained! I understand it completely now, thanks! Quote Link to comment Share on other sites More sharing options...
hubert Posted August 30, 2014 Share Posted August 30, 2014 You're right, the underscore means that this element is private to the class or to the library. Additionally Texture is 'part of' PIXI so you don't have access to the private elements in the class or the library. You will have to dig deeper. I think that you should add additional method to the texture class that will allow you to destroy textures the way you want. http://www.sevenative.com Quote Link to comment Share on other sites More sharing options...
Sebi Posted August 30, 2014 Share Posted August 30, 2014 You should be able to access the texture with BaseTexture.fromImage(your texture url)andTexture.fromImage(your texture url) or you grab it from a sprite -> yoursprite.texture and the baseTexture with yoursprite.texture.baseTexture (fromImage only loads the image if it's not in the cache already. if it's in the cache, it will just return the cache entry for you) Quote Link to comment Share on other sites More sharing options...
FedeOmoto Posted August 30, 2014 Share Posted August 30, 2014 Hi! In the Dart port of Pixi, the TextureCache object is intentionally hidden inside the Texture._cache static property as was already correctly pointed, and I think there's no need for it to be visible outside the library. If you're loading a bunch of textures using the AssetLoader, the easiest way to destroy them is something like this (Dart code follows):Texture.removeTextureFromCache('textureId').destroy(true);The Texture.removeTextureFromCache static method returns the Texture being removed from the cache, so you can destroy it (and its accompanying BaseTexture) as showed. This works OK if you know beforehand which texture ids you've to destroy. When using the AssetLoader, you will most likely end up creating Sprites from those textures, so, if you have a list of all the Sprites you're created, it's best to do something like this (Dart code follows):spriteList.forEach((sprite) => sprite.texture.destroy(true));Please let me know if any of those alternatives works OK for you, and if not, perhaps you can post a little code snippet showing your problem at which I can take a look to find the best solution. Regards,Fede Quote Link to comment Share on other sites More sharing options...
BasomtiKombucha Posted August 30, 2014 Author Share Posted August 30, 2014 Sebastian: You are right! I didn't realize this.Nevertheless, I still think that a static getter would be more practical, but it's good to know that there's no need to change the source. Funny that the BaseTexture.destroy() method behaves differently in Dart VM that it does in JavaScript. Calling it throws an error regarding the _source.src. It seems to work ok when compiled into JavaScript tho.Of course, the problem partly lingers because of this - it's hard to debug and application if it exits every time you change a level and compiling it into JavaScript after every change is too slow. Still, I guess there's not much we can do about it since I believe it to be an issue with the port itself. But I have faith that Fede will look into it soon edit: w8 a sec Fede has responded while I was writting this post, give me a sec to read it and I'll get back Quote Link to comment Share on other sites More sharing options...
BasomtiKombucha Posted August 30, 2014 Author Share Posted August 30, 2014 Yep, the error still lingers.Texture.removeTextureFromCache('textureId').destroy(true);Would be an ideal solution, but I can't make it work. To make sure I didn't screw anything (or as little as possible) by my coding, I used the example_1_basics you included in the GitHub source (https://github.com/FedeOmoto/pixi_examples/tree/master/web/1_basics) and basically just changed the _animate method like this:int temp = 0;void animate(num value) { window.animationFrame.then(animate); // Just for fun, let's rotate mr rabbit a little. bunny.rotation += 0.1; //THIS IS WHAT I ADDED if (temp == 180) { Texture.removeTextureFromCache('bunny.png').destroy(true); } temp++; //-------------------- // Render the stage. renderer.render(stage); }This should remove the texture after about 3 seconds of runtime. But instead, after those 3 seconds, I get an error: Uncaught Error: String expectedStack Trace: #0 Native_HTMLImageElement_src_Setter (dart:_blink:2709)#1 ImageElement.src= (dart:html:16480)#2 BaseTexture.destroy (package:pixi_dart/src/textures/base_texture.dart:157:15)#3 Texture.destroy (package:pixi_dart/src/textures/texture.dart:148:41)#4 animate (http://127.0.0.1:8080/1_basics/index.dart:56:58)#5 _rootRunUnary (dart:async/zone.dart:730)#6 _RootZone.runUnary (dart:async/zone.dart:864)#7 _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:488)#8 _Future._propagateToListeners (dart:async/future_impl.dart:571)#9 _Future._complete (dart:async/future_impl.dart:317)#10 _SyncCompleter.complete (dart:async/future_impl.dart:44)#11 Window.animationFrame.<anonymous closure> (dart:html:29269) Exception: String expected Tho it works if I try doing it in JavaScript via the:PIXI.TextureCache['bunny.png'].destroy(true);Instead of the error, the spinning bunny changes into a black rectangle, which is what I would expect it to do. Quote Link to comment Share on other sites More sharing options...
FedeOmoto Posted August 30, 2014 Share Posted August 30, 2014 Hi again! From the example in your first post, it seems that you're loading a SpriteSheet. If that's the case, it's even easier to free up the texture resources!Just take any of the resulting Sprites and call:sprite.texture.destroy(true);That will suffice as you'll be creating Sprites from the same BaseTexture (the Texture objects themselves will be freed up by the garbage collector when they are dereferenced). Regards,Fede Quote Link to comment Share on other sites More sharing options...
hubert Posted August 30, 2014 Share Posted August 30, 2014 Why are you adding the destroy() method to the remove from cache texture? Try doing something like this.Texture.removeTextureFromCache('bunny.png')While clalling this method dart removes the object property and everything that is under it. This is what happens under the hood in dartTexture._cache.remove(id);Remove() is a native dart method. And since dart is a garbage collector language all dereferenced elements will be deleted from memory. http://www.sevenative.com Quote Link to comment Share on other sites More sharing options...
FedeOmoto Posted August 30, 2014 Share Posted August 30, 2014 Hi BasomtiKombucha, Thank you for pointing that! My bad, sorry, there's a bug that arises only in the Dart code when trying to destroy a BaseTexture (the Dart "type checker" doesn't allow you to set an ImageElement's src proterty to null, it must be a String). It's now fixed on Pub and GitHub: https://github.com/FedeOmoto/pixihttps://pub.dartlang.org/packages/pixi_dart Can you please give it a try? Regards,Fede Quote Link to comment Share on other sites More sharing options...
FedeOmoto Posted August 30, 2014 Share Posted August 30, 2014 That's right Hubert, but since BasomtiKombucha wants to additionally destroy the Texture's BaseTexture, you've to call the destroy method (Texture.removeTextureFromCache returns the Texture being removed from the cache, so calling destroy(true) on it frees up the BaseTexture also). Why are you adding the destroy() method to the remove from cache texture? Try doing something like this.Texture.removeTextureFromCache('bunny.png')While clalling this method dart removes the object property and everything that is under it. This is what happens under the hood in dartTexture._cache.remove(id);Remove() is a native dart method. And since dart is a garbage collector language all dereferenced elements will be deleted from memory. http://www.sevenative.com Quote Link to comment Share on other sites More sharing options...
hubert Posted August 30, 2014 Share Posted August 30, 2014 Ok! Since I'm not very advanced in dart? Does cascading (method chaining) work in dart even in case of remove statement? Remove returns the element that has been removed? Laika? Is the new code working? SRSLY I want to know. http://www.sevenative.com Quote Link to comment Share on other sites More sharing options...
Sebi Posted August 30, 2014 Share Posted August 30, 2014 (nvm this post, lol) Quote Link to comment Share on other sites More sharing options...
FedeOmoto Posted August 31, 2014 Share Posted August 31, 2014 Dart supports both cascading and method chaining: http://news.dartlang.org/2012/02/method-cascades-in-dart-posted-by-gilad.html Perhaps I didn't explain myself properly, the idea is to destroy the Texture's BaseTexure after it has been removed from the cache, that's what you achieve calling:Texture.removeTextureFromCache('textureId').destroy(true);As I already said, that's convenient if you have a list of textureIds somewhere, but as Sebastian pointed out, I think it's easier (more elegant?) to just call:sprite.texture.destroy(true);Regards,Fede Ok! Since I'm not very advanced in dart? Does cascading (method chaining) work in dart even in case of remove statement? Remove returns the element that has been removed? Laika? Is the new code working? SRSLY I want to know. http://www.sevenative.com Quote Link to comment Share on other sites More sharing options...
BasomtiKombucha Posted September 1, 2014 Author Share Posted September 1, 2014 Yes now it all works flawlessly! Thanks! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.