From 64d961a8f9c51b4c524a561246e1de021524b6ee Mon Sep 17 00:00:00 2001 From: Jeffrey Han Date: Wed, 14 Jan 2015 23:10:19 -0500 Subject: [PATCH] Only load image resources when needed. - Stop loading all images on startup. - Game images are preloaded before the song starts. - Destroy skin images immediately after finishing a beatmap, potentially saving lots of memory. Signed-off-by: Jeffrey Han --- src/itdelatrisu/opsu/GameImage.java | 56 +++++++++++++++++++---- src/itdelatrisu/opsu/Utils.java | 6 +-- src/itdelatrisu/opsu/states/Game.java | 6 ++- src/itdelatrisu/opsu/states/SongMenu.java | 3 ++ 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index 94264926..299f0f21 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -313,6 +313,11 @@ public enum GameImage { */ private static int containerWidth, containerHeight; + /** + * Whether a skin image has been loaded. + */ + private static boolean skinImageLoaded = false; + /** * Initializes the GameImage class with container dimensions. * @param width the container width @@ -323,6 +328,19 @@ public enum GameImage { containerHeight = height; } + /** + * Destroys all skin images, if any have been loaded. + */ + public static void destroySkinImages() { + if (skinImageLoaded) { + for (GameImage img : GameImage.values()) { + if (img.isGameImage()) + img.destroySkinImage(); + } + skinImageLoaded = false; + } + } + /** * Constructor. * @param filename the image file name @@ -353,6 +371,8 @@ public enum GameImage { * The skin image takes priority over the default image. */ public Image getImage() { + if (defaultImage == null) + setDefaultImage(); return (skinImage != null) ? skinImage : defaultImage; } @@ -369,13 +389,14 @@ public enum GameImage { /** * Sets the default image for this resource. + * If the default image has already been loaded, this will do nothing. */ public void setDefaultImage() { + if (defaultImage != null) + return; try { - if (defaultImage != null && !defaultImage.isDestroyed()) - defaultImage.destroy(); - defaultImage = new Image(filename); + process(); } catch (SlickException e) { Log.error(String.format("Failed to set default image '%s'.", filename), e); } @@ -387,15 +408,19 @@ public enum GameImage { * @return true if a new skin image is loaded, false otherwise */ public boolean setSkinImage(File dir) { - try { - // destroy the existing image, if any - if (skinImage != null && !skinImage.isDestroyed()) - skinImage.destroy(); + if (dir == null) + return false; + // destroy the existing image, if any + destroySkinImage(); + + try { // set a new image File file = new File(dir, filename); if (file.isFile() && !Options.isBeatmapSkinIgnored()) { skinImage = new Image(file.getAbsolutePath()); + process(); + skinImageLoaded = true; return true; } else { skinImage = null; @@ -407,6 +432,21 @@ public enum GameImage { } } + /** + * Destroys the associated skin image, if any. + */ + private void destroySkinImage() { + if (skinImage == null) + return; + try { + if (!skinImage.isDestroyed()) + skinImage.destroy(); + skinImage = null; + } catch (SlickException e) { + Log.error(String.format("Failed to destroy skin image for '%s'.", this.name()), e); + } + } + /** * Sub-method for image processing actions (via an override). * @param img the image to process @@ -421,7 +461,7 @@ public enum GameImage { /** * Performs individual post-loading actions on the image. */ - public void process() { + private void process() { setImage(process_sub(getImage(), containerWidth, containerHeight)); } } \ No newline at end of file diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java index 71a68421..5c2a83d3 100644 --- a/src/itdelatrisu/opsu/Utils.java +++ b/src/itdelatrisu/opsu/Utils.java @@ -184,12 +184,8 @@ public class Utils { Log.error("Failed to load fonts.", e); } - // set default game images + // initialize game images GameImage.init(width, height); - for (GameImage img : GameImage.values()) { - img.setDefaultImage(); - img.process(); - } // initialize game mods for (GameMod mod : GameMod.values()) diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 9dca0a61..5ea8095a 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -859,8 +859,10 @@ public class Game extends BasicGameState { // set images File parent = osu.getFile().getParentFile(); for (GameImage img : GameImage.values()) { - if (img.isGameImage() && img.setSkinImage(parent)) - img.process(); + if (img.isGameImage()) { + img.setDefaultImage(); // ensure that default image has been loaded + img.setSkinImage(parent); + } } // skip button diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 4ba5a563..b3dbf676 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -581,6 +581,9 @@ public class SongMenu extends BasicGameState { // stop playing the theme song if (MusicController.isThemePlaying() && focusNode != null) MusicController.play(focusNode.osuFiles.get(focusNode.osuFileIndex), true); + + // destroy skin images, if any + GameImage.destroySkinImages(); } @Override