From fff0080ddc3b280f280f81efd6ce38d8ed9517f9 Mon Sep 17 00:00:00 2001 From: fd Date: Sun, 15 Feb 2015 18:51:07 -0500 Subject: [PATCH 1/6] Combo Color ordering General Image scaling Score fixed size width Spinner centering (slick has bad centering) Broke Ranking Panel --- src/itdelatrisu/opsu/GameData.java | 72 +- src/itdelatrisu/opsu/GameImage.java | 253 ++++- src/itdelatrisu/opsu/Opsu.java | 9 +- src/itdelatrisu/opsu/OsuHitObject.java | 5 + src/itdelatrisu/opsu/OsuParser.java | 35 +- src/itdelatrisu/opsu/Utils.java | 4 +- src/org/newdawn/slick/Image.java | 1403 ++++++++++++++++++++++++ 7 files changed, 1701 insertions(+), 80 deletions(-) create mode 100644 src/org/newdawn/slick/Image.java diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index 80617239..fdd4176f 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -457,6 +457,35 @@ public class GameData { } } } + /** + * Draws a string of scoreSymbols. + * @param str the string to draw + * @param x the starting x coordinate + * @param y the y coordinate + * @param scale the scale to apply + * @param rightAlign align right (true) or left (false) + */ + private void drawFixedSizeSymbolString(String str, int x, int y, float scale, float fixedsize, boolean rightAlign) { + char[] c = str.toCharArray(); + int cx = x; + if (rightAlign) { + for (int i = c.length - 1; i >= 0; i--) { + Image digit = getScoreSymbolImage(c[i]); + if (scale != 1.0f) + digit = digit.getScaledCopy(scale); + cx -= fixedsize; + digit.draw(cx + (fixedsize-digit.getWidth())/2, y); + } + } else { + for (int i = 0; i < c.length; i++) { + Image digit = getScoreSymbolImage(c[i]); + if (scale != 1.0f) + digit = digit.getScaledCopy(scale); + digit.draw(cx + (fixedsize-digit.getWidth())/2, y); + cx += fixedsize; + } + } + } /** * Draws game elements: @@ -470,28 +499,28 @@ public class GameData { int marginX = (int) (width * 0.008f); // score - drawSymbolString((scoreDisplay < 100000000) ? String.format("%08d", scoreDisplay) : Long.toString(scoreDisplay), - width - marginX, 0, 1.0f, true); + drawFixedSizeSymbolString((scoreDisplay < 100000000) ? String.format("%08d", scoreDisplay) : Long.toString(scoreDisplay), + width - marginX, 0, 1.0f, getScoreSymbolImage('0').getWidth()-2, true); // score percentage int symbolHeight = getScoreSymbolImage('0').getHeight(); float scorePercent = getScorePercent(); drawSymbolString( String.format((scorePercent < 10f) ? "0%.2f%%" : "%.2f%%", scorePercent), - width - marginX, symbolHeight, 0.75f, true + width - marginX, symbolHeight, 0.60f, true ); // map progress circle g.setAntiAlias(true); g.setLineWidth(2f); g.setColor(Color.white); - int circleX = width - marginX - ( // max width: "100.00%" + float circleDiameter = symbolHeight * 0.60f; + int circleX = (int) (width - marginX - ( // max width: "100.00%" getScoreSymbolImage('1').getWidth() + getScoreSymbolImage('0').getWidth() * 4 + getScoreSymbolImage('.').getWidth() + getScoreSymbolImage('%').getWidth() - ); - float circleDiameter = symbolHeight * 0.75f; + ) * 0.60f - circleDiameter); g.drawOval(circleX, symbolHeight, circleDiameter, circleDiameter); OsuFile osu = MusicController.getOsuFile(); @@ -621,18 +650,16 @@ public class GameData { * @param osu the OsuFile */ public void drawRankingElements(Graphics g, OsuFile osu) { - // grade - Grade grade = getGrade(); - if (grade != Grade.NULL) - grade.getLargeImage().draw(width * 0.985f - grade.getLargeImage().getWidth(), height * 0.09f); - + + float marginX = width * 0.01f, marginY = height * 0.025f; // header & "Ranking" text Image rankingTitle = GameImage.RANKING_TITLE.getImage(); float rankingHeight = (rankingTitle.getHeight() * 0.75f) + 3; + + g.setColor(Utils.COLOR_BLACK_ALPHA); g.fillRect(0, 0, width, rankingHeight); rankingTitle.draw((width * 0.97f) - rankingTitle.getWidth(), 0); - float marginX = width * 0.01f, marginY = height * 0.01f; Utils.FONT_LARGE.drawString(marginX, marginY, String.format("%s - %s [%s]", osu.getArtist(), osu.getTitle(), osu.version), Color.white); Utils.FONT_MEDIUM.drawString(marginX, marginY + Utils.FONT_LARGE.getLineHeight() - 6, @@ -645,19 +672,20 @@ public class GameData { Image rankingPanel = GameImage.RANKING_PANEL.getImage(); int rankingPanelWidth = rankingPanel.getWidth(); int rankingPanelHeight = rankingPanel.getHeight(); - rankingPanel.draw(0, rankingHeight - (rankingHeight / 10f)); + rankingPanel.draw(0, rankingHeight);//rankingHeight - (rankingHeight / 10f)); - float symbolTextScale = (height / 15f) / getScoreSymbolImage('0').getHeight(); - float rankResultScale = (height * 0.03f) / hitResults[HIT_300].getHeight(); + float scoreTextScale = 1.2f; //(height / 15f) / getScoreSymbolImage('0').getHeight(); + float symbolTextScale = 1.2f; //(height / 15f) / getScoreSymbolImage('0').getHeight(); + float rankResultScale = 0.5f;//(height * 0.03f) / hitResults[HIT_300].getHeight(); // score - drawSymbolString((score < 100000000) ? String.format("%08d", score) : Long.toString(score), - (int) (width * 0.18f), height / 6, symbolTextScale, false); + drawFixedSizeSymbolString((score < 100000000) ? String.format("%08d", score) : Long.toString(score), + (int) (width * 0.18f), (int) (rankingHeight+50), scoreTextScale, getScoreSymbolImage('0').getWidth()*scoreTextScale-2, false); // result counts - float resultInitialX = rankingPanelWidth * 0.20f; - float resultInitialY = rankingHeight + (rankingPanelHeight * 0.27f) + (rankingHeight / 10f); - float resultHitInitialX = rankingPanelWidth * 0.05f; + float resultInitialX = 150;// rankingPanelWidth * 0.20f; + float resultInitialY = rankingHeight + (rankingPanelHeight * 0.20f) + (rankingHeight / 10f); + float resultHitInitialX = 0;//rankingPanelWidth * 0.05f; float resultHitInitialY = resultInitialY + (getScoreSymbolImage('0').getHeight() * symbolTextScale); float resultOffsetX = rankingPanelWidth / 2f; float resultOffsetY = rankingPanelHeight * 0.2f; @@ -700,6 +728,10 @@ public class GameData { (height * 0.99f) - GameImage.RANKING_PERFECT.getImage().getHeight() ); } + // grade + Grade grade = getGrade(); + if (grade != Grade.NULL) + grade.getLargeImage().draw(width * 0.985f - grade.getLargeImage().getWidth(), rankingHeight+marginY); // mod icons int modWidth = GameMod.AUTO.getImage().getWidth(); diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index ec6a3ff3..573d79df 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -35,31 +35,31 @@ public enum GameImage { CURSOR ("cursor", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(1 + ((h - 600) / 1000f)); + return img.getScaledCopy(h / 768f); } }, CURSOR_MIDDLE ("cursormiddle", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(1 + ((h - 600) / 1000f)); + return img.getScaledCopy(h / 768f); } }, CURSOR_TRAIL ("cursortrail", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(1 + ((h - 600) / 1000f)); + return img.getScaledCopy(h / 768f); } }, CURSOR_OLD ("cursor2", "png", false, false) { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(1 + ((h - 600) / 1000f)); + return img.getScaledCopy(h / 768f); } }, CURSOR_TRAIL_OLD ("cursortrail2", "png", false, false) { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(1 + ((h - 600) / 1000f)); + return img.getScaledCopy(h / 768f); } }, @@ -183,125 +183,280 @@ public enum GameImage { 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_MISS ("hit0", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + HIT_50 ("hit50", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + HIT_100 ("hit100", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + HIT_300 ("hit300", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + HIT_100K ("hit100k", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + HIT_300K ("hit300k", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + HIT_300G ("hit300g", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, HIT_SLIDER10 ("sliderpoint10", "png"), HIT_SLIDER30 ("sliderpoint30", "png"), RANKING_SS ("ranking-X", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h / 2f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, RANKING_SS_SMALL ("ranking-X-small", "png"), RANKING_SSH ("ranking-XH", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h / 2f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, RANKING_SSH_SMALL ("ranking-XH-small", "png"), RANKING_S ("ranking-S", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h / 2f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, RANKING_S_SMALL ("ranking-S-small", "png"), RANKING_SH ("ranking-SH", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h / 2f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, RANKING_SH_SMALL ("ranking-SH-small", "png"), RANKING_A ("ranking-A", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h / 2f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, RANKING_A_SMALL ("ranking-A-small", "png"), RANKING_B ("ranking-B", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h / 2f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, RANKING_B_SMALL ("ranking-B-small", "png"), RANKING_C ("ranking-C", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h / 2f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, RANKING_C_SMALL ("ranking-C-small", "png"), RANKING_D ("ranking-D", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h / 2f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, 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()); + return img.getScaledCopy(h / 768f); } }, RANKING_PERFECT ("ranking-perfect", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h * 0.16f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, RANKING_TITLE ("ranking-title", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h * 0.15f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, RANKING_MAXCOMBO ("ranking-maxcombo", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h * 0.05f) / img.getHeight()); + return img.getScaledCopy(h / 768f); } }, RANKING_ACCURACY ("ranking-accuracy", "png") { @Override protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h * 0.05f) / img.getHeight()); + return img.getScaledCopy(h / 768f); + } + }, + DEFAULT_0 ("default-0", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + DEFAULT_1 ("default-1", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + DEFAULT_2 ("default-2", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + DEFAULT_3 ("default-3", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + DEFAULT_4 ("default-4", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + DEFAULT_5 ("default-5", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + DEFAULT_6 ("default-6", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + DEFAULT_7 ("default-7", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + DEFAULT_8 ("default-8", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + DEFAULT_9 ("default-9", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_0 ("score-0", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_1 ("score-1", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_2 ("score-2", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_3 ("score-3", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_4 ("score-4", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_5 ("score-5", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_6 ("score-6", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_7 ("score-7", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_8 ("score-8", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_9 ("score-9", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_COMMA ("score-comma", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_DOT ("score-dot", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_PERCENT ("score-percent", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); + } + }, + SCORE_X ("score-x", "png") { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(h / 768f); } }, - 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"), LIGHTING ("lighting", "png"), LIGHTING1 ("lighting1", "png"), diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index 1a81726c..ec2e6d5d 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -102,6 +102,11 @@ public class Opsu extends StateBasedGame { } catch (FileNotFoundException e) { Log.error(e); } + try { + System.setOut(new PrintStream(new FileOutputStream("jnlog.txt", false))); + } catch (FileNotFoundException e) { + Log.error(e); + } Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { @@ -113,12 +118,12 @@ public class Opsu extends StateBasedGame { Options.parseOptions(); // only allow a single instance - try { + /*try { SERVER_SOCKET = new ServerSocket(Options.getPort()); } catch (IOException e) { ErrorHandler.error(String.format("Another program is already running on port %d.", Options.getPort()), e, false); System.exit(1); - } + }*/ // set path for lwjgl natives - NOT NEEDED if using JarSplice File nativeDir = new File("./target/natives/"); diff --git a/src/itdelatrisu/opsu/OsuHitObject.java b/src/itdelatrisu/opsu/OsuHitObject.java index fec96502..46598ccd 100644 --- a/src/itdelatrisu/opsu/OsuHitObject.java +++ b/src/itdelatrisu/opsu/OsuHitObject.java @@ -296,4 +296,9 @@ public class OsuHitObject { * @return true if new combo */ public boolean isNewCombo() { return (type & TYPE_NEWCOMBO) > 0; } + + public int getComboSkip() { + return (type>>4); + } + } diff --git a/src/itdelatrisu/opsu/OsuParser.java b/src/itdelatrisu/opsu/OsuParser.java index 08999f98..de819c93 100644 --- a/src/itdelatrisu/opsu/OsuParser.java +++ b/src/itdelatrisu/opsu/OsuParser.java @@ -139,11 +139,12 @@ public class OsuParser { private static OsuFile parseFile(File file, File dir, ArrayList osuFiles, boolean parseObjects) { OsuFile osu = new OsuFile(file); + String version =""; try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) { - // initialize timing point list osu.timingPoints = new ArrayList(); + version = in.readLine(); String line = in.readLine(); String tokens[] = null; while (line != null) { @@ -491,6 +492,8 @@ public class OsuParser { } break; default: + //System.out.println("Dead: "+line+" "+file); + line = in.readLine(); break; } @@ -500,8 +503,10 @@ public class OsuParser { } // if no custom colors, use the default color scheme - if (osu.combo == null) + if (osu.combo == null){ + System.out.println("Default Combo "+version+" "+file+" "+osu.combo); osu.combo = Utils.DEFAULT_COMBO; + } // parse hit objects now? if (parseObjects) @@ -526,6 +531,7 @@ public class OsuParser { + osu.hitObjectSlider + osu.hitObjectSpinner)]; try (BufferedReader in = new BufferedReader(new FileReader(osu.getFile()))) { + String version = in.readLine(); String line = in.readLine(); while (line != null) { line = line.trim(); @@ -544,17 +550,24 @@ public class OsuParser { int comboNumber = 1; // combo number int objectIndex = 0; + boolean first = true; while ((line = in.readLine()) != null && objectIndex < osu.objects.length) { line = line.trim(); - if (!isValidLine(line)) + if (!isValidLine(line)){ + System.out.println("Not Valid :"+line); continue; + } if (line.charAt(0) == '[') break; // lines must have at minimum 5 parameters int tokenCount = line.length() - line.replace(",", "").length(); - if (tokenCount < 4) + if (tokenCount < 4){ + System.out.println("(tokenCount < 4 :"+line); + continue; + + } try { // create a new OsuHitObject for each line @@ -563,9 +576,17 @@ public class OsuParser { // set combo info // - new combo: get next combo index, reset combo number // - else: maintain combo index, increase combo number - if ((hitObject.isNewCombo() && !hitObject.isSpinner()) || objectIndex == 0) { - comboIndex = (comboIndex + 1) % osu.combo.length; - comboNumber = 1; + if (((hitObject.isNewCombo()|| first) && !hitObject.isSpinner()) ) { + int skip = 1 + hitObject.getComboSkip(); + + for(int i=0; i < skip; i++){ + comboIndex = (comboIndex + 1) % osu.combo.length; + comboNumber = 1; + } + first=false; + } + if(hitObject.getType()>15){ + System.out.println(line+" "+hitObject.isCircle()+" "+hitObject.isSlider()+" "+hitObject.isSpinner()); } hitObject.setComboIndex(comboIndex); hitObject.setComboNumber(comboNumber++); diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java index 39270d73..e42af148 100644 --- a/src/itdelatrisu/opsu/Utils.java +++ b/src/itdelatrisu/opsu/Utils.java @@ -86,8 +86,8 @@ public class Utils { /** The default map colors, used when a map does not provide custom colors. */ public static final Color[] DEFAULT_COMBO = { - COLOR_GREEN_OBJECT, COLOR_BLUE_OBJECT, - COLOR_RED_OBJECT, COLOR_ORANGE_OBJECT + COLOR_ORANGE_OBJECT, COLOR_GREEN_OBJECT, + COLOR_BLUE_OBJECT, COLOR_RED_OBJECT, }; /** Game fonts. */ diff --git a/src/org/newdawn/slick/Image.java b/src/org/newdawn/slick/Image.java new file mode 100644 index 00000000..731cd180 --- /dev/null +++ b/src/org/newdawn/slick/Image.java @@ -0,0 +1,1403 @@ +package org.newdawn.slick; + +import java.io.IOException; +import java.io.InputStream; + +import org.newdawn.slick.opengl.ImageData; +import org.newdawn.slick.opengl.InternalTextureLoader; +import org.newdawn.slick.opengl.Texture; +import org.newdawn.slick.opengl.TextureImpl; +import org.newdawn.slick.opengl.pbuffer.GraphicsFactory; +import org.newdawn.slick.opengl.renderer.Renderer; +import org.newdawn.slick.opengl.renderer.SGL; +import org.newdawn.slick.util.Log; + +/** + * An image loaded from a file and renderable to the canvas + * + * @author kevin + */ +public class Image implements Renderable { + /** The top left corner identifier */ + public static final int TOP_LEFT = 0; + /** The top right corner identifier */ + public static final int TOP_RIGHT = 1; + /** The bottom right corner identifier */ + public static final int BOTTOM_RIGHT = 2; + /** The bottom left corner identifier */ + public static final int BOTTOM_LEFT = 3; + + /** The renderer to use for all GL operations */ + protected static SGL GL = Renderer.get(); + + /** The sprite sheet currently in use */ + protected static Image inUse; + /** Use Linear Filtering */ + public static final int FILTER_LINEAR = 1; + /** Use Nearest Filtering */ + public static final int FILTER_NEAREST = 2; + + /** The OpenGL texture for this image */ + protected Texture texture; + /** The width of the image */ + protected int width; + /** The height of the image */ + protected int height; + /** The texture coordinate width to use to find our image */ + protected float textureWidth; + /** The texture coordinate height to use to find our image */ + protected float textureHeight; + /** The x texture offset to use to find our image */ + protected float textureOffsetX; + /** The y texture offset to use to find our image */ + protected float textureOffsetY; + /** Angle to rotate the image to. */ + protected float angle; + /** The alpha to draw the image at */ + protected float alpha = 1.0f; + /** The name given for the image */ + protected String ref; + /** True if this image's state has been initialised */ + protected boolean inited = false; + /** A pixelData holding the pixel data if it's been read for this texture */ + protected byte[] pixelData; + /** True if the image has been destroyed */ + protected boolean destroyed; + + /** The x coordinate of the centre of rotation */ + protected float centerX; + /** The y coordinate of the centre of rotation */ + protected float centerY; + + /** A meaningful name provided by the user of the image to tag it */ + protected String name; + + /** The colours for each of the corners */ + protected Color[] corners; + /** The OpenGL max filter */ + private int filter = SGL.GL_LINEAR; + + /** True if the image should be flipped vertically */ + private boolean flipped; + /** The transparent colour set if any */ + private Color transparent; + + /** + * Create a texture as a copy of another + * + * @param other The other texture to copy + */ + protected Image(Image other) { + this.width = other.getWidth(); + this.height = other.getHeight(); + this.texture = other.texture; + this.textureWidth = other.textureWidth; + this.textureHeight = other.textureHeight; + this.ref = other.ref; + this.textureOffsetX = other.textureOffsetX; + this.textureOffsetY = other.textureOffsetY; + + centerX = width / 2f; + centerY = height / 2f; + inited = true; + } + + /** + * Cloning constructor - only used internally. + */ + protected Image() { + } + + /** + * Creates an image using the specified texture + * + * @param texture + * The texture to use + */ + public Image(Texture texture) { + this.texture = texture; + ref = texture.toString(); + clampTexture(); + } + + /** + * Create an image based on a file at the specified location + * + * @param ref + * The location of the image file to load + * @throws SlickException + * Indicates a failure to load the image + */ + public Image(String ref) throws SlickException { + this(ref, false); + } + + /** + * Create an image based on a file at the specified location + * + * @param ref The location of the image file to load + * @param trans The color to be treated as transparent + * @throws SlickException Indicates a failure to load the image + */ + public Image(String ref, Color trans) throws SlickException { + this(ref, false, FILTER_LINEAR, trans); + } + + /** + * Create an image based on a file at the specified location + * + * @param ref The location of the image file to load + * @param flipped True if the image should be flipped on the y-axis on load + * @throws SlickException Indicates a failure to load the image + */ + public Image(String ref, boolean flipped) throws SlickException { + this(ref, flipped, FILTER_LINEAR); + } + + /** + * Create an image based on a file at the specified location + * + * @param ref The location of the image file to load + * @param flipped True if the image should be flipped on the y-axis on load + * @param filter The filtering method to use when scaling this image + * @throws SlickException Indicates a failure to load the image + */ + public Image(String ref, boolean flipped, int filter) throws SlickException { + this(ref, flipped, filter, null); + } + + /** + * Create an image based on a file at the specified location + * + * @param ref The location of the image file to load + * @param flipped True if the image should be flipped on the y-axis on load + * @param f The filtering method to use when scaling this image + * @param transparent The color to treat as transparent + * @throws SlickException Indicates a failure to load the image + */ + public Image(String ref, boolean flipped, int f, Color transparent) throws SlickException { + this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST; + this.transparent = transparent; + this.flipped = flipped; + + try { + this.ref = ref; + int[] trans = null; + if (transparent != null) { + trans = new int[3]; + trans[0] = (int) (transparent.r * 255); + trans[1] = (int) (transparent.g * 255); + trans[2] = (int) (transparent.b * 255); + } + texture = InternalTextureLoader.get().getTexture(ref, flipped, filter, trans); + } catch (IOException e) { + Log.error(e); + throw new SlickException("Failed to load image from: "+ref, e); + } + } + + /** + * Set the image filtering to be used. Note that this will also affect any + * image that was derived from this one (i.e. sub-images etc) + * + * @param f The filtering mode to use + */ + public void setFilter(int f) { + this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST; + + texture.bind(); + GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_MIN_FILTER, filter); + GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_MAG_FILTER, filter); + } + + /** + * Create an empty image + * + * @param width The width of the image + * @param height The height of the image + * @throws SlickException Indicates a failure to create the underlying resource + */ + public Image(int width, int height) throws SlickException { + this(width, height, FILTER_NEAREST); + } + + /** + * Create an empty image + * + * @param width The width of the image + * @param height The height of the image + * @param f The filter to apply to scaling the new image + * @throws SlickException Indicates a failure to create the underlying resource + */ + public Image(int width, int height, int f) throws SlickException { + ref = super.toString(); + this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST; + + try { + texture = InternalTextureLoader.get().createTexture(width, height, this.filter); + } catch (IOException e) { + Log.error(e); + throw new SlickException("Failed to create empty image "+width+"x"+height); + } + + init(); + } + + /** + * Create an image based on a file at the specified location + * + * @param in The input stream to read the image from + * @param ref The name that should be assigned to the image + * @param flipped True if the image should be flipped on the y-axis on load + * @throws SlickException Indicates a failure to load the image + */ + public Image(InputStream in, String ref, boolean flipped) throws SlickException { + this(in, ref, flipped, FILTER_LINEAR); + } + + /** + * Create an image based on a file at the specified location + * + * @param in The input stream to read the image from + * @param ref The name that should be assigned to the image + * @param flipped True if the image should be flipped on the y-axis on load + * @param filter The filter to use when scaling this image + * @throws SlickException Indicates a failure to load the image + */ + public Image(InputStream in, String ref, boolean flipped,int filter) throws SlickException { + load(in, ref, flipped, filter, null); + } + + /** + * Create an image from a pixelData of pixels + * + * @param buffer The pixelData to use to create the image + */ + Image(ImageBuffer buffer) { + this(buffer, FILTER_LINEAR); + TextureImpl.bindNone(); + } + + /** + * Create an image from a pixelData of pixels + * + * @param buffer The pixelData to use to create the image + * @param filter The filter to use when scaling this image + */ + Image(ImageBuffer buffer, int filter) { + this((ImageData) buffer, filter); + TextureImpl.bindNone(); + } + + /** + * Create an image from a image data source + * + * @param data The pixelData to use to create the image + */ + public Image(ImageData data) { + this(data, FILTER_LINEAR); + } + + /** + * Create an image from a image data source. Note that this method uses + * + * @param data The pixelData to use to create the image + * @param f The filter to use when scaling this image + */ + public Image(ImageData data, int f) { + try { + this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST; + texture = InternalTextureLoader.get().getTexture(data, this.filter); + ref = texture.toString(); + } catch (IOException e) { + Log.error(e); + } + } + + /** + * Get the OpenGL image filter in use + * + * @return The filter for magnification + */ + public int getFilter() { + return filter; + } + + /** + * Get the reference to the resource this image was loaded from, if any. Note that + * this can be null in the cases where an image was programatically generated. + * + * @return The reference to the resource the reference was loaded from + */ + public String getResourceReference() { + return ref; + } + + /** + * Set the filter to apply when drawing this image + * + * @param r The red component of the filter colour + * @param g The green component of the filter colour + * @param b The blue component of the filter colour + * @param a The alpha component of the filter colour + */ + public void setImageColor(float r, float g, float b, float a) { + setColor(TOP_LEFT, r, g, b, a); + setColor(TOP_RIGHT, r, g, b, a); + setColor(BOTTOM_LEFT, r, g, b, a); + setColor(BOTTOM_RIGHT, r, g, b, a); + } + + /** + * Set the filter to apply when drawing this image + * + * @param r The red component of the filter colour + * @param g The green component of the filter colour + * @param b The blue component of the filter colour + */ + public void setImageColor(float r, float g, float b) { + setColor(TOP_LEFT, r, g, b); + setColor(TOP_RIGHT, r, g, b); + setColor(BOTTOM_LEFT, r, g, b); + setColor(BOTTOM_RIGHT, r, g, b); + } + + /** + * Set the color of the given corner when this image is rendered. This is + * useful lots of visual effect but especially light maps + * + * @param corner The corner identifier for the corner to be set + * @param r The red component value to set (between 0 and 1) + * @param g The green component value to set (between 0 and 1) + * @param b The blue component value to set (between 0 and 1) + * @param a The alpha component value to set (between 0 and 1) + */ + public void setColor(int corner, float r, float g, float b, float a) { + if (corners == null) { + corners = new Color[] {new Color(1,1,1,1f),new Color(1,1,1,1f), new Color(1,1,1,1f), new Color(1,1,1,1f)}; + } + + corners[corner].r = r; + corners[corner].g = g; + corners[corner].b = b; + corners[corner].a = a; + } + + /** + * Set the color of the given corner when this image is rendered. This is + * useful lots of visual effect but especially light maps + * + * @param corner The corner identifier for the corner to be set + * @param r The red component value to set (between 0 and 1) + * @param g The green component value to set (between 0 and 1) + * @param b The blue component value to set (between 0 and 1) + */ + public void setColor(int corner, float r, float g, float b) { + if (corners == null) { + corners = new Color[] {new Color(1,1,1,1f),new Color(1,1,1,1f), new Color(1,1,1,1f), new Color(1,1,1,1f)}; + } + + corners[corner].r = r; + corners[corner].g = g; + corners[corner].b = b; + } + + /** + * Clamp the loaded texture to it's edges + */ + public void clampTexture() { + if (GL.canTextureMirrorClamp()) { + GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_S, SGL.GL_MIRROR_CLAMP_TO_EDGE_EXT); + GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_T, SGL.GL_MIRROR_CLAMP_TO_EDGE_EXT); + } else { + GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_S, SGL.GL_CLAMP); + GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_T, SGL.GL_CLAMP); + } + } + + /** + * Give this image a meaningful tagging name. Can be used as user data/identifier + * for the image. + * + * @param name The name to assign the image + */ + public void setName(String name) { + this.name = name; + } + + /** + * Return a meaningful tagging name that has been assigned to this image. + * + * @return A name or null if the name hasn't been set + */ + public String getName() { + return name; + } + + /** + * Get a graphics context that can be used to draw to this image + * + * @return The graphics context used to render to this image + * @throws SlickException Indicates a failure to create a graphics context + */ + public Graphics getGraphics() throws SlickException { + return GraphicsFactory.getGraphicsForImage(this); + } + + /** + * Load the image + * + * @param in The input stream to read the image from + * @param ref The name that should be assigned to the image + * @param flipped True if the image should be flipped on the y-axis on load + * @param f The filter to use when scaling this image + * @param transparent The color to treat as transparent + * @throws SlickException Indicates a failure to load the image + */ + private void load(InputStream in, String ref, boolean flipped, int f, Color transparent) throws SlickException { + this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST; + + try { + this.ref = ref; + int[] trans = null; + if (transparent != null) { + trans = new int[3]; + trans[0] = (int) (transparent.r * 255); + trans[1] = (int) (transparent.g * 255); + trans[2] = (int) (transparent.b * 255); + } + texture = InternalTextureLoader.get().getTexture(in, ref, flipped, filter, trans); + } catch (IOException e) { + Log.error(e); + throw new SlickException("Failed to load image from: "+ref, e); + } + } + + /** + * Bind to the texture of this image + */ + public void bind() { + texture.bind(); + } + + /** + * Reinitialise internal data + */ + protected void reinit() { + inited = false; + init(); + } + + /** + * Initialise internal data + */ + protected final void init() { + if (inited) { + return; + } + + inited = true; + if (texture != null) { + width = texture.getImageWidth(); + height = texture.getImageHeight(); + textureOffsetX = 0; + textureOffsetY = 0; + textureWidth = texture.getWidth(); + textureHeight = texture.getHeight(); + } + + initImpl(); + + centerX = width / 2f; + centerY = height / 2f; + } + + /** + * Hook for subclasses to perform initialisation + */ + protected void initImpl() { + + } + + /** + * Draw this image at the current location + */ + public void draw() { + draw(0,0); + } + + /** + * Draw the image based on it's center + * + * @param x The x coordinate to place the image's center at + * @param y The y coordinate to place the image's center at + */ + public void drawCentered(float x, float y) { + draw(x-(getWidth()/2),y-(getHeight()/2)); + } + + /** + * Draw this image at the specified location + * + * @param x The x location to draw the image at + * @param y The y location to draw the image at + */ + public void draw(float x, float y) { + init(); + draw(x,y,width,height); + } + + /** + * Draw this image at the specified location + * + * @param x The x location to draw the image at + * @param y The y location to draw the image at + * @param filter The color to filter with when drawing + */ + public void draw(float x, float y, Color filter) { + init(); + draw(x,y,width,height, filter); + } + + /** + * Draw this image as part of a collection of images + * + * @param x The x location to draw the image at + * @param y The y location to draw the image at + * @param width The width to render the image at + * @param height The height to render the image at + */ + public void drawEmbedded(float x,float y,float width,float height) { + init(); + + if (corners == null) { + GL.glTexCoord2f(textureOffsetX, textureOffsetY); + GL.glVertex3f(x, y, 0); + GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight); + GL.glVertex3f(x, y + height, 0); + GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY + + textureHeight); + GL.glVertex3f(x + width, y + height, 0); + GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY); + GL.glVertex3f(x + width, y, 0); + } else { + corners[TOP_LEFT].bind(); + GL.glTexCoord2f(textureOffsetX, textureOffsetY); + GL.glVertex3f(x, y, 0); + corners[BOTTOM_LEFT].bind(); + GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight); + GL.glVertex3f(x, y + height, 0); + corners[BOTTOM_RIGHT].bind(); + GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY + + textureHeight); + GL.glVertex3f(x + width, y + height, 0); + corners[TOP_RIGHT].bind(); + GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY); + GL.glVertex3f(x + width, y, 0); + } + } + + /** + * Get the x offset in texels into the source texture + * + * @return The x offset + */ + public float getTextureOffsetX() { + init(); + + return textureOffsetX; + } + + /** + * Get the y offset in texels into the source texture + * + * @return The y offset + */ + public float getTextureOffsetY() { + init(); + + return textureOffsetY; + } + + /** + * Get the width in texels into the source texture + * + * @return The width + */ + public float getTextureWidth() { + init(); + + return textureWidth; + } + + /** + * Get the height in texels into the source texture + * + * @return The height + */ + public float getTextureHeight() { + init(); + + return textureHeight; + } + + /** + * Draw the image with a given scale + * + * @param x The x position to draw the image at + * @param y The y position to draw the image at + * @param scale The scaling to apply + */ + public void draw(float x,float y,float scale) { + init(); + draw(x,y,width*scale,height*scale,Color.white); + } + + /** + * Draw the image with a given scale + * + * @param x The x position to draw the image at + * @param y The y position to draw the image at + * @param scale The scaling to apply + * @param filter The colour filter to adapt the image with + */ + public void draw(float x,float y,float scale,Color filter) { + init(); + draw(x,y,width*scale,height*scale,filter); + } + + /** + * Draw this image at a specified location and size + * + * @param x + * The x location to draw the image at + * @param y + * The y location to draw the image at + * @param width + * The width to render the image at + * @param height + * The height to render the image at + */ + public void draw(float x,float y,float width,float height) { + init(); + draw(x,y,width,height,Color.white); + } + + /** + * Draw this image at a specified location and size + * + * @param x The x location to draw the image at + * @param y The y location to draw the image at + * @param hshear The amount to shear the bottom points by horizontally + * @param vshear The amount to shear the right points by vertically + */ + public void drawSheared(float x,float y, float hshear, float vshear) { + this.drawSheared(x, y, hshear, vshear, Color.white); + } + /** + * Draw this image at a specified location and size + * + * @param x The x location to draw the image at + * @param y The y location to draw the image at + * @param hshear The amount to shear the bottom points by horizontally + * @param vshear The amount to shear the right points by vertically + * @param filter The colour filter to apply + */ + public void drawSheared(float x,float y, float hshear, float vshear, Color filter) { + if (alpha != 1) { + if (filter == null) { + filter = Color.white; + } + + filter = new Color(filter); + filter.a *= alpha; + } + if (filter != null) { + filter.bind(); + } + + texture.bind(); + + GL.glTranslatef(x, y, 0); + if (angle != 0) { + GL.glTranslatef(centerX, centerY, 0.0f); + GL.glRotatef(angle, 0.0f, 0.0f, 1.0f); + GL.glTranslatef(-centerX, -centerY, 0.0f); + } + + GL.glBegin(SGL.GL_QUADS); + init(); + + GL.glTexCoord2f(textureOffsetX, textureOffsetY); + GL.glVertex3f(0, 0, 0); + GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight); + GL.glVertex3f(hshear, height, 0); + GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY + + textureHeight); + GL.glVertex3f(width + hshear, height + vshear, 0); + GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY); + GL.glVertex3f(width, vshear, 0); + GL.glEnd(); + + if (angle != 0) { + GL.glTranslatef(centerX, centerY, 0.0f); + GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f); + GL.glTranslatef(-centerX, -centerY, 0.0f); + } + GL.glTranslatef(-x, -y, 0); + } + + /** + * Draw this image at a specified location and size + * + * @param x The x location to draw the image at + * @param y The y location to draw the image at + * @param width The width to render the image at + * @param height The height to render the image at + * @param filter The color to filter with while drawing + */ + public void draw(float x,float y,float width,float height,Color filter) { + if (alpha != 1) { + if (filter == null) { + filter = Color.white; + } + + filter = new Color(filter); + filter.a *= alpha; + } + if (filter != null) { + filter.bind(); + } + + texture.bind(); + + GL.glTranslatef(x, y, 0); + if (angle != 0) { + GL.glTranslatef(centerX, centerY, 0.0f); + GL.glRotatef(angle, 0.0f, 0.0f, 1.0f); + GL.glTranslatef(-centerX, -centerY, 0.0f); + } + + GL.glBegin(SGL.GL_QUADS); + drawEmbedded(0,0,width,height); + GL.glEnd(); + + if (angle != 0) { + GL.glTranslatef(centerX, centerY, 0.0f); + GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f); + GL.glTranslatef(-centerX, -centerY, 0.0f); + } + GL.glTranslatef(-x, -y, 0); + } + + /** + * Draw this image at a specified location and size as a silohette + * + * @param x The x location to draw the image at + * @param y The y location to draw the image at + * @param width The width to render the image at + * @param height The height to render the image at + */ + public void drawFlash(float x,float y,float width,float height) { + drawFlash(x,y,width,height,Color.white); + } + + /** + * Set the centre of the rotation when applied to this image + * + * @param x The x coordinate of center of rotation relative to the top left corner of the image + * @param y The y coordinate of center of rotation relative to the top left corner of the image + */ + public void setCenterOfRotation(float x, float y) { + centerX = x; + centerY = y; + } + + /** + * Get the x component of the center of rotation of this image + * + * @return The x component of the center of rotation + */ + public float getCenterOfRotationX() { + init(); + + return centerX; + } + + /** + * Get the y component of the center of rotation of this image + * + * @return The y component of the center of rotation + */ + public float getCenterOfRotationY() { + init(); + + return centerY; + } + + /** + * Draw this image at a specified location and size as a silohette + * + * @param x The x location to draw the image at + * @param y The y location to draw the image at + * @param width The width to render the image at + * @param height The height to render the image at + * @param col The color for the sillohette + */ + public void drawFlash(float x,float y,float width,float height, Color col) { + init(); + + col.bind(); + texture.bind(); + + if (GL.canSecondaryColor()) { + GL.glEnable(SGL.GL_COLOR_SUM_EXT); + GL.glSecondaryColor3ubEXT((byte)(col.r * 255), + (byte)(col.g * 255), + (byte)(col.b * 255)); + } + + GL.glTexEnvi(SGL.GL_TEXTURE_ENV, SGL.GL_TEXTURE_ENV_MODE, SGL.GL_MODULATE); + + GL.glTranslatef(x, y, 0); + if (angle != 0) { + GL.glTranslatef(centerX, centerY, 0.0f); + GL.glRotatef(angle, 0.0f, 0.0f, 1.0f); + GL.glTranslatef(-centerX, -centerY, 0.0f); + } + + GL.glBegin(SGL.GL_QUADS); + drawEmbedded(0,0,width,height); + GL.glEnd(); + + if (angle != 0) { + GL.glTranslatef(centerX, centerY, 0.0f); + GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f); + GL.glTranslatef(-centerX, -centerY, 0.0f); + } + GL.glTranslatef(-x, -y, 0); + + if (GL.canSecondaryColor()) { + GL.glDisable(SGL.GL_COLOR_SUM_EXT); + } + } + + /** + * Draw this image at a specified location and size in a white silohette + * + * @param x The x location to draw the image at + * @param y The y location to draw the image at + */ + public void drawFlash(float x,float y) { + drawFlash(x,y,getWidth(),getHeight()); + } + + /** + * Set the angle to rotate this image to. The angle will be normalized to + * be 0 <= angle < 360. The image will be rotated around its center. + * + * @param angle The angle to be set + */ + public void setRotation(float angle) { + this.angle = angle % 360.0f; + } + + /** + * Get the current angle of rotation for this image. + * The image will be rotated around its center. + * + * @return The current angle. + */ + public float getRotation() { + return angle; + } + + /** + * Get the alpha value to use when rendering this image + * + * @return The alpha value to use when rendering this image + */ + public float getAlpha() { + return alpha; + } + + /** + * Set the alpha value to use when rendering this image + * + * @param alpha The alpha value to use when rendering this image + */ + public void setAlpha(float alpha) { + this.alpha = alpha; + } + + /** + * Add the angle provided to the current rotation. The angle will be normalized to + * be 0 <= angle < 360. The image will be rotated around its center. + * + * @param angle The angle to add. + */ + public void rotate(float angle) { + this.angle += angle; + this.angle = this.angle % 360; + } + + /** + * Get a sub-part of this image. Note that the create image retains a reference to the + * image data so should anything change it will affect sub-images too. + * + * @param x The x coordinate of the sub-image + * @param y The y coordinate of the sub-image + * @param width The width of the sub-image + * @param height The height of the sub-image + * @return The image represent the sub-part of this image + */ + public Image getSubImage(int x,int y,int width,int height) { + init(); + + float newTextureOffsetX = ((x / (float) this.width) * textureWidth) + textureOffsetX; + float newTextureOffsetY = ((y / (float) this.height) * textureHeight) + textureOffsetY; + float newTextureWidth = ((width / (float) this.width) * textureWidth); + float newTextureHeight = ((height / (float) this.height) * textureHeight); + + Image sub = new Image(); + sub.inited = true; + sub.texture = this.texture; + sub.textureOffsetX = newTextureOffsetX; + sub.textureOffsetY = newTextureOffsetY; + sub.textureWidth = newTextureWidth; + sub.textureHeight = newTextureHeight; + + sub.width = width; + sub.height = height; + sub.ref = ref; + sub.centerX = width / 2f; + sub.centerY = height / 2f; + + return sub; + } + + /** + * Draw a section of this image at a particular location and scale on the screen + * + * @param x The x position to draw the image + * @param y The y position to draw the image + * @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image) + * @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image) + * @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) + * @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) + */ + public void draw(float x, float y, float srcx, float srcy, float srcx2, float srcy2) { + draw(x,y,x+width,y+height,srcx,srcy,srcx2,srcy2); + } + + /** + * Draw a section of this image at a particular location and scale on the screen + * + * @param x The x position to draw the image + * @param y The y position to draw the image + * @param x2 The x position of the bottom right corner of the drawn image + * @param y2 The y position of the bottom right corner of the drawn image + * @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image) + * @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image) + * @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) + * @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) + */ + public void draw(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2) { + draw(x,y,x2,y2,srcx,srcy,srcx2,srcy2,Color.white); + } + + /** + * Draw a section of this image at a particular location and scale on the screen + * + * @param x The x position to draw the image + * @param y The y position to draw the image + * @param x2 The x position of the bottom right corner of the drawn image + * @param y2 The y position of the bottom right corner of the drawn image + * @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image) + * @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image) + * @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) + * @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) + * @param filter The colour filter to apply when drawing + */ + public void draw(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2, Color filter) { + init(); + + if (alpha != 1) { + if (filter == null) { + filter = Color.white; + } + + filter = new Color(filter); + filter.a *= alpha; + } + filter.bind(); + texture.bind(); + + GL.glTranslatef(x, y, 0); + if (angle != 0) { + GL.glTranslatef(centerX, centerY, 0.0f); + GL.glRotatef(angle, 0.0f, 0.0f, 1.0f); + GL.glTranslatef(-centerX, -centerY, 0.0f); + } + + GL.glBegin(SGL.GL_QUADS); + drawEmbedded(0,0,x2-x,y2-y,srcx,srcy,srcx2,srcy2); + GL.glEnd(); + + if (angle != 0) { + GL.glTranslatef(centerX, centerY, 0.0f); + GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f); + GL.glTranslatef(-centerX, -centerY, 0.0f); + } + GL.glTranslatef(-x, -y, 0); + +// GL.glBegin(SGL.GL_QUADS); +// drawEmbedded(x,y,x2,y2,srcx,srcy,srcx2,srcy2); +// GL.glEnd(); + } + + /** + * Draw a section of this image at a particular location and scale on the screen, while this + * is image is "in use", i.e. between calls to startUse and endUse. + * + * @param x The x position to draw the image + * @param y The y position to draw the image + * @param x2 The x position of the bottom right corner of the drawn image + * @param y2 The y position of the bottom right corner of the drawn image + * @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image) + * @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image) + * @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) + * @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) + */ + public void drawEmbedded(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2) { + drawEmbedded(x,y,x2,y2,srcx,srcy,srcx2,srcy2,null); + } + + /** + * Draw a section of this image at a particular location and scale on the screen, while this + * is image is "in use", i.e. between calls to startUse and endUse. + * + * @param x The x position to draw the image + * @param y The y position to draw the image + * @param x2 The x position of the bottom right corner of the drawn image + * @param y2 The y position of the bottom right corner of the drawn image + * @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image) + * @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image) + * @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) + * @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image) + * @param filter The colour filter to apply when drawing + */ + public void drawEmbedded(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2, Color filter) { + if (filter != null) { + filter.bind(); + } + + float mywidth = x2 - x; + float myheight = y2 - y; + float texwidth = srcx2 - srcx; + float texheight = srcy2 - srcy; + + float newTextureOffsetX = (((srcx) / (width)) * textureWidth) + + textureOffsetX; + float newTextureOffsetY = (((srcy) / (height)) * textureHeight) + + textureOffsetY; + float newTextureWidth = ((texwidth) / (width)) + * textureWidth; + float newTextureHeight = ((texheight) / (height)) + * textureHeight; + + GL.glTexCoord2f(newTextureOffsetX, newTextureOffsetY); + GL.glVertex3f(x,y, 0.0f); + GL.glTexCoord2f(newTextureOffsetX, newTextureOffsetY + + newTextureHeight); + GL.glVertex3f(x,(y + myheight), 0.0f); + GL.glTexCoord2f(newTextureOffsetX + newTextureWidth, + newTextureOffsetY + newTextureHeight); + GL.glVertex3f((x + mywidth),(y + myheight), 0.0f); + GL.glTexCoord2f(newTextureOffsetX + newTextureWidth, + newTextureOffsetY); + GL.glVertex3f((x + mywidth),y, 0.0f); + } + + /** + * Draw the image in a warper rectangle. The effects this can + * have are many and varied, might be interesting though. + * + * @param x1 The top left corner x coordinate + * @param y1 The top left corner y coordinate + * @param x2 The top right corner x coordinate + * @param y2 The top right corner y coordinate + * @param x3 The bottom right corner x coordinate + * @param y3 The bottom right corner y coordinate + * @param x4 The bottom left corner x coordinate + * @param y4 The bottom left corner y coordinate + */ + public void drawWarped(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) { + Color.white.bind(); + texture.bind(); + + GL.glTranslatef(x1, y1, 0); + if (angle != 0) { + GL.glTranslatef(centerX, centerY, 0.0f); + GL.glRotatef(angle, 0.0f, 0.0f, 1.0f); + GL.glTranslatef(-centerX, -centerY, 0.0f); + } + + GL.glBegin(SGL.GL_QUADS); + init(); + + GL.glTexCoord2f(textureOffsetX, textureOffsetY); + GL.glVertex3f(0, 0, 0); + GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight); + GL.glVertex3f(x2 - x1, y2 - y1, 0); + GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY + + textureHeight); + GL.glVertex3f(x3 - x1, y3 - y1, 0); + GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY); + GL.glVertex3f(x4 - x1, y4 - y1, 0); + GL.glEnd(); + + if (angle != 0) { + GL.glTranslatef(centerX, centerY, 0.0f); + GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f); + GL.glTranslatef(-centerX, -centerY, 0.0f); + } + GL.glTranslatef(-x1, -y1, 0); + } + + /** + * Get the width of this image + * + * @return The width of this image + */ + public int getWidth() { + init(); + return width; + } + + /** + * Get the height of this image + * + * @return The height of this image + */ + public int getHeight() { + init(); + return height; + } + + /** + * Get a copy of this image. This is a shallow copy and does not + * duplicate image adata. + * + * @return The copy of this image + */ + public Image copy() { + init(); + return getSubImage(0,0,width,height); + } + + /** + * Get a scaled copy of this image with a uniform scale + * + * @param scale The scale to apply + * @return The new scaled image + */ + public Image getScaledCopy(float scale) { + init(); + return getScaledCopy((int) (width*scale),(int) (height*scale)); + } + + /** + * Get a scaled copy of this image + * + * @param width The width of the copy + * @param height The height of the copy + * @return The new scaled image + */ + public Image getScaledCopy(int width, int height) { + init(); + Image image = copy(); + image.width = width; + image.height = height; + image.centerX = width / 2f; + image.centerY = height / 2f; + return image; + } + + /** + * Make sure the texture cordinates are inverse on the y axis + */ + public void ensureInverted() { + if (textureHeight > 0) { + textureOffsetY = textureOffsetY + textureHeight; + textureHeight = -textureHeight; + } + } + + /** + * Get a copy image flipped on potentially two axis + * + * @param flipHorizontal True if we want to flip the image horizontally + * @param flipVertical True if we want to flip the image vertically + * @return The flipped image instance + */ + public Image getFlippedCopy(boolean flipHorizontal, boolean flipVertical) { + init(); + Image image = copy(); + + if (flipHorizontal) { + image.textureOffsetX = textureOffsetX + textureWidth; + image.textureWidth = -textureWidth; + } + if (flipVertical) { + image.textureOffsetY = textureOffsetY + textureHeight; + image.textureHeight = -textureHeight; + } + + return image; + } + + /** + * End the use of this sprite sheet and release the lock. + * + * @see #startUse + */ + public void endUse() { + if (inUse != this) { + throw new RuntimeException("The sprite sheet is not currently in use"); + } + inUse = null; + GL.glEnd(); + } + + /** + * Start using this sheet. This method can be used for optimal rendering of a collection + * of sprites from a single sprite sheet. First, startUse(). Then render each sprite by + * calling renderInUse(). Finally, endUse(). Between start and end there can be no rendering + * of other sprites since the rendering is locked for this sprite sheet. + */ + public void startUse() { + if (inUse != null) { + throw new RuntimeException("Attempt to start use of a sprite sheet before ending use with another - see endUse()"); + } + inUse = this; + init(); + + Color.white.bind(); + texture.bind(); + GL.glBegin(SGL.GL_QUADS); + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() { + init(); + + return "[Image "+ref+" "+width+"x"+height+" "+textureOffsetX+","+textureOffsetY+","+textureWidth+","+textureHeight+"]"; + } + + /** + * Get the OpenGL texture holding this image + * + * @return The OpenGL texture holding this image + */ + public Texture getTexture() { + return texture; + } + + /** + * Set the texture used by this image + * + * @param texture The texture used by this image + */ + public void setTexture(Texture texture) { + this.texture = texture; + reinit(); + } + + /** + * Translate an unsigned int into a signed integer + * + * @param b The byte to convert + * @return The integer value represented by the byte + */ + private int translate(byte b) { + if (b < 0) { + return 256 + b; + } + + return b; + } + + /** + * Get the colour of a pixel at a specified location in this image + * + * @param x The x coordinate of the pixel + * @param y The y coordinate of the pixel + * @return The Color of the pixel at the specified location + */ + public Color getColor(int x, int y) { + if (pixelData == null) { + pixelData = texture.getTextureData(); + } + + int xo = (int) (textureOffsetX * texture.getTextureWidth()); + int yo = (int) (textureOffsetY * texture.getTextureHeight()); + + if (textureWidth < 0) { + x = xo - x; + } else { + x = xo + x; + } + + if (textureHeight < 0) { + y = yo - y; + } else { + y = yo + y; + } + + int offset = x + (y * texture.getTextureWidth()); + offset *= texture.hasAlpha() ? 4 : 3; + + if (texture.hasAlpha()) { + return new Color(translate(pixelData[offset]),translate(pixelData[offset+1]), + translate(pixelData[offset+2]),translate(pixelData[offset+3])); + } else { + return new Color(translate(pixelData[offset]),translate(pixelData[offset+1]), + translate(pixelData[offset+2])); + } + } + + /** + * Check if this image has been destroyed + * + * @return True if this image has been destroyed + */ + public boolean isDestroyed() { + return destroyed; + } + + /** + * Destroy the image and release any native resources. + * Calls on a destroyed image have undefined results + * + * @throws SlickException Indicates a failure to release resources on the graphics card + */ + public void destroy() throws SlickException { + if (isDestroyed()) { + return; + } + + destroyed = true; + texture.release(); + GraphicsFactory.releaseGraphicsForImage(this); + } + + /** + * Flush the current pixel data to force a re-read next update + */ + public void flushPixelData() { + pixelData = null; + } +} From e02b195b71d1aa24f31302392c860d7e7d1f76b0 Mon Sep 17 00:00:00 2001 From: fd Date: Mon, 16 Feb 2015 11:34:35 -0500 Subject: [PATCH 2/6] Hard coded Ranking Panel Hard coded Scorebar Made MenuButtonBG colours darker Extends ScoresData clock bg More General Scaling --- src/itdelatrisu/opsu/GameData.java | 122 +++--- src/itdelatrisu/opsu/GameImage.java | 396 +++---------------- src/itdelatrisu/opsu/OsuGroupNode.java | 2 +- src/itdelatrisu/opsu/ScoreData.java | 2 + src/itdelatrisu/opsu/Utils.java | 4 +- src/itdelatrisu/opsu/states/GameRanking.java | 6 +- src/itdelatrisu/opsu/states/OptionsMenu.java | 3 +- src/itdelatrisu/opsu/states/SongMenu.java | 2 +- 8 files changed, 151 insertions(+), 386 deletions(-) diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index fdd4176f..57a8493f 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -97,7 +97,7 @@ public class GameData { return menuImage; Image img = getSmallImage(); - img = img.getScaledCopy((GameImage.MENU_BUTTON_BG.getImage().getHeight() * 0.45f) / img.getHeight()); + //img = img.getScaledCopy((GameImage.MENU_BUTTON_BG.getImage().getHeight() * 0.45f) / img.getHeight()); if (!small.hasSkinImage()) // save default image only this.menuImage = img; return img; @@ -564,14 +564,20 @@ public class GameData { healthRatio = (float) trackPosition / (firstObjectTime - 500); } Image scorebar = GameImage.SCOREBAR_BG.getImage(); - Image colour = (scorebarColour != null) ? - scorebarColour.getCurrentFrame() : - GameImage.SCOREBAR_COLOUR.getImage(); - float colourX = scorebar.getWidth() * 0.017f, colourY = scorebar.getHeight() * 0.3f; + Image colour; + if (scorebarColour != null){ + scorebarColour.updateNoDraw(); //TODO + colour = scorebarColour.getCurrentFrame(); + } else { + colour = GameImage.SCOREBAR_COLOUR.getImage(); + } + float colourX = 4 * GameImage.uiscale, colourY = 15 * GameImage.uiscale; + Image colourCropped = colour.getSubImage(0, 0, (int) (648 * GameImage.uiscale * healthRatio), colour.getHeight()); + + scorebar.setAlpha(1f); scorebar.draw(0, 0); - Image colourCropped = colour.getSubImage(0, 0, (int) (colour.getWidth() * healthRatio), colour.getHeight()); colourCropped.draw(colourX, colourY); - + Image ki = null; if (health >= 50f) ki = GameImage.SCOREBAR_KI.getImage(); @@ -579,7 +585,7 @@ public class GameData { ki = GameImage.SCOREBAR_KI_DANGER.getImage(); else ki = GameImage.SCOREBAR_KI_DANGER2.getImage(); - ki.drawCentered(colourX + colourCropped.getWidth(), ki.getHeight() / 2f); + ki.drawCentered(colourX + colourCropped.getWidth(), colourY);//ki.getHeight() / 2f); // combo burst if (comboBurstIndex != -1 && comboBurstAlpha > 0f) { @@ -654,41 +660,40 @@ public class GameData { float marginX = width * 0.01f, marginY = height * 0.025f; // header & "Ranking" text Image rankingTitle = GameImage.RANKING_TITLE.getImage(); - float rankingHeight = (rankingTitle.getHeight() * 0.75f) + 3; - - - g.setColor(Utils.COLOR_BLACK_ALPHA); - g.fillRect(0, 0, width, rankingHeight); - rankingTitle.draw((width * 0.97f) - rankingTitle.getWidth(), 0); - Utils.FONT_LARGE.drawString(marginX, marginY, - String.format("%s - %s [%s]", osu.getArtist(), osu.getTitle(), osu.version), Color.white); - Utils.FONT_MEDIUM.drawString(marginX, marginY + Utils.FONT_LARGE.getLineHeight() - 6, - String.format("Beatmap by %s", osu.creator), Color.white); - Utils.FONT_MEDIUM.drawString( - marginX, marginY + Utils.FONT_LARGE.getLineHeight() + Utils.FONT_MEDIUM.getLineHeight() - 10, - String.format("Played on %s.", scoreData.getTimeString()), Color.white); - // ranking panel Image rankingPanel = GameImage.RANKING_PANEL.getImage(); int rankingPanelWidth = rankingPanel.getWidth(); int rankingPanelHeight = rankingPanel.getHeight(); - rankingPanel.draw(0, rankingHeight);//rankingHeight - (rankingHeight / 10f)); + + + //Version 2 skins are a little lower + //default is version 2 + //has an ini with no version 2 is higher + float rankingHeight = 75;//height/2 -rankingPanelHeight/2 - 0;//(rankingTitle.getHeight() * 0.75f) + 3; + //if(Skin.version==2) + - float scoreTextScale = 1.2f; //(height / 15f) / getScoreSymbolImage('0').getHeight(); - float symbolTextScale = 1.2f; //(height / 15f) / getScoreSymbolImage('0').getHeight(); - float rankResultScale = 0.5f;//(height * 0.03f) / hitResults[HIT_300].getHeight(); + rankingPanel.draw(0, (int)((rankingHeight + //+ ((Skin.version==2)? 20:) + )* GameImage.uiscale));//(height -rankingTitle.getHeight()+rankingPanelHeight)/2 - rankingPanelHeight);//rankingHeight - (rankingHeight / 10f)); + //System.err.println(rankingPanelHeight); + + float scoreTextScale = 1.0f; + float symbolTextScale = 1.15f; + float rankResultScale = 0.5f;// * GameImage.uiscale; // score drawFixedSizeSymbolString((score < 100000000) ? String.format("%08d", score) : Long.toString(score), - (int) (width * 0.18f), (int) (rankingHeight+50), scoreTextScale, getScoreSymbolImage('0').getWidth()*scoreTextScale-2, false); + (int) (210 * GameImage.uiscale), (int) ((rankingHeight+50)* GameImage.uiscale), + scoreTextScale, getScoreSymbolImage('0').getWidth()*scoreTextScale-2, false); // result counts - float resultInitialX = 150;// rankingPanelWidth * 0.20f; - float resultInitialY = rankingHeight + (rankingPanelHeight * 0.20f) + (rankingHeight / 10f); - float resultHitInitialX = 0;//rankingPanelWidth * 0.05f; - float resultHitInitialY = resultInitialY + (getScoreSymbolImage('0').getHeight() * symbolTextScale); - float resultOffsetX = rankingPanelWidth / 2f; - float resultOffsetY = rankingPanelHeight * 0.2f; + float resultInitialX = 130; + float resultInitialY = rankingHeight + 140; + float resultHitInitialX = 65; + float resultHitInitialY = rankingHeight + 182 ; + float resultOffsetX = 320; + float resultOffsetY = 96; int[] rankDrawOrder = { HIT_300, HIT_300G, HIT_100, HIT_100K, HIT_50, HIT_MISS }; int[] rankResultOrder = { @@ -698,28 +703,40 @@ public class GameData { }; for (int i = 0; i < rankDrawOrder.length; i += 2) { - hitResults[rankDrawOrder[i]].getScaledCopy(rankResultScale).draw( - resultHitInitialX, resultHitInitialY - (hitResults[rankDrawOrder[i]].getHeight() * rankResultScale) + (resultOffsetY * (i / 2))); - hitResults[rankDrawOrder[i+1]].getScaledCopy(rankResultScale).draw( - resultHitInitialX + resultOffsetX, resultHitInitialY - (hitResults[rankDrawOrder[i]].getHeight() * rankResultScale) + (resultOffsetY * (i / 2))); + hitResults[rankDrawOrder[i]].getScaledCopy(rankResultScale).drawCentered( + (resultHitInitialX * GameImage.uiscale), + ((resultHitInitialY + (resultOffsetY * (i / 2))) * GameImage.uiscale) + ); + hitResults[rankDrawOrder[i+1]].getScaledCopy(rankResultScale).drawCentered( + ((resultHitInitialX + resultOffsetX) * GameImage.uiscale), + ((resultHitInitialY + (resultOffsetY * (i / 2))) * GameImage.uiscale) + ); drawSymbolString(String.format("%dx", rankResultOrder[i]), - (int) resultInitialX, (int) (resultInitialY + (resultOffsetY * (i / 2))), symbolTextScale, false); + (int) (resultInitialX * GameImage.uiscale), + (int) ((resultInitialY + (resultOffsetY * (i / 2))) * GameImage.uiscale), + symbolTextScale, false); drawSymbolString(String.format("%dx", rankResultOrder[i+1]), - (int) (resultInitialX + resultOffsetX), (int) (resultInitialY + (resultOffsetY * (i / 2))), symbolTextScale, false); + (int) ((resultInitialX + resultOffsetX) * GameImage.uiscale), + (int) ((resultInitialY + (resultOffsetY * (i / 2))) * GameImage.uiscale), + symbolTextScale, false); } // combo and accuracy Image rankingMaxCombo = GameImage.RANKING_MAXCOMBO.getImage(); Image rankingAccuracy = GameImage.RANKING_ACCURACY.getImage(); - float textY = rankingHeight + (rankingPanelHeight * 0.87f) - (rankingHeight / 10f); + float offsetX = 295; + float textY = rankingHeight + 425; float numbersX = rankingMaxCombo.getWidth() * .07f; - float numbersY = textY + rankingMaxCombo.getHeight() * 0.7f; - rankingMaxCombo.draw(width * 0.01f, textY); - rankingAccuracy.draw(rankingPanelWidth / 2f, textY); + float numbersY = textY + 30; drawSymbolString(String.format("%dx", comboMax), - (int) (width * 0.01f + numbersX), (int) numbersY, symbolTextScale, false); + (int)(25 * GameImage.uiscale),(int) (numbersY * GameImage.uiscale), + symbolTextScale, false); drawSymbolString(String.format("%02.2f%%", getScorePercent()), - (int) (rankingPanelWidth / 2f + numbersX), (int) numbersY, symbolTextScale, false); + (int) ((offsetX+20) * GameImage.uiscale), + (int) (numbersY * GameImage.uiscale), symbolTextScale, false); + rankingMaxCombo.draw((int)(10 * GameImage.uiscale), (int)(textY * GameImage.uiscale)); + rankingAccuracy.draw((int)(offsetX * GameImage.uiscale), (int)(textY * GameImage.uiscale)); + // full combo if (comboMax == fullObjectCount) { @@ -731,8 +748,21 @@ public class GameData { // grade Grade grade = getGrade(); if (grade != Grade.NULL) - grade.getLargeImage().draw(width * 0.985f - grade.getLargeImage().getWidth(), rankingHeight+marginY); + grade.getLargeImage().draw(width-grade.getLargeImage().getWidth(), 30); + //Header + g.setColor(Utils.COLOR_BLACK_ALPHA); + g.fillRect(0, 0, width, rankingHeight); + rankingTitle.draw((width * 0.97f) - rankingTitle.getWidth(), 0); + Utils.FONT_LARGE.drawString(marginX, marginY, + String.format("%s - %s [%s]", osu.getArtist(), osu.getTitle(), osu.version), Color.white); + Utils.FONT_MEDIUM.drawString(marginX, marginY + Utils.FONT_LARGE.getLineHeight() - 6, + String.format("Beatmap by %s", osu.creator), Color.white); + Utils.FONT_MEDIUM.drawString( + marginX, marginY + Utils.FONT_LARGE.getLineHeight() + Utils.FONT_MEDIUM.getLineHeight() - 10, + String.format("Played on %s.", scoreData.getTimeString()), Color.white); + + // mod icons int modWidth = GameMod.AUTO.getImage().getWidth(); float modX = (width * 0.98f) - modWidth; diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index 573d79df..ee48c646 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -32,36 +32,11 @@ import org.newdawn.slick.SlickException; */ public enum GameImage { // Cursor - CURSOR ("cursor", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - CURSOR_MIDDLE ("cursormiddle", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - CURSOR_TRAIL ("cursortrail", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - CURSOR_OLD ("cursor2", "png", false, false) { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - CURSOR_TRAIL_OLD ("cursortrail2", "png", false, false) { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + CURSOR ("cursor", "png"), + CURSOR_MIDDLE ("cursormiddle", "png"), + CURSOR_TRAIL ("cursortrail", "png"), + CURSOR_OLD ("cursor2", "png", false, false), + CURSOR_TRAIL_OLD ("cursortrail2", "png", false, false), // Game SECTION_PASS ("section-pass", "png"), @@ -168,295 +143,66 @@ public enum GameImage { // Score Data COMBO_BURST ("comboburst", "comboburst-%d", "png"), - SCOREBAR_BG ("scorebar-bg", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((w * 0.565f) / img.getWidth()); - } - }, - SCOREBAR_COLOUR ("scorebar-colour", "scorebar-colour-%d", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((w * 0.521f) / img.getWidth()); - } - }, + SCOREBAR_BG ("scorebar-bg", "png"), + SCOREBAR_COLOUR ("scorebar-colour", "scorebar-colour-%d", "png"), + //scorebar-marker? SCOREBAR_KI ("scorebar-ki", "png"), SCOREBAR_KI_DANGER ("scorebar-kidanger", "png"), SCOREBAR_KI_DANGER2 ("scorebar-kidanger2", "png"), - HIT_MISS ("hit0", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - HIT_50 ("hit50", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - HIT_100 ("hit100", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - HIT_300 ("hit300", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - HIT_100K ("hit100k", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - HIT_300K ("hit300k", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - HIT_300G ("hit300g", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + 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") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + RANKING_SS ("ranking-X", "png"), RANKING_SS_SMALL ("ranking-X-small", "png"), - RANKING_SSH ("ranking-XH", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + RANKING_SSH ("ranking-XH", "png"), RANKING_SSH_SMALL ("ranking-XH-small", "png"), - RANKING_S ("ranking-S", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + RANKING_S ("ranking-S", "png"), RANKING_S_SMALL ("ranking-S-small", "png"), - RANKING_SH ("ranking-SH", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + RANKING_SH ("ranking-SH", "png"), RANKING_SH_SMALL ("ranking-SH-small", "png"), - RANKING_A ("ranking-A", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + RANKING_A ("ranking-A", "png"), RANKING_A_SMALL ("ranking-A-small", "png"), - RANKING_B ("ranking-B", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + RANKING_B ("ranking-B", "png"), RANKING_B_SMALL ("ranking-B-small", "png"), - RANKING_C ("ranking-C", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + RANKING_C ("ranking-C", "png"), RANKING_C_SMALL ("ranking-C-small", "png"), - RANKING_D ("ranking-D", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + 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 / 768f); - } - }, - RANKING_PERFECT ("ranking-perfect", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - RANKING_TITLE ("ranking-title", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - RANKING_MAXCOMBO ("ranking-maxcombo", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - RANKING_ACCURACY ("ranking-accuracy", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - DEFAULT_0 ("default-0", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - DEFAULT_1 ("default-1", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - DEFAULT_2 ("default-2", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - DEFAULT_3 ("default-3", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - DEFAULT_4 ("default-4", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - DEFAULT_5 ("default-5", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - DEFAULT_6 ("default-6", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - DEFAULT_7 ("default-7", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - DEFAULT_8 ("default-8", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - DEFAULT_9 ("default-9", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_0 ("score-0", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_1 ("score-1", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_2 ("score-2", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_3 ("score-3", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_4 ("score-4", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_5 ("score-5", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_6 ("score-6", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_7 ("score-7", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_8 ("score-8", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_9 ("score-9", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_COMMA ("score-comma", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_DOT ("score-dot", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_PERCENT ("score-percent", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, - SCORE_X ("score-x", "png") { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(h / 768f); - } - }, + RANKING_PANEL ("ranking-panel", "png"), + RANKING_PERFECT ("ranking-perfect", "png"), + RANKING_TITLE ("ranking-title", "png"), + RANKING_MAXCOMBO ("ranking-maxcombo", "png"), + RANKING_ACCURACY ("ranking-accuracy", "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"), LIGHTING ("lighting", "png"), LIGHTING1 ("lighting1", "png"), @@ -529,18 +275,8 @@ public enum GameImage { return img.getScaledCopy((h * 0.3f) / img.getHeight()); } }, - MENU_BACK ("menu-back", "png", false, 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, false) { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy(w / 2, h / SongMenu.MAX_SONG_BUTTONS); - } - }, + MENU_BACK ("menu-back", "png", false, false), + MENU_BUTTON_BG ("menu-button-background", "png", false, false), MENU_TAB ("selection-tab", "png", false, false) { @Override protected Image process_sub(Image img, int w, int h) { @@ -625,18 +361,8 @@ public enum GameImage { return img.getScaledCopy((h / 18f) / img.getHeight()); } }, - RANKING_RETRY ("ranking-retry", "png", false, 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, false) { - @Override - protected Image process_sub(Image img, int w, int h) { - return img.getScaledCopy((h * 0.15f) / img.getHeight()); - } - }, + RANKING_RETRY ("ranking-retry", "png", false, false), + RANKING_EXIT ("ranking-back", "png", false, false), DOWNLOADS ("downloads", "png", false, false) { @Override protected Image process_sub(Image img, int w, int h) { @@ -707,6 +433,8 @@ public enum GameImage { /** Container dimensions. */ private static int containerWidth, containerHeight; + + public static float uiscale; /** * Initializes the GameImage class with container dimensions. @@ -716,6 +444,7 @@ public enum GameImage { public static void init(int width, int height) { containerWidth = width; containerHeight = height; + uiscale = containerHeight / 768f; } /** @@ -1026,13 +755,14 @@ public enum GameImage { * Performs individual post-loading actions on the image. */ private void process() { + int fakeWid = 768*containerWidth/containerHeight; if (skinImages != null) { for (int i = 0; i < skinImages.length; i++) - setImage(process_sub(getImages()[i], containerWidth, containerHeight), i); + setImage(process_sub(getImages()[i], fakeWid, 768).getScaledCopy(uiscale), i); } else if (defaultImages != null && skinImage == null) { for (int i = 0; i < defaultImages.length; i++) - setImage(process_sub(getImages()[i], containerWidth, containerHeight), i); + setImage(process_sub(getImages()[i], fakeWid, 768).getScaledCopy(uiscale), i); } else - setImage(process_sub(getImage(), containerWidth, containerHeight)); + setImage(process_sub(getImage(), fakeWid, 768).getScaledCopy(uiscale)); } } \ No newline at end of file diff --git a/src/itdelatrisu/opsu/OsuGroupNode.java b/src/itdelatrisu/opsu/OsuGroupNode.java index 69e8eb39..96cdf8e8 100644 --- a/src/itdelatrisu/opsu/OsuGroupNode.java +++ b/src/itdelatrisu/opsu/OsuGroupNode.java @@ -63,7 +63,7 @@ public class OsuGroupNode { OsuFile osu; Color textColor = Color.lightGray; Image bg = GameImage.MENU_BUTTON_BG.getImage(); - + bg.setAlpha(0.9f); if (expanded) { // expanded xOffset = bg.getWidth() / 10f; if (focus) { diff --git a/src/itdelatrisu/opsu/ScoreData.java b/src/itdelatrisu/opsu/ScoreData.java index 5ad238a1..91586c4d 100644 --- a/src/itdelatrisu/opsu/ScoreData.java +++ b/src/itdelatrisu/opsu/ScoreData.java @@ -287,6 +287,8 @@ public class ScoreData implements Comparable { // time since if (getTimeSince() != null) { Image clock = GameImage.HISTORY.getImage(); + g.setColor((focus) ? BG_FOCUS : BG_NORMAL); + g.fillRect(baseX + buttonWidth, y, Utils.FONT_DEFAULT.getWidth(" "),buttonHeight); clock.drawCentered(baseX + buttonWidth * 1.02f + clock.getWidth() / 2f, midY); Utils.FONT_DEFAULT.drawString( baseX + buttonWidth * 1.03f + clock.getWidth(), diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java index e42af148..26ea6dfe 100644 --- a/src/itdelatrisu/opsu/Utils.java +++ b/src/itdelatrisu/opsu/Utils.java @@ -70,8 +70,8 @@ public class Utils { COLOR_WHITE_ALPHA = new Color(255, 255, 255, 0.5f), COLOR_BLUE_DIVIDER = new Color(49, 94, 237), COLOR_BLUE_BACKGROUND = new Color(74, 130, 255), - COLOR_BLUE_BUTTON = new Color(50, 189, 237), - COLOR_ORANGE_BUTTON = new Color(230, 151, 87), + COLOR_BLUE_BUTTON = new Color(40, 129, 237), + COLOR_ORANGE_BUTTON = new Color(200, 90, 3), COLOR_GREEN_OBJECT = new Color(26, 207, 26), COLOR_BLUE_OBJECT = new Color(46, 136, 248), COLOR_RED_OBJECT = new Color(243, 48, 77), diff --git a/src/itdelatrisu/opsu/states/GameRanking.java b/src/itdelatrisu/opsu/states/GameRanking.java index 0ad5d6ff..c1a1b315 100644 --- a/src/itdelatrisu/opsu/states/GameRanking.java +++ b/src/itdelatrisu/opsu/states/GameRanking.java @@ -95,8 +95,10 @@ public class GameRanking extends BasicGameState { OsuFile osu = MusicController.getOsuFile(); // background - if (!osu.drawBG(width, height, 0.7f, true)) - g.setBackground(Utils.COLOR_BLACK_ALPHA); + if (!osu.drawBG(width, height, 0.7f, true)) { + GameImage.MENU_BG.getImage().draw(0,0); + //g.setBackground(Utils.COLOR_BLACK_ALPHA); + } // ranking screen elements data.drawRankingElements(g, osu); diff --git a/src/itdelatrisu/opsu/states/OptionsMenu.java b/src/itdelatrisu/opsu/states/OptionsMenu.java index 11fae815..28e48e99 100644 --- a/src/itdelatrisu/opsu/states/OptionsMenu.java +++ b/src/itdelatrisu/opsu/states/OptionsMenu.java @@ -181,7 +181,8 @@ public class OptionsMenu extends BasicGameState { float tabX = (width / 50) + (tabImage.getWidth() / 2f); float tabY = 15 + Utils.FONT_XLARGE.getLineHeight() + (tabImage.getHeight() / 2f); int tabOffset = Math.min(tabImage.getWidth(), - ((width - subtextWidth - tabImage.getWidth()) / 2) / OptionTab.SIZE); + //((width - subtextWidth - tabImage.getWidth()) / 2) / OptionTab.SIZE); + (width/3) / OptionTab.SIZE); for (OptionTab tab : OptionTab.values()) tab.button = new MenuButton(tabImage, tabX + (tab.ordinal() * tabOffset), tabY); } diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index be4d93be..f25a15b0 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -69,7 +69,7 @@ import org.newdawn.slick.state.transition.FadeOutTransition; */ public class SongMenu extends BasicGameState { /** The max number of song buttons to be shown on each screen. */ - public static final int MAX_SONG_BUTTONS = 6; + public static final int MAX_SONG_BUTTONS = 7; /** The max number of score buttons to be shown at a time. */ public static final int MAX_SCORE_BUTTONS = 7; From c48008d2a38f8582ed951f2a307f54336f6e1f0f Mon Sep 17 00:00:00 2001 From: fd Date: Mon, 16 Feb 2015 17:05:01 -0500 Subject: [PATCH 3/6] Clean up --- src/itdelatrisu/opsu/GameData.java | 60 +++++++++----------- src/itdelatrisu/opsu/GameImage.java | 11 +--- src/itdelatrisu/opsu/Opsu.java | 9 +-- src/itdelatrisu/opsu/OsuHitObject.java | 5 +- src/itdelatrisu/opsu/OsuParser.java | 20 ++----- src/itdelatrisu/opsu/states/OptionsMenu.java | 3 +- src/org/newdawn/slick/Image.java | 28 +++++++++ 7 files changed, 70 insertions(+), 66 deletions(-) diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index 57a8493f..74ac8a0f 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -97,7 +97,6 @@ public class GameData { return menuImage; Image img = getSmallImage(); - //img = img.getScaledCopy((GameImage.MENU_BUTTON_BG.getImage().getHeight() * 0.45f) / img.getHeight()); if (!small.hasSkinImage()) // save default image only this.menuImage = img; return img; @@ -463,6 +462,7 @@ public class GameData { * @param x the starting x coordinate * @param y the y coordinate * @param scale the scale to apply + * @param fixedsize the width to use for all symbols * @param rightAlign align right (true) or left (false) */ private void drawFixedSizeSymbolString(String str, int x, int y, float scale, float fixedsize, boolean rightAlign) { @@ -557,7 +557,6 @@ public class GameData { if (!breakPeriod) { // scorebar - // TODO: these might need to be scaled by cropping the empty (transparent) space around the images... float healthRatio = healthDisplay / 100f; if (firstObject) { // gradually move ki before map begins if (firstObjectTime >= 1500 && trackPosition < firstObjectTime - 500) @@ -566,13 +565,13 @@ public class GameData { Image scorebar = GameImage.SCOREBAR_BG.getImage(); Image colour; if (scorebarColour != null){ - scorebarColour.updateNoDraw(); //TODO + scorebarColour.updateNoDraw(); //TODO deprecated method colour = scorebarColour.getCurrentFrame(); } else { colour = GameImage.SCOREBAR_COLOUR.getImage(); } float colourX = 4 * GameImage.uiscale, colourY = 15 * GameImage.uiscale; - Image colourCropped = colour.getSubImage(0, 0, (int) (648 * GameImage.uiscale * healthRatio), colour.getHeight()); + Image colourCropped = colour.getSubImage(0, 0, (int) (645 * GameImage.uiscale * healthRatio), colour.getHeight()); scorebar.setAlpha(1f); scorebar.draw(0, 0); @@ -585,7 +584,7 @@ public class GameData { ki = GameImage.SCOREBAR_KI_DANGER.getImage(); else ki = GameImage.SCOREBAR_KI_DANGER2.getImage(); - ki.drawCentered(colourX + colourCropped.getWidth(), colourY);//ki.getHeight() / 2f); + ki.drawCentered(colourX + colourCropped.getWidth(), colourY); // combo burst if (comboBurstIndex != -1 && comboBurstAlpha > 0f) { @@ -662,30 +661,24 @@ public class GameData { Image rankingTitle = GameImage.RANKING_TITLE.getImage(); // ranking panel Image rankingPanel = GameImage.RANKING_PANEL.getImage(); - int rankingPanelWidth = rankingPanel.getWidth(); - int rankingPanelHeight = rankingPanel.getHeight(); - //Version 2 skins are a little lower - //default is version 2 - //has an ini with no version 2 is higher - float rankingHeight = 75;//height/2 -rankingPanelHeight/2 - 0;//(rankingTitle.getHeight() * 0.75f) + 3; - //if(Skin.version==2) - + //TODO Version 2 skins + float rankingHeight = 75; + + rankingPanel.draw(0, (int) (rankingHeight * GameImage.uiscale)); - rankingPanel.draw(0, (int)((rankingHeight - //+ ((Skin.version==2)? 20:) - )* GameImage.uiscale));//(height -rankingTitle.getHeight()+rankingPanelHeight)/2 - rankingPanelHeight);//rankingHeight - (rankingHeight / 10f)); - //System.err.println(rankingPanelHeight); - float scoreTextScale = 1.0f; float symbolTextScale = 1.15f; - float rankResultScale = 0.5f;// * GameImage.uiscale; + float rankResultScale = 0.5f; // score - drawFixedSizeSymbolString((score < 100000000) ? String.format("%08d", score) : Long.toString(score), - (int) (210 * GameImage.uiscale), (int) ((rankingHeight+50)* GameImage.uiscale), - scoreTextScale, getScoreSymbolImage('0').getWidth()*scoreTextScale-2, false); + drawFixedSizeSymbolString( + (score < 100000000) ? String.format("%08d", score) : Long.toString(score), + (int) (210 * GameImage.uiscale), + (int) ((rankingHeight + 50) * GameImage.uiscale), + scoreTextScale, + getScoreSymbolImage('0').getWidth() * scoreTextScale - 2, false); // result counts float resultInitialX = 130; @@ -724,18 +717,21 @@ public class GameData { // combo and accuracy Image rankingMaxCombo = GameImage.RANKING_MAXCOMBO.getImage(); Image rankingAccuracy = GameImage.RANKING_ACCURACY.getImage(); - float offsetX = 295; + float accuracyX = 295; float textY = rankingHeight + 425; - float numbersX = rankingMaxCombo.getWidth() * .07f; float numbersY = textY + 30; drawSymbolString(String.format("%dx", comboMax), - (int)(25 * GameImage.uiscale),(int) (numbersY * GameImage.uiscale), - symbolTextScale, false); - drawSymbolString(String.format("%02.2f%%", getScorePercent()), - (int) ((offsetX+20) * GameImage.uiscale), + (int) (25 * GameImage.uiscale), (int) (numbersY * GameImage.uiscale), symbolTextScale, false); - rankingMaxCombo.draw((int)(10 * GameImage.uiscale), (int)(textY * GameImage.uiscale)); - rankingAccuracy.draw((int)(offsetX * GameImage.uiscale), (int)(textY * GameImage.uiscale)); + drawSymbolString(String.format("%02.2f%%", getScorePercent()), + (int) ((accuracyX + 20) * GameImage.uiscale), + (int) (numbersY * GameImage.uiscale), symbolTextScale, false); + rankingMaxCombo.draw( + (int) (10 * GameImage.uiscale), + (int) (textY * GameImage.uiscale)); + rankingAccuracy.draw( + (int) (accuracyX * GameImage.uiscale), + (int) (textY * GameImage.uiscale)); // full combo @@ -748,11 +744,11 @@ public class GameData { // grade Grade grade = getGrade(); if (grade != Grade.NULL) - grade.getLargeImage().draw(width-grade.getLargeImage().getWidth(), 30); + grade.getLargeImage().draw(width-grade.getLargeImage().getWidth(), rankingHeight); //Header g.setColor(Utils.COLOR_BLACK_ALPHA); - g.fillRect(0, 0, width, rankingHeight); + g.fillRect(0, 0, width, 100 * GameImage.uiscale); rankingTitle.draw((width * 0.97f) - rankingTitle.getWidth(), 0); Utils.FONT_LARGE.drawString(marginX, marginY, String.format("%s - %s [%s]", osu.getArtist(), osu.getTitle(), osu.version), Color.white); diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index ee48c646..351c92d8 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -18,8 +18,6 @@ package itdelatrisu.opsu; -import itdelatrisu.opsu.states.SongMenu; - import java.io.File; import java.util.ArrayList; import java.util.List; @@ -42,12 +40,7 @@ public enum GameImage { 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()); - } - }, + SKIP ("play-skip", "png"), COUNTDOWN_READY ("ready", "png") { @Override protected Image process_sub(Image img, int w, int h) { @@ -276,6 +269,7 @@ public enum GameImage { } }, MENU_BACK ("menu-back", "png", false, false), + //MENU_BACK ("menu-back", "menu-back-%d","png") //TODO menu-back animation MENU_BUTTON_BG ("menu-button-background", "png", false, false), MENU_TAB ("selection-tab", "png", false, false) { @Override @@ -434,6 +428,7 @@ public enum GameImage { /** Container dimensions. */ private static int containerWidth, containerHeight; + /** value ui should be scaled by */ public static float uiscale; /** diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index ec2e6d5d..1a81726c 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -102,11 +102,6 @@ public class Opsu extends StateBasedGame { } catch (FileNotFoundException e) { Log.error(e); } - try { - System.setOut(new PrintStream(new FileOutputStream("jnlog.txt", false))); - } catch (FileNotFoundException e) { - Log.error(e); - } Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { @@ -118,12 +113,12 @@ public class Opsu extends StateBasedGame { Options.parseOptions(); // only allow a single instance - /*try { + try { SERVER_SOCKET = new ServerSocket(Options.getPort()); } catch (IOException e) { ErrorHandler.error(String.format("Another program is already running on port %d.", Options.getPort()), e, false); System.exit(1); - }*/ + } // set path for lwjgl natives - NOT NEEDED if using JarSplice File nativeDir = new File("./target/natives/"); diff --git a/src/itdelatrisu/opsu/OsuHitObject.java b/src/itdelatrisu/opsu/OsuHitObject.java index 46598ccd..59eb9678 100644 --- a/src/itdelatrisu/opsu/OsuHitObject.java +++ b/src/itdelatrisu/opsu/OsuHitObject.java @@ -297,8 +297,11 @@ public class OsuHitObject { */ public boolean isNewCombo() { return (type & TYPE_NEWCOMBO) > 0; } + /** + * Returns the number of extra skips on the combo colours + */ public int getComboSkip() { - return (type>>4); + return (type >> 4); } } diff --git a/src/itdelatrisu/opsu/OsuParser.java b/src/itdelatrisu/opsu/OsuParser.java index de819c93..ef4504ab 100644 --- a/src/itdelatrisu/opsu/OsuParser.java +++ b/src/itdelatrisu/opsu/OsuParser.java @@ -139,12 +139,11 @@ public class OsuParser { private static OsuFile parseFile(File file, File dir, ArrayList osuFiles, boolean parseObjects) { OsuFile osu = new OsuFile(file); - String version =""; try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) { + // initialize timing point list osu.timingPoints = new ArrayList(); - version = in.readLine(); String line = in.readLine(); String tokens[] = null; while (line != null) { @@ -492,8 +491,6 @@ public class OsuParser { } break; default: - //System.out.println("Dead: "+line+" "+file); - line = in.readLine(); break; } @@ -503,10 +500,8 @@ public class OsuParser { } // if no custom colors, use the default color scheme - if (osu.combo == null){ - System.out.println("Default Combo "+version+" "+file+" "+osu.combo); + if (osu.combo == null) osu.combo = Utils.DEFAULT_COMBO; - } // parse hit objects now? if (parseObjects) @@ -531,7 +526,6 @@ public class OsuParser { + osu.hitObjectSlider + osu.hitObjectSpinner)]; try (BufferedReader in = new BufferedReader(new FileReader(osu.getFile()))) { - String version = in.readLine(); String line = in.readLine(); while (line != null) { line = line.trim(); @@ -553,21 +547,15 @@ public class OsuParser { boolean first = true; while ((line = in.readLine()) != null && objectIndex < osu.objects.length) { line = line.trim(); - if (!isValidLine(line)){ - System.out.println("Not Valid :"+line); + if (!isValidLine(line)) continue; - } if (line.charAt(0) == '[') break; // lines must have at minimum 5 parameters int tokenCount = line.length() - line.replace(",", "").length(); - if (tokenCount < 4){ - System.out.println("(tokenCount < 4 :"+line); - + if (tokenCount < 4) continue; - - } try { // create a new OsuHitObject for each line diff --git a/src/itdelatrisu/opsu/states/OptionsMenu.java b/src/itdelatrisu/opsu/states/OptionsMenu.java index 28e48e99..c3388732 100644 --- a/src/itdelatrisu/opsu/states/OptionsMenu.java +++ b/src/itdelatrisu/opsu/states/OptionsMenu.java @@ -181,8 +181,7 @@ public class OptionsMenu extends BasicGameState { float tabX = (width / 50) + (tabImage.getWidth() / 2f); float tabY = 15 + Utils.FONT_XLARGE.getLineHeight() + (tabImage.getHeight() / 2f); int tabOffset = Math.min(tabImage.getWidth(), - //((width - subtextWidth - tabImage.getWidth()) / 2) / OptionTab.SIZE); - (width/3) / OptionTab.SIZE); + (width/2) / OptionTab.SIZE); for (OptionTab tab : OptionTab.values()) tab.button = new MenuButton(tabImage, tabX + (tab.ordinal() * tabOffset), tabY); } diff --git a/src/org/newdawn/slick/Image.java b/src/org/newdawn/slick/Image.java index 731cd180..c2480ff4 100644 --- a/src/org/newdawn/slick/Image.java +++ b/src/org/newdawn/slick/Image.java @@ -1,3 +1,31 @@ +/* + * Copyright (c) 2013, Slick2D + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the Slick2D nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. +*/ + package org.newdawn.slick; import java.io.IOException; From 987a40612322ec3b477f5d712c1e5477d3089649 Mon Sep 17 00:00:00 2001 From: fd Date: Mon, 16 Feb 2015 17:13:16 -0500 Subject: [PATCH 4/6] Clean up2 --- src/itdelatrisu/opsu/OsuParser.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/itdelatrisu/opsu/OsuParser.java b/src/itdelatrisu/opsu/OsuParser.java index ef4504ab..188a6acb 100644 --- a/src/itdelatrisu/opsu/OsuParser.java +++ b/src/itdelatrisu/opsu/OsuParser.java @@ -573,9 +573,7 @@ public class OsuParser { } first=false; } - if(hitObject.getType()>15){ - System.out.println(line+" "+hitObject.isCircle()+" "+hitObject.isSlider()+" "+hitObject.isSpinner()); - } + hitObject.setComboIndex(comboIndex); hitObject.setComboNumber(comboNumber++); From ffed4b260a547f7ace1f48c655a0ea5c7112d654 Mon Sep 17 00:00:00 2001 From: fd Date: Tue, 17 Feb 2015 22:03:11 -0500 Subject: [PATCH 5/6] Back and Skip animation removed minimum time before skip button is shown. --- src/itdelatrisu/opsu/GameImage.java | 19 ++++++++++++---- src/itdelatrisu/opsu/MenuButton.java | 31 +++++++++++++++------------ src/itdelatrisu/opsu/Utils.java | 18 ++++++++++++---- src/itdelatrisu/opsu/states/Game.java | 21 ++++++++++++------ 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index 351c92d8..5a3c2a33 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -22,6 +22,7 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import org.newdawn.slick.Animation; import org.newdawn.slick.Image; import org.newdawn.slick.SlickException; @@ -40,7 +41,7 @@ public enum GameImage { SECTION_PASS ("section-pass", "png"), SECTION_FAIL ("section-fail", "png"), WARNINGARROW ("play-warningarrow", "png"), - SKIP ("play-skip", "png"), + SKIP ("play-skip", "play-skip-%d","png"), COUNTDOWN_READY ("ready", "png") { @Override protected Image process_sub(Image img, int w, int h) { @@ -138,7 +139,7 @@ public enum GameImage { COMBO_BURST ("comboburst", "comboburst-%d", "png"), SCOREBAR_BG ("scorebar-bg", "png"), SCOREBAR_COLOUR ("scorebar-colour", "scorebar-colour-%d", "png"), - //scorebar-marker? + //TODO scorebar-marker? SCOREBAR_KI ("scorebar-ki", "png"), SCOREBAR_KI_DANGER ("scorebar-kidanger", "png"), SCOREBAR_KI_DANGER2 ("scorebar-kidanger2", "png"), @@ -268,8 +269,7 @@ public enum GameImage { return img.getScaledCopy((h * 0.3f) / img.getHeight()); } }, - MENU_BACK ("menu-back", "png", false, false), - //MENU_BACK ("menu-back", "menu-back-%d","png") //TODO menu-back animation + MENU_BACK ("menu-back", "menu-back-%d","png"), MENU_BUTTON_BG ("menu-button-background", "png", false, false), MENU_TAB ("selection-tab", "png", false, false) { @Override @@ -537,6 +537,17 @@ public enum GameImage { setDefaultImage(); return (skinImage != null) ? skinImage : defaultImage; } + + /** + * Returns an Animation based on the image array. + * If no image array exist, returns the single image as an animation. + */ + public Animation getAnimation(int duration){ + Image[] images = getImages(); + if (images == null) + images = new Image[]{ getImage() }; + return new Animation(images, duration); + } /** * Returns the image array associated with this resource. diff --git a/src/itdelatrisu/opsu/MenuButton.java b/src/itdelatrisu/opsu/MenuButton.java index e7308601..75263404 100644 --- a/src/itdelatrisu/opsu/MenuButton.java +++ b/src/itdelatrisu/opsu/MenuButton.java @@ -347,20 +347,23 @@ public class MenuButton { */ private void setHoverRadius() { int xOffset = 0, yOffset = 0; - if (dir != Expand.CENTER) { - // offset by difference between normal/scaled image dimensions - xOffset = (int) ((scale - 1f) * img.getWidth()); - yOffset = (int) ((scale - 1f) * img.getHeight()); - if (dir == Expand.UP || dir == Expand.DOWN) - xOffset = 0; // no horizontal offset - if (dir == Expand.RIGHT || dir == Expand.LEFT) - yOffset = 0; // no vertical offset - if (dir == Expand.RIGHT || dir == Expand.DOWN_RIGHT || dir == Expand.UP_RIGHT) - xOffset *= -1; // flip x for right - if (dir == Expand.DOWN || dir == Expand.DOWN_LEFT || dir == Expand.DOWN_RIGHT) - yOffset *= -1; // flip y for down + if(img != null){ + if (dir != Expand.CENTER) { + // offset by difference between normal/scaled image dimensions + xOffset = (int) ((scale - 1f) * img.getWidth()); + yOffset = (int) ((scale - 1f) * img.getHeight()); + if (dir == Expand.UP || dir == Expand.DOWN) + xOffset = 0; // no horizontal offset + if (dir == Expand.RIGHT || dir == Expand.LEFT) + yOffset = 0; // no vertical offset + if (dir == Expand.RIGHT || dir == Expand.DOWN_RIGHT || dir == Expand.UP_RIGHT) + xOffset *= -1; // flip x for right + if (dir == Expand.DOWN || dir == Expand.DOWN_LEFT || dir == Expand.DOWN_RIGHT) + yOffset *= -1; // flip y for down + } + this.xRadius = ((img.getWidth() * scale) + xOffset) / 2f; + this.yRadius = ((img.getHeight() * scale) + yOffset) / 2f; + } - this.xRadius = ((img.getWidth() * scale) + xOffset) / 2f; - this.yRadius = ((img.getHeight() * scale) + yOffset) / 2f; } } \ No newline at end of file diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java index 26ea6dfe..4fd95635 100644 --- a/src/itdelatrisu/opsu/Utils.java +++ b/src/itdelatrisu/opsu/Utils.java @@ -229,11 +229,21 @@ public class Utils { DownloadNode.init(width, height); // back button - Image back = GameImage.MENU_BACK.getImage(); - backButton = new MenuButton(back, - back.getWidth() / 2f, - height - (back.getHeight() / 2f)); + //TODO: this is annoying perhaps we can just pass in GameImage to MenuButton? + if (GameImage.MENU_BACK.getImages() != null){ + Animation back = GameImage.MENU_BACK.getAnimation(200); + backButton = new MenuButton(back, + back.getWidth() / 2f, + height - (back.getHeight() / 2f)); + }else{ + Image back = GameImage.MENU_BACK.getImage(); + backButton = new MenuButton(GameImage.MENU_BACK.getImage(), + back.getWidth() / 2f, + height - (back.getHeight() / 2f)); + } backButton.setHoverExpand(MenuButton.Expand.UP_RIGHT); + + } /** diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 1d5163b6..6e504270 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -45,6 +45,7 @@ import java.util.Stack; import java.util.concurrent.TimeUnit; import org.lwjgl.input.Keyboard; +import org.newdawn.slick.Animation; import org.newdawn.slick.Color; import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; @@ -268,7 +269,6 @@ public class Game extends BasicGameState { // skip beginning if (objectIndex == 0 && - firstObjectTime - SKIP_OFFSET > 5000 && trackPosition < osu.objects[0].getTime() - SKIP_OFFSET) skipButton.draw(); @@ -782,7 +782,6 @@ public class Game extends BasicGameState { int firstObjectTime = osu.objects[0].getTime(); int trackPosition = MusicController.getPosition(); if (objectIndex == 0 && - firstObjectTime - SKIP_OFFSET > 4000 && trackPosition < firstObjectTime - SKIP_OFFSET) { if (isLeadIn()) { leadInTime = 0; @@ -810,12 +809,20 @@ public class Game extends BasicGameState { } // skip button - Image skip = GameImage.SKIP.getImage(); - skipButton = new MenuButton(skip, - width - (skip.getWidth() / 2f), - height - (skip.getHeight() / 2f)); + //TODO: this is annoying perhaps we can just pass in GameImage to MenuButton? + if (GameImage.SKIP.getImages() != null){ + Animation back = GameImage.SKIP.getAnimation(200); + skipButton = new MenuButton(back, + width - back.getWidth() / 2f, + height - (back.getHeight() / 2f)); + }else{ + Image back = GameImage.SKIP.getImage(); + skipButton = new MenuButton(GameImage.SKIP.getImage(), + width - back.getWidth() / 2f, + height - (back.getHeight() / 2f)); + } skipButton.setHoverExpand(MenuButton.Expand.UP_LEFT); - + // load other images... ((GamePauseMenu) game.getState(Opsu.STATE_GAMEPAUSEMENU)).loadImages(); data.loadImages(); From 1dc71aaa7f3f5830ff59bce677720f6159192c99 Mon Sep 17 00:00:00 2001 From: fd Date: Tue, 17 Feb 2015 22:54:20 -0500 Subject: [PATCH 6/6] Merge quick bad fix --- src/itdelatrisu/opsu/states/OptionsMenu.java | 2 +- src/itdelatrisu/opsu/states/SongMenu.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/itdelatrisu/opsu/states/OptionsMenu.java b/src/itdelatrisu/opsu/states/OptionsMenu.java index f5906489..53beaee2 100644 --- a/src/itdelatrisu/opsu/states/OptionsMenu.java +++ b/src/itdelatrisu/opsu/states/OptionsMenu.java @@ -182,7 +182,7 @@ public class OptionsMenu extends BasicGameState { // game option coordinate modifiers textY = (int) (tabY + tabImage.getHeight()); - offsetY = (height - textY - GameImage.MENU_BACK.getImage().getHeight()) / maxOptionsScreen; + offsetY = (height - textY - GameImage.MENU_BACK.getAnimation(1).getHeight()) / maxOptionsScreen; } @Override diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 9b7bf462..3153d141 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -69,7 +69,7 @@ import org.newdawn.slick.state.transition.FadeOutTransition; */ public class SongMenu extends BasicGameState { /** The max number of song buttons to be shown on each screen. */ - public static final int MAX_SONG_BUTTONS = 7; + public static final int MAX_SONG_BUTTONS = 6; /** The max number of score buttons to be shown at a time. */ public static final int MAX_SCORE_BUTTONS = 7; @@ -253,7 +253,7 @@ public class SongMenu extends BasicGameState { search.setMaxLength(60); // selection buttons - float selectX = GameImage.MENU_BACK.getImage().getWidth() * 1.75f; + float selectX = GameImage.MENU_BACK.getAnimation(1).getWidth() * 1.75f; float selectY = height - GameImage.SELECTION_MODS.getImage().getHeight() / 2f; float selectOffset = GameImage.SELECTION_MODS.getImage().getWidth() * 1.05f; selectModsButton = new MenuButton(GameImage.SELECTION_MODS_OVERLAY.getImage(),