Merge branch 'knorkemergingsliders'
This commit is contained in:
commit
25f310887d
|
@ -913,7 +913,9 @@ public class GameData {
|
||||||
float oldColorAlpha = hitResult.color.a;
|
float oldColorAlpha = hitResult.color.a;
|
||||||
Colors.WHITE_FADE.a = alpha;
|
Colors.WHITE_FADE.a = alpha;
|
||||||
hitResult.color.a = alpha;
|
hitResult.color.a = alpha;
|
||||||
|
if (!Options.isShrinkingSliders()) {
|
||||||
hitResult.curve.draw(hitResult.color);
|
hitResult.curve.draw(hitResult.color);
|
||||||
|
}
|
||||||
Colors.WHITE_FADE.a = oldWhiteAlpha;
|
Colors.WHITE_FADE.a = oldWhiteAlpha;
|
||||||
hitResult.color.a = oldColorAlpha;
|
hitResult.color.a = oldColorAlpha;
|
||||||
}
|
}
|
||||||
|
|
|
@ -502,7 +502,14 @@ public class Options {
|
||||||
FORCE_DEFAULT_PLAYFIELD ("Force Default Playfield", "ForceDefaultPlayfield", "Override the song background with the default playfield background.", false),
|
FORCE_DEFAULT_PLAYFIELD ("Force Default Playfield", "ForceDefaultPlayfield", "Override the song background with the default playfield background.", false),
|
||||||
IGNORE_BEATMAP_SKINS ("Ignore All Beatmap Skins", "IgnoreBeatmapSkins", "Never use skin element overrides provided by beatmaps.", false),
|
IGNORE_BEATMAP_SKINS ("Ignore All Beatmap Skins", "IgnoreBeatmapSkins", "Never use skin element overrides provided by beatmaps.", false),
|
||||||
SNAKING_SLIDERS ("Snaking sliders", "SnakingSliders", "Sliders gradually snake out from their starting point.", true),
|
SNAKING_SLIDERS ("Snaking sliders", "SnakingSliders", "Sliders gradually snake out from their starting point.", true),
|
||||||
|
SHRINKING_SLIDERS ("Shrinking sliders", "ShrinkingSliders", "Sliders shrinks when sliderball passes - unstable!", false),
|
||||||
FALLBACK_SLIDERS ("Fallback sliders", "FallbackSliders", "Enable this if sliders won't render", false),
|
FALLBACK_SLIDERS ("Fallback sliders", "FallbackSliders", "Enable this if sliders won't render", false),
|
||||||
|
MERGING_SLIDERS ("Merging sliders", "MergingSliders", "Merge sliders (aka knorkesliders) - unstable!", false) {
|
||||||
|
@Override
|
||||||
|
public boolean showCondition() {
|
||||||
|
return !FALLBACK_SLIDERS.bool;
|
||||||
|
}
|
||||||
|
},
|
||||||
SHOW_HIT_LIGHTING ("Show Hit Lighting", "HitLighting", "Adds an effect behind hit explosions.", true),
|
SHOW_HIT_LIGHTING ("Show Hit Lighting", "HitLighting", "Adds an effect behind hit explosions.", true),
|
||||||
SHOW_COMBO_BURSTS ("Show Combo Bursts", "ComboBurst", "A character image is displayed at combo milestones.", true),
|
SHOW_COMBO_BURSTS ("Show Combo Bursts", "ComboBurst", "A character image is displayed at combo milestones.", true),
|
||||||
SHOW_PERFECT_HIT ("Show Perfect Hits", "PerfectHit", "Whether to show perfect hit result bursts (300s, slider ticks).", true),
|
SHOW_PERFECT_HIT ("Show Perfect Hits", "PerfectHit", "Whether to show perfect hit result bursts (300s, slider ticks).", true),
|
||||||
|
@ -1775,6 +1782,9 @@ public class Options {
|
||||||
|
|
||||||
public static boolean isFallbackSliders() { return GameOption.FALLBACK_SLIDERS.getBooleanValue(); }
|
public static boolean isFallbackSliders() { return GameOption.FALLBACK_SLIDERS.getBooleanValue(); }
|
||||||
|
|
||||||
|
public static boolean isShrinkingSliders() { return GameOption.SHRINKING_SLIDERS.getBooleanValue(); }
|
||||||
|
public static boolean isMergingSliders() { return !isFallbackSliders() && GameOption.MERGING_SLIDERS.getBooleanValue(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the fixed circle size override, if any.
|
* Returns the fixed circle size override, if any.
|
||||||
* @return the CS value (0, 10], 0f if disabled
|
* @return the CS value (0, 10], 0f if disabled
|
||||||
|
|
|
@ -122,6 +122,10 @@ public class Slider extends GameObject {
|
||||||
private int tickExpand = 0;
|
private int tickExpand = 0;
|
||||||
private final int TICKEXPAND = 200;
|
private final int TICKEXPAND = 200;
|
||||||
|
|
||||||
|
public int baseSliderFrom;
|
||||||
|
|
||||||
|
private boolean reversed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the Slider data type with images and dimensions.
|
* Initializes the Slider data type with images and dimensions.
|
||||||
* @param container the game container
|
* @param container the game container
|
||||||
|
@ -193,6 +197,9 @@ public class Slider extends GameObject {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(Graphics g, int trackPosition, boolean mirror) {
|
public void draw(Graphics g, int trackPosition, boolean mirror) {
|
||||||
|
if (trackPosition > getEndTime()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Color orig = color;
|
Color orig = color;
|
||||||
if (mirror) {
|
if (mirror) {
|
||||||
color = mirrorColor;
|
color = mirrorColor;
|
||||||
|
@ -217,10 +224,9 @@ public class Slider extends GameObject {
|
||||||
if (GameMod.HIDDEN.isActive() && trackPosition > getTime()) {
|
if (GameMod.HIDDEN.isActive() && trackPosition > getTime()) {
|
||||||
curveAlpha = Math.max(0f, 1f - ((float) (trackPosition - getTime()) / (getEndTime() - getTime())) * 1.05f);
|
curveAlpha = Math.max(0f, 1f - ((float) (trackPosition - getTime()) / (getEndTime() - getTime())) * 1.05f);
|
||||||
}
|
}
|
||||||
curveColor.a = curveAlpha;
|
|
||||||
|
|
||||||
float curveInterval = Options.isSliderSnaking() ? alpha : 1f;
|
curveColor.a = curveAlpha;
|
||||||
curve.draw(curveColor, curveInterval);
|
boolean isCurveCompletelyDrawn = drawSliderTrack(trackPosition, alpha);
|
||||||
color.a = alpha;
|
color.a = alpha;
|
||||||
|
|
||||||
g.pushTransform();
|
g.pushTransform();
|
||||||
|
@ -246,20 +252,9 @@ public class Slider extends GameObject {
|
||||||
|
|
||||||
// ticks
|
// ticks
|
||||||
if (ticksT != null) {
|
if (ticksT != null) {
|
||||||
float tickScale = 0.5f + 0.5f * AnimationEquation.OUT_BACK.calc(decorationsAlpha);
|
drawSliderTicks(g, trackPosition, curveAlpha, decorationsAlpha, mirror);
|
||||||
Image tick = GameImage.SLIDER_TICK.getImage().getScaledCopy(tickScale);
|
|
||||||
for (int i = 0; i < ticksT.length; i++) {
|
|
||||||
Vec2f c = curve.pointAt(ticksT[i]);
|
|
||||||
Colors.WHITE_FADE.a = Math.min(curveAlpha, decorationsAlpha);
|
|
||||||
g.pushTransform();
|
|
||||||
if (mirror) {
|
|
||||||
g.rotate(c.x, c.y, -180f);
|
|
||||||
}
|
|
||||||
tick.drawCentered(c.x, c.y, Colors.WHITE_FADE);
|
|
||||||
g.popTransform();
|
|
||||||
Colors.WHITE_FADE.a = alpha;
|
Colors.WHITE_FADE.a = alpha;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
g.pushTransform();
|
g.pushTransform();
|
||||||
if (mirror) {
|
if (mirror) {
|
||||||
|
@ -285,7 +280,7 @@ public class Slider extends GameObject {
|
||||||
g.popTransform();
|
g.popTransform();
|
||||||
|
|
||||||
// repeats
|
// repeats
|
||||||
if (curveInterval == 1.0f) {
|
if (isCurveCompletelyDrawn) {
|
||||||
for (int tcurRepeat = currentRepeats; tcurRepeat <= currentRepeats + 1; tcurRepeat++) {
|
for (int tcurRepeat = currentRepeats; tcurRepeat <= currentRepeats + 1; tcurRepeat++) {
|
||||||
if (hitObject.getRepeatCount() - 1 > tcurRepeat) {
|
if (hitObject.getRepeatCount() - 1 > tcurRepeat) {
|
||||||
Image arrow = GameImage.REVERSEARROW.getImage();
|
Image arrow = GameImage.REVERSEARROW.getImage();
|
||||||
|
@ -369,6 +364,70 @@ public class Slider extends GameObject {
|
||||||
color = orig;
|
color = orig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void drawSliderTicks(Graphics g, int trackPosition, float curveAlpha, float decorationsAlpha, boolean mirror) {
|
||||||
|
float tickScale = 0.5f + 0.5f * AnimationEquation.OUT_BACK.calc(decorationsAlpha);
|
||||||
|
Image tick = GameImage.SLIDER_TICK.getImage().getScaledCopy(tickScale);
|
||||||
|
|
||||||
|
// calculate which ticks need to be drawn (don't draw if sliderball crossed it)
|
||||||
|
int min = 0;
|
||||||
|
int max = ticksT.length;
|
||||||
|
if (trackPosition > getTime()) {
|
||||||
|
for (int i = 0; i < ticksT.length; ) {
|
||||||
|
if (((trackPosition - getTime()) % sliderTime) / sliderTime < ticksT[i]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
min = ++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentRepeats % 2 == 1) {
|
||||||
|
max -= min;
|
||||||
|
min = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = min; i < max; i++) {
|
||||||
|
Vec2f c = curve.pointAt(ticksT[i]);
|
||||||
|
Colors.WHITE_FADE.a = Math.min(curveAlpha, decorationsAlpha);
|
||||||
|
g.pushTransform();
|
||||||
|
if (mirror) {
|
||||||
|
g.rotate(c.x, c.y, -180f);
|
||||||
|
}
|
||||||
|
tick.drawCentered(c.x, c.y, Colors.WHITE_FADE);
|
||||||
|
g.popTransform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean drawSliderTrack(int trackPosition, float snakingSliderProgress) {
|
||||||
|
float curveIntervalTo = Options.isSliderSnaking() ? snakingSliderProgress : 1f;
|
||||||
|
float curveIntervalFrom = 0f;
|
||||||
|
if (Options.isShrinkingSliders()) {
|
||||||
|
float sliderprogress = (trackPosition - getTime() - (sliderTime * (repeats - 1))) / sliderTime;
|
||||||
|
if (sliderprogress > 0) {
|
||||||
|
curveIntervalFrom = sliderprogress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Options.isMergingSliders()) {
|
||||||
|
if (Options.isShrinkingSliders() && curveIntervalFrom > 0) {
|
||||||
|
int curvelen = curve.getCurvePoints().length;
|
||||||
|
if (repeats % 2 == 0) {
|
||||||
|
game.spliceSliderCurve(baseSliderFrom + (int) ((1f - curveIntervalFrom) * curvelen), baseSliderFrom + curvelen);
|
||||||
|
} else {
|
||||||
|
game.setSlidercurveFrom(baseSliderFrom + (int) (curveIntervalFrom * curvelen) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
game.setSlidercurveTo(baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length));
|
||||||
|
} else {
|
||||||
|
if (Options.isShrinkingSliders() && curveIntervalFrom > 0) {
|
||||||
|
int curvelen = curve.getCurvePoints().length;
|
||||||
|
if (repeats % 2 == 0) {
|
||||||
|
curve.splice((int) ((1f - curveIntervalFrom) * curvelen), curvelen);
|
||||||
|
curveIntervalFrom = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curve.draw(curveColor, curveIntervalFrom, curveIntervalTo);
|
||||||
|
}
|
||||||
|
return curveIntervalTo == 1f;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the slider hit result.
|
* Calculates the slider hit result.
|
||||||
* @return the hit result (GameData.HIT_* constants)
|
* @return the hit result (GameData.HIT_* constants)
|
||||||
|
@ -550,6 +609,9 @@ public class Slider extends GameObject {
|
||||||
|
|
||||||
// calculate and send slider result
|
// calculate and send slider result
|
||||||
hitResult();
|
hitResult();
|
||||||
|
if (Options.isMergingSliders()) {
|
||||||
|
game.setSlidercurveFrom(baseSliderFrom + curve.getCurvePoints().length + 1);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,11 @@ public abstract class Curve {
|
||||||
private CurveRenderState renderState;
|
private CurveRenderState renderState;
|
||||||
|
|
||||||
/** Points along the curve (set by inherited classes). */
|
/** Points along the curve (set by inherited classes). */
|
||||||
protected Vec2f[] curve;
|
public Vec2f[] curve;
|
||||||
|
|
||||||
|
public Vec2f[] getCurvePoints() {
|
||||||
|
return curve;
|
||||||
|
}
|
||||||
|
|
||||||
private Color fallbackSliderColor = new Color(20, 20, 20);
|
private Color fallbackSliderColor = new Color(20, 20, 20);
|
||||||
|
|
||||||
|
@ -117,29 +121,32 @@ public abstract class Curve {
|
||||||
* Draws the full curve to the graphics context.
|
* Draws the full curve to the graphics context.
|
||||||
* @param color the color filter
|
* @param color the color filter
|
||||||
*/
|
*/
|
||||||
public void draw(Color color) { draw(color, 1f); }
|
public void draw(Color color) { draw(color, 0f, 1f); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws the curve in the range [0, t] (where the full range is [0, 1]) to the graphics context.
|
* Draws the curve in the range [0, t] (where the full range is [0, 1]) to the graphics context.
|
||||||
* @param color the color filter
|
* @param color the color filter
|
||||||
* @param t set the curve interval to [0, t]
|
* @param t1 interval to draw from
|
||||||
|
* @param t2 interval to draw to
|
||||||
*/
|
*/
|
||||||
public void draw(Color color, float t) {
|
public void draw(Color color, float t1, float t2) {
|
||||||
if (curve == null)
|
if (curve == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
t = Utils.clamp(t, 0f, 1f);
|
t1 = Utils.clamp(t1, 0f, 1f);
|
||||||
|
t2 = Utils.clamp(t2, 0f, 1f);
|
||||||
|
|
||||||
// peppysliders
|
// peppysliders
|
||||||
if (Options.isFallbackSliders() || Options.getSkin().getSliderStyle() == Skin.STYLE_PEPPYSLIDER || !mmsliderSupported) {
|
if (Options.isFallbackSliders() || Options.getSkin().getSliderStyle() == Skin.STYLE_PEPPYSLIDER || !mmsliderSupported) {
|
||||||
int drawUpTo = (int) (curve.length * t);
|
int drawFrom = (int) (curve.length * t1);
|
||||||
|
int drawUpTo = (int) (curve.length * t2);
|
||||||
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
||||||
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
||||||
for (int i = 0; i < drawUpTo; i++)
|
for (int i = drawFrom; i < drawUpTo; i++)
|
||||||
hitCircleOverlay.drawCentered(curve[i].x, curve[i].y, Colors.WHITE_FADE);
|
hitCircleOverlay.drawCentered(curve[i].x, curve[i].y, Colors.WHITE_FADE);
|
||||||
float a = fallbackSliderColor.a;
|
float a = fallbackSliderColor.a;
|
||||||
fallbackSliderColor.a = color.a;
|
fallbackSliderColor.a = color.a;
|
||||||
for (int i = 0; i < drawUpTo; i++)
|
for (int i = drawFrom; i < drawUpTo; i++)
|
||||||
hitCircle.drawCentered(curve[i].x, curve[i].y, fallbackSliderColor);
|
hitCircle.drawCentered(curve[i].x, curve[i].y, fallbackSliderColor);
|
||||||
fallbackSliderColor.a = a;
|
fallbackSliderColor.a = a;
|
||||||
}
|
}
|
||||||
|
@ -148,10 +155,14 @@ public abstract class Curve {
|
||||||
else {
|
else {
|
||||||
if (renderState == null)
|
if (renderState == null)
|
||||||
renderState = new CurveRenderState(hitObject, curve);
|
renderState = new CurveRenderState(hitObject, curve);
|
||||||
renderState.draw(color, borderColor, t);
|
renderState.draw(color, borderColor, t1, t2); // TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void splice(int from, int to) {
|
||||||
|
renderState.splice(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the angle of the first control point.
|
* Returns the angle of the first control point.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,6 +20,7 @@ package itdelatrisu.opsu.render;
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
|
import itdelatrisu.opsu.objects.Circle;
|
||||||
import itdelatrisu.opsu.objects.curves.Vec2f;
|
import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
@ -59,11 +60,14 @@ public class CurveRenderState {
|
||||||
/** The HitObject associated with the curve to be drawn. */
|
/** The HitObject associated with the curve to be drawn. */
|
||||||
protected HitObject hitObject;
|
protected HitObject hitObject;
|
||||||
|
|
||||||
/** The points along the curve to be drawn. */
|
|
||||||
protected Vec2f[] curve;
|
protected Vec2f[] curve;
|
||||||
|
|
||||||
/** The point to which the curve has last been rendered into the texture (as an index into {@code curve}). */
|
/** The point to which the curve has last been rendered into the texture (as an index into {@code curve}). */
|
||||||
private int lastPointDrawn;
|
private int lastPointDrawn;
|
||||||
|
private int firstPointDrawn;
|
||||||
|
|
||||||
|
private int spliceFrom;
|
||||||
|
private int spliceTo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the width and height of the container that Curves get drawn into.
|
* Set the width and height of the container that Curves get drawn into.
|
||||||
|
@ -85,7 +89,7 @@ public class CurveRenderState {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undo the static state. Static state setup caused by calls to
|
* Undo the static state. Static state setup caused by calls to
|
||||||
* {@link #draw(org.newdawn.slick.Color, org.newdawn.slick.Color, float)}
|
* {@link #draw(org.newdawn.slick.Color, org.newdawn.slick.Color, float, float)}
|
||||||
* are undone.
|
* are undone.
|
||||||
*/
|
*/
|
||||||
public static void shutdown() {
|
public static void shutdown() {
|
||||||
|
@ -99,25 +103,8 @@ public class CurveRenderState {
|
||||||
* @param curve the points along the curve to be drawn
|
* @param curve the points along the curve to be drawn
|
||||||
*/
|
*/
|
||||||
public CurveRenderState(HitObject hitObject, Vec2f[] curve) {
|
public CurveRenderState(HitObject hitObject, Vec2f[] curve) {
|
||||||
fbo = null;
|
|
||||||
this.hitObject = hitObject;
|
this.hitObject = hitObject;
|
||||||
this.curve = curve;
|
this.curve = curve;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw a curve to the screen that's tinted with `color`. The first time
|
|
||||||
* this is called this caches the image result of the curve and on subsequent
|
|
||||||
* runs it just draws the cached copy to the screen.
|
|
||||||
* @param color tint of the curve
|
|
||||||
* @param borderColor the curve border color
|
|
||||||
* @param t the point up to which the curve should be drawn (in the interval [0, 1])
|
|
||||||
*/
|
|
||||||
public void draw(Color color, Color borderColor, float t) {
|
|
||||||
t = Utils.clamp(t, 0.0f, 1.0f);
|
|
||||||
float alpha = color.a;
|
|
||||||
|
|
||||||
// if this curve hasn't been drawn, draw it and cache the result
|
|
||||||
if (fbo == null) {
|
|
||||||
FrameBufferCache cache = FrameBufferCache.getInstance();
|
FrameBufferCache cache = FrameBufferCache.getInstance();
|
||||||
Rendertarget mapping = cache.get(hitObject);
|
Rendertarget mapping = cache.get(hitObject);
|
||||||
if (mapping == null)
|
if (mapping == null)
|
||||||
|
@ -126,14 +113,33 @@ public class CurveRenderState {
|
||||||
createVertexBuffer(fbo.getVbo());
|
createVertexBuffer(fbo.getVbo());
|
||||||
//write impossible value to make sure the fbo is cleared
|
//write impossible value to make sure the fbo is cleared
|
||||||
lastPointDrawn = -1;
|
lastPointDrawn = -1;
|
||||||
|
spliceFrom = spliceTo = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int drawUpTo = (int) (t * curve.length);
|
public void splice(int from, int to) {
|
||||||
|
spliceFrom = from * 2;
|
||||||
|
spliceTo = to * 2;
|
||||||
|
firstPointDrawn = -1; // force redraw
|
||||||
|
lastPointDrawn = -1; // force redraw
|
||||||
|
}
|
||||||
|
|
||||||
if (lastPointDrawn != drawUpTo) {
|
/**
|
||||||
if (drawUpTo == lastPointDrawn)
|
* Draw a curve to the screen that's tinted with `color`. The first time
|
||||||
return;
|
* this is called this caches the image result of the curve and on subsequent
|
||||||
|
* runs it just draws the cached copy to the screen.
|
||||||
|
* @param color tint of the curve
|
||||||
|
* @param borderColor the curve border color
|
||||||
|
* @param t2 the point up to which the curve should be drawn (in the interval [0, 1])
|
||||||
|
*/
|
||||||
|
public void draw(Color color, Color borderColor, float t1, float t2) {
|
||||||
|
t1 = Utils.clamp(t1, 0.0f, 1.0f);
|
||||||
|
t2 = Utils.clamp(t2, 0.0f, 1.0f);
|
||||||
|
float alpha = color.a;
|
||||||
|
|
||||||
|
int drawFrom = (int) (t1 * curve.length);
|
||||||
|
int drawUpTo = (int) (t2 * curve.length);
|
||||||
|
|
||||||
|
if (lastPointDrawn != drawUpTo || firstPointDrawn != drawFrom) {
|
||||||
int oldFb = GL11.glGetInteger(EXTFramebufferObject.GL_FRAMEBUFFER_BINDING_EXT);
|
int oldFb = GL11.glGetInteger(EXTFramebufferObject.GL_FRAMEBUFFER_BINDING_EXT);
|
||||||
int oldTex = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
int oldTex = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||||
//glGetInteger requires a buffer of size 16, even though just 4
|
//glGetInteger requires a buffer of size 16, even though just 4
|
||||||
|
@ -147,8 +153,14 @@ public class CurveRenderState {
|
||||||
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
if (firstPointDrawn != drawFrom) {
|
||||||
this.renderCurve(color, borderColor, lastPointDrawn, drawUpTo);
|
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||||
|
firstPointDrawn = drawFrom;
|
||||||
|
this.renderCurve(color, borderColor, drawFrom, drawUpTo, true);
|
||||||
|
} else {
|
||||||
|
this.renderCurve(color, borderColor, lastPointDrawn, drawUpTo, false);
|
||||||
|
}
|
||||||
lastPointDrawn = drawUpTo;
|
lastPointDrawn = drawUpTo;
|
||||||
color.a = 1f;
|
color.a = 1f;
|
||||||
|
|
||||||
|
@ -270,19 +282,27 @@ public class CurveRenderState {
|
||||||
private void createVertexBuffer(int bufferID) {
|
private void createVertexBuffer(int bufferID) {
|
||||||
int arrayBufferBinding = GL11.glGetInteger(GL15.GL_ARRAY_BUFFER_BINDING);
|
int arrayBufferBinding = GL11.glGetInteger(GL15.GL_ARRAY_BUFFER_BINDING);
|
||||||
FloatBuffer buff = BufferUtils.createByteBuffer(4 * (4 + 2) * (2 * curve.length - 1) * (NewCurveStyleState.DIVIDES + 2)).asFloatBuffer();
|
FloatBuffer buff = BufferUtils.createByteBuffer(4 * (4 + 2) * (2 * curve.length - 1) * (NewCurveStyleState.DIVIDES + 2)).asFloatBuffer();
|
||||||
for (int i = 0; i < curve.length; ++i) {
|
if (curve.length > 0) {
|
||||||
|
fillCone(buff, curve[0].x, curve[0].y);
|
||||||
|
}
|
||||||
|
for (int i = 1; i < curve.length; ++i) {
|
||||||
float x = curve[i].x;
|
float x = curve[i].x;
|
||||||
float y = curve[i].y;
|
float y = curve[i].y;
|
||||||
fillCone(buff, x, y);
|
fillCone(buff, x, y);
|
||||||
if (i != 0) {
|
|
||||||
float last_x = curve[i - 1].x;
|
float last_x = curve[i - 1].x;
|
||||||
float last_y = curve[i - 1].y;
|
float last_y = curve[i - 1].y;
|
||||||
double diff_x = x - last_x;
|
double diff_x = x - last_x;
|
||||||
double diff_y = y - last_y;
|
double diff_y = y - last_y;
|
||||||
|
float dist = Utils.distance(x, y, last_x, last_y);
|
||||||
|
if (dist < Circle.diameter / 8) {
|
||||||
x = (float) (x - diff_x / 2);
|
x = (float) (x - diff_x / 2);
|
||||||
y = (float) (y - diff_y / 2);
|
y = (float) (y - diff_y / 2);
|
||||||
fillCone(buff, x, y);
|
} else {
|
||||||
|
// don't mind me
|
||||||
|
x = -100f;
|
||||||
|
y = -100f;
|
||||||
}
|
}
|
||||||
|
fillCone(buff, x, y);
|
||||||
}
|
}
|
||||||
buff.flip();
|
buff.flip();
|
||||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferID);
|
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferID);
|
||||||
|
@ -295,7 +315,7 @@ public class CurveRenderState {
|
||||||
* @param color the color of the curve
|
* @param color the color of the curve
|
||||||
* @param borderColor the curve border color
|
* @param borderColor the curve border color
|
||||||
*/
|
*/
|
||||||
private void renderCurve(Color color, Color borderColor, int from, int to) {
|
private void renderCurve(Color color, Color borderColor, int from, int to, boolean clearFirst) {
|
||||||
staticState.initGradient();
|
staticState.initGradient();
|
||||||
RenderState state = saveRenderState();
|
RenderState state = saveRenderState();
|
||||||
staticState.initShaderProgram();
|
staticState.initShaderProgram();
|
||||||
|
@ -310,8 +330,15 @@ public class CurveRenderState {
|
||||||
//2*4 is for skipping the first 2 floats (u,v)
|
//2*4 is for skipping the first 2 floats (u,v)
|
||||||
GL20.glVertexAttribPointer(staticState.attribLoc, 4, GL11.GL_FLOAT, false, 6 * 4, 2 * 4);
|
GL20.glVertexAttribPointer(staticState.attribLoc, 4, GL11.GL_FLOAT, false, 6 * 4, 2 * 4);
|
||||||
GL20.glVertexAttribPointer(staticState.texCoordLoc, 2, GL11.GL_FLOAT, false, 6 * 4, 0);
|
GL20.glVertexAttribPointer(staticState.texCoordLoc, 2, GL11.GL_FLOAT, false, 6 * 4, 0);
|
||||||
for (int i = from * 2; i < to * 2 - 1; ++i)
|
if (clearFirst) {
|
||||||
|
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
for (int i = from * 2; i < to * 2 - 1; ++i) {
|
||||||
|
if (spliceFrom <= i && i <= spliceTo) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
GL11.glDrawArrays(GL11.GL_TRIANGLE_FAN, i * (NewCurveStyleState.DIVIDES + 2), NewCurveStyleState.DIVIDES + 2);
|
GL11.glDrawArrays(GL11.GL_TRIANGLE_FAN, i * (NewCurveStyleState.DIVIDES + 2), NewCurveStyleState.DIVIDES + 2);
|
||||||
|
}
|
||||||
GL11.glFlush();
|
GL11.glFlush();
|
||||||
GL20.glDisableVertexAttribArray(staticState.texCoordLoc);
|
GL20.glDisableVertexAttribArray(staticState.texCoordLoc);
|
||||||
GL20.glDisableVertexAttribArray(staticState.attribLoc);
|
GL20.glDisableVertexAttribArray(staticState.attribLoc);
|
||||||
|
|
|
@ -52,9 +52,7 @@ import itdelatrisu.opsu.ui.*;
|
||||||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.*;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
import org.lwjgl.input.Keyboard;
|
import org.lwjgl.input.Keyboard;
|
||||||
import org.lwjgl.opengl.Display;
|
import org.lwjgl.opengl.Display;
|
||||||
|
@ -72,6 +70,7 @@ import org.newdawn.slick.state.transition.EasedFadeOutTransition;
|
||||||
import org.newdawn.slick.state.transition.EmptyTransition;
|
import org.newdawn.slick.state.transition.EmptyTransition;
|
||||||
import org.newdawn.slick.state.transition.FadeInTransition;
|
import org.newdawn.slick.state.transition.FadeInTransition;
|
||||||
import yugecin.opsudance.*;
|
import yugecin.opsudance.*;
|
||||||
|
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
|
||||||
import yugecin.opsudance.ui.SBOverlay;
|
import yugecin.opsudance.ui.SBOverlay;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -281,6 +280,8 @@ public class Game extends BasicGameState {
|
||||||
private final Cursor mirrorCursor;
|
private final Cursor mirrorCursor;
|
||||||
private final SBOverlay sbOverlay;
|
private final SBOverlay sbOverlay;
|
||||||
|
|
||||||
|
private FakeCombinedCurve knorkesliders;
|
||||||
|
|
||||||
public Game(int state) {
|
public Game(int state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
mirrorCursor = new Cursor(true);
|
mirrorCursor = new Cursor(true);
|
||||||
|
@ -1453,8 +1454,22 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
this.leadInTime += epiImgTime;
|
this.leadInTime += epiImgTime;
|
||||||
SoundController.mute(false);
|
SoundController.mute(false);
|
||||||
|
|
||||||
|
if (Options.isMergingSliders()) {
|
||||||
|
// let's create knorkesliders
|
||||||
|
List<Vec2f> curvepoints = new ArrayList<>();
|
||||||
|
for (GameObject gameObject : gameObjects) {
|
||||||
|
if (gameObject.isSlider()) {
|
||||||
|
((Slider) gameObject).baseSliderFrom = curvepoints.size();
|
||||||
|
curvepoints.addAll(Arrays.asList(((Slider) gameObject).getCurve().getCurvePoints()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
knorkesliders = new FakeCombinedCurve(curvepoints.toArray(new Vec2f[curvepoints.size()]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slidercurveFrom = 0;
|
||||||
|
slidercurveTo = 0;
|
||||||
|
|
||||||
Dancer.instance.setGameObjects(gameObjects);
|
Dancer.instance.setGameObjects(gameObjects);
|
||||||
sbOverlay.setGameObjects(gameObjects);
|
sbOverlay.setGameObjects(gameObjects);
|
||||||
|
@ -1495,12 +1510,32 @@ public class Game extends BasicGameState {
|
||||||
GameMod.loadModState(previousMods);
|
GameMod.loadModState(previousMods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float slidercurveFrom;
|
||||||
|
private float slidercurveTo;
|
||||||
|
|
||||||
|
public void setSlidercurveFrom(int slidercurveFrom) {
|
||||||
|
float pos = (float) slidercurveFrom / knorkesliders.getCurvePoints().length;
|
||||||
|
this.slidercurveFrom = Math.max(pos, this.slidercurveFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlidercurveTo(int slidercurveTo) {
|
||||||
|
float pos = (float) slidercurveTo / knorkesliders.getCurvePoints().length;
|
||||||
|
this.slidercurveTo = Math.max(pos, this.slidercurveTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spliceSliderCurve(int from, int to) {
|
||||||
|
this.knorkesliders.splice(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws hit objects, hit results, and follow points.
|
* Draws hit objects, hit results, and follow points.
|
||||||
* @param g the graphics context
|
* @param g the graphics context
|
||||||
* @param trackPosition the track position
|
* @param trackPosition the track position
|
||||||
*/
|
*/
|
||||||
private void drawHitObjects(Graphics g, int trackPosition) {
|
private void drawHitObjects(Graphics g, int trackPosition) {
|
||||||
|
if (Options.isMergingSliders()) {
|
||||||
|
knorkesliders.draw(Color.white, this.slidercurveFrom, this.slidercurveTo);
|
||||||
|
}
|
||||||
// include previous object in follow points
|
// include previous object in follow points
|
||||||
int lastObjectIndex = -1;
|
int lastObjectIndex = -1;
|
||||||
if (objectIndex > 0 && objectIndex < beatmap.objects.length &&
|
if (objectIndex > 0 && objectIndex < beatmap.objects.length &&
|
||||||
|
|
|
@ -82,7 +82,9 @@ public class OptionsMenu extends BasicGameState {
|
||||||
GameOption.FORCE_DEFAULT_PLAYFIELD,
|
GameOption.FORCE_DEFAULT_PLAYFIELD,
|
||||||
GameOption.IGNORE_BEATMAP_SKINS,
|
GameOption.IGNORE_BEATMAP_SKINS,
|
||||||
GameOption.SNAKING_SLIDERS,
|
GameOption.SNAKING_SLIDERS,
|
||||||
|
GameOption.SHRINKING_SLIDERS,
|
||||||
GameOption.FALLBACK_SLIDERS,
|
GameOption.FALLBACK_SLIDERS,
|
||||||
|
GameOption.MERGING_SLIDERS,
|
||||||
GameOption.SHOW_HIT_LIGHTING,
|
GameOption.SHOW_HIT_LIGHTING,
|
||||||
GameOption.SHOW_COMBO_BURSTS,
|
GameOption.SHOW_COMBO_BURSTS,
|
||||||
GameOption.SHOW_PERFECT_HIT,
|
GameOption.SHOW_PERFECT_HIT,
|
||||||
|
|
46
src/yugecin/opsudance/objects/curves/FakeCombinedCurve.java
Normal file
46
src/yugecin/opsudance/objects/curves/FakeCombinedCurve.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.objects.curves;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
|
import itdelatrisu.opsu.objects.curves.Curve;
|
||||||
|
import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||||
|
|
||||||
|
public class FakeCombinedCurve extends Curve {
|
||||||
|
|
||||||
|
public FakeCombinedCurve(Vec2f[] points) {
|
||||||
|
super(new HitObject(0, 0, 0), false);
|
||||||
|
this.curve = points;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vec2f pointAt(float t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getEndAngle() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getStartAngle() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user