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 <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2015-01-14 23:10:19 -05:00
parent 05a671e627
commit 64d961a8f9
4 changed files with 56 additions and 15 deletions

View File

@ -313,6 +313,11 @@ public enum GameImage {
*/ */
private static int containerWidth, containerHeight; private static int containerWidth, containerHeight;
/**
* Whether a skin image has been loaded.
*/
private static boolean skinImageLoaded = false;
/** /**
* Initializes the GameImage class with container dimensions. * Initializes the GameImage class with container dimensions.
* @param width the container width * @param width the container width
@ -323,6 +328,19 @@ public enum GameImage {
containerHeight = height; 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. * Constructor.
* @param filename the image file name * @param filename the image file name
@ -353,6 +371,8 @@ public enum GameImage {
* The skin image takes priority over the default image. * The skin image takes priority over the default image.
*/ */
public Image getImage() { public Image getImage() {
if (defaultImage == null)
setDefaultImage();
return (skinImage != null) ? skinImage : defaultImage; return (skinImage != null) ? skinImage : defaultImage;
} }
@ -369,13 +389,14 @@ public enum GameImage {
/** /**
* Sets the default image for this resource. * Sets the default image for this resource.
* If the default image has already been loaded, this will do nothing.
*/ */
public void setDefaultImage() { public void setDefaultImage() {
if (defaultImage != null)
return;
try { try {
if (defaultImage != null && !defaultImage.isDestroyed())
defaultImage.destroy();
defaultImage = new Image(filename); defaultImage = new Image(filename);
process();
} catch (SlickException e) { } catch (SlickException e) {
Log.error(String.format("Failed to set default image '%s'.", filename), 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 * @return true if a new skin image is loaded, false otherwise
*/ */
public boolean setSkinImage(File dir) { public boolean setSkinImage(File dir) {
try { if (dir == null)
// destroy the existing image, if any return false;
if (skinImage != null && !skinImage.isDestroyed())
skinImage.destroy();
// destroy the existing image, if any
destroySkinImage();
try {
// set a new image // set a new image
File file = new File(dir, filename); File file = new File(dir, filename);
if (file.isFile() && !Options.isBeatmapSkinIgnored()) { if (file.isFile() && !Options.isBeatmapSkinIgnored()) {
skinImage = new Image(file.getAbsolutePath()); skinImage = new Image(file.getAbsolutePath());
process();
skinImageLoaded = true;
return true; return true;
} else { } else {
skinImage = null; 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). * Sub-method for image processing actions (via an override).
* @param img the image to process * @param img the image to process
@ -421,7 +461,7 @@ public enum GameImage {
/** /**
* Performs individual post-loading actions on the image. * Performs individual post-loading actions on the image.
*/ */
public void process() { private void process() {
setImage(process_sub(getImage(), containerWidth, containerHeight)); setImage(process_sub(getImage(), containerWidth, containerHeight));
} }
} }

View File

@ -184,12 +184,8 @@ public class Utils {
Log.error("Failed to load fonts.", e); Log.error("Failed to load fonts.", e);
} }
// set default game images // initialize game images
GameImage.init(width, height); GameImage.init(width, height);
for (GameImage img : GameImage.values()) {
img.setDefaultImage();
img.process();
}
// initialize game mods // initialize game mods
for (GameMod mod : GameMod.values()) for (GameMod mod : GameMod.values())

View File

@ -859,8 +859,10 @@ public class Game extends BasicGameState {
// set images // set images
File parent = osu.getFile().getParentFile(); File parent = osu.getFile().getParentFile();
for (GameImage img : GameImage.values()) { for (GameImage img : GameImage.values()) {
if (img.isGameImage() && img.setSkinImage(parent)) if (img.isGameImage()) {
img.process(); img.setDefaultImage(); // ensure that default image has been loaded
img.setSkinImage(parent);
}
} }
// skip button // skip button

View File

@ -581,6 +581,9 @@ public class SongMenu extends BasicGameState {
// stop playing the theme song // stop playing the theme song
if (MusicController.isThemePlaying() && focusNode != null) if (MusicController.isThemePlaying() && focusNode != null)
MusicController.play(focusNode.osuFiles.get(focusNode.osuFileIndex), true); MusicController.play(focusNode.osuFiles.get(focusNode.osuFileIndex), true);
// destroy skin images, if any
GameImage.destroySkinImages();
} }
@Override @Override