Skip to content

Commit

Permalink
Merge pull request #263 from yugecin/experimentalsliders
Browse files Browse the repository at this point in the history
add slider style from yugecin/opsu-dance
  • Loading branch information
itdelatrisu committed Mar 9, 2017
2 parents 5e45f04 + ff3a22e commit 959f46c
Show file tree
Hide file tree
Showing 14 changed files with 862 additions and 19 deletions.
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
15 changes: 15 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
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();
}
}
68 changes: 68 additions & 0 deletions src/itdelatrisu/opsu/objects/curves/FakeCombinedCurve.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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.beatmap.HitObject;
import itdelatrisu.opsu.render.LegacyCurveRenderState;
import org.newdawn.slick.Color;

import java.util.ArrayList;
import java.util.List;

public class FakeCombinedCurve extends Curve {

private List<Integer> pointsToRender;

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

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

public void addRange(int from, int to) {
pointsToRender.add(from);
pointsToRender.add(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;
}

}
6 changes: 6 additions & 0 deletions src/itdelatrisu/opsu/options/OptionGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ public class OptionGroup {
GameOption.SHOW_FOLLOW_POINTS,
GameOption.SCREENSHOT_FORMAT,
}),
new OptionGroup("EXPERIMENTAL SLIDERS", new GameOption[] {
GameOption.EXPERIMENTAL_SLIDERS,
GameOption.EXPERIMENTAL_SLIDERS_MERGE,
GameOption.EXPERIMENTAL_SLIDERS_SHRINK,
GameOption.EXPERIMENTAL_SLIDERS_DRAW_ENDCIRCLES,
}),
new OptionGroup("MAIN MENU", new GameOption[] {
GameOption.DYNAMIC_BACKGROUND,
GameOption.PARALLAX,
Expand Down
Loading

0 comments on commit 959f46c

Please sign in to comment.