package render;
import frame.ADXGame;
import io.ADXTextFile;
import org.lwjgl.opengl.ARBFragmentShader;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.ARBVertexShader;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
/**
* The Shader class. Creates, compiles and link the 2 shaders at creation and
* enables the user to pass variables to the shading program.
*
* @author Alexandre Desbiens
* @version 1.0.0
*/
public class ADXShader {
private int program = -1;
private int vertexShader = -1;
private int fragmentShader = -1;
/**
* Base constructor with the two path to the shader files.
*
* @param vertexFileName
* @param fragmentFileName
*/
public ADXShader(String vertexFileName, String fragmentFileName) {
if (vertexFileName != null) {
vertexShader = createShader(vertexFileName, ARBVertexShader.GL_VERTEX_SHADER_ARB);
}
if (fragmentFileName != null) {
fragmentShader = createShader(fragmentFileName, ARBFragmentShader.GL_FRAGMENT_SHADER_ARB);
}
program = ARBShaderObjects.glCreateProgramObjectARB();
if (program == 0) {
return;
}
if (vertexShader > 0) {
ARBShaderObjects.glAttachObjectARB(program, vertexShader);
}
if (fragmentShader > 0) {
ARBShaderObjects.glAttachObjectARB(program, fragmentShader);
}
ARBShaderObjects.glLinkProgramARB(program);
if (ARBShaderObjects.glGetObjectParameteriARB(program, ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB) == GL11.GL_FALSE) {
ADXGame.postWarning("Error while linking program");
ADXGame.postWarning(getLogInfo(program));
return;
}
ARBShaderObjects.glValidateProgramARB(program);
if (ARBShaderObjects.glGetObjectParameteriARB(program, ARBShaderObjects.GL_OBJECT_VALIDATE_STATUS_ARB) == GL11.GL_FALSE) {
ADXGame.postWarning("Error while validating program");
ADXGame.postWarning(getLogInfo(program));
return;
}
}
public int getProgram() {
return program;
}
/* Integer Uniforms */
public void setUniform(String name, int value) {
int loc = GL20.glGetUniformLocation(program, name);
if (loc == -1) {
postUniformWarning(name);
return;
}
GL20.glUniform1i(loc, value);
}
public void setUniform(String name, int val1, int val2) {
int loc = GL20.glGetUniformLocation(program, name);
if (loc == -1) {
postUniformWarning(name);
return;
}
GL20.glUniform2i(loc, val1, val2);
}
public void setUniform(String name, int val1, int val2, int val3) {
int loc = GL20.glGetUniformLocation(program, name);
if (loc == -1) {
postUniformWarning(name);
return;
}
GL20.glUniform3i(loc, val1, val2, val3);
}
public void setUniform(String name, int val1, int val2, int val3, int val4) {
int loc = GL20.glGetUniformLocation(program, name);
if (loc == -1) {
postUniformWarning(name);
return;
}
GL20.glUniform4i(loc, val1, val2, val3, val4);
}
/* Floating Point Uniforms */
public void setUniform(String name, float value) {
int loc = GL20.glGetUniformLocation(program, name);
if (loc == -1) {
postUniformWarning(name);
return;
}
GL20.glUniform1f(loc, value);
}
public void setUniform(String name, float val1, float val2) {
int loc = GL20.glGetUniformLocation(program, name);
if (loc == -1) {
postUniformWarning(name);
return;
}
GL20.glUniform2f(loc, val1, val2);
}
public void setUniform(String name, float val1, float val2, float val3) {
int loc = GL20.glGetUniformLocation(program, name);
if (loc == -1) {
postUniformWarning(name);
return;
}
GL20.glUniform3f(loc, val1, val2, val3);
}
public void setUniform(String name, float val1, float val2, float val3, float val4) {
int loc = GL20.glGetUniformLocation(program, name);
if (loc == -1) {
postUniformWarning(name);
return;
}
GL20.glUniform4f(loc, val1, val2, val3, val4);
}
/**
* Creates the shader file and links it to the program.
*
* @param fileName Name of the shader file on disk
* @param shaderType Type of shader, vertex or fragment
* @return ID of the created shader
*/
private int createShader(String fileName, int shaderType) {
int shader = 0;
try {
shader = ARBShaderObjects.glCreateShaderObjectARB(shaderType);
if (shader == 0) {
return 0;
}
ADXTextFile f = new ADXTextFile(fileName);
ARBShaderObjects.glShaderSourceARB(shader, f.readAll());
ARBShaderObjects.glCompileShaderARB(shader);
if (ARBShaderObjects.glGetObjectParameteriARB(shader, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE) {
ADXGame.postWarning("Error when compiling shader");
ADXGame.postWarning(getLogInfo(shader));
return -1;
}
return shader;
} catch (Exception e) {
e.printStackTrace();
ARBShaderObjects.glDeleteObjectARB(shader);
return -1;
}
}
private static String getLogInfo(int object) {
return ARBShaderObjects.glGetInfoLogARB(object, ARBShaderObjects.glGetObjectParameteriARB(object, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB));
}
private void postUniformWarning(String name) {
ADXGame.postWarning("Specified Shader uniform " + name + " has not been found.");
}
}