diff --git a/source/funkin/FunkinMemory.hx b/source/funkin/FunkinMemory.hx index a83ab0499..adfdf44e7 100644 --- a/source/funkin/FunkinMemory.hx +++ b/source/funkin/FunkinMemory.hx @@ -117,10 +117,7 @@ class FunkinMemory */ public static function cacheTexture(key:String):Void { - if (currentCachedTextures.exists(key)) - { - return; // Already cached. - } + if (currentCachedTextures.exists(key)) return; if (previousCachedTextures.exists(key)) { @@ -135,13 +132,13 @@ class FunkinMemory if (graphic == null) { FlxG.log.warn('Failed to cache graphic: $key'); + return; } - else - { - trace('Successfully cached graphic: $key'); - graphic.persist = true; - currentCachedTextures.set(key, graphic); - } + + trace('Successfully cached graphic: $key'); + graphic.persist = true; + currentCachedTextures.set(key, graphic); + forceRender(graphic); } /** @@ -150,26 +147,54 @@ class FunkinMemory */ static function permanentCacheTexture(key:String):Void { - if (permanentCachedTextures.exists(key)) - { - return; // Already cached. - } + if (permanentCachedTextures.exists(key)) return; var graphic:Null = FlxGraphic.fromAssetKey(key, false, null, true); if (graphic == null) { FlxG.log.warn('Failed to cache graphic: $key'); - } - else - { - trace('Successfully cached graphic: $key'); - graphic.persist = true; - permanentCachedTextures.set(key, graphic); + return; } + trace('Successfully cached graphic: $key'); + graphic.persist = true; + permanentCachedTextures.set(key, graphic); + forceRender(graphic); currentCachedTextures = permanentCachedTextures; } + /** + * Forces the GPU to load and upload a FlxGraphic. + */ + private static function forceRender(graphic:FlxGraphic):Void + { + if (graphic == null) return; + + var bmp:Null = FlxG.bitmap.get(graphic.key); + if (bmp != null && bmp.bitmap != null) var _:Int = bmp.bitmap.width; // Trigger + + // Draws sprite and actually caches it. + var sprite = new flixel.FlxSprite(); + sprite.loadGraphic(graphic); + sprite.draw(); // Draw sprite and load it into game's memory. + sprite.destroy(); + } + + /** + * Checks, if graphic with given path cached in memory. + */ + public static inline function isGraphicCached(path:String):Bool + return permanentCachedTextures.exists(path) || currentCachedTextures.exists(path) || previousCachedTextures.exists(path); + + public static function getCachedGraphic(path:String):Null + { + if (permanentCachedTextures.exists(path)) return permanentCachedTextures.get(path); + if (currentCachedTextures.exists(path)) return currentCachedTextures.get(path); + if (previousCachedTextures.exists(path)) return previousCachedTextures.get(path); // just in case + + return null; + } + /** * Prepares the cache for purging unused textures. */ diff --git a/source/funkin/graphics/FunkinSprite.hx b/source/funkin/graphics/FunkinSprite.hx index cfdfb32e0..72fe611b4 100644 --- a/source/funkin/graphics/FunkinSprite.hx +++ b/source/funkin/graphics/FunkinSprite.hx @@ -12,6 +12,7 @@ import flixel.math.FlxPoint; import flixel.graphics.frames.FlxFrame.FlxFrameAngle; import flixel.FlxCamera; import openfl.system.System; +import funkin.FunkinMemory; using StringTools; @@ -23,20 +24,6 @@ using StringTools; @:nullSafety class FunkinSprite extends FlxSprite { - /** - * An internal list of all the textures cached with `cacheTexture`. - * This excludes any temporary textures like those from `FlxText` or `makeSolidColor`. - */ - static var currentCachedTextures:Map = []; - - /** - * An internal list of textures that were cached in the previous state. - * We don't know whether we want to keep them cached or not. - */ - static var previousCachedTextures:Map = []; - - static var permanentCachedTextures:Map = []; - /** * @param x Starting X position * @param y Starting Y position @@ -216,122 +203,40 @@ class FunkinSprite extends FlxSprite return FlxG.bitmap.get(key) != null; } - /** - * Ensure the texture with the given key is cached. - * @param key The key of the texture to cache. - */ + @:deprecated("Use FunkinMemory.cacheTexture() instead") public static function cacheTexture(key:String):Void { - // We don't want to cache the same texture twice. - if (currentCachedTextures.exists(key)) return; - - if (previousCachedTextures.exists(key)) - { - // Move the graphic from the previous cache to the current cache. - var graphic = previousCachedTextures.get(key); - previousCachedTextures.remove(key); - if (graphic != null) currentCachedTextures.set(key, graphic); - return; - } - - // Else, texture is currently uncached. - var graphic:FlxGraphic = FlxGraphic.fromAssetKey(key, false, null, true); - if (graphic == null) - { - FlxG.log.warn('Failed to cache graphic: $key'); - } - else - { - trace('Successfully cached graphic: $key'); - graphic.persist = true; - currentCachedTextures.set(key, graphic); - } + FunkinMemory.cacheTexture(Paths.image(key)); } + @:deprecated("Use FunkinMemory.permanentCacheTexture() instead") public static function permanentCacheTexture(key:String):Void { - // We don't want to cache the same texture twice. - if (permanentCachedTextures.exists(key)) return; - - // Else, texture is currently uncached. - var graphic:FlxGraphic = FlxGraphic.fromAssetKey(key, false, null, true); - if (graphic == null) - { - FlxG.log.warn('Failed to cache graphic: $key'); - } - else - { - trace('Successfully cached graphic: $key'); - graphic.persist = true; - permanentCachedTextures.set(key, graphic); - } - - currentCachedTextures = permanentCachedTextures; + @:privateAccess FunkinMemory.permanentCacheTexture(Paths.image(key)); } + @:deprecated("Use FunkinMemory.cacheTexture() instead") public static function cacheSparrow(key:String):Void { - cacheTexture(Paths.image(key)); + FunkinMemory.cacheTexture(Paths.image(key)); } + @:deprecated("Use FunkinMemory.cacheTexture() instead") public static function cachePacker(key:String):Void { - cacheTexture(Paths.image(key)); + FunkinMemory.cacheTexture(Paths.image(key)); } - /** - * Call this, then `cacheTexture` to keep the textures we still need, then `purgeCache` to remove the textures that we won't be using anymore. - */ + @:deprecated("Use FunkinMemory.preparePurgeTextureCache() instead") public static function preparePurgeCache():Void { - previousCachedTextures = currentCachedTextures; - - for (graphicKey in previousCachedTextures.keys()) - { - if (!permanentCachedTextures.exists(graphicKey)) continue; - previousCachedTextures.remove(graphicKey); - } - - currentCachedTextures = permanentCachedTextures; + FunkinMemory.preparePurgeTextureCache(); } + @:deprecated("Use FunkinMemory.purgeCache() instead") public static function purgeCache():Void { - // Everything that is in previousCachedTextures but not in currentCachedTextures should be destroyed. - for (graphicKey in previousCachedTextures.keys()) - { - var graphic = previousCachedTextures.get(graphicKey); - if (graphic == null) continue; - FlxG.bitmap.remove(graphic); - graphic.destroy(); - previousCachedTextures.remove(graphicKey); - } - @:privateAccess - if (FlxG.bitmap._cache == null) - { - @:privateAccess - FlxG.bitmap._cache = new Map(); - System.gc(); - return; - } - - @:privateAccess - for (key in FlxG.bitmap._cache.keys()) - { - var obj:Null = FlxG.bitmap.get(key); - if (obj == null) continue; - if (obj.persist) continue; - if (permanentCachedTextures.exists(key)) continue; - if (!(obj.useCount <= 0 || key.contains("characters") || key.contains("charSelect") || key.contains("results"))) continue; - - FlxG.bitmap.removeKey(key); - obj.destroy(); - } - openfl.Assets.cache.clear("songs"); - openfl.Assets.cache.clear("sounds"); - openfl.Assets.cache.clear("music"); - - System.gc(); + FunkinMemory.purgeCache(); } static function isGraphicCached(graphic:FlxGraphic):Bool diff --git a/source/funkin/play/character/MultiSparrowCharacter.hx b/source/funkin/play/character/MultiSparrowCharacter.hx index 0b97837e1..bf4d53d12 100644 --- a/source/funkin/play/character/MultiSparrowCharacter.hx +++ b/source/funkin/play/character/MultiSparrowCharacter.hx @@ -94,6 +94,7 @@ class MultiSparrowCharacter extends BaseCharacter { trace('Concatenating multi-sparrow atlas: ${asset}'); subTexture.parent.destroyOnNoUse = false; + FunkinMemory.cacheTexture(Paths.image(asset)); } texture.addAtlas(subTexture);