Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add slider style from yugecin/opsu-dance #263

Merged
merged 7 commits into from
Mar 9, 2017
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added res/slidergradient_ex.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/itdelatrisu/opsu/Container.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.options.Options;
import itdelatrisu.opsu.render.CurveRenderState;
import itdelatrisu.opsu.render.LegacyCurveRenderState;
import itdelatrisu.opsu.ui.UI;

import org.lwjgl.opengl.Display;
Expand Down Expand Up @@ -179,6 +180,7 @@ private void close_sub() {

// delete OpenGL objects involved in the Curve rendering
CurveRenderState.shutdown();
LegacyCurveRenderState.shutdown();

// destroy watch service
if (!Options.isWatchServiceEnabled())
Expand Down
12 changes: 10 additions & 2 deletions src/itdelatrisu/opsu/GameData.java
Original file line number Diff line number Diff line change
Expand Up @@ -1088,14 +1088,18 @@ else if (Options.isHitLightingEnabled() && !hitResult.hideResult && hitResult.re
*/
private void drawHitAnimations(HitObjectResult hitResult, int trackPosition) {
// fade out slider curve
if (hitResult.result != HIT_SLIDER_REPEAT && hitResult.curve != null) {
if (hitResult.result != HIT_SLIDER_REPEAT && hitResult.curve != null && !(Options.isExperimentalSliderStyle() && Options.isShrinkingSliders())) {
float progress = AnimationEquation.OUT_CUBIC.calc(
(float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME);
float alpha = 1f - progress;
float oldWhiteAlpha = Colors.WHITE_FADE.a;
float oldColorAlpha = hitResult.color.a;
Colors.WHITE_FADE.a = hitResult.color.a = alpha;
hitResult.curve.draw(hitResult.color);
if (Options.isExperimentalSliderStyle()) {
hitResult.curve.draw(hitResult.color, Options.isMergingSliders() ? 1 : 0, hitResult.curve.getCurvePoints().length);
} else {
hitResult.curve.draw(hitResult.color);
}
Colors.WHITE_FADE.a = oldWhiteAlpha;
hitResult.color.a = oldColorAlpha;
}
Expand Down Expand Up @@ -1125,6 +1129,10 @@ private void drawHitAnimations(HitObjectResult hitResult, int trackPosition) {
fc.drawCentered(hitResult.x, hitResult.y);
}

if (hitResult.result != HIT_SLIDER_REPEAT && hitResult.curve != null && !Options.isDrawSliderEndCircles()) {
return;
}

// hit circles
float progress = AnimationEquation.OUT_CUBIC.calc(
(float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME);
Expand Down
1 change: 1 addition & 0 deletions src/itdelatrisu/opsu/GameImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ protected Image process_sub(Image img, int w, int h) {

// Slider
SLIDER_GRADIENT ("slidergradient", "png"),
SLIDER_GRADIENT_EX ("slidergradient_ex", "png"),
SLIDER_BALL ("sliderb", "sliderb%d", "png"),
SLIDER_FOLLOWCIRCLE ("sliderfollowcircle", "png"),
REVERSEARROW ("reversearrow", "png"),
Expand Down
25 changes: 25 additions & 0 deletions src/itdelatrisu/opsu/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,21 @@ public static float clamp(float val, float low, float high) {
return val;
}

/**
* Clamps a value between a lower and upper bound.
* @param val the value to clamp
* @param low the lower bound
* @param high the upper bound
* @return the clamped value
*/
public static double clamp(double val, double low, double high) {
if (val < low)
return low;
if (val > high)
return high;
return val;
}

/**
* Returns the distance between two points.
* @param x1 the x-component of the first point
Expand Down Expand Up @@ -741,4 +756,14 @@ public static long getUsedMemory() {
Runtime r = Runtime.getRuntime();
return r.totalMemory() - r.freeMemory();
}

public static class Pair<F, S> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh... not a fan of this abstraction. It's barely more clear than just adding 2 elements in a row to your lists since this still doesn't tell you what they are, plus it's extra overhead.

public F first;
public S second;
public Pair(F first, S second) {
this.first = first;
this.second = second;
}
}

}
13 changes: 13 additions & 0 deletions src/itdelatrisu/opsu/beatmap/HitObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,19 @@ else if ((type & HitObject.TYPE_SLIDER) > 0) {
}
}

/**
* Constructor to make fake/temp hitobj
* @param x xpos
* @param y ypos
* @param time time
*/
public HitObject( float x, float y, int time) {
this.x = x;
this.y = y;
this.time = time;
this.type = HitObject.TYPE_CIRCLE;
}

/**
* Returns the raw starting x coordinate.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/itdelatrisu/opsu/objects/Circle.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
*/
public class Circle implements GameObject {
/** The diameter of hit circles. */
private static float diameter;
public static float diameter;

/** The associated HitObject. */
private HitObject hitObject;
Expand Down
70 changes: 62 additions & 8 deletions src/itdelatrisu/opsu/objects/Slider.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ public class Slider implements GameObject {
/** Container dimensions. */
private static int containerWidth, containerHeight;

/** Curve color for experimental style sliders. */
private static Color curveColor = new Color(0, 0, 0, 20);

/** Start index of this slider in the merged slider. */
public int baseSliderFrom;

/**
* Initializes the Slider data type with images and dimensions.
* @param container the game container
Expand Down Expand Up @@ -212,11 +218,18 @@ public void draw(Graphics g, int trackPosition) {
Math.max(0f, 1f - ((float) (trackPosition - hitObject.getTime()) / (getEndTime() - hitObject.getTime())) * 1.05f);
}

float curveInterval = Options.isSliderSnaking() ? alpha : 1f;
curve.draw(color,curveInterval);
boolean isCurveCompletelyDrawn;
if (!Options.isExperimentalSliderStyle()) {
isCurveCompletelyDrawn = Options.isSliderSnaking() || alpha == 1f;
curve.draw(color, isCurveCompletelyDrawn ? 1f : alpha);
} else {
curveColor.a = sliderAlpha;
isCurveCompletelyDrawn = drawSliderTrack(trackPosition, Utils.clamp(1d - (double) (timeDiff - approachTime + fadeInTime) / fadeInTime, 0d, 1d));
color.a = alpha;
}

// end circle (only draw if ball still has to go there)
if (curveInterval == 1f && currentRepeats < repeatCount - (repeatCount % 2 == 0 ? 1 : 0)) {
if (isCurveCompletelyDrawn && (!Options.isExperimentalSliderStyle() || Options.isDrawSliderEndCircles()) && currentRepeats < repeatCount - (repeatCount % 2 == 0 ? 1 : 0)) {
Color circleColor = new Color(color);
Color overlayColor = new Color(Colors.WHITE_FADE);
if (currentRepeats == 0) {
Expand All @@ -228,7 +241,7 @@ public void draw(Graphics g, int trackPosition) {
// fade in end circle after repeats
circleColor.a = overlayColor.a = sliderAlpha * getCircleAlphaAfterRepeat(trackPosition, true);
}
Vec2f endCircPos = curve.pointAt(curveInterval);
Vec2f endCircPos = curve.pointAt(1f);
hitCircle.drawCentered(endCircPos.x, endCircPos.y, circleColor);
hitCircleOverlay.drawCentered(endCircPos.x, endCircPos.y, overlayColor);
}
Expand Down Expand Up @@ -277,13 +290,15 @@ public void draw(Graphics g, int trackPosition) {
}

// repeats
if (curveInterval == 1.0f) {
if (isCurveCompletelyDrawn) {
for (int tcurRepeat = currentRepeats; tcurRepeat <= currentRepeats + 1 && tcurRepeat < repeatCount - 1; tcurRepeat++) {
Image arrow = GameImage.REVERSEARROW.getImage();
// bouncing animation
//arrow = arrow.getScaledCopy((float) (1 + 0.2d * ((trackPosition + sliderTime * tcurRepeat) % 292) / 292));
float colorLuminance = Utils.getLuminance(color);
Color arrowColor = colorLuminance < 0.8f ? Color.white : Color.black;
Color arrowColor = Color.white;
if (!Options.isExperimentalSliderStyle() && Utils.getLuminance(color) >= 0.8f) {
arrowColor = Color.black;
}
if (tcurRepeat == 0) {
arrow.setAlpha(Options.isSliderSnaking() ? decorationsAlpha : 1f);
} else {
Expand Down Expand Up @@ -406,6 +421,42 @@ private void drawSliderTicks(int trackPosition, float curveAlpha, float decorati
}
}

/**
* Draws the slider track for the experimental style sliders.
* @param trackPosition position of the song
* @param snakingSliderProgress progress of the snaking sliders [0, 1]
* @return true if the track was completely drawn
*/
private boolean drawSliderTrack(int trackPosition, double snakingSliderProgress) {
double curveIntervalTo = Options.isSliderSnaking() ? snakingSliderProgress : 1d;
double curveIntervalFrom = 0d;
if (Options.isShrinkingSliders()) {
double sliderprogress = (trackPosition - hitObject.getTime() - ((double) sliderTime * (hitObject.getRepeatCount() - 1))) / (double) sliderTime;
if (sliderprogress > 0) {
curveIntervalFrom = sliderprogress;
}
}
int curvelen = curve.getCurvePoints().length;
if (Options.isMergingSliders()) {
if (Options.isShrinkingSliders() && curveIntervalFrom > 0) {
if (hitObject.getRepeatCount() % 2 == 0) {
game.addMergedSliderPointsToRender(baseSliderFrom, baseSliderFrom + (int) ((1d - curveIntervalFrom) * curvelen));
} else {
game.addMergedSliderPointsToRender(baseSliderFrom + (int) (curveIntervalFrom * curvelen) + 1, baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length));
}
} else {
game.addMergedSliderPointsToRender(baseSliderFrom, baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length));
}
} else {
if (Options.isShrinkingSliders() && curveIntervalFrom > 0 && hitObject.getRepeatCount() % 2 == 0) {
curve.splice((int) ((1d - curveIntervalFrom) * curvelen), curvelen);
curveIntervalFrom = 0d;
}
curve.draw(curveColor, (int) (curveIntervalFrom * curvelen), (int) (curveIntervalTo * curvelen));
}
return curveIntervalTo == 1d;
}

/**
* Get the alpha level used to fade in circles & reversearrows after repeat
* @param trackPosition current trackposition, in ms
Expand Down Expand Up @@ -707,7 +758,6 @@ else if (GameMod.RELAX.isActive() && trackPosition >= time)

// calculate and send slider result
hitResult();

return true;
}

Expand Down Expand Up @@ -753,6 +803,10 @@ private float getT(int trackPosition, boolean raw) {
}
}

public Curve getCurve() {
return curve;
}

@Override
public void reset() {
sliderClickedInitial = false;
Expand Down
40 changes: 37 additions & 3 deletions src/itdelatrisu/opsu/objects/curves/Curve.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.options.Options;
import itdelatrisu.opsu.render.CurveRenderState;
import itdelatrisu.opsu.render.LegacyCurveRenderState;
import itdelatrisu.opsu.skins.Skin;
import itdelatrisu.opsu.ui.Colors;

Expand All @@ -42,7 +43,7 @@ public abstract class Curve {
protected static float CURVE_POINTS_SEPERATION = 5;

/** The curve border color. */
private static Color borderColor;
protected static Color borderColor;

/** Whether mmsliders are supported. */
private static boolean mmsliderSupported = false;
Expand All @@ -59,9 +60,20 @@ public abstract class Curve {
/** Per-curve render-state used for the new style curve renders. */
private CurveRenderState renderState;

/** Per-curve render-state used for the legacy style curve renders. */
protected LegacyCurveRenderState legacyRenderState;

/** Points along the curve (set by inherited classes). */
protected Vec2f[] curve;

/**
* Get the curve points
* @return curve points
*/
public Vec2f[] getCurvePoints() {
return curve;
}

/**
* Constructor.
* @param hitObject the associated HitObject
Expand Down Expand Up @@ -96,9 +108,10 @@ public static void init(int width, int height, float circleDiameter, Color borde

ContextCapabilities capabilities = GLContext.getCapabilities();
mmsliderSupported = capabilities.OpenGL30;
if (mmsliderSupported)
if (mmsliderSupported) {
CurveRenderState.init(width, height, circleDiameter);
else {
LegacyCurveRenderState.init(width, height, circleDiameter);
} else {
if (Options.getSkin().getSliderStyle() != Skin.STYLE_PEPPYSLIDER)
Log.warn("New slider style requires OpenGL 3.0.");
}
Expand Down Expand Up @@ -147,6 +160,25 @@ public void draw(Color color, float t) {
}
}

public void draw(Color color, int from, int to) {
if (curve == null)
return;
if (legacyRenderState == null)
legacyRenderState = new LegacyCurveRenderState(hitObject, curve);
legacyRenderState.draw(color, borderColor, from, to);
}

/**
* Splice the curve to draw (= flag a part of it as 'do not draw'). Bases on the curve point indices.
* @param from start index to splice
* @param to end index to splice
*/
public void splice(int from, int to) {
if (legacyRenderState == null)
return;
legacyRenderState.splice(from, to);
}

/**
* Returns the angle of the first control point.
*/
Expand Down Expand Up @@ -175,5 +207,7 @@ public void draw(Color color, float t) {
public void discardGeometry() {
if (renderState != null)
renderState.discardGeometry();
if (legacyRenderState != null)
legacyRenderState.discardGeometry();
}
}
67 changes: 67 additions & 0 deletions src/itdelatrisu/opsu/objects/curves/FakeCombinedCurve.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* opsu! - an open-source osu! client
* Copyright (C) 2014-2017 Jeffrey Han
*
* opsu! 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! 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!. If not, see <http://www.gnu.org/licenses/>.
*/
package itdelatrisu.opsu.objects.curves;

import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.render.LegacyCurveRenderState;
import org.newdawn.slick.Color;

import java.util.LinkedList;

public class FakeCombinedCurve extends Curve {

private LinkedList<Utils.Pair<Integer, Integer>> pointsToRender;

public FakeCombinedCurve(Vec2f[] points) {
super(new HitObject(0, 0, 0), false);
this.curve = points;
pointsToRender = new LinkedList<>();
}

public void initForFrame() {
pointsToRender.clear();
}

public void addRange(int from, int to) {
pointsToRender.add(new Utils.Pair<>(from, to));
}

@Override
public void draw(Color color) {
if (legacyRenderState == null)
legacyRenderState = new LegacyCurveRenderState(hitObject, curve);
legacyRenderState.draw(color, borderColor, pointsToRender);
}

@Override
public Vec2f pointAt(float t) {
return null;
}

@Override
public float getEndAngle() {
return 0;
}

@Override
public float getStartAngle() {
return 0;
}

}
Loading