201 lines
4.9 KiB
C++
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);
|
|
}
|