package codechicken.lib.render; import org.lwjgl.opengl.ARBShaderObjects; import org.lwjgl.opengl.ARBVertexShader; import org.lwjgl.opengl.GL11; import org.lwjgl.util.vector.Matrix4f; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import static org.lwjgl.opengl.ARBShaderObjects.*; public class ShaderProgram { int programID; public ShaderProgram() { programID = glCreateProgramObjectARB(); if (programID == 0) { throw new RuntimeException("Unable to allocate shader program object."); } } public void attach(int shaderType, String resource) { InputStream stream = ShaderProgram.class.getResourceAsStream(resource); if (stream == null) { throw new RuntimeException("Unable to locate resource: " + resource); } attach(shaderType, stream); } public void use() { glUseProgramObjectARB(programID); } public static void restore() { glUseProgramObjectARB(0); } public void link() { glLinkProgramARB(programID); if (glGetObjectParameteriARB(programID, GL_OBJECT_LINK_STATUS_ARB) == GL11.GL_FALSE) { throw new RuntimeException("Error linking program: " + getInfoLog(programID)); } glValidateProgramARB(programID); if (glGetObjectParameteriARB(programID, GL_OBJECT_VALIDATE_STATUS_ARB) == GL11.GL_FALSE) { throw new RuntimeException("Error validating program: " + getInfoLog(programID)); } use(); onLink(); restore(); } public void attach(int shaderType, InputStream stream) { if (stream == null) { throw new RuntimeException("Invalid shader inputstream"); } int shaderID = 0; try { shaderID = glCreateShaderObjectARB(shaderType); if (shaderID == 0) { throw new RuntimeException("Unable to allocate shader object."); } try { glShaderSourceARB(shaderID, asString(stream)); } catch (IOException e) { throw new RuntimeException("Error reading inputstream.", e); } glCompileShaderARB(shaderID); if (glGetObjectParameteriARB(shaderID, GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE) { throw new RuntimeException("Error compiling shader: " + getInfoLog(shaderID)); } glAttachObjectARB(programID, shaderID); } catch (RuntimeException e) { glDeleteObjectARB(shaderID); throw e; } } public static String asString(InputStream stream) throws IOException { StringBuilder sb = new StringBuilder(); BufferedReader bin = new BufferedReader(new InputStreamReader(stream)); String line; while ((line = bin.readLine()) != null) { sb.append(line).append('\n'); } stream.close(); return sb.toString(); } private static String getInfoLog(int shaderID) { return glGetInfoLogARB(shaderID, glGetObjectParameteriARB(shaderID, GL_OBJECT_INFO_LOG_LENGTH_ARB)); } public int getUniformLoc(String name) { return ARBShaderObjects.glGetUniformLocationARB(programID, name); } public int getAttribLoc(String name) { return ARBVertexShader.glGetAttribLocationARB(programID, name); } public void uniformTexture(String name, int textureIndex) { ARBShaderObjects.glUniform1iARB(getUniformLoc(name), textureIndex); } public void onLink() { } public void glVertexAttributeMat4(int loc, Matrix4f matrix) { ARBVertexShader.glVertexAttrib4fARB(loc, matrix.m00, matrix.m01, matrix.m02, matrix.m03); ARBVertexShader.glVertexAttrib4fARB(loc + 1, matrix.m10, matrix.m11, matrix.m12, matrix.m13); ARBVertexShader.glVertexAttrib4fARB(loc + 2, matrix.m20, matrix.m21, matrix.m22, matrix.m23); ARBVertexShader.glVertexAttrib4fARB(loc + 3, matrix.m30, matrix.m31, matrix.m32, matrix.m33); } }