opsu-dance/src/com/osufx/sunpy/Shader.java
2018-11-15 20:37:51 +01:00

205 lines
6.6 KiB
Java

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() : "";
}
}