Renderer/src/main/java/electrosphere/renderer/shader/ShaderProgram.java
2024-07-30 17:31:47 -04:00

793 lines
38 KiB
Java

package electrosphere.renderer.shader;
import static org.lwjgl.opengl.GL11.GL_TRUE;
import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS;
import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.GL_VERTEX_SHADER;
import static org.lwjgl.opengl.GL20.glAttachShader;
import static org.lwjgl.opengl.GL20.glCompileShader;
import static org.lwjgl.opengl.GL20.glCreateProgram;
import static org.lwjgl.opengl.GL20.glCreateShader;
import static org.lwjgl.opengl.GL20.glDeleteShader;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetProgrami;
import static org.lwjgl.opengl.GL20.glGetShaderi;
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
import static org.lwjgl.opengl.GL20.glLinkProgram;
import static org.lwjgl.opengl.GL20.glShaderSource;
import static org.lwjgl.opengl.GL32.GL_GEOMETRY_SHADER;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.management.RuntimeErrorException;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL40;
import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.OpenGLState;
import electrosphere.util.FileUtils;
/**
* A shader program
*/
public class ShaderProgram {
//
//Program stuff
//
int vertexShader;
int geometryShader;
int fragmentShader;
int shaderId;
//
//Uniform locations
//
public int shaderVertexModelLoc;
public int shaderVertexViewLoc;
public int shaderVertexProjectionLoc;
public int shaderVertexViewPosLoc;
public int shaderVertexBonesLoc;
public int shaderVertexHasBonesLoc;
public int shaderVertexNumBonesLoc;
//Uniforms
public Map<Integer,Object> uniformMap = new HashMap<Integer,Object>();
//keeps track of programs that have already been compiled and returns them instead of recompiling from scratch
static Map<String,ShaderProgram> alreadyCompiledMap = new HashMap<String,ShaderProgram>();
public static ShaderProgram smart_assemble_shader(boolean ContainsBones, boolean apply_lighting){
//return shader if it has already been compiled
String shaderKey = ContainsBones + "-" + apply_lighting;
if(alreadyCompiledMap.containsKey(shaderKey)){
return alreadyCompiledMap.get(shaderKey);
}
String vertex_shader_path = "";
if(ContainsBones){
vertex_shader_path = "/Shaders/VertexShader.vs";
} else {
vertex_shader_path = "/Shaders/VertexShaderNoBones.vs";
}
String fragment_shader_path = "/Shaders/FragmentShader.fs";
//
//Create ShaderProgram object
//
ShaderProgram rVal = new ShaderProgram();
//
//Read in shader programs
//
String tempForReadingShaders = "";
try {
BufferedReader br = new BufferedReader(new InputStreamReader(FileUtils.getAssetFileAsStream(vertex_shader_path)));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
tempForReadingShaders = sb.toString();
} finally {
br.close();
}
} catch (IOException e) {
}
String vertexShaderSource = tempForReadingShaders;
//This try-catch block reads the FragmentShader source into memory
try {
BufferedReader br = new BufferedReader(new InputStreamReader(FileUtils.getAssetFileAsStream(fragment_shader_path)));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
tempForReadingShaders = sb.toString();
} finally {
br.close();
}
} catch (IOException e) {
}
String fragmentShaderSource = tempForReadingShaders;
//Creates a new shader object and assigns its 'pointer' to the integer "vertexShader"
rVal.vertexShader = glCreateShader(GL20.GL_VERTEX_SHADER);
//This alerts openGL to the presence of a vertex shader and points the shader at its source
glShaderSource(rVal.vertexShader, vertexShaderSource);
//Compiles the source for the vertex shader object
glCompileShader(rVal.vertexShader);
//The following tests if the vertex shader compiles successfully
int success;
success = glGetShaderi(rVal.vertexShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Vertex Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.vertexShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.vertexShader)));
}
//Creates and opengl object for a fragment shader and assigns its 'pointer' to the integer fragmentShader
rVal.fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
//This points the opengl shadder object to its proper source
glShaderSource(rVal.fragmentShader, fragmentShaderSource);
//This compiles the shader object
glCompileShader(rVal.fragmentShader);
//This tests for the success of the compile attempt
success = glGetShaderi(rVal.fragmentShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Fragment Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.fragmentShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.fragmentShader)));
}
//This creates a shader program opengl object and assigns its 'pointer' to the integer shaderProgram
rVal.shaderId = glCreateProgram();
//This attaches the vertex and fragment shaders to the program
glAttachShader(rVal.shaderId, rVal.vertexShader);
glAttachShader(rVal.shaderId, rVal.fragmentShader);
//This links the program to the GPU (I think its to the GPU anyway)
glLinkProgram(rVal.shaderId);
//Tests for the success of the shader program creation
success = glGetProgrami(rVal.shaderId, GL_LINK_STATUS);
if (success != GL_TRUE) {
throw new RuntimeException(glGetProgramInfoLog(rVal.shaderId));
}
//Deletes the individual shader objects to free up memory
glDeleteShader(rVal.vertexShader);
glDeleteShader(rVal.fragmentShader);
//
//Set locations
//
rVal.shaderVertexModelLoc = glGetUniformLocation(rVal.shaderId, "model");
rVal.shaderVertexViewLoc = glGetUniformLocation(rVal.shaderId, "view");
rVal.shaderVertexProjectionLoc = glGetUniformLocation(rVal.shaderId, "projection");
rVal.shaderVertexViewPosLoc = glGetUniformLocation(rVal.shaderId, "viewPos");
if(ContainsBones){
rVal.shaderVertexBonesLoc = glGetUniformLocation(rVal.shaderId, "bones");
rVal.shaderVertexNumBonesLoc = glGetUniformLocation(rVal.shaderId, "numBones");
}
rVal.shaderVertexHasBonesLoc = glGetUniformLocation(rVal.shaderId, "hasBones");
alreadyCompiledMap.put(shaderKey,rVal);
return rVal;
}
/**
* Intelligently assembles a shader for use in OIT part of render pipeline
* @param ContainsBones True if contains bones
* @param apply_lighting True if should apply lighting
* @return The int-pointer to the shader compiled
*/
public static ShaderProgram smartAssembleOITProgram(boolean ContainsBones, boolean apply_lighting){
//return shader if it has already been compiled
String shaderKey = "oit" + ContainsBones + "-" + apply_lighting;
if(alreadyCompiledMap.containsKey(shaderKey)){
return alreadyCompiledMap.get(shaderKey);
}
String vertex_shader_path = "";
if(ContainsBones){
vertex_shader_path = "/Shaders/oit/general/VertexShader.vs";
} else {
vertex_shader_path = "/Shaders/oit/general/VertexShaderNoBones.vs";
}
String fragment_shader_path = "/Shaders/oit/general/FragmentShader.fs";
//
//Create ShaderProgram object
//
ShaderProgram rVal = new ShaderProgram();
//
//Read in shader programs
//
String tempForReadingShaders = "";
try {
BufferedReader br = new BufferedReader(new InputStreamReader(FileUtils.getAssetFileAsStream(vertex_shader_path)));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
tempForReadingShaders = sb.toString();
} finally {
br.close();
}
} catch (IOException e) {
}
String vertexShaderSource = tempForReadingShaders;
//This try-catch block reads the FragmentShader source into memory
try {
BufferedReader br = new BufferedReader(new InputStreamReader(FileUtils.getAssetFileAsStream(fragment_shader_path)));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
tempForReadingShaders = sb.toString();
} finally {
br.close();
}
} catch (IOException e) {
}
String fragmentShaderSource = tempForReadingShaders;
//Creates a new shader object and assigns its 'pointer' to the integer "vertexShader"
rVal.vertexShader = glCreateShader(GL20.GL_VERTEX_SHADER);
//This alerts openGL to the presence of a vertex shader and points the shader at its source
glShaderSource(rVal.vertexShader, vertexShaderSource);
//Compiles the source for the vertex shader object
glCompileShader(rVal.vertexShader);
//The following tests if the vertex shader compiles successfully
int success;
success = glGetShaderi(rVal.vertexShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Vertex Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.vertexShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.vertexShader)));
}
//Creates and opengl object for a fragment shader and assigns its 'pointer' to the integer fragmentShader
rVal.fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
//This points the opengl shadder object to its proper source
glShaderSource(rVal.fragmentShader, fragmentShaderSource);
//This compiles the shader object
glCompileShader(rVal.fragmentShader);
//This tests for the success of the compile attempt
success = glGetShaderi(rVal.fragmentShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Fragment Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.fragmentShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.fragmentShader)));
}
//This creates a shader program opengl object and assigns its 'pointer' to the integer shaderProgram
rVal.shaderId = glCreateProgram();
//This attaches the vertex and fragment shaders to the program
glAttachShader(rVal.shaderId, rVal.vertexShader);
glAttachShader(rVal.shaderId, rVal.fragmentShader);
//This links the program to the GPU (I think its to the GPU anyway)
glLinkProgram(rVal.shaderId);
//Tests for the success of the shader program creation
success = glGetProgrami(rVal.shaderId, GL_LINK_STATUS);
if (success != GL_TRUE) {
throw new RuntimeException(glGetProgramInfoLog(rVal.shaderId));
}
//Deletes the individual shader objects to free up memory
glDeleteShader(rVal.vertexShader);
glDeleteShader(rVal.fragmentShader);
//
//Set locations
//
rVal.shaderVertexModelLoc = glGetUniformLocation(rVal.shaderId, "model");
rVal.shaderVertexViewLoc = glGetUniformLocation(rVal.shaderId, "view");
rVal.shaderVertexProjectionLoc = glGetUniformLocation(rVal.shaderId, "projection");
rVal.shaderVertexViewPosLoc = glGetUniformLocation(rVal.shaderId, "viewPos");
if(ContainsBones){
rVal.shaderVertexBonesLoc = glGetUniformLocation(rVal.shaderId, "bones");
rVal.shaderVertexNumBonesLoc = glGetUniformLocation(rVal.shaderId, "numBones");
}
rVal.shaderVertexHasBonesLoc = glGetUniformLocation(rVal.shaderId, "hasBones");
alreadyCompiledMap.put(shaderKey,rVal);
return rVal;
}
public static ShaderProgram load_default_shader_program(){
//
//Create ShaderProgram object
//
ShaderProgram rVal = new ShaderProgram();
//
//Read in shader programs
//
String tempForReadingShaders = "";
try {
BufferedReader br = new BufferedReader(new FileReader(FileUtils.getAssetFile("/Shaders/VertexShader.vs")));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
tempForReadingShaders = sb.toString();
} finally {
br.close();
}
} catch (IOException e) {
}
String vertexShaderSource = tempForReadingShaders;
//This try-catch block reads the FragmentShader source into memory
try {
BufferedReader br = new BufferedReader(new FileReader(FileUtils.getAssetFile("/Shaders/FragmentShader.fs")));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
tempForReadingShaders = sb.toString();
} finally {
br.close();
}
} catch (IOException e) {
}
String fragmentShaderSource = tempForReadingShaders;
//Creates a new shader object and assigns its 'pointer' to the integer "vertexShader"
rVal.vertexShader = glCreateShader(GL_VERTEX_SHADER);
//This alerts openGL to the presence of a vertex shader and points the shader at its source
glShaderSource(rVal.vertexShader, vertexShaderSource);
//Compiles the source for the vertex shader object
glCompileShader(rVal.vertexShader);
//The following tests if the vertex shader compiles successfully
int success;
success = glGetShaderi(rVal.vertexShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Vertex Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.vertexShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.vertexShader)));
}
//Creates and opengl object for a fragment shader and assigns its 'pointer' to the integer fragmentShader
rVal.fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
//This points the opengl shadder object to its proper source
glShaderSource(rVal.fragmentShader, fragmentShaderSource);
//This compiles the shader object
glCompileShader(rVal.fragmentShader);
//This tests for the success of the compile attempt
success = glGetShaderi(rVal.fragmentShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Fragment Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.fragmentShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.fragmentShader)));
}
//This creates a shader program opengl object and assigns its 'pointer' to the integer shaderProgram
rVal.shaderId = glCreateProgram();
//This attaches the vertex and fragment shaders to the program
glAttachShader(rVal.shaderId, rVal.vertexShader);
glAttachShader(rVal.shaderId, rVal.fragmentShader);
//This links the program to the GPU (I think its to the GPU anyway)
glLinkProgram(rVal.shaderId);
//Tests for the success of the shader program creation
success = glGetProgrami(rVal.shaderId, GL_LINK_STATUS);
if (success != GL_TRUE) {
throw new RuntimeException(glGetProgramInfoLog(rVal.shaderId));
}
//Deletes the individual shader objects to free up memory
glDeleteShader(rVal.vertexShader);
glDeleteShader(rVal.fragmentShader);
//
//Set locations
//
rVal.shaderVertexModelLoc = glGetUniformLocation(rVal.shaderId, "model");
rVal.shaderVertexViewLoc = glGetUniformLocation(rVal.shaderId, "view");
rVal.shaderVertexProjectionLoc = glGetUniformLocation(rVal.shaderId, "projection");
rVal.shaderVertexViewPosLoc = glGetUniformLocation(rVal.shaderId, "viewPos");
rVal.shaderVertexBonesLoc = glGetUniformLocation(rVal.shaderId, "bones");
rVal.shaderVertexNumBonesLoc = glGetUniformLocation(rVal.shaderId, "numBones");
rVal.shaderVertexHasBonesLoc = glGetUniformLocation(rVal.shaderId, "hasBones");
return rVal;
}
public static ShaderProgram loadSpecificShader(String vertexPath, String fragmentPath){
ShaderProgram rVal = new ShaderProgram();
//
//Read in shader programs
//
String vertexShaderSource = "";
String fragmentShaderSource = "";
try {
vertexShaderSource = FileUtils.getAssetFileAsString(vertexPath);
fragmentShaderSource = FileUtils.getAssetFileAsString(fragmentPath);
} catch(IOException ex){
}
//Creates a new shader object and assigns its 'pointer' to the integer "vertexShader"
rVal.vertexShader = glCreateShader(GL_VERTEX_SHADER);
//This alerts openGL to the presence of a vertex shader and points the shader at its source
glShaderSource(rVal.vertexShader, vertexShaderSource);
//Compiles the source for the vertex shader object
glCompileShader(rVal.vertexShader);
//The following tests if the vertex shader compiles successfully
int success;
success = glGetShaderi(rVal.vertexShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
List<Object> errorLines = new LinkedList<Object>();
LoggerInterface.loggerRenderer.WARNING("Failed to load " + vertexPath + " ... attempting alternatives");
//report failed to load shader
errorLines.add("Vertex Shader failed to compile!");
errorLines.add("Source File is: " + vertexPath);
errorLines.add("Source is: ");
errorLines.add(GL20.glGetShaderSource(rVal.vertexShader));
errorLines.add(new RuntimeException(GL20.glGetShaderInfoLog(rVal.vertexShader)));
// LoggerInterface.loggerRenderer.WARNING("Vertex Shader failed to compile!");
// LoggerInterface.loggerRenderer.WARNING("Source File is: " + vertexPath);
// LoggerInterface.loggerRenderer.WARNING("Source is: ");
// LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.vertexShader));
// LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.vertexShader)));
//attempt loading alternative shaders
List<String> availableAlternatives = Globals.shaderOptionMap.getAlternativesForFile(vertexPath);
int alternativesAttempted = 0;
if(availableAlternatives != null){
for(String alternative : availableAlternatives){
alternativesAttempted++;
//load file
try {
vertexShaderSource = FileUtils.getAssetFileAsString(alternative);
} catch (IOException e) {
LoggerInterface.loggerEngine.ERROR("Failed to load shader alternative " + alternative, e);
}
//Creates a new shader object and assigns its 'pointer' to the integer "vertexShader"
rVal.vertexShader = glCreateShader(GL_VERTEX_SHADER);
//This alerts openGL to the presence of a vertex shader and points the shader at its source
glShaderSource(rVal.vertexShader, vertexShaderSource);
//Compiles the source for the vertex shader object
glCompileShader(rVal.vertexShader);
//The following tests if the vertex shader compiles successfully
success = glGetShaderi(rVal.vertexShader, GL_COMPILE_STATUS);
if (success == GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Successfully loaded alternative shader " + alternative);
break;
} else {
errorLines.add("Vertex Shader failed to compile!");
errorLines.add("Source File is: " + vertexPath);
errorLines.add("Source is: ");
errorLines.add(GL20.glGetShaderSource(rVal.vertexShader));
errorLines.add(new RuntimeException(GL20.glGetShaderInfoLog(rVal.vertexShader)));
// LoggerInterface.loggerRenderer.WARNING("Vertex Shader failed to compile!");
// LoggerInterface.loggerRenderer.WARNING("Source File is: " + vertexPath);
// LoggerInterface.loggerRenderer.WARNING("Source is: ");
// LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.vertexShader));
// LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.vertexShader)));
}
}
if(success != GL_TRUE){
for(Object object : errorLines){
if(object instanceof String){
LoggerInterface.loggerRenderer.WARNING((String)object);
} else if(object instanceof RuntimeErrorException){
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", (RuntimeErrorException)object);
}
}
}
LoggerInterface.loggerRenderer.WARNING("Attempted " + alternativesAttempted + " alternative shaders");
}
}
//Creates and opengl object for a fragment shader and assigns its 'pointer' to the integer fragmentShader
rVal.fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
//This points the opengl shadder object to its proper source
glShaderSource(rVal.fragmentShader, fragmentShaderSource);
//This compiles the shader object
glCompileShader(rVal.fragmentShader);
//This tests for the success of the compile attempt
success = glGetShaderi(rVal.fragmentShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
List<Object> errorLines = new LinkedList<Object>();
LoggerInterface.loggerRenderer.WARNING("Failed to load " + fragmentPath + " ... attempting alternatives");
//report failed to load shader
errorLines.add("Fragment Shader failed to compile!");
errorLines.add("Source File is: " + fragmentPath);
errorLines.add("Source is: ");
errorLines.add(GL20.glGetShaderSource(rVal.fragmentShader));
errorLines.add(new RuntimeException(GL20.glGetShaderInfoLog(rVal.fragmentShader)));
// LoggerInterface.loggerRenderer.WARNING("Fragment Shader failed to compile!");
// LoggerInterface.loggerRenderer.WARNING("Source File is: " + fragmentPath);
// LoggerInterface.loggerRenderer.WARNING("Source is: ");
// LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.fragmentShader));
// LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.fragmentShader)));
//attempt loading alternative shaders
List<String> availableAlternatives = Globals.shaderOptionMap.getAlternativesForFile(fragmentPath);
int alternativesAttempted = 0;
if(availableAlternatives != null){
for(String alternative : availableAlternatives){
alternativesAttempted++;
//load file
try {
fragmentShaderSource = FileUtils.getAssetFileAsString(alternative);
} catch (IOException e) {
LoggerInterface.loggerEngine.ERROR("Failed to load shader alternative " + alternative, e);
}
//Creates a new shader object and assigns its 'pointer' to the integer "vertexShader"
rVal.fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
//This alerts openGL to the presence of a vertex shader and points the shader at its source
glShaderSource(rVal.fragmentShader, fragmentShaderSource);
//Compiles the source for the vertex shader object
glCompileShader(rVal.fragmentShader);
//The following tests if the vertex shader compiles successfully
success = glGetShaderi(rVal.fragmentShader, GL_COMPILE_STATUS);
if (success == GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Successfully loaded alternative shader " + alternative);
break;
} else {
errorLines.add("Fragment Shader failed to compile!");
errorLines.add("Source File is: " + fragmentPath);
errorLines.add("Source is: ");
errorLines.add(GL20.glGetShaderSource(rVal.fragmentShader));
errorLines.add(new RuntimeException(GL20.glGetShaderInfoLog(rVal.fragmentShader)));
// LoggerInterface.loggerRenderer.WARNING("Fragment Shader failed to compile!");
// LoggerInterface.loggerRenderer.WARNING("Source File is: " + fragmentPath);
// LoggerInterface.loggerRenderer.WARNING("Source is: ");
// LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.fragmentShader));
// LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.fragmentShader)));
}
}
if(success != GL_TRUE){
for(Object object : errorLines){
if(object instanceof String){
LoggerInterface.loggerRenderer.WARNING((String)object);
} else if(object instanceof RuntimeErrorException){
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", (RuntimeErrorException)object);
}
}
}
LoggerInterface.loggerRenderer.WARNING("Attempted " + alternativesAttempted + " alternative shaders");
}
}
//This creates a shader program opengl object and assigns its 'pointer' to the integer shaderProgram
rVal.shaderId = glCreateProgram();
//This attaches the vertex and fragment shaders to the program
glAttachShader(rVal.shaderId, rVal.vertexShader);
glAttachShader(rVal.shaderId, rVal.fragmentShader);
//This links the program to the GPU (I think its to the GPU anyway)
glLinkProgram(rVal.shaderId);
//Tests for the success of the shader program creation
success = glGetProgrami(rVal.shaderId, GL_LINK_STATUS);
if (success != GL_TRUE) {
LoggerInterface.loggerRenderer.ERROR(glGetProgramInfoLog(rVal.shaderId), new RuntimeException(glGetProgramInfoLog(rVal.shaderId)));
LoggerInterface.loggerRenderer.WARNING("Shader sources: " + vertexPath + " " + fragmentPath);
return Globals.defaultMeshShader;
// throw new RuntimeException(glGetProgramInfoLog(rVal.shaderProgram));
}
//Deletes the individual shader objects to free up memory
glDeleteShader(rVal.vertexShader);
glDeleteShader(rVal.fragmentShader);
//
//Set locations
//
rVal.shaderVertexModelLoc = glGetUniformLocation(rVal.shaderId, "model");
rVal.shaderVertexViewLoc = glGetUniformLocation(rVal.shaderId, "view");
rVal.shaderVertexProjectionLoc = glGetUniformLocation(rVal.shaderId, "projection");
rVal.shaderVertexViewPosLoc = glGetUniformLocation(rVal.shaderId, "viewPos");
return rVal;
}
public static ShaderProgram loadSpecificShader(String vertexPath, String geometryPath, String fragmentPath){
ShaderProgram rVal = new ShaderProgram();
//
//Read in shader programs
//
String vertexShaderSource = "";
String geometryShaderSource = "";
String fragmentShaderSource = "";
try {
vertexShaderSource = FileUtils.getAssetFileAsString(vertexPath);
geometryShaderSource = FileUtils.getAssetFileAsString(geometryPath);
fragmentShaderSource = FileUtils.getAssetFileAsString(fragmentPath);
} catch(IOException ex){
}
//Creates a new shader object and assigns its 'pointer' to the integer "vertexShader"
rVal.vertexShader = glCreateShader(GL_VERTEX_SHADER);
//This alerts openGL to the presence of a vertex shader and points the shader at its source
glShaderSource(rVal.vertexShader, vertexShaderSource);
//Compiles the source for the vertex shader object
glCompileShader(rVal.vertexShader);
//The following tests if the vertex shader compiles successfully
int success;
success = glGetShaderi(rVal.vertexShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Vertex Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.vertexShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.vertexShader)));
}
//Creates a new shader object and assigns its 'pointer' to the integer "vertexShader"
rVal.geometryShader = glCreateShader(GL_GEOMETRY_SHADER);
//This alerts openGL to the presence of a vertex shader and points the shader at its source
glShaderSource(rVal.geometryShader, geometryShaderSource);
//Compiles the source for the vertex shader object
glCompileShader(rVal.geometryShader);
//The following tests if the vertex shader compiles successfully
success = glGetShaderi(rVal.geometryShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Geometry Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.geometryShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.geometryShader)));
}
//Creates and opengl object for a fragment shader and assigns its 'pointer' to the integer fragmentShader
rVal.fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
//This points the opengl shadder object to its proper source
glShaderSource(rVal.fragmentShader, fragmentShaderSource);
//This compiles the shader object
glCompileShader(rVal.fragmentShader);
//This tests for the success of the compile attempt
success = glGetShaderi(rVal.fragmentShader, GL_COMPILE_STATUS);
if (success != GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Fragment Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL20.glGetShaderSource(rVal.fragmentShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL20.glGetShaderInfoLog(rVal.fragmentShader)));
}
//This creates a shader program opengl object and assigns its 'pointer' to the integer shaderProgram
rVal.shaderId = glCreateProgram();
//This attaches the vertex and fragment shaders to the program
glAttachShader(rVal.shaderId, rVal.vertexShader);
glAttachShader(rVal.shaderId, rVal.geometryShader);
glAttachShader(rVal.shaderId, rVal.fragmentShader);
//This links the program to the GPU (I think its to the GPU anyway)
glLinkProgram(rVal.shaderId);
//Tests for the success of the shader program creation
success = glGetProgrami(rVal.shaderId, GL_LINK_STATUS);
if (success != GL_TRUE) {
throw new RuntimeException(glGetProgramInfoLog(rVal.shaderId));
}
//Deletes the individual shader objects to free up memory
glDeleteShader(rVal.vertexShader);
glDeleteShader(rVal.geometryShader);
glDeleteShader(rVal.fragmentShader);
//
//Set locations
//
rVal.shaderVertexModelLoc = glGetUniformLocation(rVal.shaderId, "model");
rVal.shaderVertexViewLoc = glGetUniformLocation(rVal.shaderId, "view");
rVal.shaderVertexProjectionLoc = glGetUniformLocation(rVal.shaderId, "projection");
rVal.shaderVertexViewPosLoc = glGetUniformLocation(rVal.shaderId, "viewPos");
return rVal;
}
/**
* Sets the value of a uniform on this shader
* @param uniformLocation the uniform location
* @param value the value
*/
public void setUniform(int uniformLocation, Object value){
if(!uniformMap.containsKey(uniformLocation) || !uniformMap.get(uniformLocation).equals(value)){
uniformMap.put(uniformLocation,value);
if(value instanceof Matrix4f){
Matrix4f currentUniform = (Matrix4f)value;
GL40.glUniformMatrix4fv(uniformLocation, false, currentUniform.get(new float[16]));
}
if(value instanceof Matrix4d){
Matrix4d currentUniform = (Matrix4d)value;
GL40.glUniformMatrix4fv(uniformLocation, false, currentUniform.get(new float[16]));
}
if(value instanceof Vector3f){
Vector3f currentUniform = (Vector3f)value;
GL40.glUniform3fv(uniformLocation, currentUniform.get(BufferUtils.createFloatBuffer(3)));
}
if(value instanceof Integer){
int currentInform = (Integer)value;
GL40.glUniform1i(uniformLocation, currentInform);
}
}
}
//returned if the uniform isn't found
public static final int INVALID_UNIFORM_NAME = -1;
/**
* Tries to set a uniform
* @param uniformName The name of the uniform
* @param value The value to set the uniform to
*/
public void setUniform(OpenGLState openGLState, String uniformName, Object value){
int uniformLocation = glGetUniformLocation(this.getShaderId(), uniformName);
if(uniformLocation == INVALID_UNIFORM_NAME){
LoggerInterface.loggerRenderer.DEBUG_LOOP("Searched for uniform in a shader that does not contain it. Uniform name: \"" + uniformName + "\"");
} else {
setUniform(uniformLocation, value);
}
}
/**
* Gets the id of the shader
* @return The shader id
*/
public int getShaderId(){
return shaderId;
}
}