205 lines
6.6 KiB
Java
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() : "";
|
|
}
|
|
}
|