Shader tm

This commit is contained in:
Emily 2018-11-15 20:37:51 +01:00
parent 02448503c7
commit 9a3ecc06aa
11 changed files with 682 additions and 53 deletions

15
res/sh_Cursor.vertex Normal file
View File

@ -0,0 +1,15 @@
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 = m_Position;
v_Color = vec4(1.0, 0.0, 0.0, 1.0);
v_TexCoord = m_TexCoord;
}

13
res/sh_Texture.frag Normal file
View File

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

View File

@ -0,0 +1,92 @@
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

@ -0,0 +1,204 @@
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;
private 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;
this.started = true;
}
public void End() {
if (!this.started)
return;
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

@ -0,0 +1,133 @@
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.glUniform1(this.Location, FloatBuffer.wrap( new float[]{ (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:
GL20.glUniform2(this.Location, FloatBuffer.wrap( (float[])Value ));
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.glUniform1(this.Location, BufferUtils.createIntBuffer(1).put((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

@ -0,0 +1,39 @@
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

@ -17,6 +17,7 @@
*/
package itdelatrisu.opsu.render;
import com.osufx.sunpy.Shader;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.HitObject;
@ -248,7 +249,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(0);
GL20.glUseProgram(Shader.currentShader);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPushMatrix();

View File

@ -307,7 +307,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 final Cursor mirrorCursor;
private Cursor mirrorCursor;
private final MoveStoryboard moveStoryboardOverlay;
private final StoryboardOverlay storyboardOverlay;
private final OptionsOverlay optionsOverlay;
@ -318,7 +318,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);
@ -1501,6 +1501,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());
@ -1577,7 +1578,7 @@ public class Game extends ComplexOpsuState {
replayidx++;
}
displayContainer.drawCursor = false;
displayContainer.drawCursor = false;*/
isInGame = true;
if (!skippedToCheckpoint) {

View File

@ -18,18 +18,34 @@
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.EXTFramebufferObject;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL14;
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.*;
/**
@ -55,8 +71,7 @@ public class Cursor {
/** The time it takes for the cursor to scale, in milliseconds. */
private static final float CURSOR_SCALE_TIME = 125;
/** Stores all previous cursor locations to display a trail. */
private LinkedList<Point> trail = new LinkedList<>();
private TrailList trail = new TrailList();
private boolean newStyle;
@ -70,6 +85,10 @@ public class Cursor {
private Color filter;
private Rendertarget fbo;
private Shader cursorTrailShader;
public Cursor() {
this(false);
}
@ -77,6 +96,9 @@ 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) {
@ -89,6 +111,10 @@ 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;
}
@ -168,6 +194,78 @@ 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();
/*
// 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();
Color.white.bind();
TextureImpl.unbind();
cursorTrailShader.Begin();
GL11.glBegin(GL11.GL_QUADS);
//GL11.glBindTexture(GL11.GL_TEXTURE_2D, );
//cursorTrailShader.Properties.set("m_Sampler", txt.getTextureID());
//cursorTrailShader.Properties.set("g_FadeClock", 0.4f);
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);
break;
}
//GL11.glEnd();
GL11.glEnd();
cursorTrailShader.End();
/*
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);
}
/**
@ -176,34 +274,22 @@ public class Cursor {
* @param mouseY y coordinate to set position to
*/
public void setCursorPosition(int delta, int mouseX, int mouseY) {
// 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));
}
nowtime = System.currentTimeMillis();
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 max = (int) (10 * FPSmod);
if (trail.size() > max)
removeCount = trail.size() - max;
int removecount = 0;
TrailNode newfirst = trail.first;
while (newfirst != null && newfirst.value.time < nowtime - 175) {
newfirst = newfirst.next;
removecount++;
}
int cursortraillength = OPTION_DANCE_CURSOR_TRAIL_OVERRIDE.val;
if (cursortraillength > 20) {
removeCount = trail.size() - cursortraillength;
trail.first = newfirst;
if (newfirst == null) {
trail.last = null;
}
// remove points from the lists
for (int i = 0; i < removeCount && !trail.isEmpty(); i++)
trail.remove();
trail.size -= removecount;
}
/**
@ -211,8 +297,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);
@ -222,16 +308,11 @@ 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 (int i = 0; ; i++) {
if (i == k) {
trail.add(new Point(x1, y1));
added = true;
i = 0;
}
for (;;) {
if (x1 == x2)
break;
trail.add(new Trailpart(x1, y1));
x1 += ix;
d += dy2;
if (d > dx) {
@ -240,14 +321,10 @@ public class Cursor {
}
}
} else {
for (int i = 0; ; i++) {
if (i == k) {
trail.add(new Point(x1, y1));
added = true;
i = 0;
}
for (;;) {
if (y1 == y2)
break;
trail.add(new Trailpart(x1, y1));
y1 += iy;
d += dx2;
if (d > dy) {
@ -256,7 +333,64 @@ public class Cursor {
}
}
}
return added;
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;
}
}
/**
@ -289,11 +423,7 @@ 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

@ -92,7 +92,7 @@ public class DisplayContainer implements ErrorDumpable, SkinChangedListener {
private long exitconfirmation;
public final Cursor cursor;
public Cursor cursor;
public boolean drawCursor;
private final List<ResolutionChangedListener> resolutionChangedListeners;
@ -106,8 +106,6 @@ public class DisplayContainer implements ErrorDumpable, SkinChangedListener {
public DisplayContainer()
{
this.resolutionChangedListeners = new ArrayList<>();
this.cursor = new Cursor();
drawCursor = true;
skinservice.addSkinChangedListener(this);
@ -271,6 +269,8 @@ 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,6 +35,7 @@ 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
}