From a027330be37ecb6360d698b6bac6f0a770ee12e9 Mon Sep 17 00:00:00 2001 From: yugecin Date: Fri, 26 Oct 2018 22:52:23 +0200 Subject: [PATCH 1/3] attempt to fix merged sliders rendering wrong cones --- src/itdelatrisu/opsu/GameData.java | 2 +- src/itdelatrisu/opsu/objects/Slider.java | 54 ++++++++++++------- .../opsu/objects/curves/Curve.java | 4 +- .../opsu/render/CurveRenderState.java | 46 ++++++---------- .../opsu/render/FrameBufferCache.java | 16 +----- src/itdelatrisu/opsu/states/Game.java | 35 ++++++++---- .../opsudance/options/OptionGroups.java | 2 +- src/yugecin/opsudance/options/Options.java | 2 +- 8 files changed, 84 insertions(+), 77 deletions(-) diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index a588ca4f..5b7d3d51 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -957,7 +957,7 @@ public class GameData { private void drawHitAnimations(HitObjectResult hitResult, int trackPosition) { // fade out slider curve if (hitResult.result != HIT_SLIDER_REPEAT && hitResult.result != HIT_SLIDER_REPEAT_M && hitResult.curve != null) { - if (!OPTION_SHRINKING_SLIDERS.state) { + if (!OPTION_SHRINKING_SLIDERS.state && hitResult.curve.getCurvePoints().length > 0) { float progress = AnimationEquation.OUT_CUBIC.calc( (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); float alpha = 1f - progress; diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 56a45337..e81aac36 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -124,7 +124,7 @@ public class Slider extends GameObject { private int comboColorIndex; - public int baseSliderFrom; + public int curveStartIndex; /** * Initializes the Slider data type with images and dimensions. @@ -205,9 +205,9 @@ public class Slider extends GameObject { final int fadeInTime = game.getFadeInTime(); float scale = timeDiff / (float) approachTime; float approachScale = 1 + scale * 3; - double fadeinScale = (timeDiff - approachTime + fadeInTime) / (double) fadeInTime; - float alpha = Utils.clamp(1 - (float) fadeinScale, 0, 1); - float decorationsAlpha = Utils.clamp(-2.0f * (float) fadeinScale, 0, 1); + float fadeinScale = (timeDiff - approachTime + fadeInTime) / (float) fadeInTime; + float alpha = Utils.clamp(1f - fadeinScale, 0f, 1f); + float decorationsAlpha = Utils.clamp(-2.0f * fadeinScale, 0f, 1f); boolean overlayAboveNumber = SkinService.skin.isHitCircleOverlayAboveNumber(); float oldAlpha = Colors.WHITE_FADE.a; Colors.WHITE_FADE.a = color.a = alpha; @@ -222,7 +222,7 @@ public class Slider extends GameObject { } curveColor.a = sliderAlpha; - boolean isCurveCompletelyDrawn = drawSliderTrack(trackPosition, Utils.clamp(1d - fadeinScale, 0d, 1d)); + boolean isCurveCompletelyDrawn = drawSliderTrack(trackPosition, Utils.clamp(1f - fadeinScale, 0f, 1f)); color.a = alpha; // end circle (only draw if ball still has to go there) @@ -448,38 +448,46 @@ public class Slider extends GameObject { } } - private boolean drawSliderTrack(int trackPosition, double snakingSliderProgress) { - double curveIntervalTo = OPTION_SNAKING_SLIDERS.state ? snakingSliderProgress : 1d; - double curveIntervalFrom = 0d; + /** + * @return {@code true} if track is completely drawn (snaking, shrinking etc) + */ + private boolean drawSliderTrack(int trackPosition, float snakingSliderProgress) + { + int curvelen = curve.curve.length; + if (curvelen == 0) { + return true; + } + float curveIntervalTo = OPTION_SNAKING_SLIDERS.state ? snakingSliderProgress : 1f; + float curveIntervalFrom = 0f; if (OPTION_SHRINKING_SLIDERS.state) { - double sliderprogress = (trackPosition - getTime() - ((double) sliderTime * (repeats - 1))) / (double) sliderTime; + float sliderprogress = (trackPosition - getTime() - sliderTime * (repeats - 1)) / sliderTime; if (sliderprogress > 0) { curveIntervalFrom = sliderprogress; } } - int curvelen = curve.getCurvePoints().length; if (!OPTION_FALLBACK_SLIDERS.state && OPTION_MERGING_SLIDERS.state) { - if (OPTION_SHRINKING_SLIDERS.state && curveIntervalFrom > 0) { + if (OPTION_SHRINKING_SLIDERS.state && curveIntervalFrom > 0d) { if (hitObject.getRepeatCount() % 2 == 0) { - game.addMergedSliderPointsToRender(baseSliderFrom, baseSliderFrom + (int) ((1d - curveIntervalFrom) * curvelen)); + game.addMergedSliderPointsToRender(curveStartIndex, curveStartIndex + (int) ((1d - curveIntervalFrom) * curvelen)); } else { - game.addMergedSliderPointsToRender(baseSliderFrom + (int) (curveIntervalFrom * curvelen) + 1, baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length)); + game.addMergedSliderPointsToRender(curveStartIndex + (int) (curveIntervalFrom * curvelen) + 1, curveStartIndex + (int) (curveIntervalTo * (curvelen - 1))); } } else { - game.addMergedSliderPointsToRender(baseSliderFrom, baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length)); + int to = (int) (curveIntervalTo * (curvelen - 1)); + game.addMergedSliderPointsToRender(curveStartIndex, curveStartIndex + to); } } else { if (OPTION_SHRINKING_SLIDERS.state && curveIntervalFrom > 0 && repeats % 2 == 0) { if (OPTION_FALLBACK_SLIDERS.state) { - curveIntervalTo = 1d - curveIntervalFrom; + curveIntervalTo = 1f - curveIntervalFrom; } else { - curve.splice((int) ((1d - curveIntervalFrom) * curvelen), curvelen); + curve.splice((int) ((1f - curveIntervalFrom) * curvelen), curvelen); } - curveIntervalFrom = 0d; + curveIntervalFrom = 0f; } curve.draw(curveColor, (int) (curveIntervalFrom * curvelen), (int) (curveIntervalTo * curvelen)); } - return curveIntervalTo == 1d; + return curveIntervalTo == 1f; } /** @@ -830,6 +838,16 @@ public class Slider extends GameObject { return curve; } + public Vec2f[] getCurvePoints() + { + return curve.curve; + } + + public int getCurvePointsCount() + { + return curve.curve.length; + } + public int getRepeats() { return repeats; } diff --git a/src/itdelatrisu/opsu/objects/curves/Curve.java b/src/itdelatrisu/opsu/objects/curves/Curve.java index bf1f5353..ef455cc7 100644 --- a/src/itdelatrisu/opsu/objects/curves/Curve.java +++ b/src/itdelatrisu/opsu/objects/curves/Curve.java @@ -91,10 +91,8 @@ public abstract class Curve { } /** - * Set the width and height of the container that Curves get drawn into. + * Init curves for given circle diameter * Should be called before any curves are drawn. - * @param width the container width - * @param height the container height * @param circleDiameter the circle diameter * @param borderColor the curve border color */ diff --git a/src/itdelatrisu/opsu/render/CurveRenderState.java b/src/itdelatrisu/opsu/render/CurveRenderState.java index c69aa034..87548940 100644 --- a/src/itdelatrisu/opsu/render/CurveRenderState.java +++ b/src/itdelatrisu/opsu/render/CurveRenderState.java @@ -75,7 +75,7 @@ public class CurveRenderState { private final int mirrors; /** - * Set the width and height of the container that Curves get drawn into. + * Init curves for given circle diameter * Should be called before any curves are drawn. * @param circleDiameter the circle diameter */ @@ -83,7 +83,6 @@ public class CurveRenderState { // equivalent to what happens in Slider.init() scale = (int) (circleDiameter * HitObject.getXMultiplier()); // convert from Osupixels (640x480) //scale = scale * 118 / 128; //for curves exactly as big as the sliderball - FrameBufferCache.init(width, height); NewCurveStyleState.initUnitCone(); } @@ -293,31 +292,20 @@ public class CurveRenderState { */ private void createVertexBuffer(int bufferID) { int arrayBufferBinding = GL11.glGetInteger(GL15.GL_ARRAY_BUFFER_BINDING); - FloatBuffer buff = BufferUtils.createByteBuffer(4 * (4 + 2) * (2 * curve.length - 1) * mirrors * (NewCurveStyleState.DIVIDES + 2)).asFloatBuffer(); - if (curve.length > 0) { - fillCone(buff, curve[0].x, curve[0].y, 0); - } + FloatBuffer buff = BufferUtils.createByteBuffer(4 * (4 + 2) * (curve.length) * mirrors * (NewCurveStyleState.DIVIDES + 2)).asFloatBuffer(); for (int mirror = 0; mirror < mirrors; mirror++) { final float angle = 360f * mirror / mirrors; + float lastx = curve[0].x; + float lasty = curve[0].y; + fillCone(buff, lastx, lasty, angle); for (int i = 1; i < curve.length; ++i) { float x = curve[i].x; float y = curve[i].y; fillCone(buff, x, y, angle); - float last_x = curve[i - 1].x; - float last_y = curve[i - 1].y; - double diff_x = x - last_x; - double diff_y = y - last_y; - float dist = Utils.distance(x, y, last_x, last_y); - if (dist < gameObjectRenderer.circleDiameter / 8) { - x = (float) (x - diff_x / 2); - y = (float) (y - diff_y / 2); - } else { - // don't mind me - x = -100f; - y = -100f; - } - fillCone(buff, x, y, angle); + //fillCone(buff, (x + lastx) / 2f, (y + lasty) / 2f, angle); + //lastx = x; + //lasty = y; } } buff.flip(); @@ -349,16 +337,15 @@ public class CurveRenderState { if (clearFirst) { GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); } - int max = mirrors; - if (!OPTION_DANCE_MIRROR.state) { - max = 1; - } - for (int i = 0; i < max; i++) { + final int mirrors = OPTION_DANCE_MIRROR.state ? this.mirrors : 1; + for (int i = 0; i < mirrors; i++) { if (pointsToRender == null) { renderCurve(from, to, i); } else { renderCurve(i); } + //from++; + //to++; } GL11.glFlush(); GL20.glDisableVertexAttribArray(staticState.texCoordLoc); @@ -367,15 +354,16 @@ public class CurveRenderState { } private void renderCurve(int from, int to, int mirror) { + // since there are len*2-1 points, subtract mirror index if (from > 0) { from -= mirror; } to -= mirror; - for (int i = from * 2; i < to * 2 - 1; ++i) { + for (int i = from; i < to - 1; ++i) { if (spliceFrom <= i && i <= spliceTo) { continue; } - final int index = i + curve.length * 2 * mirror; + final int index = i + curve.length * mirror; GL11.glDrawArrays(GL11.GL_TRIANGLE_FAN, index * (NewCurveStyleState.DIVIDES + 2), NewCurveStyleState.DIVIDES + 2); } } @@ -383,8 +371,8 @@ public class CurveRenderState { private void renderCurve(int mirror) { Iterator iter = pointsToRender.iterator(); while (iter.hasNext()) { - for (int i = iter.next() * 2, end = iter.next() * 2 - 1; i < end; ++i) { - final int index = i + curve.length * 2 * mirror; + for (int i = iter.next(), end = iter.next(); i < end; ++i) { + final int index = i + curve.length * mirror; GL11.glDrawArrays(GL11.GL_TRIANGLE_FAN, index * (NewCurveStyleState.DIVIDES + 2), NewCurveStyleState.DIVIDES + 2); } } diff --git a/src/itdelatrisu/opsu/render/FrameBufferCache.java b/src/itdelatrisu/opsu/render/FrameBufferCache.java index bf1a96aa..ae8da4fe 100644 --- a/src/itdelatrisu/opsu/render/FrameBufferCache.java +++ b/src/itdelatrisu/opsu/render/FrameBufferCache.java @@ -23,6 +23,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import static yugecin.opsudance.core.InstanceContainer.*; + /** * This is cache for OpenGL FrameBufferObjects. This is currently only used * to draw curve objects of the new slider style. Does currently not integrate @@ -40,20 +42,6 @@ public class FrameBufferCache { /** */ private ArrayList cache; - /** Container dimensions. */ - public static int width, height; - - /** - * Set the width and height of the framebuffers in this cache. - * Should be called before anything is inserted into the map. - * @param width the container width - * @param height the container height - */ - public static void init(int width, int height) { - FrameBufferCache.width = width; - FrameBufferCache.height = height; - } - /** * Constructor. */ diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 78375d13..2c470c38 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -68,6 +68,7 @@ import yugecin.opsudance.utils.GLHelper; import static itdelatrisu.opsu.GameImage.*; import static itdelatrisu.opsu.ui.Colors.*; +import static java.lang.System.arraycopy; import static org.lwjgl.input.Keyboard.*; import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.core.InstanceContainer.*; @@ -1672,22 +1673,36 @@ public class Game extends ComplexOpsuState { } if (knorkesliders == null) { // let's create knorkesliders - List curvepoints = new ArrayList<>(); - for (GameObject gameObject : gameObjects) { - if (gameObject.isSlider()) { - ((Slider) gameObject).baseSliderFrom = curvepoints.size(); - curvepoints.addAll(Arrays.asList(((Slider) gameObject).getCurve().getCurvePoints())); + int totalpoints = 0; + ArrayList sliders = new ArrayList<>(); + for (GameObject o : gameObjects) { + if (o.isSlider()) { + final Slider s = (Slider) o; + final int len = s.getCurvePointsCount(); + if (len > 0) { + sliders.add(s); + s.curveStartIndex = totalpoints; + totalpoints += s.getCurvePointsCount(); + } } } - if (curvepoints.size() > 0) { - knorkesliders = new FakeCombinedCurve(curvepoints.toArray(new Vec2f[curvepoints.size()])); + if (totalpoints > 0) { + Vec2f[] combinedcurve = new Vec2f[totalpoints]; + int idx = 0; + for (Slider s : sliders) { + int len = s.getCurvePointsCount(); + arraycopy(s.getCurvePoints(), 0, combinedcurve, idx, len); + idx += len; + } + knorkesliders = new FakeCombinedCurve(combinedcurve); } } else { - int base = 0; + int startIndex = 0; for (GameObject gameObject : gameObjects) { if (gameObject.isSlider()) { - ((Slider) gameObject).baseSliderFrom = base; - base += ((Slider) gameObject).getCurve().getCurvePoints().length; + final Slider s = (Slider) gameObject; + s.curveStartIndex = startIndex; + startIndex += s.getCurvePointsCount(); } } } diff --git a/src/yugecin/opsudance/options/OptionGroups.java b/src/yugecin/opsudance/options/OptionGroups.java index de2ff0c2..aa523efb 100644 --- a/src/yugecin/opsudance/options/OptionGroups.java +++ b/src/yugecin/opsudance/options/OptionGroups.java @@ -50,7 +50,7 @@ public class OptionGroups { OPTION_FALLBACK_SLIDERS, OPTION_SHRINKING_SLIDERS, OPTION_MERGING_SLIDERS, - //OPTION_MERGING_SLIDERS_MIRROR_POOL, + OPTION_MERGING_SLIDERS_MIRROR_POOL, OPTION_DRAW_SLIDER_ENDCIRCLES, }), new OptionTab("DANCING HITCIRCLES", new Option[] { diff --git a/src/yugecin/opsudance/options/Options.java b/src/yugecin/opsudance/options/Options.java index 6a0aed32..eabed981 100644 --- a/src/yugecin/opsudance/options/Options.java +++ b/src/yugecin/opsudance/options/Options.java @@ -496,7 +496,7 @@ public class Options { } }; - public static final NumericOption OPTION_MERGING_SLIDERS_MIRROR_POOL = new NumericOption("Merging sliders mirror pool", "MergingSliderMirrorPool", "Amount of mirrors to calculate for merging sliders (impacts performance)", 2, 1, 5) { + public static final NumericOption OPTION_MERGING_SLIDERS_MIRROR_POOL = new NumericOption("Mirrors", "MergingSliderMirrorPool", "Amount of mirrors to calculate for merging sliders (impacts performance)", 2, 2, 6) { @Override public String getValueString () { return String.valueOf(val); From 28f5cfe5c8f2c61ab1b09b038f56b68b88eb43ef Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 28 Oct 2018 17:10:39 +0100 Subject: [PATCH 2/3] don't search on options that should be hidden --- src/yugecin/opsudance/options/Option.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/yugecin/opsudance/options/Option.java b/src/yugecin/opsudance/options/Option.java index 7f31a142..67930849 100644 --- a/src/yugecin/opsudance/options/Option.java +++ b/src/yugecin/opsudance/options/Option.java @@ -70,6 +70,9 @@ public class Option { * @return true if this option does need to be filtered */ public boolean filter(String searchString) { + if (!showCondition()) { + return filtered = true; + } if (searchString == null || searchString.length() == 0) { filtered = false; return false; From 559e609b817930820dea56f3f32fbc875d87eb6f Mon Sep 17 00:00:00 2001 From: yugecin Date: Sun, 28 Oct 2018 17:19:11 +0100 Subject: [PATCH 3/3] fix song menu footer buttons misalignment --- src/itdelatrisu/opsu/states/SongMenu.java | 6 +++--- src/itdelatrisu/opsu/ui/MenuButton.java | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 70bf2129..29805417 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -37,6 +37,7 @@ import itdelatrisu.opsu.beatmap.BeatmapWatchService.BeatmapWatchServiceListener; import itdelatrisu.opsu.beatmap.LRUCache; import itdelatrisu.opsu.db.BeatmapDB; import itdelatrisu.opsu.db.ScoreDB; +import itdelatrisu.opsu.objects.curves.Vec2f; import itdelatrisu.opsu.states.ButtonMenu.MenuState; import itdelatrisu.opsu.ui.Colors; import itdelatrisu.opsu.ui.DropdownMenu; @@ -48,7 +49,6 @@ import itdelatrisu.opsu.ui.UI; import itdelatrisu.opsu.ui.animations.AnimatedValue; import itdelatrisu.opsu.ui.animations.AnimationEquation; -import java.awt.Point; import java.io.File; import java.nio.file.Path; import java.nio.file.StandardWatchEventKinds; @@ -405,7 +405,7 @@ public class SongMenu extends ComplexOpsuState { // selection buttons // TODO: the origin should be bottomleft or something float selectX = width * (isWidescreen ? 0.164f : 0.1875f); - final float footerButtonWidth = footerHeight * 0.84f; + final float footerButtonWidth = footerHeight * 0.85f; selectModeButton = new MenuButton(SELECTION_MODE_OVERLAY, selectX, footerY); selectX += footerHeight + 2; selectModsButton = new MenuButton(SELECTION_MODS_OVERLAY, selectX, footerY); @@ -614,7 +614,7 @@ public class SongMenu extends ComplexOpsuState { } // selection buttons - Point c; + Vec2f c; c = selectModeButton.bottomLeft(); SELECTION_MODE.getImage().draw(c.x, c.y - SELECTION_MODE.getHeight()); selectModeButton.draw(); diff --git a/src/itdelatrisu/opsu/ui/MenuButton.java b/src/itdelatrisu/opsu/ui/MenuButton.java index bc26188c..3ad31a95 100644 --- a/src/itdelatrisu/opsu/ui/MenuButton.java +++ b/src/itdelatrisu/opsu/ui/MenuButton.java @@ -20,11 +20,10 @@ package itdelatrisu.opsu.ui; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.Utils; +import itdelatrisu.opsu.objects.curves.Vec2f; import itdelatrisu.opsu.ui.animations.AnimatedValue; import itdelatrisu.opsu.ui.animations.AnimationEquation; -import java.awt.Point; - import org.newdawn.slick.Animation; import org.newdawn.slick.Color; import org.newdawn.slick.Font; @@ -177,8 +176,8 @@ public class MenuButton { */ public float getY() { return y; } - public Point bottomLeft() { - return new Point((int) (x - xRadius), (int) (y + yRadius)); + public Vec2f bottomLeft() { + return new Vec2f(x - xRadius, y + yRadius); } /**