Compare commits

..

No commits in common. "kockout-wdata" and "master" have entirely different histories.

24 changed files with 71 additions and 1724 deletions

View File

@ -1,15 +0,0 @@
attribute vec4 m_Position;
attribute vec2 m_TexCoord;
attribute float m_Time;
varying vec4 v_Color;
varying vec2 v_TexCoord;
uniform float g_FadeClock;
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; //m_Position;
v_Color = vec4(1.0, 0.0, 0.0, g_FadeClock);
v_TexCoord = m_TexCoord;
}

View File

@ -1,13 +0,0 @@
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
varying vec2 v_TexCoord;
uniform sampler2D m_Sampler;
void main(void)
{
gl_FragColor = v_Color * texture2D(m_Sampler, v_TexCoord);
}

View File

@ -4,7 +4,6 @@ package awlex.ospu;
* Created by Awlex on 10.10.2016.
*/
import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.objects.GameObject;
import itdelatrisu.opsu.objects.curves.Vec2f;
import org.newdawn.slick.Color;
@ -36,15 +35,6 @@ public class FakeGameObject extends GameObject {
this.start.y = this.end.y = (start.end.y + end.start.y) / 2;
}
@Override
public GameObject clone(GameData a) {
FakeGameObject o = new FakeGameObject();
o.halfTime = this.halfTime;
o.start = this.start;
o.end = this.end;
return o;
}
@Override
public void draw(Graphics g, int trackPosition, boolean mirrored) {

View File

@ -1,92 +0,0 @@
package com.osufx.sunpy;
import java.util.HashMap;
public class PropertyCollection {
private HashMap<String, ShaderProperty> properties = new HashMap<>();
private Shader owner;
private boolean changed = false;
public PropertyCollection(Shader owner) {
this.owner = owner;
}
public void Clear() {
this.changed = true;
this.properties.clear();
}
public void Add(ShaderProperty prop) {
this.properties.put(prop.Name, prop);
}
public void Replace(ShaderProperty prop) {
this.properties.replace(prop.Name, prop);
}
public void Replace(String key, Object value) {
if (!this.properties.containsKey(key))
return;
ShaderProperty prop = this.properties.get(key);
if (value.getClass() != prop.Type){
System.out.println(String.format("%s variable %s does not take value type %s", this.owner.name, key, value.getClass()));
return;
}
if (prop.Value != null && prop.Value == value)
return;
prop.Value = value;
}
public void Remove(String key) {
this.properties.remove(key);
}
public void Set() {
if (!this.changed)
return;
for (ShaderProperty prop : this.properties.values()) {
prop.Set();
}
this.changed = false;
}
public ShaderProperty get(String propName) {
if (!this.properties.containsKey(propName))
return null;
return this.properties.get(propName);
}
public void set(String propName, Object value) {
if (!this.owner.loaded)
return;
if (!this.properties.containsKey(propName)) {
System.out.println(String.format("Property %s does not exist!", propName));
return;
}
ShaderProperty prop = this.properties.get(propName);
if (value.getClass() != prop.Type){
System.out.println(String.format("%s variable %s does not take value type %s", this.owner.name, propName, value.getClass()));
return;
}
if (prop.Value != null && prop.Value == value)
return;
prop.Value = value;
if (this.owner.started)
prop.Set();
else
this.changed = true;
}
}

View File

@ -1,213 +0,0 @@
package com.osufx.sunpy;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
import java.io.InputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.*;
public class Shader {
public String name;
public int programId = -1;
public boolean loaded = false;
public boolean started = false;
public PropertyCollection Properties;
public static HashMap<String, Object> globalProperties = new HashMap<>();
public static List<Shader> loadedShaders = new ArrayList<>();
public static int currentShader = 0;
public HashMap<String, Integer> attribLoc = new HashMap<>();
private static final String[] attribs = new String[] {
"m_Position",
"m_Color",
"m_TexCoord",
"m_Time",
"m_Direction"
};
private HashMap<Integer, String> shaderParts = new HashMap<>();
private int previousShader;
public Shader(String vertexShader, String fragmentShader) {
String vertexString;
String fragmentString;
try {
InputStream vertexStream = ResourceLoader.getResourceAsStream(vertexShader);
vertexString = convertStreamToString(vertexStream);
InputStream fragmentStream = ResourceLoader.getResourceAsStream(fragmentShader);
fragmentString = convertStreamToString(fragmentStream);
} catch (Exception e){
e.printStackTrace();
return;
}
this.name = String.format("%s/%s", vertexShader, fragmentShader);
this.Properties = new PropertyCollection(this);
this.programId = GL20.glCreateProgram();
this.shaderParts.put(GL20.glCreateShader(GL20.GL_VERTEX_SHADER), vertexString);
this.shaderParts.put(GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER), fragmentString);
this.CompileParts();
this.Compile();
}
public Shader(String shader, final int shaderType) {
if (shaderType != GL20.GL_FRAGMENT_SHADER && shaderType != GL20.GL_VERTEX_SHADER){
System.out.println("Invalid shader type");
return;
}
String shaderString;
try {
InputStream shaderStream = ResourceLoader.getResourceAsStream(shader);
shaderString = convertStreamToString(shaderStream);
} catch (Exception e) {
e.printStackTrace();
return;
}
this.name = String.format("%s/%s",
shaderType == GL20.GL_FRAGMENT_SHADER ? "Fragment" : "Vertex",
shader);
this.Properties = new PropertyCollection(this);
this.programId = GL20.glCreateProgram();
this.shaderParts.put(GL20.glCreateShader(shaderType), shaderString);
this.CompileParts();
this.Compile();
}
public void CompileParts() {
for (Map.Entry<Integer, String> entry : this.shaderParts.entrySet()) {
int handle = entry.getKey();
String source = entry.getValue();
GL20.glShaderSource(handle, source);
GL20.glCompileShader(handle);
int res = GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS);
if (res != GL11.GL_TRUE) {
String error = GL20.glGetShaderInfoLog(handle, 1024);
Log.error("Shader compilation failed.", new Exception(error));
}
}
}
public void Compile() {
this.Properties.Clear();
for (int handler : this.shaderParts.keySet()) {
GL20.glAttachShader(this.programId, handler);
}
GL20.glLinkProgram(this.programId);
int res = GL20.glGetProgrami(this.programId, GL20.GL_LINK_STATUS);
if (res != GL11.GL_TRUE) {
String error = GL20.glGetProgramInfoLog(this.programId, 1024);
Log.error("Program linking failed.", new Exception(error));
}
for (int handler : this.shaderParts.keySet()) {
GL20.glDeleteShader(handler);
}
for (int i = 0; i < attribs.length; i++) {
int attrib = GL20.glGetAttribLocation(this.programId, attribs[i]);
this.attribLoc.put(attribs[i], attrib);
//GL20.glBindAttribLocation(this.programId, i, attribLoc[i]);
}
/*for (int handler : this.shaderParts.keySet()) {
GL20.glDetachShader(this.programId, handler);
}*/
this.loaded = res == GL11.GL_TRUE;
if (this.loaded) {
int uniCount = GL20.glGetProgrami(this.programId, GL20.GL_ACTIVE_UNIFORMS);
for (int i = 0; i < uniCount; i++) {
IntBuffer length = BufferUtils.createIntBuffer(1);
IntBuffer size = BufferUtils.createIntBuffer(1);
IntBuffer type = BufferUtils.createIntBuffer(1);
ByteBuffer name = ByteBuffer.allocateDirect(64);
GL20.glGetActiveUniform(this.programId, i, length, size, type, name);
byte[] buf = new byte[length.get(0)];
name.get(buf, 0, buf.length);
String propName = new String(buf);
int propLocation = GL20.glGetUniformLocation(programId, propName);
UniformType propUniformType = UniformType.map.get(type.get(0));
Class propType = ShaderProperty.ConvertType(propUniformType.name());
System.out.println(String.format("propName:%s PropUniformType:%s PropType:%s", propName, propUniformType, propType));
this.Properties.Add(new ShaderProperty(
propName,
propLocation,
propType,
propUniformType
));
}
for (Map.Entry<String, Object> entry : globalProperties.entrySet()) {
this.Properties.Replace(entry.getKey(), entry.getValue());
}
loadedShaders.add(this);
}
}
public void Begin(){
if (this.started || !this.loaded)
return;
GL20.glUseProgram(this.programId);
this.previousShader = currentShader;
currentShader = this.programId;
GL20.glEnableVertexAttribArray(this.attribLoc.get("m_Position"));
GL20.glEnableVertexAttribArray(this.attribLoc.get("m_TexCoord"));
//this.Properties.set("m_Sampler", 0);
this.started = true;
}
public void End() {
if (!this.started)
return;
GL11.glFlush();
GL20.glDisableVertexAttribArray(this.attribLoc.get("m_TexCoord"));
GL20.glDisableVertexAttribArray(this.attribLoc.get("m_Position"));
GL20.glUseProgram(this.previousShader);
currentShader = this.previousShader;
this.started = false;
}
static String convertStreamToString(InputStream is) {
Scanner s = new Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
}

