From f8dad2889fe582ac8ecd4be512d3a9b1804ce827 Mon Sep 17 00:00:00 2001 From: Jeffrey Han Date: Thu, 15 Jan 2015 18:16:46 -0500 Subject: [PATCH] Added support for multiple GameImage file extensions. Specifically, the main menu background and pause/fail backgrounds now accept JPGs as well as PNGs. Other changes: - Don't draw the default pause/fail background if the buttons are skinned and the background is unskinned. - Preload logo and main menu background. Signed-off-by: Jeffrey Han --- src/itdelatrisu/opsu/GameImage.java | 329 +++++++++++------- src/itdelatrisu/opsu/Utils.java | 2 + .../opsu/states/GamePauseMenu.java | 16 +- src/itdelatrisu/opsu/states/MainMenu.java | 23 +- 4 files changed, 224 insertions(+), 146 deletions(-) diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index 3eeb9e47..c99d95c1 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -21,6 +21,8 @@ package itdelatrisu.opsu; import itdelatrisu.opsu.states.Options; import java.io.File; +import java.util.ArrayList; +import java.util.List; import org.newdawn.slick.Image; import org.newdawn.slick.SlickException; @@ -31,60 +33,60 @@ import org.newdawn.slick.util.Log; */ public enum GameImage { // Game - SECTION_PASS ("section-pass.png"), - SECTION_FAIL ("section-fail.png"), - WARNINGARROW ("play-warningarrow.png"), - SKIP ("play-skip.png") { + SECTION_PASS ("section-pass", "png"), + SECTION_FAIL ("section-fail", "png"), + WARNINGARROW ("play-warningarrow", "png"), + SKIP ("play-skip", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h * 0.1f) / img.getHeight()); } }, - COUNTDOWN_READY ("ready.png") { + COUNTDOWN_READY ("ready", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h / 3f) / img.getHeight()); } }, - COUNTDOWN_3 ("count3.png") { + COUNTDOWN_3 ("count3", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h / 3f) / img.getHeight()); } }, - COUNTDOWN_2 ("count2.png") { + COUNTDOWN_2 ("count2", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h / 3f) / img.getHeight()); } }, - COUNTDOWN_1 ("count1.png") { + COUNTDOWN_1 ("count1", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h / 3f) / img.getHeight()); } }, - COUNTDOWN_GO ("go.png") { + COUNTDOWN_GO ("go", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h / 3f) / img.getHeight()); } }, - HITCIRCLE_SELECT ("hitcircleselect.png"), - UNRANKED ("play-unranked.png"), + HITCIRCLE_SELECT ("hitcircleselect", "png"), + UNRANKED ("play-unranked", "png"), // Game Pause/Fail - PAUSE_CONTINUE ("pause-continue.png"), - PAUSE_RETRY ("pause-retry.png"), - PAUSE_BACK ("pause-back.png"), - PAUSE_OVERLAY ("pause-overlay.png") { + PAUSE_CONTINUE ("pause-continue", "png"), + PAUSE_RETRY ("pause-retry", "png"), + PAUSE_BACK ("pause-back", "png"), + PAUSE_OVERLAY ("pause-overlay", "png|jpg") { @Override protected Image process_sub(Image img, int w, int h) { img.setAlpha(0.7f); return img.getScaledCopy(w, h); } }, - FAIL_BACKGROUND ("fail-background.png") { + FAIL_BACKGROUND ("fail-background", "png|jpg") { @Override protected Image process_sub(Image img, int w, int h) { img.setAlpha(0.7f); @@ -93,214 +95,233 @@ public enum GameImage { }, // Circle - HITCIRCLE ("hitcircle.png"), - HITCIRCLE_OVERLAY ("hitcircleoverlay.png"), - APPROACHCIRCLE ("approachcircle.png"), + HITCIRCLE ("hitcircle", "png"), + HITCIRCLE_OVERLAY ("hitcircleoverlay", "png"), + APPROACHCIRCLE ("approachcircle", "png"), // Slider - SLIDER_FOLLOWCIRCLE ("sliderfollowcircle.png"), - REVERSEARROW ("reversearrow.png"), - SLIDER_TICK ("sliderscorepoint.png"), + SLIDER_FOLLOWCIRCLE ("sliderfollowcircle", "png"), + REVERSEARROW ("reversearrow", "png"), + SLIDER_TICK ("sliderscorepoint", "png"), // Spinner - SPINNER_CIRCLE ("spinner-circle.png"), - SPINNER_APPROACHCIRCLE ("spinner-approachcircle.png"), - SPINNER_METRE ("spinner-metre.png"), - SPINNER_SPIN ("spinner-spin.png"), - SPINNER_CLEAR ("spinner-clear.png"), - SPINNER_OSU ("spinner-osu.png"), + SPINNER_CIRCLE ("spinner-circle", "png"), + SPINNER_APPROACHCIRCLE ("spinner-approachcircle", "png"), + SPINNER_METRE ("spinner-metre", "png"), + SPINNER_SPIN ("spinner-spin", "png"), + SPINNER_CLEAR ("spinner-clear", "png"), + SPINNER_OSU ("spinner-osu", "png"), // Game Score - SCOREBAR_BG ("scorebar-bg.png") { + SCOREBAR_BG ("scorebar-bg", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(w / 2, img.getHeight()); } }, - SCOREBAR_COLOUR ("scorebar-colour.png") { + SCOREBAR_COLOUR ("scorebar-colour", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(w / 2, img.getHeight()); } }, - SCOREBAR_KI ("scorebar-ki.png"), - SCOREBAR_KI_DANGER ("scorebar-kidanger.png"), - SCOREBAR_KI_DANGER2 ("scorebar-kidanger2.png"), - HIT_MISS ("hit0.png"), - HIT_50 ("hit50.png"), - HIT_100 ("hit100.png"), - HIT_300 ("hit300.png"), - HIT_100K ("hit100k.png"), - HIT_300K ("hit300k.png"), - HIT_300G ("hit300g.png"), - HIT_SLIDER10 ("sliderpoint10.png"), - HIT_SLIDER30 ("sliderpoint30.png"), - RANKING_SS ("ranking-X.png"), - RANKING_SS_SMALL ("ranking-X-small.png"), - RANKING_SSH ("ranking-XH.png"), - RANKING_SSH_SMALL ("ranking-XH-small.png"), - RANKING_S ("ranking-S.png"), - RANKING_S_SMALL ("ranking-S-small.png"), - RANKING_SH ("ranking-SH.png"), - RANKING_SH_SMALL ("ranking-SH-small.png"), - RANKING_A ("ranking-A.png"), - RANKING_A_SMALL ("ranking-A-small.png"), - RANKING_B ("ranking-B.png"), - RANKING_B_SMALL ("ranking-B-small.png"), - RANKING_C ("ranking-C.png"), - RANKING_C_SMALL ("ranking-C-small.png"), - RANKING_D ("ranking-D.png"), - RANKING_D_SMALL ("ranking-D-small.png"), - RANKING_PANEL ("ranking-panel.png") { + SCOREBAR_KI ("scorebar-ki", "png"), + SCOREBAR_KI_DANGER ("scorebar-kidanger", "png"), + SCOREBAR_KI_DANGER2 ("scorebar-kidanger2", "png"), + HIT_MISS ("hit0", "png"), + HIT_50 ("hit50", "png"), + HIT_100 ("hit100", "png"), + HIT_300 ("hit300", "png"), + HIT_100K ("hit100k", "png"), + HIT_300K ("hit300k", "png"), + HIT_300G ("hit300g", "png"), + HIT_SLIDER10 ("sliderpoint10", "png"), + HIT_SLIDER30 ("sliderpoint30", "png"), + RANKING_SS ("ranking-X", "png"), + RANKING_SS_SMALL ("ranking-X-small", "png"), + RANKING_SSH ("ranking-XH", "png"), + RANKING_SSH_SMALL ("ranking-XH-small", "png"), + RANKING_S ("ranking-S", "png"), + RANKING_S_SMALL ("ranking-S-small", "png"), + RANKING_SH ("ranking-SH", "png"), + RANKING_SH_SMALL ("ranking-SH-small", "png"), + RANKING_A ("ranking-A", "png"), + RANKING_A_SMALL ("ranking-A-small", "png"), + RANKING_B ("ranking-B", "png"), + RANKING_B_SMALL ("ranking-B-small", "png"), + RANKING_C ("ranking-C", "png"), + RANKING_C_SMALL ("ranking-C-small", "png"), + RANKING_D ("ranking-D", "png"), + RANKING_D_SMALL ("ranking-D-small", "png"), + RANKING_PANEL ("ranking-panel", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h * 0.63f) / img.getHeight()); } }, - RANKING_PERFECT ("ranking-perfect.png") { + RANKING_PERFECT ("ranking-perfect", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h * 0.16f) / img.getHeight()); } }, - RANKING_TITLE ("ranking-title.png") { + RANKING_TITLE ("ranking-title", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h * 0.15f) / img.getHeight()); } }, - RANKING_MAXCOMBO ("ranking-maxcombo.png") { + RANKING_MAXCOMBO ("ranking-maxcombo", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h * 0.05f) / img.getHeight()); } }, - RANKING_ACCURACY ("ranking-accuracy.png") { + RANKING_ACCURACY ("ranking-accuracy", "png") { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h * 0.05f) / img.getHeight()); } }, - DEFAULT_0 ("default-0.png"), - DEFAULT_1 ("default-1.png"), - DEFAULT_2 ("default-2.png"), - DEFAULT_3 ("default-3.png"), - DEFAULT_4 ("default-4.png"), - DEFAULT_5 ("default-5.png"), - DEFAULT_6 ("default-6.png"), - DEFAULT_7 ("default-7.png"), - DEFAULT_8 ("default-8.png"), - DEFAULT_9 ("default-9.png"), - SCORE_0 ("score-0.png"), - SCORE_1 ("score-1.png"), - SCORE_2 ("score-2.png"), - SCORE_3 ("score-3.png"), - SCORE_4 ("score-4.png"), - SCORE_5 ("score-5.png"), - SCORE_6 ("score-6.png"), - SCORE_7 ("score-7.png"), - SCORE_8 ("score-8.png"), - SCORE_9 ("score-9.png"), - SCORE_COMMA ("score-comma.png"), - SCORE_DOT ("score-dot.png"), - SCORE_PERCENT ("score-percent.png"), - SCORE_X ("score-x.png"), + DEFAULT_0 ("default-0", "png"), + DEFAULT_1 ("default-1", "png"), + DEFAULT_2 ("default-2", "png"), + DEFAULT_3 ("default-3", "png"), + DEFAULT_4 ("default-4", "png"), + DEFAULT_5 ("default-5", "png"), + DEFAULT_6 ("default-6", "png"), + DEFAULT_7 ("default-7", "png"), + DEFAULT_8 ("default-8", "png"), + DEFAULT_9 ("default-9", "png"), + SCORE_0 ("score-0", "png"), + SCORE_1 ("score-1", "png"), + SCORE_2 ("score-2", "png"), + SCORE_3 ("score-3", "png"), + SCORE_4 ("score-4", "png"), + SCORE_5 ("score-5", "png"), + SCORE_6 ("score-6", "png"), + SCORE_7 ("score-7", "png"), + SCORE_8 ("score-8", "png"), + SCORE_9 ("score-9", "png"), + SCORE_COMMA ("score-comma", "png"), + SCORE_DOT ("score-dot", "png"), + SCORE_PERCENT ("score-percent", "png"), + SCORE_X ("score-x", "png"), // Non-Game Components - MENU_BACK ("menu-back.png", false) { + MENU_BACK ("menu-back", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h * 0.1f) / img.getHeight()); } }, - MENU_BUTTON_BG ("menu-button-background.png", false) { + MENU_BUTTON_BG ("menu-button-background", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(w / 2, h / 6); } }, - MENU_TAB ("selection-tab.png", false) { + MENU_TAB ("selection-tab", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h * 0.033f) / img.getHeight()); } }, - MENU_SEARCH ("search.png", false) { + MENU_SEARCH ("search", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(Utils.FONT_BOLD.getLineHeight() * 2f / img.getHeight()); } }, - MENU_OPTIONS ("options.png", false) { + MENU_OPTIONS ("options", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(Utils.FONT_BOLD.getLineHeight() * 2f / img.getHeight()); } }, - MENU_MUSICNOTE ("music-note.png", false) { + MENU_MUSICNOTE ("music-note", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { int r = (int) (Utils.FONT_LARGE.getLineHeight() * 0.75f + Utils.FONT_DEFAULT.getLineHeight()); return img.getScaledCopy(r, r); } }, - MENU_LOADER ("loader.png", false) { + MENU_LOADER ("loader", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { int r = (int) (Utils.FONT_LARGE.getLineHeight() * 0.75f + Utils.FONT_DEFAULT.getLineHeight()); return img.getScaledCopy(r / 48f); } }, - MENU_LOGO ("logo.png", false) { + MENU_BG ("menu-background", "png|jpg", false) { + @Override + protected Image process_sub(Image img, int w, int h) { + img.setAlpha(0.9f); + return img.getScaledCopy(w, h); + } + }, + MENU_LOGO ("logo", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h / 1.2f) / img.getHeight()); } }, - MENU_PlAY ("menu-play.png", false) { + MENU_PlAY ("menu-play", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(MENU_LOGO.getImage().getWidth() * 0.83f / img.getWidth()); } }, - MENU_EXIT ("menu-exit.png", false) { + MENU_EXIT ("menu-exit", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(MENU_LOGO.getImage().getWidth() * 0.66f / img.getWidth()); } }, - MENU_BUTTON_MID ("button-middle.png", false) { + MENU_BUTTON_MID ("button-middle", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(w / 2, img.getHeight()); } }, - MENU_BUTTON_LEFT ("button-left.png", false), - MENU_BUTTON_RIGHT ("button-right.png", false), + MENU_BUTTON_LEFT ("button-left", "png", false), + MENU_BUTTON_RIGHT ("button-right", "png", false), - MUSIC_PLAY ("music-play.png", false), - MUSIC_PAUSE ("music-pause.png", false), - MUSIC_NEXT ("music-next.png", false), - MUSIC_PREVIOUS ("music-previous.png", false), + MUSIC_PLAY ("music-play", "png", false), + MUSIC_PAUSE ("music-pause", "png", false), + MUSIC_NEXT ("music-next", "png", false), + MUSIC_PREVIOUS ("music-previous", "png", false), - RANKING_RETRY ("ranking-retry.png", false) { + RANKING_RETRY ("ranking-retry", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h * 0.15f) / img.getHeight()); } }, - RANKING_EXIT ("ranking-back.png", false) { + RANKING_EXIT ("ranking-back", "png", false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy((h * 0.15f) / img.getHeight()); } }; + /** + * Image file types. + */ + private static final byte + IMG_PNG = 1, + IMG_JPG = 2; + /** * The file name. */ private String filename; + /** + * Image file type. + */ + private byte type; + /** * Whether or not the image is related to gameplay. * Game images are skinnable per beatmap, while other images are not. @@ -350,22 +371,43 @@ public enum GameImage { } } + /** + * Returns the bitmask image type from a type string. + * @param type the type string + * @return the byte bitmask + */ + private static byte getType(String type) { + byte b = 0; + String[] s = type.split("\\|"); + for (int i = 0; i < s.length; i++) { + if (s[i].equals("png")) + b |= IMG_PNG; + else if (s[i].equals("jpg")) + b |= IMG_JPG; + } + return b; + } + /** * Constructor. * @param filename the image file name + * @param type the file types (separated by '|') */ - GameImage(String filename) { + GameImage(String filename, String type) { this.filename = filename; + this.type = getType(type); this.gameImage = true; } /** * Constructor. * @param filename the image file name + * @param type the file types (separated by '|') * @param gameImage whether or not the image is related to gameplay */ - GameImage(String filename, boolean gameImage) { + GameImage(String filename, String type, boolean gameImage) { this.filename = filename; + this.type = getType(type); this.gameImage = gameImage; } @@ -396,6 +438,19 @@ public enum GameImage { this.defaultImage = img; } + /** + * Returns a list of possible filenames (with extensions). + * @return filename list + */ + private List getFileNames() { + List list = new ArrayList(2); + if ((type & IMG_PNG) != 0) + list.add(String.format("%s.png", filename)); + if ((type & IMG_JPG) != 0) + list.add(String.format("%s.jpg", filename)); + return list; + } + /** * Sets the default image for this resource. * If the default image has already been loaded, this will do nothing. @@ -403,12 +458,20 @@ public enum GameImage { public void setDefaultImage() { if (defaultImage != null) return; - try { - defaultImage = new Image(filename); - process(); - } catch (SlickException e) { - Log.error(String.format("Failed to set default image '%s'.", filename), e); + for (String name : getFileNames()) { + try { + // try loading the image + Image img = new Image(name); + + // image successfully loaded + this.defaultImage = img; + process(); + return; + } catch (SlickException | RuntimeException e) { + continue; + } } + Log.error(String.format("Failed to set default image '%s'.", filename)); } /** @@ -423,24 +486,42 @@ public enum GameImage { // 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()); + // beatmap skins disabled + if (Options.isBeatmapSkinIgnored()) + return false; + + // look for a skin image + String errorFile = null; + for (String name : getFileNames()) { + File file = new File(dir, name); + if (!file.isFile()) + continue; + try { + // try loading the image + Image img = new Image(file.getAbsolutePath()); + + // image successfully loaded + this.skinImage = img; process(); skinImageLoaded = true; return true; - } else { - skinImage = null; - return false; + } catch (SlickException | RuntimeException e) { + errorFile = file.getAbsolutePath(); + continue; } - } catch (SlickException e) { - Log.error(String.format("Failed to set skin image '%s'.", filename), e); - return false; } + skinImage = null; + if (errorFile != null) + Log.error(String.format("Failed to set skin image '%s'.", errorFile)); + return false; } + /** + * Returns whether a skin image is currently loaded. + * @return true if skin image exists + */ + public boolean hasSkinImage() { return (skinImage != null && !skinImage.isDestroyed()); } + /** * Destroys the associated skin image, if any. */ diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java index 5c2a83d3..97d6fe21 100644 --- a/src/itdelatrisu/opsu/Utils.java +++ b/src/itdelatrisu/opsu/Utils.java @@ -186,6 +186,8 @@ public class Utils { // initialize game images GameImage.init(width, height); + GameImage.MENU_LOGO.setDefaultImage(); + GameImage.MENU_BG.setDefaultImage(); // initialize game mods for (GameMod mod : GameMod.values()) diff --git a/src/itdelatrisu/opsu/states/GamePauseMenu.java b/src/itdelatrisu/opsu/states/GamePauseMenu.java index 7877e9dd..e3b9faaa 100644 --- a/src/itdelatrisu/opsu/states/GamePauseMenu.java +++ b/src/itdelatrisu/opsu/states/GamePauseMenu.java @@ -84,11 +84,19 @@ public class GamePauseMenu extends BasicGameState { @Override public void render(GameContainer container, StateBasedGame game, Graphics g) throws SlickException { - // background - if (gameState.getRestart() != Game.Restart.LOSE) - GameImage.PAUSE_OVERLAY.getImage().draw(); + // get background image + GameImage bg = (gameState.getRestart() == Game.Restart.LOSE) ? + GameImage.FAIL_BACKGROUND : GameImage.PAUSE_OVERLAY; + + // don't draw default background if button skinned and background unskinned + boolean buttonsSkinned = + GameImage.PAUSE_CONTINUE.hasSkinImage() || + GameImage.PAUSE_RETRY.hasSkinImage() || + GameImage.PAUSE_BACK.hasSkinImage(); + if (!buttonsSkinned || bg.hasSkinImage()) + bg.getImage().draw(); else - GameImage.FAIL_BACKGROUND.getImage().draw(); + g.setBackground(Color.black); // draw buttons if (gameState.getRestart() != Game.Restart.LOSE) diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index 02003cc6..3c163dfd 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -93,11 +93,6 @@ public class MainMenu extends BasicGameState { */ private Stack previous; - /** - * Main menu background image (optional). - */ - private Image backgroundImage; - /** * Background alpha level (for fade-in effect). */ @@ -160,14 +155,6 @@ public class MainMenu extends BasicGameState { musicPrevious.setHoverScale(1.5f); reset(); - - // menu background - try { - backgroundImage = new Image("menu-background.jpg").getScaledCopy(width, height); - backgroundImage.setAlpha(0.9f); - } catch (Exception e) { - // optional - } } @Override @@ -181,11 +168,11 @@ public class MainMenu extends BasicGameState { if (Options.isDynamicBackgroundEnabled() && osu != null && osu.drawBG(width, height, bgAlpha)) ; - else if (backgroundImage != null) { - backgroundImage.setAlpha(bgAlpha); - backgroundImage.draw(); - } else - g.setBackground(Utils.COLOR_BLUE_BACKGROUND); + else { + Image bg = GameImage.MENU_BG.getImage(); + bg.setAlpha(bgAlpha); + bg.draw(); + } // draw buttons if (logoTimer > 0) {