voxspatium/src/Shader.cpp

201 lines
4.9 KiB
C++

#include "Shader.h"
/** Compile a shader from file */
void Shader::compileShader(const string& filePath, GLuint& id)
{
// Load shader file
std::ifstream shaderFile(filePath);
if(shaderFile.fail())
{
fatalError("Failed to open file @"+filePath);
}
string fileContents = "";
string line;
while(std::getline(shaderFile, line))
{
fileContents += line + "\n";
}
shaderFile.close();
const char* contentsPointer = fileContents.c_str();
// Create the shader with the contents of the file
glShaderSource(id, 1, &contentsPointer, nullptr);
glCompileShader(id);
GLint isCompiled = 0;
glGetShaderiv(id, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength);
// The maxLength includes the NULL character
std::vector<GLchar> errorLog(maxLength);
glGetShaderInfoLog(id, maxLength, &maxLength, &errorLog[0]);
glDeleteShader(id);
// Exit with failure.
std::printf("%s\n", &(errorLog[0]));
fatalError("Shader " + filePath + " failed to compile");
}
}
/** Create new shader from vertex and fragment files */
Shader& Shader::createShader(const string& vertexShaderFilePath, const string& fragmentShaderFilePath)
{
Shader* shader = new Shader();
shader->m_programID = glCreateProgram();
shader->m_vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
if(shader->m_vertexShaderID == 0)
{
fatalError("Vertex shader failed to be created!");
}
shader->m_fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
if(shader->m_fragmentShaderID == 0)
{
fatalError("Fragment shader failed to be created!");
}
Shader::compileShader(vertexShaderFilePath, shader->m_vertexShaderID);
Shader::compileShader(fragmentShaderFilePath, shader->m_fragmentShaderID);
return *shader;
}
/** Get uniform location */
GLuint Shader::getUniformLocation(const string& uniformName)
{
auto it = m_uniforms.find(uniformName);
if (it == m_uniforms.end())
{
// Get uniform location
GLint r = glGetUniformLocation(m_programID, uniformName.c_str());
if ( r == GL_INVALID_OPERATION || r < 0 )
log_warn("Uniform " + uniformName + " doesn't exist in program.");
// Add it to the cache
m_uniforms[uniformName] = r;
return r;
}
else
{
return it->second;
}
}
/** Link the shaders together */
void Shader::linkShaders()
{
// Attach our shaders to our program
glAttachShader(m_programID, m_vertexShaderID);
glAttachShader(m_programID, m_fragmentShaderID);
// Link our program
glLinkProgram(m_programID);
// Note the different functions here: glGetProgram* instead of glGetShader*.
GLint isLinked = 0;
glGetProgramiv(m_programID, GL_LINK_STATUS, (int *)&isLinked);
if(isLinked == GL_FALSE)
{
GLint maxLength = 0;
glGetProgramiv(m_programID, GL_INFO_LOG_LENGTH, &maxLength);
// The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetProgramInfoLog(m_programID, maxLength, &maxLength, &infoLog[0]);
// We don't need the program anymore.
glDeleteProgram(m_programID);
// Don't leak shaders either.
glDeleteShader(m_vertexShaderID);
glDeleteShader(m_fragmentShaderID);
fatalError("Shader linking failed!");
std::printf("%s\n", &(infoLog[0]));
}
// Always detach shaders after a successful link.
glDetachShader(m_programID, m_vertexShaderID);
glDetachShader(m_programID, m_fragmentShaderID);
glDeleteShader(m_vertexShaderID);
glDeleteShader(m_fragmentShaderID);
}
/** Bind attribute location */
void Shader::addAttribute(const string& attribName)
{
glBindAttribLocation(m_programID, m_attributes++, attribName.c_str());
}
/** Bind the shader for usage */
void Shader::start()
{
glUseProgram(m_programID);
}
/** Unbind the shader */
void Shader::stop()
{
glUseProgram(0);
}
void Shader::setUniform(const string& name, float x, float y, float z)
{
glUniform3f(getUniformLocation(name), x, y, z);
}
void Shader::setUniform(const string& name, const vec3& v)
{
glUniform3fv(getUniformLocation(name), 1, value_ptr(v));
}
void Shader::setUniform(const string& name, const dvec3& v)
{
glUniform3dv(getUniformLocation(name), 1, value_ptr(v));
}
void Shader::setUniform(const string& name, const vec4& v)
{
glUniform4fv(getUniformLocation(name), 1, value_ptr(v));
}
void Shader::setUniform(const string& name, const dvec4& v)
{
glUniform4dv(getUniformLocation(name), 1, value_ptr(v));
}
void Shader::setUniform(const string& name, const dmat4& m)
{
glUniformMatrix4dv(getUniformLocation(name), 1, GL_FALSE, value_ptr(m));
}
void Shader::setUniform(const string& name, const mat4& m)
{
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, value_ptr(m));
}
void Shader::setUniform(const string& name, const mat3& m)
{
glUniformMatrix3fv(getUniformLocation(name), 1, GL_FALSE, value_ptr(m));
}
void Shader::setUniform(const string& name, float val)
{
glUniform1f(getUniformLocation(name), val);
}
void Shader::setUniform(const string& name, int val)
{
glUniform1i(getUniformLocation(name), val);
}