package com.bitwaffle.spaceguts.graphics.glsl;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL40;
import org.lwjgl.util.vector.Matrix3f;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;
public class GLSLProgram {
private int handle;
private String logString;
private boolean linked;
private FloatBuffer matrix4fBuffer = BufferUtils.createFloatBuffer(16);
private FloatBuffer matrix3fBuffer = BufferUtils.createFloatBuffer(9);
public GLSLProgram() {
handle = GL20.glCreateProgram();
if (handle == 0)
System.out.println("Error creating shader program!!!");
linked = false;
}
public void addShader(GLSLShader shader) {
GL20.glAttachShader(handle, shader.getHandle());
}
public boolean link() {
if (linked)
return true;
if (handle <= 0)
return false;
GL20.glLinkProgram(handle);
int status = GL20.glGetProgram(handle, GL20.GL_LINK_STATUS);
if (status == GL11.GL_FALSE) {
int length = GL20.glGetProgram(handle, GL20.GL_INFO_LOG_LENGTH);
logString = "";
if (length > 0) {
logString = GL20.glGetProgramInfoLog(handle, length);
}
return false;
} else {
linked = true;
return linked;
}
}
public void use(){
if(handle <= 0 || !linked)
return;
GL20.glUseProgram(handle);
}
public String log() { return logString; }
public int getHandle() { return handle; }
public boolean isLinked() { return linked; }
public void bindAttribLocation(int location, String name){
GL20.glBindAttribLocation(handle, location, name);
}
public void bindFragDataLocation(int location, String name){
GL30.glBindFragDataLocation(handle, location, name);
}
public void setUniform(String name, float x, float y, float z){
int loc = getUniformLocation(name);
if(loc >= 0){
GL20.glUniform3f(loc, x, y, z);
} else{
System.out.println("Uniform variable " + name + " not found!");
}
}
public void setUniform(String name, Vector3f v){
this.setUniform(name, v.x, v.y, v.z);
}
public void setUniform(String name, float x, float y, float z, float w){
int loc = getUniformLocation(name);
if(loc >= 0){
GL20.glUniform4f(loc, x, y, z, w);
} else{
System.out.println("Uniform variable " + name + " not found!");
}
}
public void setUniform(String name, Vector4f v){
this.setUniform(name, v.x, v.y, v.z, v.w);
}
public void setUniform(String name, Matrix4f m){
int loc = getUniformLocation(name);
if(loc >= 0){
matrix4fBuffer.clear();
m.store(matrix4fBuffer);
matrix4fBuffer.rewind();
GL20.glUniformMatrix4(loc, false, matrix4fBuffer);
} else{
System.out.println("Uniform variable " + name + " not found!");
}
}
public void setUniform(String name, Matrix3f m){
int loc = getUniformLocation(name);
if(loc >= 0){
matrix3fBuffer.clear();
m.store(matrix3fBuffer);
matrix3fBuffer.rewind();
GL20.glUniformMatrix4(loc, false, matrix3fBuffer);
} else{
System.out.println("Uniform variable " + name + " not found!");
}
}
public void setUniform(String name, float val){
int loc = getUniformLocation(name);
if(loc >= 0){
GL20.glUniform1f(loc, val);
} else{
System.out.println("Uniform variable " + name + " not found!");
}
}
public void setUniform(String name, int val){
int loc = getUniformLocation(name);
if(loc >= 0){
GL20.glUniform1i(loc, val);
} else{
System.out.println("Uniform variable " + name + " not found!");
}
}
public void setUniform(String name, boolean val){
int loc = getUniformLocation(name);
if(loc >= 0){
GL20.glUniform1i(loc, val ? 1 : 0);
} else{
System.out.println("Uniform variable " + name + " not found!");
}
}
public void printActiveUniforms(){
int nUniforms, location, maxLen;
String name;
maxLen = GL20.glGetProgram(handle, GL20.GL_ACTIVE_UNIFORM_MAX_LENGTH);
nUniforms = GL20.glGetProgram(handle, GL20.GL_ACTIVE_UNIFORMS);
System.out.println("\n Active Uniforms");
System.out.println("------------------------------------------------");
for(int i = 0; i < nUniforms; i++){
name = GL20.glGetActiveUniform(handle, i, maxLen);
location = GL20.glGetUniformLocation(handle, name);
System.out.println(" " + location + " | " + name);
}
}
public void printActiveAttribs(){
int location, maxLength, nAttribs;
String name;
maxLength = GL20.glGetProgram(handle, GL20.GL_ACTIVE_ATTRIBUTE_MAX_LENGTH);
nAttribs = GL20.glGetProgram(handle, GL20.GL_ACTIVE_ATTRIBUTES);
System.out.println("\n Active Atributes");
System.out.println("------------------------------------------------");
for(int i = 0; i < nAttribs; i++){
name = GL20.glGetActiveAttrib(handle, i, maxLength);
location = GL20.glGetAttribLocation(handle, name);
System.out.println(" " + location + " | " + name);
}
}
public int getUniformLocation(String name){
return GL20.glGetUniformLocation(handle, name);
}
public int getSubroutineIndex(String subroutine){
byte[] bytes = (subroutine + "\u0000").getBytes();
ByteBuffer phongBuf = BufferUtils.createByteBuffer(bytes.length + 1);
phongBuf.put(bytes);
phongBuf.rewind();
return GL40.glGetSubroutineIndex(this.getHandle(), GL20.GL_VERTEX_SHADER, phongBuf);
}
public void useVertexSubRoutines(int[] subroutines){
IntBuffer buf = BufferUtils.createIntBuffer(subroutines.length);
buf.put(subroutines);
buf.rewind();
GL40.glUniformSubroutinesu(GL20.GL_VERTEX_SHADER, buf);
}
public void useFragmentSubRoutines(int[] subroutines){
IntBuffer buf = BufferUtils.createIntBuffer(subroutines.length);
buf.put(subroutines);
buf.rewind();
GL40.glUniformSubroutinesu(GL20.GL_FRAGMENT_SHADER, buf);
}
}