From 2b83657907952c5edc8385b8f7f7d19826f1428a Mon Sep 17 00:00:00 2001 From: yugecin Date: Fri, 26 Oct 2018 00:05:59 +0200 Subject: [PATCH] refactor replaystuff cursor drawing --- src/itdelatrisu/opsu/states/Game.java | 80 +++++++++---- src/yugecin/opsudance/ReplayCursor.java | 83 ++----------- src/yugecin/opsudance/ReplayCursors.java | 112 ++++++++++++++++++ src/yugecin/opsudance/ReplayPlayback.java | 20 ++-- .../opsudance/core/DisplayContainer.java | 1 + .../opsudance/core/InstanceContainer.java | 1 + 6 files changed, 192 insertions(+), 105 deletions(-) create mode 100644 src/yugecin/opsudance/ReplayCursors.java diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 0532c7dd..9e97bb2f 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -724,6 +724,10 @@ public class Game extends ComplexOpsuState { UI.draw(g); + if (replayCursors == null) { + return; + } + //g.setColor(new Color(0.2f, 0.2f, 0.2f)); //g.fillRect(0, 0, ReplayPlayback.SQSIZE * 2, displayContainer.height); //g.setColor(Color.black); @@ -740,6 +744,7 @@ public class Game extends ComplexOpsuState { replayPlayback.render(renderDelta, g, ypos, trackPosition); //} } + replayCursors.draw(); } @Override @@ -1473,7 +1478,8 @@ public class Game extends ComplexOpsuState { return true; } - private LinkedList replays; + private ReplayPlayback[] replays; + private ReplayCursors replayCursors; @Override public void enter() { overlays.clear(); @@ -1485,7 +1491,7 @@ public class Game extends ComplexOpsuState { super.enter(); - File replaydir = new File("d:/Users/Robin/games/osu/osr-stuff-master/xi/"); + File replaydir = new File("d:/Users/Robin/games/osu/osr-stuff-master/xi3/"); if (!replaydir.exists()) { bubNotifs.sendf(Colors.BUB_RED, "replay folder '%s' does not exist", replaydir.getAbsolutePath()); displayContainer.switchStateInstantly(songMenuState); @@ -1499,18 +1505,28 @@ public class Game extends ComplexOpsuState { } }); - if (replays != null) { - for (ReplayPlayback r : replays) { - r.cursor.destroy(); - } + if (replayCursors != null) { + replayCursors.destroy(); } - replays = new LinkedList<>(); - float hueshift = 360f / files.length + 6; - float hue = 0; + final ArrayList actualReplays = new ArrayList<>(50); + final ArrayList hitdatas = new ArrayList<>(50); for (File file : files) { final String datafilename = file.getName().substring(0, file.getName().length() - 3) + "ope"; final File hitdatafile = new File(file.getParentFile(), datafilename); if (!hitdatafile.exists()) { + bubNotifs.sendf(Colors.BUB_RED, "no hitdata file for %s", file.getName()); + continue; + } + final ReplayPlayback.HitData hitdata; + try { + hitdata = new ReplayPlayback.HitData(hitdatafile); + } catch (Exception e) { + bubNotifs.sendf( + Colors.BUB_RED, + "cannot parse hitdata for '%s': %s", + hitdatafile.getName(), + e.toString() + ); continue; } Replay r = new Replay(file); @@ -1520,24 +1536,39 @@ public class Game extends ComplexOpsuState { bubNotifs.sendf(Colors.BUB_RED, "could not load replay %s", file.getName()); continue; } - final ReplayPlayback.HitData hitdata = new ReplayPlayback.HitData(hitdatafile); - replays.add(new ReplayPlayback(r, hitdata, new Color(Color.white))); - hue += hueshift; + actualReplays.add(r); + hitdatas.add(hitdata); } - replays.sort(new Comparator() { + actualReplays.sort(new Comparator() { @Override - public int compare(ReplayPlayback o1, ReplayPlayback o2) { - return Integer.compare(o2.replay.score, o1.replay.score); + public int compare(Replay o1, Replay o2) { + return Integer.compare(o2.score, o1.score); } }); - hue = 180; - for (ReplayPlayback r : replays) { - Color c = new Color(java.awt.Color.getHSBColor((hue) / 360f, .7f, 1.0f).getRGB()); - r.color = c; - r.cursor.filter = c; + replayCursors = new ReplayCursors(actualReplays.size()); + replays = new ReplayPlayback[actualReplays.size()]; + + float hueshift = 360f / actualReplays.size(); + float hue = 180; + + final Iterator hitdataIter = hitdatas.iterator(); + final Iterator replayIter = actualReplays.iterator(); + int idx = 0; + while (replayIter.hasNext()) { + final Color c = new Color(java.awt.Color.HSBtoRGB((hue) / 360f, .7f, 1.0f)); + final ReplayCursor cursor = new ReplayCursor(c); + replays[idx] = new ReplayPlayback( + replayIter.next(), + hitdataIter.next(), + c, + cursor + ); + replayCursors.playbacks[idx] = replays[idx]; + hue += hueshift; + idx++; } displayContainer.drawCursor = false; @@ -1810,11 +1841,10 @@ public class Game extends ComplexOpsuState { knorkesliders = null; - if (replays != null) { - for (ReplayPlayback r : replays) { - r.cursor.destroy(); - } - replays.clear(); + if (replayCursors != null) { + replayCursors.destroy(); + replayCursors = null; + replays = null; } Dancer.instance.setGameObjects(null); diff --git a/src/yugecin/opsudance/ReplayCursor.java b/src/yugecin/opsudance/ReplayCursor.java index bc858dfb..e888132b 100644 --- a/src/yugecin/opsudance/ReplayCursor.java +++ b/src/yugecin/opsudance/ReplayCursor.java @@ -19,15 +19,10 @@ package yugecin.opsudance; import java.awt.Point; -import java.nio.IntBuffer; import java.util.Iterator; -import org.lwjgl.BufferUtils; import org.lwjgl.opengl.*; import org.newdawn.slick.*; -import org.newdawn.slick.opengl.Texture; - -import itdelatrisu.opsu.render.Rendertarget; import static itdelatrisu.opsu.GameImage.*; import static yugecin.opsudance.core.InstanceContainer.*; @@ -40,80 +35,31 @@ public class ReplayCursor public Color filter; - private Rendertarget fbo; - - private static long nowtime; - public ReplayCursor(Color filter) { this.filter = filter; this.lastPosition = new Point(width2, 0); - this.fbo = Rendertarget.createRTTFramebuffer(width, height); } - public void draw() + public void drawTrail(float trailw2, float trailh2, float txtw, float txth) { - nowtime = System.currentTimeMillis(); - - // stuff copied from CurveRenderState and stuff, I don't know what I'm doing - int oldFb = GL11.glGetInteger(EXTFramebufferObject.GL_FRAMEBUFFER_BINDING_EXT); - int oldTex = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); - //glGetInteger requires a buffer of size 16, even though just 4 - //values are returned in this specific case - IntBuffer oldViewport = BufferUtils.createIntBuffer(16); - GL11.glGetInteger(GL11.GL_VIEWPORT, oldViewport); - EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fbo.getID()); - GL11.glViewport(0, 0, fbo.width, fbo.height); - // render - GL11.glClearColor(0f, 0f, 0f, 0f); - GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); - - final Image img = CURSOR_TRAIL.getImage(); - final Texture txt = img.getTexture(); - Color.white.bind(); - txt.bind(); - float alpha = 0f; float alphaIncrease = .5f / trail.size; - float trailwidth2 = img.getWidth() * OPTION_CURSOR_SIZE.val / 100f / 2f; - float trailheight2 = img.getHeight() * OPTION_CURSOR_SIZE.val / 100f / 2f; - float txtwidth = txt.getWidth(); - float txtheight = txt.getHeight(); - GL11.glBegin(GL11.GL_QUADS); for (Trailpart p : trail) { alpha += alphaIncrease; GL11.glColor4f(filter.r, filter.g, filter.b, alpha); GL11.glTexCoord2f(0f, 0f); - GL11.glVertex3f(p.x - trailwidth2, p.y - trailheight2, 0f); - GL11.glTexCoord2f(txtwidth, 0); - GL11.glVertex3f(p.x + trailwidth2, p.y - trailheight2, 0f); - GL11.glTexCoord2f(txtwidth, txtheight); - GL11.glVertex3f(p.x + trailwidth2, p.y + trailheight2, 0f); - GL11.glTexCoord2f(0f, txtheight); - GL11.glVertex3f(p.x - trailwidth2, p.y + trailheight2, 0f); + GL11.glVertex3f(p.x - trailw2, p.y - trailh2, 0f); + GL11.glTexCoord2f(txtw, 0); + GL11.glVertex3f(p.x + trailw2, p.y - trailh2, 0f); + GL11.glTexCoord2f(txtw, txth); + GL11.glVertex3f(p.x + trailw2, p.y + trailh2, 0f); + GL11.glTexCoord2f(0f, txth); + GL11.glVertex3f(p.x - trailw2, p.y + trailh2, 0f); } - GL11.glEnd(); - - GL11.glBindTexture(GL11.GL_TEXTURE_2D, oldTex); - EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, oldFb); - GL11.glViewport(oldViewport.get(0), oldViewport.get(1), oldViewport.get(2), oldViewport.get(3)); - - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); - GL11.glEnable(GL11.GL_TEXTURE_2D); - GL11.glDisable(GL11.GL_TEXTURE_1D); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, fbo.getTextureID()); - GL11.glBegin(GL11.GL_QUADS); - GL11.glColor4f(1f, 1f, 1f, 1f); - GL11.glTexCoord2f(1f, 1f); - GL11.glVertex2i(fbo.width, 0); - GL11.glTexCoord2f(0f, 1f); - GL11.glVertex2i(0, 0); - GL11.glTexCoord2f(0f, 0f); - GL11.glVertex2i(0, fbo.height); - GL11.glTexCoord2f(1f, 0f); - GL11.glVertex2i(fbo.width, fbo.height); - GL11.glEnd(); - GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); - + } + + public void drawCursor() + { CURSOR.getScaledImage(OPTION_CURSOR_SIZE.val / 100f).drawCentered(lastPosition.x, lastPosition.y, filter); CURSOR_MIDDLE.getScaledImage(OPTION_CURSOR_SIZE.val / 100f).drawCentered(lastPosition.x, lastPosition.y, filter); } @@ -186,11 +132,6 @@ public class ReplayCursor return trail.size != size; } - public void destroy() - { - this.fbo.destroyRTT(); - } - private static class TrailList implements Iterable { TrailNode first; diff --git a/src/yugecin/opsudance/ReplayCursors.java b/src/yugecin/opsudance/ReplayCursors.java new file mode 100644 index 00000000..e05de1e6 --- /dev/null +++ b/src/yugecin/opsudance/ReplayCursors.java @@ -0,0 +1,112 @@ +/* + * opsu!dance - fork of opsu! with cursordance auto + * Copyright (C) 2018 yugecin + * + * opsu!dance is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opsu!dance is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opsu!dance. If not, see . + */ + +package yugecin.opsudance; + +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.*; +import org.newdawn.slick.*; +import org.newdawn.slick.opengl.Texture; + +import itdelatrisu.opsu.render.Rendertarget; + +import static itdelatrisu.opsu.GameImage.*; +import static yugecin.opsudance.core.InstanceContainer.*; +import static yugecin.opsudance.options.Options.*; + +import java.nio.IntBuffer; + +public class ReplayCursors +{ + public final ReplayPlayback[] playbacks; + + private final Rendertarget fbo; + + public ReplayCursors(int amount) + { + this.playbacks = new ReplayPlayback[amount]; + this.fbo = Rendertarget.createRTTFramebuffer(width, height); + } + + public void draw() + { + final Image img = CURSOR_TRAIL.getImage(); + final Texture txt = img.getTexture(); + + final float trailw2 = img.getWidth() * OPTION_CURSOR_SIZE.val / 100f / 2f; + final float trailh2 = img.getHeight() * OPTION_CURSOR_SIZE.val / 100f / 2f; + float txtw = txt.getWidth(); + float txth = txt.getHeight(); + + for (ReplayPlayback p : playbacks) { + if (!p.shouldDrawCursor()) { + continue; + } + // stuff copied from CurveRenderState and stuff, I don't know what I'm doing + int oldFb = GL11.glGetInteger(EXTFramebufferObject.GL_FRAMEBUFFER_BINDING_EXT); + int oldTex = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + IntBuffer oldViewport = BufferUtils.createIntBuffer(16); + GL11.glGetInteger(GL11.GL_VIEWPORT, oldViewport); + EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fbo.getID()); + GL11.glViewport(0, 0, fbo.width, fbo.height); + GL11.glClearColor(0f, 0f, 0f, 0f); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); + + txt.bind(); + GL11.glBegin(GL11.GL_QUADS); + p.cursor.drawTrail(trailw2, trailh2, txtw, txth); + GL11.glEnd(); + + GL11.glBindTexture(GL11.GL_TEXTURE_2D, oldTex); + EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, oldFb); + GL11.glViewport(oldViewport.get(0), oldViewport.get(1), oldViewport.get(2), oldViewport.get(3)); + + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); + //GL11.glEnable(GL11.GL_TEXTURE_2D); + //GL11.glDisable(GL11.GL_TEXTURE_1D); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, fbo.getTextureID()); + GL11.glBegin(GL11.GL_QUADS); + GL11.glColor4f(1f, 1f, 1f, 1f); + GL11.glTexCoord2f(1f, 1f); + GL11.glVertex2i(fbo.width, 0); + GL11.glTexCoord2f(0f, 1f); + GL11.glVertex2i(0, 0); + GL11.glTexCoord2f(0f, 0f); + GL11.glVertex2i(0, fbo.height); + GL11.glTexCoord2f(1f, 0f); + GL11.glVertex2i(fbo.width, fbo.height); + GL11.glEnd(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + + // something have to be drawn or things are broken... yeah... + CURSOR.getImage().draw(width, height); + } + + for (ReplayPlayback p : playbacks) { + if (!p.shouldDrawCursor()) { + continue; + } + p.cursor.drawCursor(); + } + } + + public void destroy() + { + this.fbo.destroyRTT(); + } +} diff --git a/src/yugecin/opsudance/ReplayPlayback.java b/src/yugecin/opsudance/ReplayPlayback.java index 6374e449..f87f305a 100644 --- a/src/yugecin/opsudance/ReplayPlayback.java +++ b/src/yugecin/opsudance/ReplayPlayback.java @@ -45,8 +45,8 @@ public class ReplayPlayback { public ReplayFrame currentFrame; public ReplayFrame nextFrame; private int frameIndex; - public Color color; - public Color originalcolor; + private Color color; + private final Color originalcolor; public final ReplayCursor cursor; private int keydelay[]; public static final int SQSIZE = 15; @@ -71,15 +71,13 @@ public class ReplayPlayback { private static final Color missedColor = new Color(0.4f, 0.4f, 0.4f, 1f); - public ReplayPlayback(Replay replay, HitData hitdata, Color color) { + public ReplayPlayback(Replay replay, HitData hitdata, Color color, ReplayCursor cursor) { this.replay = replay; this.hitdata = hitdata; resetFrameIndex(); - this.color = color; - this.originalcolor = new Color(color); - Color cursorcolor = new Color(color); - //cursorcolor.a = 0.5f; - cursor = new ReplayCursor(cursorcolor); + this.color = new Color(color); + this.originalcolor = color; + this.cursor = cursor; keydelay = new int[4]; this.player = replay.playerName; this.playerwidth = Fonts.SMALLBOLD.getWidth(this.player); @@ -298,7 +296,11 @@ public class ReplayPlayback { y = height - y; } cursor.setCursorPosition(renderdelta, currentFrame.getScaledX(), y); - cursor.draw(); + } + + public boolean shouldDrawCursor() + { + return !missed; } private void processKeys() { diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index 2fed84d0..e08f6c46 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -174,6 +174,7 @@ public class DisplayContainer implements ErrorDumpable, SkinChangedListener { public void run() throws Exception { while(!exitRequested && !(Display.isCloseRequested() && state.onCloseRequest()) || !confirmExit()) { + nowtime = System.currentTimeMillis(); delta = getDelta(); timeSinceLastRender += delta; diff --git a/src/yugecin/opsudance/core/InstanceContainer.java b/src/yugecin/opsudance/core/InstanceContainer.java index ea53fd90..d23672b5 100644 --- a/src/yugecin/opsudance/core/InstanceContainer.java +++ b/src/yugecin/opsudance/core/InstanceContainer.java @@ -82,6 +82,7 @@ public class InstanceContainer { public static boolean isWidescreen; public static int mouseX, mouseY; public static int renderDelta; + public static long nowtime; public static void kickstart() { updater = new Updater();