View File

@ -1,134 +0,0 @@
package com.osufx.sunpy;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL20;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
public class ShaderProperty {
public String Name;
public int Location;
public Class Type;
public UniformType ActiveUniformType;
public Object Value;
public ShaderProperty(String Name, int Location, Class Type, UniformType ActiveUniformType) {
this.Name = Name;
this.Location = Location;
this.Type = Type;
this.ActiveUniformType = ActiveUniformType;
}
public void Set() {
if (Value == null)
return;
switch (this.ActiveUniformType) {
case Bool:
GL20.glUniform1(this.Location, IntBuffer.wrap( new int[]{ (boolean)Value ? 1 : 0 } ));
break;
case Int:
GL20.glUniform1(this.Location, IntBuffer.wrap( new int[]{ (int)Value } ));
break;
case Float:
GL20.glUniform1f(this.Location, (float)Value);
break;
case BoolVec2:
GL20.glUniform2(this.Location, IntBuffer.wrap( boolArrayToIntArray( (boolean[])Value ) ));
break;
case IntVec2:
GL20.glUniform2(this.Location, IntBuffer.wrap( (int[])Value ));
break;
case FloatVec2:
float[] value = (float[])Value;
GL20.glUniform2f(this.Location, value[0], value[1]);
break;
case FloatMat2:
GL20.glUniformMatrix2(this.Location, false, FloatBuffer.wrap( (float[])Value ));
break;
case BoolVec3:
GL20.glUniform3(this.Location, IntBuffer.wrap( boolArrayToIntArray( (boolean[])Value ) ));
break;
case IntVec3:
GL20.glUniform3(this.Location, IntBuffer.wrap( (int[])Value ));
break;
case FloatVec3:
GL20.glUniform3(this.Location, FloatBuffer.wrap( (float[])Value ));
break;
case FloatMat3:
GL20.glUniformMatrix3(this.Location, false, FloatBuffer.wrap( (float[])Value ));
break;
case BoolVec4:
GL20.glUniform4(this.Location, IntBuffer.wrap( boolArrayToIntArray( (boolean[])Value ) ));
break;
case IntVec4:
GL20.glUniform4(this.Location, IntBuffer.wrap( (int[])Value ));
break;
case FloatVec4:
GL20.glUniform4(this.Location, FloatBuffer.wrap( (float[])Value ));
break;
case FloatMat4:
GL20.glUniformMatrix4(this.Location, false, FloatBuffer.wrap( (float[])Value ));
break;
case Sampler2D:
GL20.glUniform1i(this.Location, (int) Value);
break;
}
}
public static Class ConvertType(String type) {
switch (type) {
default:
//throw new Exception(String.format("Uniform type %s is not supported.", type));
System.out.println(String.format("Uniform type %s is not supported.", type));
return null;
case "Bool":
return Boolean.class;
case "Int":
return Integer.class;
case "Float":
return Float.class;
case "BoolVec2":
return boolean[].class;
case "IntVec2":
return int[].class;
case "FloatVec2":
return float[].class;
case "BoolVec3":
return boolean[].class;
case "IntVec3":
return int[].class;
case "FloatVec3":
return float[].class;
case "BoolVec4":
return boolean[].class;
case "IntVec4":
return int[].class;
case "FloatVec4":
return float[].class;
case "FloatMat2":
return float[].class;
case "FloatMat3":
return float[].class;
case "FloatMat4":
return float[].class;
case "Sampler2D":
case "SamplerCube":
return Integer.class;
}
}
/*public static Type ConvertType(int type) {
(UniformType)24;
}*/
public static int[] boolArrayToIntArray(boolean[] array) {
int[] value = new int[array.length];
for (int i = 0; i < array.length; i++)
value[i] = array[i] ? 1 : 0;
return value;
}
}

View File

@ -1,39 +0,0 @@
package com.osufx.sunpy;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import java.util.HashMap;
public enum UniformType {
Int(GL11.GL_INT),
Float(GL11.GL_FLOAT),
FloatVec2(GL20.GL_FLOAT_VEC2),
FloatVec3(GL20.GL_FLOAT_VEC3),
FloatVec4(GL20.GL_FLOAT_VEC4),
IntVec2(GL20.GL_INT_VEC2),
IntVec3(GL20.GL_INT_VEC3),
IntVec4(GL20.GL_INT_VEC4),
Bool(GL20.GL_BOOL),
BoolVec2(GL20.GL_BOOL_VEC2),
BoolVec3(GL20.GL_BOOL_VEC3),
BoolVec4(GL20.GL_BOOL_VEC4),
FloatMat2(GL20.GL_FLOAT_MAT2),
FloatMat3(GL20.GL_FLOAT_MAT3),
FloatMat4(GL20.GL_FLOAT_MAT4),
Sampler2D(GL20.GL_SAMPLER_2D),
SamplerCube(GL20.GL_SAMPLER_CUBE);
private final int glIndex;
public static HashMap<Integer, UniformType> map = new HashMap<>();
static {
for (UniformType v : UniformType.values()) {
map.put(v.glIndex, v);
}
}
UniformType(int glIndex) {
this.glIndex = glIndex;
}
}

View File

