Snaking sliders initial implementation.
Draws curves in a range from 0 to x (where x is a value between 0 and 1) while blending them in (if enabled in the options) Cache a unit-cone once and re-use that with scaling and translation instead of generating it each time again. This is more for readability than performance (since presumably feeding it mostly constants like before would be faster) Only draws the cones in the curve once if possible (only possible if consective calls to draw with the intervals x_1 before x_2 are made and [0, x_1] [0, x_2] with x_1 < x_2 holds true) minor refactoring and cleanup Omg my code is such a mess. I feel like I've committed a crime against humanity by just randomly putting that random vbo id into the class called "Rendertarget". But there's really no good place for it now (that has a way to clean it up). But if "Rendertarget" will ever be used by anything else but the sliders I'm gonna pull that out. added blending in for return arrows and ticks
This commit is contained in:
parent
e0da6a2444
commit
131138ea8c
|
@ -907,7 +907,7 @@ 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;
|
||||||
hitResult.curve.draw(hitResult.color);
|
hitResult.curve.draw(hitResult.color,1.0f);
|
||||||
Colors.WHITE_FADE.a = oldWhiteAlpha;
|
Colors.WHITE_FADE.a = oldWhiteAlpha;
|
||||||
hitResult.color.a = oldColorAlpha;
|
hitResult.color.a = oldColorAlpha;
|
||||||
}
|
}
|
||||||
|
|
|
@ -417,6 +417,7 @@ public class Options {
|
||||||
BACKGROUND_DIM ("Background Dim", "DimLevel", "Percentage to dim the background image during gameplay.", 50, 0, 100),
|
BACKGROUND_DIM ("Background Dim", "DimLevel", "Percentage to dim the background image during gameplay.", 50, 0, 100),
|
||||||
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),
|
||||||
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),
|
||||||
|
@ -941,6 +942,12 @@ public class Options {
|
||||||
*/
|
*/
|
||||||
public static boolean isBeatmapSkinIgnored() { return GameOption.IGNORE_BEATMAP_SKINS.getBooleanValue(); }
|
public static boolean isBeatmapSkinIgnored() { return GameOption.IGNORE_BEATMAP_SKINS.getBooleanValue(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not sliders should snake in or just appear fully at once.
|
||||||
|
* @return true if sliders should snake in
|
||||||
|
*/
|
||||||
|
public static boolean isSliderSnaking() { return GameOption.SNAKING_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
|
||||||
|
|
|
@ -30,6 +30,7 @@ import itdelatrisu.opsu.objects.curves.Curve;
|
||||||
import itdelatrisu.opsu.objects.curves.Vec2f;
|
import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||||
import itdelatrisu.opsu.states.Game;
|
import itdelatrisu.opsu.states.Game;
|
||||||
import itdelatrisu.opsu.ui.Colors;
|
import itdelatrisu.opsu.ui.Colors;
|
||||||
|
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||||
|
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.GameContainer;
|
import org.newdawn.slick.GameContainer;
|
||||||
|
@ -179,20 +180,27 @@ public class Slider implements GameObject {
|
||||||
float approachScale = 1 + scale * 3;
|
float approachScale = 1 + scale * 3;
|
||||||
float fadeinScale = (timeDiff - approachTime + fadeInTime) / (float) fadeInTime;
|
float fadeinScale = (timeDiff - approachTime + fadeInTime) / (float) fadeInTime;
|
||||||
float alpha = Utils.clamp(1 - fadeinScale, 0, 1);
|
float alpha = Utils.clamp(1 - fadeinScale, 0, 1);
|
||||||
|
float decorationsAlpha = Utils.clamp(-2.0f * fadeinScale, 0, 1);
|
||||||
boolean overlayAboveNumber = Options.getSkin().isHitCircleOverlayAboveNumber();
|
boolean overlayAboveNumber = Options.getSkin().isHitCircleOverlayAboveNumber();
|
||||||
|
|
||||||
float oldAlpha = Colors.WHITE_FADE.a;
|
float oldAlpha = Colors.WHITE_FADE.a;
|
||||||
Colors.WHITE_FADE.a = color.a = alpha;
|
Colors.WHITE_FADE.a = color.a = alpha;
|
||||||
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
||||||
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
||||||
Vec2f endPos = curve.pointAt(1);
|
Vec2f endPos = curve.pointAt(1);
|
||||||
|
|
||||||
curve.draw(color);
|
float curveInterval;
|
||||||
|
if(Options.isSliderSnaking()){
|
||||||
|
curveInterval = alpha;
|
||||||
|
} else {
|
||||||
|
curveInterval = 1.0f;
|
||||||
|
}
|
||||||
|
curve.draw(color,curveInterval);
|
||||||
color.a = alpha;
|
color.a = alpha;
|
||||||
|
|
||||||
// end circle
|
// end circle
|
||||||
hitCircle.drawCentered(endPos.x, endPos.y, color);
|
Vec2f endCircPos = curve.pointAt(curveInterval);
|
||||||
hitCircleOverlay.drawCentered(endPos.x, endPos.y, Colors.WHITE_FADE);
|
hitCircle.drawCentered(endCircPos.x, endCircPos.y, color);
|
||||||
|
hitCircleOverlay.drawCentered(endCircPos.x, endCircPos.y, Colors.WHITE_FADE);
|
||||||
|
|
||||||
// start circle
|
// start circle
|
||||||
hitCircle.drawCentered(x, y, color);
|
hitCircle.drawCentered(x, y, color);
|
||||||
|
@ -201,10 +209,13 @@ public class Slider implements GameObject {
|
||||||
|
|
||||||
// ticks
|
// ticks
|
||||||
if (ticksT != null) {
|
if (ticksT != null) {
|
||||||
Image tick = GameImage.SLIDER_TICK.getImage();
|
float tickScale = 0.5f + 0.5f*AnimationEquation.OUT_BACK.calc(decorationsAlpha);
|
||||||
|
Image tick = GameImage.SLIDER_TICK.getImage().getScaledCopy(tickScale);
|
||||||
for (int i = 0; i < ticksT.length; i++) {
|
for (int i = 0; i < ticksT.length; i++) {
|
||||||
Vec2f c = curve.pointAt(ticksT[i]);
|
Vec2f c = curve.pointAt(ticksT[i]);
|
||||||
|
Colors.WHITE_FADE.a = decorationsAlpha;
|
||||||
tick.drawCentered(c.x , c.y , Colors.WHITE_FADE);
|
tick.drawCentered(c.x , c.y , Colors.WHITE_FADE);
|
||||||
|
Colors.WHITE_FADE.a = alpha;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (GameMod.HIDDEN.isActive()) {
|
if (GameMod.HIDDEN.isActive()) {
|
||||||
|
@ -224,16 +235,23 @@ public class Slider implements GameObject {
|
||||||
hitCircleOverlay.drawCentered(x, y, Colors.WHITE_FADE);
|
hitCircleOverlay.drawCentered(x, y, Colors.WHITE_FADE);
|
||||||
|
|
||||||
// repeats
|
// repeats
|
||||||
|
if (curveInterval == 1.0f) {
|
||||||
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();
|
||||||
if (tcurRepeat != currentRepeats) {
|
if (tcurRepeat != currentRepeats) {
|
||||||
if (sliderTime == 0)
|
if (sliderTime == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
float t = Math.max(getT(trackPosition, true), 0);
|
float t = Math.max(getT(trackPosition, true), 0);
|
||||||
arrow.setAlpha((float) (t - Math.floor(t)));
|
arrow.setAlpha((float) (t - Math.floor(t)));
|
||||||
} else
|
} else {
|
||||||
|
if(Options.isSliderSnaking()){
|
||||||
|
arrow.setAlpha(decorationsAlpha);
|
||||||
|
} else {
|
||||||
arrow.setAlpha(1f);
|
arrow.setAlpha(1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (tcurRepeat % 2 == 0) {
|
if (tcurRepeat % 2 == 0) {
|
||||||
// last circle
|
// last circle
|
||||||
arrow.setRotation(curve.getEndAngle());
|
arrow.setRotation(curve.getEndAngle());
|
||||||
|
@ -245,6 +263,7 @@ public class Slider implements GameObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (timeDiff >= 0) {
|
if (timeDiff >= 0) {
|
||||||
// approach circle
|
// approach circle
|
||||||
|
|
|
@ -20,6 +20,7 @@ package itdelatrisu.opsu.objects.curves;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
import itdelatrisu.opsu.Options;
|
||||||
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
import itdelatrisu.opsu.render.CurveRenderState;
|
import itdelatrisu.opsu.render.CurveRenderState;
|
||||||
import itdelatrisu.opsu.skins.Skin;
|
import itdelatrisu.opsu.skins.Skin;
|
||||||
|
@ -111,28 +112,31 @@ public abstract class Curve {
|
||||||
public abstract Vec2f pointAt(float t);
|
public abstract Vec2f pointAt(float t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws the full curve 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]
|
||||||
*/
|
*/
|
||||||
public void draw(Color color) {
|
public void draw(Color color, float t) {
|
||||||
if (curve == null)
|
if (curve == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
t = Utils.clamp(t, 0.0f, 1.0f);
|
||||||
// peppysliders
|
// peppysliders
|
||||||
if (Options.getSkin().getSliderStyle() == Skin.STYLE_PEPPYSLIDER || !mmsliderSupported) {
|
if (Options.getSkin().getSliderStyle() == Skin.STYLE_PEPPYSLIDER || !mmsliderSupported) {
|
||||||
|
int drawUpTo = (int)(curve.length*t);
|
||||||
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 < curve.length; i++)
|
for (int i = 0; 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);
|
||||||
for (int i = 0; i < curve.length; i++)
|
for (int i = 0; i < drawUpTo; i++)
|
||||||
hitCircle.drawCentered(curve[i].x, curve[i].y, color);
|
hitCircle.drawCentered(curve[i].x, curve[i].y, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mmsliders
|
// mmsliders
|
||||||
else {
|
else {
|
||||||
if (renderState == null)
|
if (renderState == null)
|
||||||
renderState = new CurveRenderState(hitObject);
|
renderState = new CurveRenderState(hitObject,curve);
|
||||||
renderState.draw(color, borderColor, curve);
|
renderState.draw(color, borderColor, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
package itdelatrisu.opsu.render;
|
package itdelatrisu.opsu.render;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
import itdelatrisu.opsu.objects.curves.Vec2f;
|
import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||||
import itdelatrisu.opsu.ui.Colors;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
|
@ -59,6 +59,12 @@ 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;
|
||||||
|
|
||||||
|
/** The point to which the curve has last been rendered into the texture (as an index into {@code curve}) */
|
||||||
|
private int lastPointDrawn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
* Should be called before any curves are drawn.
|
* Should be called before any curves are drawn.
|
||||||
|
@ -74,11 +80,12 @@ public class CurveRenderState {
|
||||||
scale = (int) (circleDiameter * HitObject.getXMultiplier()); // convert from Osupixels (640x480)
|
scale = (int) (circleDiameter * HitObject.getXMultiplier()); // convert from Osupixels (640x480)
|
||||||
//scale = scale * 118 / 128; //for curves exactly as big as the sliderball
|
//scale = scale * 118 / 128; //for curves exactly as big as the sliderball
|
||||||
FrameBufferCache.init(width, height);
|
FrameBufferCache.init(width, height);
|
||||||
|
NewCurveStyleState.initUnitCone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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, itdelatrisu.opsu.objects.curves.Vec2f[])}
|
* {@link #draw(org.newdawn.slick.Color, org.newdawn.slick.Color, float)}
|
||||||
* are undone.
|
* are undone.
|
||||||
*/
|
*/
|
||||||
public static void shutdown() {
|
public static void shutdown() {
|
||||||
|
@ -89,10 +96,12 @@ public class CurveRenderState {
|
||||||
/**
|
/**
|
||||||
* Creates an object to hold the render state that's necessary to draw a curve.
|
* Creates an object to hold the render state that's necessary to draw a curve.
|
||||||
* @param hitObject the HitObject that represents this curve, just used as a unique ID
|
* @param hitObject the HitObject that represents this curve, just used as a unique ID
|
||||||
|
* @param curve the points along the curve to be drawn
|
||||||
*/
|
*/
|
||||||
public CurveRenderState(HitObject hitObject) {
|
public CurveRenderState(HitObject hitObject, Vec2f[] curve) {
|
||||||
fbo = null;
|
fbo = null;
|
||||||
this.hitObject = hitObject;
|
this.hitObject = hitObject;
|
||||||
|
this.curve = curve;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,9 +110,10 @@ public class CurveRenderState {
|
||||||
* runs it just draws the cached copy to the screen.
|
* runs it just draws the cached copy to the screen.
|
||||||
* @param color tint of the curve
|
* @param color tint of the curve
|
||||||
* @param borderColor the curve border color
|
* @param borderColor the curve border color
|
||||||
* @param curve the points along the curve to be drawn
|
* @param t the point up to which the curve should be drawn (in the interval [0, 1])
|
||||||
*/
|
*/
|
||||||
public void draw(Color color, Color borderColor, Vec2f[] curve) {
|
public void draw(Color color, Color borderColor, float t) {
|
||||||
|
t = Utils.clamp(t, 0.0f, 1.0f);
|
||||||
float alpha = color.a;
|
float alpha = color.a;
|
||||||
|
|
||||||
// if this curve hasn't been drawn, draw it and cache the result
|
// if this curve hasn't been drawn, draw it and cache the result
|
||||||
|
@ -113,26 +123,40 @@ public class CurveRenderState {
|
||||||
if (mapping == null)
|
if (mapping == null)
|
||||||
mapping = cache.insert(hitObject);
|
mapping = cache.insert(hitObject);
|
||||||
fbo = mapping;
|
fbo = mapping;
|
||||||
|
createVertexBuffer(fbo.getVbo());
|
||||||
|
//write impossible value to make sure the fbo is cleared
|
||||||
|
lastPointDrawn = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int drawUpTo = (int) (t * curve.length);
|
||||||
|
|
||||||
|
if (lastPointDrawn != drawUpTo) {
|
||||||
|
|
||||||
|
if (drawUpTo == lastPointDrawn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
//values are returned in this specific case
|
//values are returned in this specific case
|
||||||
IntBuffer oldViewport = BufferUtils.createIntBuffer(16);
|
IntBuffer oldViewport = BufferUtils.createIntBuffer(16);
|
||||||
GL11.glGetInteger(GL11.GL_VIEWPORT, oldViewport);
|
GL11.glGetInteger(GL11.GL_VIEWPORT, oldViewport);
|
||||||
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fbo.getID());
|
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fbo.getID());
|
||||||
GL11.glViewport(0, 0, fbo.width, fbo.height);
|
GL11.glViewport(0, 0, fbo.width, fbo.height);
|
||||||
|
if (lastPointDrawn <= 0 || lastPointDrawn > drawUpTo) {
|
||||||
|
lastPointDrawn = 0;
|
||||||
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);
|
||||||
Colors.WHITE_FADE.a = 1.0f;
|
}
|
||||||
this.draw_curve(color, borderColor, curve);
|
|
||||||
|
this.renderCurve(color, borderColor, lastPointDrawn, drawUpTo);
|
||||||
|
lastPointDrawn = drawUpTo;
|
||||||
color.a = 1f;
|
color.a = 1f;
|
||||||
|
|
||||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, oldTex);
|
GL11.glBindTexture(GL11.GL_TEXTURE_2D, oldTex);
|
||||||
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, oldFb);
|
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, oldFb);
|
||||||
GL11.glViewport(oldViewport.get(0), oldViewport.get(1), oldViewport.get(2), oldViewport.get(3));
|
GL11.glViewport(oldViewport.get(0), oldViewport.get(1), oldViewport.get(2), oldViewport.get(3));
|
||||||
Colors.WHITE_FADE.a = alpha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw a fullscreen quad with the texture that contains the curve
|
// draw a fullscreen quad with the texture that contains the curve
|
||||||
|
@ -180,7 +204,7 @@ public class CurveRenderState {
|
||||||
* Backup the current state of the relevant OpenGL state and change it to
|
* Backup the current state of the relevant OpenGL state and change it to
|
||||||
* what's needed to draw the curve.
|
* what's needed to draw the curve.
|
||||||
*/
|
*/
|
||||||
private RenderState startRender() {
|
private RenderState saveRenderState() {
|
||||||
RenderState state = new RenderState();
|
RenderState state = new RenderState();
|
||||||
state.smoothedPoly = GL11.glGetBoolean(GL11.GL_POLYGON_SMOOTH);
|
state.smoothedPoly = GL11.glGetBoolean(GL11.GL_POLYGON_SMOOTH);
|
||||||
state.blendEnabled = GL11.glGetBoolean(GL11.GL_BLEND);
|
state.blendEnabled = GL11.glGetBoolean(GL11.GL_BLEND);
|
||||||
|
@ -219,7 +243,7 @@ public class CurveRenderState {
|
||||||
* Restore the old OpenGL state that's backed up in {@code state}.
|
* Restore the old OpenGL state that's backed up in {@code state}.
|
||||||
* @param state the old state to restore
|
* @param state the old state to restore
|
||||||
*/
|
*/
|
||||||
private void endRender(RenderState state) {
|
private void restoreRenderState(RenderState state) {
|
||||||
GL11.glMatrixMode(GL11.GL_PROJECTION);
|
GL11.glMatrixMode(GL11.GL_PROJECTION);
|
||||||
GL11.glPopMatrix();
|
GL11.glPopMatrix();
|
||||||
GL11.glMatrixMode(GL11.GL_MODELVIEW);
|
GL11.glMatrixMode(GL11.GL_MODELVIEW);
|
||||||
|
@ -241,24 +265,18 @@ public class CurveRenderState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do the actual drawing of the curve into the currently bound framebuffer.
|
* Write the vertices and (with position and texture coordinates) for the full
|
||||||
* @param color the color of the curve
|
* curve into the OpenGL buffer with the ID specified by {@code bufferID}
|
||||||
* @param borderColor the curve border color
|
* @param bufferID the buffer ID for the OpenGL buffer the vertices should be written into
|
||||||
* @param curve the points along the curve
|
|
||||||
*/
|
*/
|
||||||
private void draw_curve(Color color, Color borderColor, Vec2f[] curve) {
|
private void createVertexBuffer(int bufferID)
|
||||||
staticState.initGradient();
|
{
|
||||||
RenderState state = startRender();
|
int arrayBufferBinding = GL11.glGetInteger(GL15.GL_ARRAY_BUFFER_BINDING);
|
||||||
int vtx_buf;
|
|
||||||
// the size is: floatsize * (position + texture coordinates) * (number of cones) * (vertices in a cone)
|
|
||||||
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();
|
||||||
staticState.initShaderProgram();
|
|
||||||
vtx_buf = GL15.glGenBuffers();
|
|
||||||
for (int i = 0; i < curve.length; ++i) {
|
for (int i = 0; i < curve.length; ++i) {
|
||||||
float x = curve[i].x;
|
float x = curve[i].x;
|
||||||
float y = curve[i].y;
|
float y = curve[i].y;
|
||||||
//if (i == 0 || i == curve.length - 1){
|
fillCone(buff, x, y);
|
||||||
fillCone(buff, x, y, NewCurveStyleState.DIVIDES);
|
|
||||||
if (i != 0) {
|
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;
|
||||||
|
@ -266,12 +284,25 @@ public class CurveRenderState {
|
||||||
double diff_y = y - last_y;
|
double diff_y = y - last_y;
|
||||||
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, NewCurveStyleState.DIVIDES);
|
fillCone(buff, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buff.flip();
|
buff.flip();
|
||||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vtx_buf);
|
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferID);
|
||||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buff, GL15.GL_STATIC_DRAW);
|
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buff, GL15.GL_STATIC_DRAW);
|
||||||
|
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, arrayBufferBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do the actual drawing of the curve into the currently bound framebuffer.
|
||||||
|
* @param color the color of the curve
|
||||||
|
* @param borderColor the curve border color
|
||||||
|
*/
|
||||||
|
private void renderCurve(Color color, Color borderColor, int from, int to) {
|
||||||
|
staticState.initGradient();
|
||||||
|
RenderState state = saveRenderState();
|
||||||
|
staticState.initShaderProgram();
|
||||||
|
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, fbo.getVbo());
|
||||||
GL20.glUseProgram(staticState.program);
|
GL20.glUseProgram(staticState.program);
|
||||||
GL20.glEnableVertexAttribArray(staticState.attribLoc);
|
GL20.glEnableVertexAttribArray(staticState.attribLoc);
|
||||||
GL20.glEnableVertexAttribArray(staticState.texCoordLoc);
|
GL20.glEnableVertexAttribArray(staticState.texCoordLoc);
|
||||||
|
@ -282,63 +313,37 @@ 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 = 0; i < curve.length * 2 - 1; ++i)
|
for (int i = from*2; i < to * 2 - 1; ++i)
|
||||||
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();
|
||||||
GL20.glDisableVertexAttribArray(staticState.texCoordLoc);
|
GL20.glDisableVertexAttribArray(staticState.texCoordLoc);
|
||||||
GL20.glDisableVertexAttribArray(staticState.attribLoc);
|
GL20.glDisableVertexAttribArray(staticState.attribLoc);
|
||||||
GL15.glDeleteBuffers(vtx_buf);
|
restoreRenderState(state);
|
||||||
endRender(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill {@code buff} with the texture coordinates and positions for a cone
|
* Fill {@code buff} with the texture coordinates and positions for a cone
|
||||||
* with {@code DIVIDES} ground corners that has its center at the coordinates
|
* that has its center at the coordinates {@code (x1,y1)}.
|
||||||
* {@code (x1,y1)}.
|
|
||||||
* @param buff the buffer to be filled
|
* @param buff the buffer to be filled
|
||||||
* @param x1 x-coordinate of the cone
|
* @param x1 x-coordinate of the cone
|
||||||
* @param y1 y-coordinate of the cone
|
* @param y1 y-coordinate of the cone
|
||||||
* @param DIVIDES the base of the cone is a regular polygon with this many sides
|
|
||||||
*/
|
*/
|
||||||
protected void fillCone(FloatBuffer buff, float x1, float y1, final int DIVIDES) {
|
protected void fillCone(FloatBuffer buff, float x1, float y1) {
|
||||||
float divx = containerWidth / 2.0f;
|
float divx = containerWidth / 2.0f;
|
||||||
float divy = containerHeight / 2.0f;
|
float divy = containerHeight / 2.0f;
|
||||||
float offx = -1.0f;
|
float offx = -1.0f;
|
||||||
float offy = 1.0f;
|
float offy = 1.0f;
|
||||||
float x, y;
|
|
||||||
float radius = scale / 2;
|
float radius = scale / 2;
|
||||||
buff.put(1.0f);
|
|
||||||
buff.put(0.5f);
|
for(int i = 0; i<NewCurveStyleState.unitCone.length/6; ++i)
|
||||||
//GL11.glTexCoord2d(1.0, 0.5);
|
{
|
||||||
x = offx + x1 / divx;
|
buff.put(NewCurveStyleState.unitCone[i*6+0]);
|
||||||
y = offy - y1 / divy;
|
buff.put(NewCurveStyleState.unitCone[i*6+1]);
|
||||||
buff.put(x);
|
buff.put(offx + (x1 + radius * NewCurveStyleState.unitCone[i*6+2])/divx);
|
||||||
buff.put(y);
|
buff.put(offy - (y1 + radius * NewCurveStyleState.unitCone[i*6+3])/divy);
|
||||||
buff.put(0f);
|
buff.put(NewCurveStyleState.unitCone[i*6+4]);
|
||||||
buff.put(1f);
|
buff.put(NewCurveStyleState.unitCone[i*6+5]);
|
||||||
//GL11.glVertex4f(x, y, 0.0f, 1.0f);
|
|
||||||
for (int j = 0; j < DIVIDES; ++j) {
|
|
||||||
double phase = j * (float) Math.PI * 2 / DIVIDES;
|
|
||||||
buff.put(0.0f);
|
|
||||||
buff.put(0.5f);
|
|
||||||
//GL11.glTexCoord2d(0.0, 0.5);
|
|
||||||
x = (x1 + radius * (float) Math.sin(phase)) / divx;
|
|
||||||
y = (y1 + radius * (float) Math.cos(phase)) / divy;
|
|
||||||
buff.put((offx + x));
|
|
||||||
buff.put((offy - y));
|
|
||||||
buff.put(1f);
|
|
||||||
buff.put(1f);
|
|
||||||
//GL11.glVertex4f(x + 90 * (float) Math.sin(phase), y + 90 * (float) Math.cos(phase), 1.0f, 1.0f);
|
|
||||||
}
|
}
|
||||||
buff.put(0.0f);
|
|
||||||
buff.put(0.5f);
|
|
||||||
//GL11.glTexCoord2d(0.0, 0.5);
|
|
||||||
x = (x1 + radius * (float) Math.sin(0.0)) / divx;
|
|
||||||
y = (y1 + radius * (float) Math.cos(0.0)) / divy;
|
|
||||||
buff.put((offx + x));
|
|
||||||
buff.put((offy - y));
|
|
||||||
buff.put(1f);
|
|
||||||
buff.put(1f);
|
|
||||||
//GL11.glVertex4f(x + 90 * (float) Math.sin(0.0), y + 90 * (float) Math.cos(0.0), 1.0f, 1.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -354,6 +359,13 @@ public class CurveRenderState {
|
||||||
*/
|
*/
|
||||||
protected static final int DIVIDES = 30;
|
protected static final int DIVIDES = 30;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to hold the dummy vertex data (texture coordinates and position)
|
||||||
|
* of a cone with DIVIDES vertices at its base, that is centered around
|
||||||
|
* (0,0) and has a radius of 1 (so that it can be translated and scaled easily).
|
||||||
|
*/
|
||||||
|
protected static float[] unitCone = new float[(DIVIDES+2)*6];
|
||||||
|
|
||||||
/** OpenGL shader program ID used to draw and recolor the curve. */
|
/** OpenGL shader program ID used to draw and recolor the curve. */
|
||||||
protected int program = 0;
|
protected int program = 0;
|
||||||
|
|
||||||
|
@ -398,6 +410,47 @@ public class CurveRenderState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the data into {@code unitCone} if it hasn't already been initialized.
|
||||||
|
*/
|
||||||
|
public static void initUnitCone() {
|
||||||
|
int index = 0;
|
||||||
|
//check if initialization has already happened
|
||||||
|
if (unitCone[0] == 0.0f) {
|
||||||
|
|
||||||
|
//tip of the cone
|
||||||
|
//vec2 texture coordinates
|
||||||
|
unitCone[index++] = 1.0f;
|
||||||
|
unitCone[index++] = 0.5f;
|
||||||
|
|
||||||
|
//vec4 position
|
||||||
|
unitCone[index++] = 0.0f;
|
||||||
|
unitCone[index++] = 0.0f;
|
||||||
|
unitCone[index++] = 0.0f;
|
||||||
|
unitCone[index++] = 1.0f;
|
||||||
|
for (int j = 0; j < NewCurveStyleState.DIVIDES; ++j) {
|
||||||
|
double phase = j * (float) Math.PI * 2 / NewCurveStyleState.DIVIDES;
|
||||||
|
//vec2 texture coordinates
|
||||||
|
unitCone[index++] = 0.0f;
|
||||||
|
unitCone[index++] = 0.5f;
|
||||||
|
//vec4 positon
|
||||||
|
unitCone[index++] = (float) Math.sin(phase);
|
||||||
|
unitCone[index++] = (float) Math.cos(phase);
|
||||||
|
unitCone[index++] = 1.0f;
|
||||||
|
unitCone[index++] = 1.0f;
|
||||||
|
}
|
||||||
|
//vec2 texture coordinates
|
||||||
|
unitCone[index++] = 0.0f;
|
||||||
|
unitCone[index++] = 0.5f;
|
||||||
|
//vec4 positon
|
||||||
|
unitCone[index++] = (float) Math.sin(0.0f);
|
||||||
|
unitCone[index++] = (float) Math.cos(0.0f);
|
||||||
|
unitCone[index++] = 1.0f;
|
||||||
|
unitCone[index++] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles and links the shader program for the new style curve objects
|
* Compiles and links the shader program for the new style curve objects
|
||||||
* if it hasn't already been compiled and linked.
|
* if it hasn't already been compiled and linked.
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.lwjgl.opengl.EXTFramebufferObject;
|
import org.lwjgl.opengl.EXTFramebufferObject;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL15;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a rendertarget. For now this maps to an OpenGL FBO via LWJGL.
|
* Represents a rendertarget. For now this maps to an OpenGL FBO via LWJGL.
|
||||||
|
@ -31,6 +32,9 @@ public class Rendertarget {
|
||||||
/** The dimensions. */
|
/** The dimensions. */
|
||||||
public final int width, height;
|
public final int width, height;
|
||||||
|
|
||||||
|
/** ID of the vertex buffer associated with this rendertarget*/
|
||||||
|
private final int vboID;
|
||||||
|
|
||||||
/** The FBO ID. */
|
/** The FBO ID. */
|
||||||
private final int fboID;
|
private final int fboID;
|
||||||
|
|
||||||
|
@ -49,6 +53,7 @@ public class Rendertarget {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
fboID = EXTFramebufferObject.glGenFramebuffersEXT();
|
fboID = EXTFramebufferObject.glGenFramebuffersEXT();
|
||||||
|
vboID = GL15.glGenBuffers();
|
||||||
textureID = GL11.glGenTextures();
|
textureID = GL11.glGenTextures();
|
||||||
depthBufferID = EXTFramebufferObject.glGenRenderbuffersEXT();
|
depthBufferID = EXTFramebufferObject.glGenRenderbuffersEXT();
|
||||||
}
|
}
|
||||||
|
@ -60,19 +65,27 @@ public class Rendertarget {
|
||||||
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fboID);
|
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fboID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the FBO ID.
|
* Get the ID of the VBO associated with this Rendertarget.
|
||||||
|
* @return OpenGL buffer ID for the VBO
|
||||||
|
*/
|
||||||
|
public int getVbo() {
|
||||||
|
return vboID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the FBO ID.
|
||||||
|
* @return the OpenGL FBO ID
|
||||||
*/
|
*/
|
||||||
// NOTE: use judiciously, try to avoid if possible and consider adding a
|
|
||||||
// method to this class if you find yourself calling this repeatedly.
|
|
||||||
public int getID() {
|
public int getID() {
|
||||||
return fboID;
|
return fboID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the texture ID.
|
* Get the texture ID of the texture this rendertarget renders into.
|
||||||
|
* @return the OpenGL texture ID
|
||||||
*/
|
*/
|
||||||
// NOTE: try not to use, could be moved into separate class.
|
|
||||||
public int getTextureID() {
|
public int getTextureID() {
|
||||||
return textureID;
|
return textureID;
|
||||||
}
|
}
|
||||||
|
@ -89,6 +102,7 @@ public class Rendertarget {
|
||||||
* and a renderbuffer that it renders the depth to.
|
* and a renderbuffer that it renders the depth to.
|
||||||
* @param width the width
|
* @param width the width
|
||||||
* @param height the height
|
* @param height the height
|
||||||
|
* @return the newly created Rendertarget instance
|
||||||
*/
|
*/
|
||||||
public static Rendertarget createRTTFramebuffer(int width, int height) {
|
public static Rendertarget createRTTFramebuffer(int width, int height) {
|
||||||
int old_framebuffer = GL11.glGetInteger(EXTFramebufferObject.GL_FRAMEBUFFER_BINDING_EXT);
|
int old_framebuffer = GL11.glGetInteger(EXTFramebufferObject.GL_FRAMEBUFFER_BINDING_EXT);
|
||||||
|
@ -122,5 +136,6 @@ public class Rendertarget {
|
||||||
EXTFramebufferObject.glDeleteFramebuffersEXT(fboID);
|
EXTFramebufferObject.glDeleteFramebuffersEXT(fboID);
|
||||||
EXTFramebufferObject.glDeleteRenderbuffersEXT(depthBufferID);
|
EXTFramebufferObject.glDeleteRenderbuffersEXT(depthBufferID);
|
||||||
GL11.glDeleteTextures(textureID);
|
GL11.glDeleteTextures(textureID);
|
||||||
|
GL15.glDeleteBuffers(vboID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@ public class OptionsMenu extends BasicGameState {
|
||||||
GameOption.BACKGROUND_DIM,
|
GameOption.BACKGROUND_DIM,
|
||||||
GameOption.FORCE_DEFAULT_PLAYFIELD,
|
GameOption.FORCE_DEFAULT_PLAYFIELD,
|
||||||
GameOption.IGNORE_BEATMAP_SKINS,
|
GameOption.IGNORE_BEATMAP_SKINS,
|
||||||
|
GameOption.SNAKING_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,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user