@ -170,7 +170,7 @@ public class GameData {
HIT_ANIMATION_RESULT = 12; // not a hit result
/** Hit result-related images (indexed by HIT_* constants to HIT_MAX). */
public static Image[] hitResults;
private Image[] hitResults;
/** Counts of each hit result so far (indexed by HIT_* constants to HIT_MAX). */
private int[] hitResultCount;
@ -1222,7 +1222,7 @@ public class GameData {
/**
* Increases the combo streak by one.
*/
protected void incrementComboStreak() {
private void incrementComboStreak() {
combo++;
comboPopTime = 0;
if (combo > comboMax)
@ -1404,7 +1404,7 @@ public class GameData {
* @param noIncrementCombo if the combo should not be incremented by this result
* @return the actual hit result (HIT_* constants)
*/
protected int handleHitResult(int time, int result, float x, float y, Color color, boolean end,
private int handleHitResult(int time, int result, float x, float y, Color color, boolean end,
HitObject hitObject, HitObjectType hitResultType, int repeat, boolean noIncrementCombo) {
// update health, score, and combo streak based on hit result
int hitValue = 0;

View File

@ -83,13 +83,6 @@ public class Circle extends GameObject {
super.updateStartEndPositions(time);
}
@Override
public GameObject clone(GameData data) {
Circle c = new Circle(hitObject, game, data, comboColorIndex, comboEnd);
c.isreplay = true;
return c;
}
@Override
public void draw(Graphics g, int trackPosition, boolean mirror) {
Color orig = color;
@ -172,13 +165,12 @@ public class Circle extends GameObject {
return false;
}
private boolean isreplay;
@Override
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
int time = hitObject.getTime();
int[] hitResultOffset = game.getHitResultOffsets();
boolean isAutoMod = !isreplay && GameMod.AUTO.isActive();
boolean isAutoMod = GameMod.AUTO.isActive();
if (trackPosition > time + hitResultOffset[GameData.HIT_50]) {
if (isAutoMod) {// "auto" mod: catch any missed notes due to lag

View File

@ -18,7 +18,6 @@
package itdelatrisu.opsu.objects;
import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.objects.curves.Vec2f;
@ -30,7 +29,7 @@ import org.newdawn.slick.Graphics;
*/
public class DummyObject extends GameObject {
/** The associated HitObject. */
public final HitObject hitObject;
private HitObject hitObject;
/** The scaled starting x, y coordinates. */
private float x, y;
@ -50,11 +49,6 @@ public class DummyObject extends GameObject {
updateStartEndPositions(0);
}
@Override
public GameObject clone(GameData a) {
return new DummyObject(this.hitObject);
}
@Override
public void draw(Graphics g, int trackPosition, boolean mirror) {}

View File

@ -18,7 +18,6 @@
package itdelatrisu.opsu.objects;
import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.objects.curves.Vec2f;
import org.newdawn.slick.Color;
@ -115,6 +114,4 @@ public abstract class GameObject {
return hue;
}
public abstract GameObject clone(GameData data);
}

View File

@ -189,13 +189,6 @@ public class Slider extends GameObject {
repeats = hitObject.getRepeatCount();
}
@Override
public GameObject clone(GameData data) {
Slider s = new Slider(hitObject, game, data, comboColorIndex, comboEnd);
s.isreplay = true;
return s;
}
@Override
public void draw(Graphics g, int trackPosition, boolean mirror) {
if (trackPosition > getEndTime()) {
@ -637,12 +630,11 @@ public class Slider extends GameObject {
return false;
}
boolean isreplay;
@Override
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
int repeatCount = hitObject.getRepeatCount();
int[] hitResultOffset = game.getHitResultOffsets();
boolean isAutoMod = !isreplay && GameMod.AUTO.isActive();
boolean isAutoMod = GameMod.AUTO.isActive();
if (!sliderClickedInitial) {
int time = hitObject.getTime();

View File

@ -18,7 +18,6 @@
package itdelatrisu.opsu.objects;
import awlex.ospu.FakeGameObject;
import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameData.HitObjectType;
import itdelatrisu.opsu.GameImage;
@ -171,12 +170,6 @@ public class Spinner extends GameObject {
rotationsNeeded = spinsPerMinute * (hitObject.getEndTime() - hitObject.getTime()) / 60000f;
}
@Override
public GameObject clone(GameData data) {
//return new DummyObject(hitObject);
return new Spinner(hitObject, game, data);
}
@Override
public void draw(Graphics g, int trackPosition, boolean mirror) {
if (mirror) {

View File

@ -17,7 +17,6 @@
*/
package itdelatrisu.opsu.render;
import com.osufx.sunpy.Shader;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.HitObject;
@ -249,7 +248,7 @@ public class CurveRenderState {
GL11.glTexParameteri(GL11.GL_TEXTURE_1D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_1D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
GL20.glUseProgram(Shader.currentShader);
GL20.glUseProgram(0);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPushMatrix();

View File

@ -45,8 +45,6 @@ import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.*;
import org.lwjgl.input.Keyboard;
@ -59,7 +57,6 @@ import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.*;
import yugecin.opsudance.ReplayPlayback.HitData;
import yugecin.opsudance.core.state.ComplexOpsuState;
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
import yugecin.opsudance.options.OptionGroups;
@ -307,7 +304,7 @@ public class Game extends ComplexOpsuState {
MUSICBAR_HOVER = new Color(12, 9, 10, 0.35f),
MUSICBAR_FILL = new Color(255, 255, 255, 0.75f);
private Cursor mirrorCursor;
private final Cursor mirrorCursor;
private final MoveStoryboard moveStoryboardOverlay;
private final StoryboardOverlay storyboardOverlay;
private final OptionsOverlay optionsOverlay;
@ -318,7 +315,7 @@ public class Game extends ComplexOpsuState {
public Game() {
super();
//mirrorCursor = new Cursor(true);
mirrorCursor = new Cursor(true);
this.moveStoryboardOverlay = new MoveStoryboard();
this.optionsOverlay = new OptionsOverlay(OptionGroups.storyboardOptions);
this.storyboardOverlay = new StoryboardOverlay(moveStoryboardOverlay, optionsOverlay, this);
@ -725,28 +722,6 @@ public class Game extends ComplexOpsuState {
}
UI.draw(g);
if (replayCursors == null) {
return;
}
//g.setColor(new Color(0.2f, 0.2f, 0.2f));
//g.fillRect(0, 0, ReplayPlayback.SQSIZE * 2, displayContainer.height);
//g.setColor(Color.black);
//g.fillRect(ReplayPlayback.SQSIZE * 2, 0, ReplayPlayback.SQSIZE * 2, displayContainer.height);
float totalHeight = 0f;
for (ReplayPlayback replayPlayback : replays) {
totalHeight += replayPlayback.getHeight();
}
float ypos = (height - totalHeight) / 2f - ReplayPlayback.lineHeight;
for (ReplayPlayback replayPlayback : replays) {
float h = replayPlayback.getHeight();
ypos += h;
//if (h > 0f) {
replayPlayback.render(renderDelta, g, ypos, trackPosition);
//}
}
replayCursors.draw();
}
@Override
@ -935,7 +910,6 @@ public class Game extends ComplexOpsuState {
// set mouse coordinates
autoMousePosition.set(autoPoint.x, autoPoint.y);
autoMousePosition.set(-100, -100);
}
if (isReplay) {
@ -1480,16 +1454,6 @@ public class Game extends ComplexOpsuState {
return true;
}
static class ReplayData {
final HitData hitdata;
final Replay replay;
ReplayData(HitData hitdata, Replay replay) {
this.hitdata = hitdata;
this.replay = replay;
}
}
private ReplayPlayback[] replays;
private ReplayCursors replayCursors;
@Override
public void enter() {
overlays.clear();
@ -1501,84 +1465,7 @@ public class Game extends ComplexOpsuState {
super.enter();
/*
File replaydir = new File("d:/Users/Robin/games/osu/osr-stuff-master/xi/");
if (!replaydir.exists()) {
bubNotifs.sendf(Colors.BUB_RED, "replay folder '%s' does not exist", replaydir.getAbsolutePath());
displayContainer.switchStateInstantly(songMenuState);
return;
}
File[] files = replaydir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".osr");
}
});
if (replayCursors != null) {
replayCursors.destroy();
}
final ArrayList<ReplayData> rdata = new ArrayList<>(50);
for (File file : files) {
final String datafilename = file.getName().substring(0, file.getName().length() - 3) + "ope";
final File hitdatafile = new File(file.getParentFile(), datafilename);
if (!hitdatafile.exists()) {
bubNotifs.sendf(Colors.BUB_RED, "no hitdata file for %s", file.getName());
continue;
}
final ReplayPlayback.HitData hitdata;
try {
hitdata = new ReplayPlayback.HitData(hitdatafile);
} catch (Exception e) {
bubNotifs.sendf(
Colors.BUB_RED,
"cannot parse hitdata for '%s': %s",
hitdatafile.getName(),
e.toString()
);
continue;
}
final Replay r = new Replay(file);
try {
r.load();
} catch (IOException e) {
bubNotifs.sendf(Colors.BUB_RED, "could not load replay %s", file.getName());
continue;
}
rdata.add(new ReplayData(hitdata, r));
}
rdata.sort(new Comparator<ReplayData>() {
@Override
public int compare(ReplayData o1, ReplayData o2) {
return Integer.compare(o2.replay.score, o1.replay.score);
}
});
replayCursors = new ReplayCursors(rdata.size());
replays = new ReplayPlayback[rdata.size()];
float hueshift = 360f / rdata.size();
float hue = 180;
int replayidx = 0;
for (ReplayData d : rdata) {
final Color c = new Color(java.awt.Color.HSBtoRGB((hue) / 360f, .7f, 1.0f));
final ReplayCursor cursor = new ReplayCursor(c);
replays[replayidx] = new ReplayPlayback(
d.replay,
d.hitdata,
c,
cursor
);
replayCursors.playbacks[replayidx] = replays[replayidx];
hue += hueshift;
replayidx++;
}
displayContainer.drawCursor = false;*/
displayContainer.drawCursor = false;
isInGame = true;
if (!skippedToCheckpoint) {
@ -1862,12 +1749,6 @@ public class Game extends ComplexOpsuState {
knorkesliders = null;
if (replayCursors != null) {
replayCursors.destroy();
replayCursors = null;
replays = null;
}
Dancer.instance.setGameObjects(null);
Cursor.lastObjColor = Color.white;
@ -1885,6 +1766,10 @@ public class Game extends ComplexOpsuState {
GameMod.loadModState(previousMods);
}
/**
* Adjusts the beatmap's local music offset.
* @param sign the sign (multiplier)
*/
public void adjustLocalMusicOffset(int amount) {
int newOffset = beatmap.localMusicOffset + amount;
barNotifs.send(String.format("Local beatmap offset set to %dms", newOffset));

View File

@ -18,31 +18,18 @@
package itdelatrisu.opsu.ui;
import com.osufx.sunpy.Shader;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.render.Rendertarget;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import java.awt.Point;
import java.nio.IntBuffer;
import java.util.Iterator;
import java.util.LinkedList;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.*;
import org.newdawn.slick.*;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureImpl;
import yugecin.opsudance.Dancer;
import yugecin.opsudance.ReplayPlayback;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.options.Options.*;
import static itdelatrisu.opsu.GameImage.CURSOR;
import static itdelatrisu.opsu.GameImage.CURSOR_MIDDLE;
import static itdelatrisu.opsu.GameImage.CURSOR_TRAIL;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
@ -68,7 +55,8 @@ public class Cursor {
/** The time it takes for the cursor to scale, in milliseconds. */
private static final float CURSOR_SCALE_TIME = 125;
private TrailList trail = new TrailList();
/** Stores all previous cursor locations to display a trail. */
private LinkedList<Point> trail = new LinkedList<>();
private boolean newStyle;
@ -80,12 +68,6 @@ public class Cursor {
private boolean isMirrored;
private Color filter;
private Rendertarget fbo;
private Shader cursorTrailShader;
public Cursor() {
this(false);
}
@ -93,14 +75,6 @@ public class Cursor {
public Cursor(boolean isMirrored) {
resetLocations(0, 0);
this.isMirrored = isMirrored;
this.lastPosition = new Point(width2, 0);
this.filter = new Color(255,255,255);
this.cursorTrailShader = new Shader("sh_Cursor.vertex", "sh_Texture.frag");
}
public Cursor(Color filter) {
this(false);
this.filter = filter;
}
/**
@ -108,10 +82,6 @@ public class Cursor {
* @param mousePressed whether or not the mouse button is pressed
*/
public void draw(boolean mousePressed) {
if (fbo == null) {
this.fbo = Rendertarget.createRTTFramebuffer(width, height);
}
/*
if (OPTION_DISABLE_CURSOR.state) {
return;
}
@ -161,10 +131,6 @@ public class Cursor {
lastCursorColor = filter = Dancer.cursorColorOverride.getColor();
}
if (this.filter != null) {
filter = this.filter;
}
// draw a fading trail
float alpha = 0f;
float t = 2f / trail.size();
@ -173,7 +139,7 @@ public class Cursor {
cursorTrail.startUse();
for (Point p : trail) {
alpha += t;
cursorTrail.setImageColor(filter.r, filter.g, filter.b, alpha * 0.25f);
cursorTrail.setImageColor(filter.r, filter.g, filter.b, alpha);
cursorTrail.drawEmbedded(
p.x - (cursorTrailWidth / 2f), p.y - (cursorTrailHeight / 2f),
cursorTrailWidth, cursorTrailHeight, cursorTrailRotation);
@ -191,110 +157,6 @@ public class Cursor {
if (hasMiddle) {
cursorMiddle.drawCentered(lastPosition.x, lastPosition.y, OPTION_DANCE_CURSOR_ONLY_COLOR_TRAIL.state ? Color.white : filter);
}
*/
final Image img = CURSOR_TRAIL.getImage();
final Texture txt = img.getTexture();
final float trailw2 = img.getWidth() * OPTION_CURSOR_SIZE.val / 100f / 2f;
final float trailh2 = img.getHeight() * OPTION_CURSOR_SIZE.val / 100f / 2f;
float txtw = txt.getWidth();
float txth = txt.getHeight();
//img.draw(0f,0f);
/*
// stuff copied from CurveRenderState and stuff, I don't know what I'm doing
int oldFb = GL11.glGetInteger(EXTFramebufferObject.GL_FRAMEBUFFER_BINDING_EXT);
int oldTex = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
IntBuffer oldViewport = BufferUtils.createIntBuffer(16);
GL11.glGetInteger(GL11.GL_VIEWPORT, oldViewport);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fbo.getID());
GL11.glViewport(0, 0, fbo.width, fbo.height);
GL11.glClearColor(0f, 0f, 0f, 0f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
*/
//Color.white.bind();
//GL20.glVertexAttrib4f(cursorTrailShader.attribLoc.get("m_Position"), 1f, 1f, 1f, 1f);
//GL11.glBindTexture(GL11.GL_TEXTURE_2D, );
//cursorTrailShader.Properties.set("m_Sampler", txt.getTextureID());
//GL20.glUniform1i(cursorTrailShader.attribLoc.get("m_Sampler"), txt.getTextureID());
//IntBuffer buf = BufferUtils.createIntBuffer(1).put(txt.getTextureID());
cursorTrailShader.Begin();
GL13.glActiveTexture(GL13.GL_TEXTURE5);
//GL11.glEnable(GL11.GL_TEXTURE_2D);
//GL11.glGenTextures();
//txt.bind();
//TextureImpl.unbind();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, txt.getTextureID());
//GL33.glBindSampler(GL20.GL_SAMPLER_2D, txt.getTextureID());
//GL20.glUniform1i(cursorTrailShader.attribLoc.get("m_Sampler"), 0);
//cursorTrailShader.Properties.set("m_TexCoord", new float[] { txtw, txth });
int idd = GL20.glGetAttribLocation(cursorTrailShader.programId, "m_TexCoord");
cursorTrailShader.Properties.set("m_Sampler", 5);
//GL20.glUniform1i(cursorTrailShader.Properties.get("m_Sampler").Location, 5);
cursorTrailShader.Properties.set("g_FadeClock", 0.04f);
GL11.glBegin(GL11.GL_QUADS);
float alpha = 0f;
float alphaIncrease = .4f / trail.size;
for (Trailpart p : trail) {
//alpha += alphaIncrease;
//GL11.glColor4f(filter.r, filter.g, filter.b, 1f);
GL11.glTexCoord2f(0f, 0f);
GL20.glVertexAttrib2f(idd, 0f, 0f);
GL11.glVertex3f(p.x - trailw2, p.y - trailh2, 0f);
GL11.glTexCoord2f(txtw, 0);
GL20.glVertexAttrib2f(idd, txtw, 0);
GL11.glVertex3f(p.x + trailw2, p.y - trailh2, 0f);
GL11.glTexCoord2f(txtw, txth);
GL20.glVertexAttrib2f(idd, txtw, txth);
GL11.glVertex3f(p.x + trailw2, p.y + trailh2, 0f);
GL11.glTexCoord2f(0f, txth);
GL20.glVertexAttrib2f(idd, 0f, txth);
GL11.glVertex3f(p.x - trailw2, p.y + trailh2, 0f);
//break;
}
GL11.glEnd();
cursorTrailShader.End();
GL13.glActiveTexture(GL13.GL_TEXTURE0);
/*
GL11.glBindTexture(GL11.GL_TEXTURE_2D, oldTex);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, oldFb);
GL11.glViewport(oldViewport.get(0), oldViewport.get(1), oldViewport.get(2), oldViewport.get(3));
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
//GL11.glEnable(GL11.GL_TEXTURE_2D);
//GL11.glDisable(GL11.GL_TEXTURE_1D);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, fbo.getTextureID());
GL11.glBegin(GL11.GL_QUADS);
GL11.glColor4f(1f, 1f, 1f, 1f);
GL11.glTexCoord2f(1f, 1f);
GL11.glVertex2i(fbo.width, 0);
GL11.glTexCoord2f(0f, 1f);
GL11.glVertex2i(0, 0);
GL11.glTexCoord2f(0f, 0f);
GL11.glVertex2i(0, fbo.height);
GL11.glTexCoord2f(1f, 0f);
GL11.glVertex2i(fbo.width, fbo.height);
GL11.glEnd();
GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
*/
CURSOR.getScaledImage(OPTION_CURSOR_SIZE.val / 100f).drawCentered(lastPosition.x, lastPosition.y, filter);
CURSOR_MIDDLE.getScaledImage(OPTION_CURSOR_SIZE.val / 100f).drawCentered(lastPosition.x, lastPosition.y, filter);
}
/**
@ -303,22 +165,34 @@ public class Cursor {
* @param mouseY y coordinate to set position to
*/
public void setCursorPosition(int delta, int mouseX, int mouseY) {
nowtime = System.currentTimeMillis();
// TODO: use an image buffer
int removeCount = 0;
float FPSmod = Math.max(1000 / Math.max(delta, 1), 1) / 30f; // TODO
if (newStyle) {
// new style: add all points between cursor movements
if ((lastPosition.x == 0 && lastPosition.y == 0) || !addCursorPoints(lastPosition.x, lastPosition.y, mouseX, mouseY)) {
trail.add(new Point(mouseX, mouseY));
}
lastPosition.move(mouseX, mouseY);
addCursorPoints(lastPosition.x, lastPosition.y, mouseX, mouseY);
lastPosition.move(mouseX, mouseY);
removeCount = (int) (trail.size() / (6 * FPSmod)) + 1;
} else {
// old style: sample one point at a time
trail.add(new Point(mouseX, mouseY));
int removecount = 0;
TrailNode newfirst = trail.first;
while (newfirst != null && newfirst.value.time < nowtime - 175) {
newfirst = newfirst.next;
removecount++;
int max = (int) (10 * FPSmod);
if (trail.size() > max)
removeCount = trail.size() - max;
}
trail.first = newfirst;
if (newfirst == null) {
trail.last = null;
int cursortraillength = OPTION_DANCE_CURSOR_TRAIL_OVERRIDE.val;
if (cursortraillength > 20) {
removeCount = trail.size() - cursortraillength;
}
trail.size -= removecount;
// remove points from the lists
for (int i = 0; i < removeCount && !trail.isEmpty(); i++)
trail.remove();
}
/**
@ -326,8 +200,8 @@ public class Cursor {
* @author http://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm#Java
*/
private boolean addCursorPoints(int x1, int y1, int x2, int y2) {
int size = trail.size;
// delta of exact value and rounded value of the dependent variable
boolean added = false;
int d = 0;
int dy = Math.abs(y2 - y1);
int dx = Math.abs(x2 - x1);
@ -337,11 +211,16 @@ public class Cursor {
int ix = x1 < x2 ? 1 : -1; // increment direction
int iy = y1 < y2 ? 1 : -1;
int k = 5; // sample size
if (dy <= dx) {
for (;;) {
for (int i = 0; ; i++) {
if (i == k) {
trail.add(new Point(x1, y1));
added = true;
i = 0;
}
if (x1 == x2)
break;
trail.add(new Trailpart(x1, y1));
x1 += ix;
d += dy2;
if (d > dx) {
@ -350,10 +229,14 @@ public class Cursor {
}
}
} else {
for (;;) {
for (int i = 0; ; i++) {
if (i == k) {
trail.add(new Point(x1, y1));
added = true;
i = 0;
}
if (y1 == y2)
break;
trail.add(new Trailpart(x1, y1));
y1 += iy;
d += dx2;
if (d > dy) {
@ -362,64 +245,7 @@ public class Cursor {
}
}
}
return trail.size != size;
}
private static class TrailList implements Iterable<Trailpart>
{
TrailNode first;
TrailNode last;
int size;
public void add(Trailpart t)
{
if (last == null) {
last = first = new TrailNode(t);
} else {
TrailNode n = new TrailNode(t);
last.next = n;
last = n;
}
size++;
}
@Override
public Iterator<Trailpart> iterator()
{
return new Iterator<Trailpart>() {
TrailNode node = first;
@Override
public boolean hasNext() {
return node != null;
}
@Override
public Trailpart next() {
Trailpart v = node.value;
node = node.next;
return v;
}
};
}
}
private static class TrailNode
{
TrailNode next;
Trailpart value;
TrailNode(Trailpart t) {
value = t;
}
}
private static class Trailpart {
int x, y;
long time;
Trailpart(int x, int y) {
this.x = x;
this.y = y;
this.time = nowtime;
}
return added;
}
/**
@ -452,7 +278,11 @@ public class Cursor {
* Resets all cursor location data.
*/
public void resetLocations(int mouseX, int mouseY) {
trail.clear();
lastPosition = new Point(mouseX, mouseY);
for (int i = 0; i < 50; i++) {
trail.add(new Point(lastPosition));
}
}
/**

View File

@ -1,191 +0,0 @@
/*
* opsu! - an open-source osu! client
* Copyright (C) 2014, 2015 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 yugecin.opsudance;
import java.awt.Point;
import java.util.Iterator;
import org.lwjgl.opengl.*;
import org.newdawn.slick.*;
import static itdelatrisu.opsu.GameImage.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
public class ReplayCursor
{
private final Point lastPosition;
private TrailList trail = new TrailList();
public Color filter;
public ReplayCursor(Color filter) {
this.filter = filter;
this.lastPosition = new Point(width2, 0);
}
public void drawTrail(float trailw2, float trailh2, float txtw, float txth)
{
float alpha = 0f;
float alphaIncrease = .4f / trail.size;
for (Trailpart p : trail) {
alpha += alphaIncrease;
GL11.glColor4f(filter.r, filter.g, filter.b, alpha);
GL11.glTexCoord2f(0f, 0f);
GL11.glVertex3f(p.x - trailw2, p.y - trailh2, 0f);
GL11.glTexCoord2f(txtw, 0);
GL11.glVertex3f(p.x + trailw2, p.y - trailh2, 0f);
GL11.glTexCoord2f(txtw, txth);
GL11.glVertex3f(p.x + trailw2, p.y + trailh2, 0f);
GL11.glTexCoord2f(0f, txth);
GL11.glVertex3f(p.x - trailw2, p.y + trailh2, 0f);
}
}
public void drawCursor()
{
CURSOR.getScaledImage(OPTION_CURSOR_SIZE.val / 100f).drawCentered(lastPosition.x, lastPosition.y, filter);
CURSOR_MIDDLE.getScaledImage(OPTION_CURSOR_SIZE.val / 100f).drawCentered(lastPosition.x, lastPosition.y, filter);
}
/**
* Sets the cursor position to given point and updates trail.
* @param mouseX x coordinate to set position to
* @param mouseY y coordinate to set position to
*/
public void setCursorPosition(int delta, int mouseX, int mouseY) {
nowtime = System.currentTimeMillis();
addCursorPoints(lastPosition.x, lastPosition.y, mouseX, mouseY);
lastPosition.move(mouseX, mouseY);
int removecount = 0;
TrailNode newfirst = trail.first;
while (newfirst != null && newfirst.value.time < nowtime - 175) {
newfirst = newfirst.next;
removecount++;
}
trail.first = newfirst;
if (newfirst == null) {
trail.last = null;
}
trail.size -= removecount;
}
/**
* Adds all points between (x1, y1) and (x2, y2) to the cursor point lists.
* @author http://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm#Java
*/
private boolean addCursorPoints(int x1, int y1, int x2, int y2) {
int size = trail.size;
// delta of exact value and rounded value of the dependent variable
int d = 0;
int dy = Math.abs(y2 - y1);
int dx = Math.abs(x2 - x1);
int dy2 = (dy << 1); // slope scaling factors to avoid floating
int dx2 = (dx << 1); // point
int ix = x1 < x2 ? 1 : -1; // increment direction
int iy = y1 < y2 ? 1 : -1;
if (dy <= dx) {
for (;;) {
if (x1 == x2)
break;
trail.add(new Trailpart(x1, y1));
x1 += ix;
d += dy2;
if (d > dx) {
y1 += iy;
d -= dx2;
}
}
} else {
for (;;) {
if (y1 == y2)
break;
trail.add(new Trailpart(x1, y1));
y1 += iy;
d += dx2;
if (d > dy) {
x1 += ix;
d -= dy2;
}
}
}
return trail.size != size;
}
private static class TrailList implements Iterable<Trailpart>
{
TrailNode first;
TrailNode last;
int size;
public void add(Trailpart t)
{
if (last == null) {
last = first = new TrailNode(t);
} else {
TrailNode n = new TrailNode(t);
last.next = n;
last = n;
}
size++;
}
@Override
public Iterator<Trailpart> iterator()
{
return new Iterator<Trailpart>() {
TrailNode node = first;
@Override
public boolean hasNext() {
return node != null;
}
@Override
public Trailpart next() {
Trailpart v = node.value;
node = node.next;
return v;
}
};
}
}
private static class TrailNode
{
TrailNode next;
Trailpart value;
TrailNode(Trailpart t) {
value = t;
}
}
private static class Trailpart {
int x, y;
long time;
Trailpart(int x, int y) {
this.x = x;
this.y = y;
this.time = nowtime;
}
}
}

View File

@ -1,111 +0,0 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
* Copyright (C) 2018 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;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.*;
import org.newdawn.slick.*;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureImpl;
import itdelatrisu.opsu.render.Rendertarget;
import static itdelatrisu.opsu.GameImage.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
import java.nio.IntBuffer;
public class ReplayCursors
{
public final ReplayPlayback[] playbacks;
private final Rendertarget fbo;
public ReplayCursors(int amount)
{
this.playbacks = new ReplayPlayback[amount];
this.fbo = Rendertarget.createRTTFramebuffer(width, height);
}
public void draw()
{
final Image img = CURSOR_TRAIL.getImage();
final Texture txt = img.getTexture();
final float trailw2 = img.getWidth() * OPTION_CURSOR_SIZE.val / 100f / 2f;
final float trailh2 = img.getHeight() * OPTION_CURSOR_SIZE.val / 100f / 2f;
float txtw = txt.getWidth();
float txth = txt.getHeight();
for (ReplayPlayback p : playbacks) {
if (!p.shouldDrawCursor()) {
continue;
}
// stuff copied from CurveRenderState and stuff, I don't know what I'm doing
int oldFb = GL11.glGetInteger(EXTFramebufferObject.GL_FRAMEBUFFER_BINDING_EXT);
int oldTex = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
IntBuffer oldViewport = BufferUtils.createIntBuffer(16);
GL11.glGetInteger(GL11.GL_VIEWPORT, oldViewport);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fbo.getID());
GL11.glViewport(0, 0, fbo.width, fbo.height);
GL11.glClearColor(0f, 0f, 0f, 0f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
txt.bind();
TextureImpl.unbind();
GL11.glBegin(GL11.GL_QUADS);
p.cursor.drawTrail(trailw2, trailh2, txtw, txth);
GL11.glEnd();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, oldTex);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, oldFb);
GL11.glViewport(oldViewport.get(0), oldViewport.get(1), oldViewport.get(2), oldViewport.get(3));
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
//GL11.glEnable(GL11.GL_TEXTURE_2D);
//GL11.glDisable(GL11.GL_TEXTURE_1D);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, fbo.getTextureID());
GL11.glBegin(GL11.GL_QUADS);
GL11.glColor4f(1f, 1f, 1f, 1f);
GL11.glTexCoord2f(1f, 1f);
GL11.glVertex2i(fbo.width, 0);
GL11.glTexCoord2f(0f, 1f);
GL11.glVertex2i(0, 0);
GL11.glTexCoord2f(0f, 0f);
GL11.glVertex2i(0, fbo.height);
GL11.glTexCoord2f(1f, 0f);
GL11.glVertex2i(fbo.width, fbo.height);
GL11.glEnd();
GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
for (ReplayPlayback p : playbacks) {
if (!p.shouldDrawCursor()) {
continue;
}
p.cursor.drawCursor();
}
}
public void destroy()
{
this.fbo.destroyRTT();
}
}

View File

@ -1,490 +0,0 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
* Copyright (C) 2017 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;
import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.replay.Replay;
import itdelatrisu.opsu.replay.ReplayFrame;
import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import yugecin.opsudance.core.Entrypoint;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.LinkedList;
import static itdelatrisu.opsu.GameData.*;
import static itdelatrisu.opsu.Utils.*;
import static itdelatrisu.opsu.ui.animations.AnimationEquation.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
public class ReplayPlayback
{
private final HitData hitdata;
public final Replay replay;
public ReplayFrame currentFrame;
public ReplayFrame nextFrame;
private int frameIndex;
private Color color;
private final Color originalcolor;
public final ReplayCursor cursor;
private int keydelay[];
public final int PADDING = 3;
public final int sqsize;
public final int unitHeight;
public static int lineHeight;
private boolean hr;
private String player;
private String mods;
private int playerwidth;
private int modwidth;
private String currentAcc;
private int currentAccWidth;
private final int ACCMAXWIDTH;
private int c300, c100, c50, fakecmiss;
private Image hitImage;
private int hitImageTimer = 0;
private boolean knockedout;
private final LinkedList<MissIndicator> missIndicators;
private Image gradeImage;
private static final Color missedColor = new Color(0.4f, 0.4f, 0.4f, 1f);
public ReplayPlayback(Replay replay, HitData hitdata, Color color, ReplayCursor cursor) {
this.missIndicators = new LinkedList<>();
this.replay = replay;
this.hitdata = hitdata;
resetFrameIndex();
this.color = new Color(color);
this.originalcolor = color;
this.cursor = cursor;
keydelay = new int[4];
this.player = replay.playerName;
this.playerwidth = Fonts.SMALLBOLD.getWidth(this.player);
this.mods = "";
this.currentAcc = "100,00%";
this.currentAccWidth = Fonts.SMALLBOLD.getWidth(currentAcc);
this.ACCMAXWIDTH = currentAccWidth + 10;
this.unitHeight = (int) (Fonts.SMALLBOLD.getLineHeight() * 0.9f);
this.sqsize = unitHeight - PADDING;
lineHeight = this.unitHeight;
if ((replay.mods & 0x1) > 0) {
this.mods += "NF";
}
if ((replay.mods & 0x2) > 0) {
this.mods += "EZ";
}
if ((replay.mods & 0x8) > 0 && (replay.mods & 0x200) == 0) {
this.mods += "HD";
}
if ((replay.mods & 0x10) > 0) {
this.mods += "HR";
hr = true;
}
if ((replay.mods & 0x20) > 0) {
this.mods += "SD";
}
if ((replay.mods & 0x40) > 0) {
this.mods += "DT";
}
if ((replay.mods & 0x80) > 0) {
this.mods += "RL";
}
if ((replay.mods & 0x100) > 0) {
this.mods += "HT";
}
if ((replay.mods & 0x200) > 0) {
this.mods += "NC";
}
if ((replay.mods & 0x400) > 0) {
this.mods += "FL";
}
if ((replay.mods & 0x4000) > 0) {
this.mods += "PF";
}
if (this.mods.length() > 0) {
this.mods = " +" + this.mods;
this.modwidth = Fonts.SMALLBOLD.getWidth(this.mods);
}
updateGradeImage();
}
public void resetFrameIndex() {
frameIndex = 0;
currentFrame = replay.frames[frameIndex++];
nextFrame = replay.frames[frameIndex];
}
private void updateGradeImage() {
if (knockedout || !OPTION_RP_SHOW_GRADES.state) {
gradeImage = null;
return;
}
boolean silver = (replay.mods & 0x408) > 0 && (replay.mods & 0x200) == 0;
GameData.Grade grade = GameData.getGrade(c300, c100, c50, fakecmiss, silver);
if (grade == GameData.Grade.NULL) {
if ((replay.mods & 0x8) > 0 && (replay.mods & 0x200) == 0) {
grade = GameData.Grade.SSH;
} else {
grade = GameData.Grade.SS;
}
}
gradeImage = grade.getSmallImage().getScaledCopy(unitHeight, unitHeight);
}
private int HITIMAGETIMEREXPAND = 250;
private int HITIMAGETIMERFADESTART = 500;
private int HITIMAGETIMERFADEEND = 700;
private float HITIMAGETIMERFADEDELTA = HITIMAGETIMERFADEEND - HITIMAGETIMERFADESTART;
private int HITIMAGEDEADFADE = 4000;
private float SHRINKTIME = 500f;
private void showHitImage(int renderdelta, int xpos, float ypos) {
if (hitImage == null) {
return;
}
hitImageTimer += renderdelta;
if (!knockedout && hitImageTimer > HITIMAGETIMERFADEEND) {
hitImage = null;
return;
}
Color color = new Color(1f, 1f, 1f, 1f);
if (!knockedout && hitImageTimer > HITIMAGETIMERFADESTART) {
color.a = (HITIMAGETIMERFADEEND - hitImageTimer) / HITIMAGETIMERFADEDELTA;
}
if (knockedout) {
if (hitImageTimer > HITIMAGEDEADFADE) {
this.color.a = color.a = 0f;
} else {
this.color.a = color.a = 1f - AnimationEquation.IN_CIRC.calc((float) hitImageTimer / HITIMAGEDEADFADE);
}
}
float scale = 1f;
float offset = 0f;
if (hitImageTimer < HITIMAGETIMEREXPAND) {
scale = AnimationEquation.OUT_EXPO.calc((float) hitImageTimer / HITIMAGETIMEREXPAND);
offset = unitHeight / 2f * (1f - scale);
}
hitImage.draw(xpos, 2f + ypos + offset, scale, color);
}
public float getHeight() {
if (hitImageTimer < HITIMAGEDEADFADE) {
return unitHeight;
}
if (hitImageTimer >= HITIMAGEDEADFADE + SHRINKTIME) {
return 0f;
}
return unitHeight * (1f - AnimationEquation.OUT_QUART.calc((hitImageTimer - HITIMAGEDEADFADE) / SHRINKTIME));
}
public void render(int renderdelta, Graphics g, float ypos, int time)
{
while (nextFrame != null && nextFrame.getTime() < time) {
currentFrame = nextFrame;
processKeys();
frameIndex++;
if (frameIndex >= replay.frames.length) {
nextFrame = null;
continue;
}
nextFrame = replay.frames[frameIndex];
}
processKeys();
g.setColor(color);
if (!knockedout) {
for (int i = 0; i < 4; i++) {
if (keydelay[i] > 0) {
g.fillRect(sqsize * i, ypos + PADDING, sqsize, sqsize);
}
keydelay[i] -= renderdelta;
}
boolean hitschanged = false;
while (!hitdata.acc.isEmpty() && hitdata.acc.getFirst().time <= time) {
currentAcc = String.format("%.2f%%", hitdata.acc.removeFirst().acc).replace('.', ',');
currentAccWidth = Fonts.SMALLBOLD.getWidth(currentAcc);
}
while (!hitdata.time300.isEmpty() && hitdata.time300.getFirst() <= time) {
hitdata.time300.removeFirst();
c300++;
hitschanged = true;
}
while (!hitdata.time100.isEmpty() && hitdata.time100.getFirst() <= time) {
hitdata.time100.removeFirst();
hitImageTimer = 0;
hitImage = GameData.hitResults[GameData.HIT_100];
c100++;
hitschanged = true;
}
while (!hitdata.time50.isEmpty() && hitdata.time50.getFirst() <= time) {
hitdata.time50.removeFirst();
hitImageTimer = 0;
hitImage = GameData.hitResults[GameData.HIT_50];
c50++;
hitschanged = true;
}
while (!hitdata.timeCombobreaks.isEmpty() && hitdata.timeCombobreaks.getFirst() <= time) {
hitdata.timeCombobreaks.removeFirst();
hitImageTimer = 0;
hitImage = GameData.hitResults[GameData.HIT_MISS];
fakecmiss++;
hitschanged = true;
if (OPTION_RP_SHOW_MISSES.state) {
float posx = currentFrame.getScaledX();
float posy = currentFrame.getScaledY();
if (hr) {
posy = height - posy;
}
this.missIndicators.add(new MissIndicator(posx, posy));
}
if (OPTION_RP_KNOCKOUT.state) {
knockedout = true;
color = new Color(missedColor);
}
}
if (hitImage != null) {
final float h = hitImage.getHeight();
if (h == 0) {
hitImage = null;
} else {
hitImage = hitImage.getScaledCopy(unitHeight / h);
}
}
if (hitschanged) {
updateGradeImage();
}
}
int xpos = sqsize * (OPTION_RP_SHOW_MOUSECOLUMN.state ? 5 : 3);
if (OPTION_RP_SHOW_ACC.state) {
Fonts.SMALLBOLD.drawString(xpos + ACCMAXWIDTH - currentAccWidth - 10, ypos, currentAcc, new Color(.4f, .4f, .4f, color.a));
xpos += ACCMAXWIDTH;
}
if (gradeImage != null) {
gradeImage.draw(xpos, ypos);
xpos += sqsize + 10;
}
Fonts.SMALLBOLD.drawString(xpos, ypos, this.player, color);
xpos += playerwidth;
if (!this.mods.isEmpty()) {
Fonts.SMALLBOLD.drawString(xpos, ypos, this.mods, new Color(1f, 1f, 1f, color.a));
xpos += modwidth;
}
xpos += 10;
if (OPTION_RP_SHOW_HITS.state) {
showHitImage(renderdelta, xpos, ypos);
}
if (OPTION_RP_SHOW_MISSES.state) {
final Iterator<MissIndicator> iter = this.missIndicators.iterator();
while (iter.hasNext()) {
final MissIndicator mi = iter.next();
if (mi.timer >= HITIMAGEDEADFADE) {
iter.remove();
continue;
}
float progress = (float) mi.timer / HITIMAGEDEADFADE;
float failposy = mi.posy + 50f * OUT_QUART.calc(progress);
Color col = new Color(originalcolor);
col.a = 1f - IN_QUAD.calc(clamp(progress * 2f, 0f, 1f));
Fonts.SMALLBOLD.drawString(mi.posx - playerwidth / 2, failposy, player, col);
Color failimgcol = new Color(1f, 1f, 1f, col.a);
Image failimg = hitResults[HIT_MISS].getScaledCopy(unitHeight, unitHeight);
failimg.draw(mi.posx + playerwidth / 2 + 5, failposy + 2f, failimgcol);
mi.timer += renderdelta;
}
}
if (knockedout) {
return;
}
int y = currentFrame.getScaledY();
if (hr) {
y = height - y;
}
cursor.setCursorPosition(renderdelta, currentFrame.getScaledX(), y);
}
public boolean shouldDrawCursor()
{
return !knockedout;
}
private void processKeys() {
int keys = currentFrame.getKeys();
if ((keys & 5) == 5) {
keydelay[0] = OPTION_RP_KEYPRESS_DELAY.val;
}
if ((keys & 10) == 10) {
keydelay[1] = OPTION_RP_KEYPRESS_DELAY.val;
}
if ((keys ^ 5) == 4) {
keydelay[2] = OPTION_RP_KEYPRESS_DELAY.val;
}
if ((keys ^ 10) == 8) {
keydelay[3] = OPTION_RP_KEYPRESS_DELAY.val;
}
}
private static class MissIndicator
{
private float posx, posy;
private int timer;
private MissIndicator(float posx, float posy)
{
this.posx = posx;
this.posy = posy;
this.timer = 0;
}
}
public static class HitData
{
LinkedList<Integer> time300 = new LinkedList<>();
LinkedList<Integer> time100 = new LinkedList<>();
LinkedList<Integer> time50 = new LinkedList<>();
LinkedList<Integer> timeCombobreaks = new LinkedList<>();
LinkedList<AccData> acc = new LinkedList<>();
LinkedList<ComboData> combo = new LinkedList<>();
public HitData(File file) {
try (InputStream in = new FileInputStream(file)) {
int lasttime = -1;
int lastcombo = 0;
int last300 = 0;
int last100 = 0;
int last50 = 0;
while (true) {
byte[] time = new byte[4];
int rd = in.read(time);
if (rd <= 0) {
break;
}
if (rd != 4) {
throw new RuntimeException("expected 4 bytes, got " + rd);
}
byte[] _time = { time[3], time[2], time[1], time[0] };
lasttime = ByteBuffer.wrap(_time).getInt();
lasttime += 200;
int type = in.read();
if (type == -1) {
throw new RuntimeException();
}
if (in.read(time) != 4) {
throw new RuntimeException();
}
_time = new byte[] { time[3], time[2], time[1], time[0] };
switch (type) {
case 1:
int this100 = ByteBuffer.wrap(_time).getInt();
spread(time100, lasttime, this100 - last100);
last100 = this100;
break;
case 3:
int this300 = ByteBuffer.wrap(_time).getInt();
spread(time300, lasttime, this300 - last300);
last300 = this300;
break;
case 5:
int this50 = ByteBuffer.wrap(_time).getInt();
spread(time50, lasttime, this50 - last50);
last50 = this50;
break;
case 10:
acc.add(new AccData(lasttime, ByteBuffer.wrap(_time).getFloat()));
break;
case 12:
int c = ByteBuffer.wrap(_time).getInt();
combo.add(new ComboData(lasttime, c));
if (c < lastcombo) {
timeCombobreaks.add(lasttime);
}
lastcombo = c;
break;
default:
throw new RuntimeException("unexpected data");
}
}
if (lasttime == -1) {
throw new RuntimeException("nodata");
}
Entrypoint.sout(String.format(
"%s lastcombo %d lasttime %d",
file.getName(),
lastcombo,
lasttime
));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void spread(LinkedList<Integer> list, int time, int d) {
if (list.isEmpty() || d <= 1) {
list.add(time);
return;
}
int dtime = time - list.getLast();
int inc = dtime / d;
int ttime = list.getLast();
for (int i = 0; i < d; i++) {
ttime += inc;
if (i == d - 1) {
ttime = time;
}
list.add(ttime);
}
}
}
public static class AccData {
public int time;
public float acc;
public AccData(int time, float acc) {
this.time = time;
this.acc = acc;
}
}
public static class ComboData {
public int time;
public int combo;
public ComboData(int time, int combo) {
this.time = time;
this.combo = combo;
}
}
}

View File

@ -92,7 +92,7 @@ public class DisplayContainer implements ErrorDumpable, SkinChangedListener {
private long exitconfirmation;
public Cursor cursor;
public final Cursor cursor;
public boolean drawCursor;
private final List<ResolutionChangedListener> resolutionChangedListeners;
@ -106,6 +106,8 @@ public class DisplayContainer implements ErrorDumpable, SkinChangedListener {
public DisplayContainer()
{
this.resolutionChangedListeners = new ArrayList<>();
this.cursor = new Cursor();
drawCursor = true;
skinservice.addSkinChangedListener(this);
@ -172,7 +174,6 @@ public class DisplayContainer implements ErrorDumpable, SkinChangedListener {
public void run() throws Exception {
while(!exitRequested && !(Display.isCloseRequested() && state.onCloseRequest()) || !confirmExit()) {
nowtime = System.currentTimeMillis();
delta = getDelta();
timeSinceLastRender += delta;
@ -269,8 +270,6 @@ public class DisplayContainer implements ErrorDumpable, SkinChangedListener {
glVersion = GL11.glGetString(GL11.GL_VERSION);
glVendor = GL11.glGetString(GL11.GL_VENDOR);
GLHelper.hideNativeCursor();
this.cursor = new Cursor();
drawCursor = true;
}
// TODO: move this elsewhere

View File

@ -35,7 +35,6 @@ public class Entrypoint {
try {
InstanceContainer.kickstart();
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, e.getMessage(), "Cannot start " + PROJECT_NAME, JOptionPane.ERROR_MESSAGE);
// TODO replace with errorhandler
}

View File

@ -82,7 +82,6 @@ public class InstanceContainer {
public static boolean isWidescreen;
public static int mouseX, mouseY;
public static int renderDelta;
public static long nowtime;
public static void kickstart() {
updater = new Updater();

View File

@ -161,15 +161,6 @@ public class OptionGroups {
OPTION_DANCE_RGB_CURSOR_INC,
OPTION_DANCE_CURSOR_TRAIL_OVERRIDE,
}),
new OptionTab("REPLAYSTUFF", new Option[] {
OPTION_RP_KNOCKOUT,
OPTION_RP_SHOW_MISSES,
OPTION_RP_SHOW_GRADES,
OPTION_RP_SHOW_HITS,
OPTION_RP_SHOW_ACC,
OPTION_RP_SHOW_MOUSECOLUMN,
OPTION_RP_KEYPRESS_DELAY,
}),
new OptionTab("MISC", new Option[] {
OPTION_DANCE_HIDE_UI,
OPTION_DANCE_REMOVE_BG,

View File

@ -373,7 +373,7 @@ public class Options {
}
};
public static final NumericOption OPTION_CURSOR_SIZE = new NumericOption("Size", "CursorSize", "Change the cursor scale.", 100, 10, 200) {
public static final NumericOption OPTION_CURSOR_SIZE = new NumericOption("Size", "CursorSize", "Change the cursor scale.", 100, 50, 200) {
@Override
public String getValueString () {
return String.format("%.2fx", val / 100f);
@ -998,19 +998,4 @@ public class Options {
public static final ToggleOption OPTION_PIPPI_SLIDER_FOLLOW_EXPAND = new ToggleOption("Followcircle expand", "PippiFollowExpand", "Increase radius in followcircles", false);
public static final ToggleOption OPTION_PIPPI_PREVENT_WOBBLY_STREAMS = new ToggleOption("Prevent wobbly streams", "PippiPreventWobblyStreams", "Force linear mover while doing streams to prevent wobbly pippi", true);
public static final ToggleOption
OPTION_RP_KNOCKOUT = new ToggleOption("Knockout", "ReplayKnockout", "Remove replays on combobreaks.", true),
OPTION_RP_SHOW_MISSES = new ToggleOption("Show misses", "ReplayShowMiss", "Show falling miss indicators.", true),
OPTION_RP_SHOW_GRADES = new ToggleOption("Show grades", "ReplayShowGrades", "Show grades next to players.", true),
OPTION_RP_SHOW_HITS = new ToggleOption("Show hits", "ReplayShowHits", "Show miss, 50, 100 hits next to players.", true),
OPTION_RP_SHOW_MOUSECOLUMN = new ToggleOption("Mouse buttons column", "ReplayShowMouseColumn", "Preserve space for mouse button columns.", true),
OPTION_RP_SHOW_ACC = new ToggleOption("Show accuracy", "ReplayShowAcc", "Show accuracy next to players.", true);
public static final NumericOption
OPTION_RP_KEYPRESS_DELAY = new NumericOption("Key indicator delay", "ReplayKeyDelay", "How long the key indicator should show after the key being released (ms).", 10, 1, 50) {
@Override
public String getValueString() {
return String.valueOf(val);
}
};
}