When writing the X11 (linux) implementation there was a problem with X11 defining a "Display" type and we also have a Display class in the engine. So to fix that problem and minimize the risk for running into other name conflicts. We move everything from global namespace.
197 lines
No EOL
3.7 KiB
C++
197 lines
No EOL
3.7 KiB
C++
|
|
#include <Spectre/Math/Color.h>
|
|
#include <Spectre/Graphics/OpenGL.h>
|
|
#include <Spectre/Graphics/ShaderProgram.h>
|
|
#include <Spectre/System/File.h>
|
|
|
|
namespace sp {
|
|
|
|
ShaderProgram::ShaderProgram() :
|
|
m_id (0)
|
|
{
|
|
}
|
|
|
|
ShaderProgram::~ShaderProgram()
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
void ShaderProgram::create()
|
|
{
|
|
destroy();
|
|
|
|
m_id = glCreateProgram();
|
|
}
|
|
|
|
void ShaderProgram::destroy()
|
|
{
|
|
if (m_id > 0) {
|
|
glDeleteProgram(m_id);
|
|
m_id = 0;
|
|
}
|
|
}
|
|
|
|
void ShaderProgram::addShader(const Shader& shader)
|
|
{
|
|
glAttachShader(m_id, shader.getHandle());
|
|
}
|
|
|
|
bool ShaderProgram::loadFromFile(const std::string& filename)
|
|
{
|
|
std::string extension = file::getExtension(filename);
|
|
|
|
// Meta file. load real shaders.
|
|
if (extension == "shader.glsl") {
|
|
|
|
// FIXME: This is ugly :)
|
|
std::string base_name = filename.substr(0, filename.length() - extension.length());
|
|
|
|
// vert and frag are not optional. they must exist.
|
|
return loadFromFile(base_name + "vert.glsl", Shader::Type::Vertex) &&
|
|
loadFromFile(base_name + "frag.glsl", Shader::Type::Fragment);
|
|
|
|
} else if (extension == "vert.glsl") {
|
|
return loadFromFile(filename, Shader::Type::Vertex);
|
|
} else if (extension == "frag.glsl") {
|
|
return loadFromFile(filename, Shader::Type::Fragment);
|
|
}
|
|
|
|
m_error = "Invalid file extension: " + extension;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ShaderProgram::loadFromFile(const std::string& filename, Shader::Type type)
|
|
{
|
|
Shader shader(type);
|
|
|
|
if (!shader.loadFromFile(filename)) {
|
|
m_error = shader.getName() + ": " + shader.getError();
|
|
return false;
|
|
}
|
|
|
|
addShader(shader);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ShaderProgram::loadFromMemory(const std::string& source, Shader::Type type)
|
|
{
|
|
Shader shader(type);
|
|
|
|
if (!shader.loadFromMemory(source)) {
|
|
m_error = shader.getError();
|
|
return false;
|
|
}
|
|
|
|
addShader(shader);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ShaderProgram::link()
|
|
{
|
|
glLinkProgram(m_id);
|
|
|
|
if (!isLinked()) {
|
|
m_error = fetchErrorLog();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ShaderProgram::isLinked() const
|
|
{
|
|
// Make sure we have a id first.
|
|
if (m_id) {
|
|
|
|
// Query OpenGL for link status.
|
|
GLint status;
|
|
glGetProgramiv(m_id, GL_LINK_STATUS, &status);
|
|
return status == GL_TRUE;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ShaderProgram::enable() const
|
|
{
|
|
glUseProgram(m_id);
|
|
}
|
|
|
|
void ShaderProgram::disable() const
|
|
{
|
|
glUseProgram(0);
|
|
}
|
|
|
|
std::string ShaderProgram::getLastError() const
|
|
{
|
|
return m_error;
|
|
}
|
|
|
|
bool ShaderProgram::setMVPMatrix(const Matrix4f& matrix)
|
|
{
|
|
return setUniform("u_MVP", matrix);
|
|
}
|
|
|
|
bool ShaderProgram::setUniform(const std::string& name, const Matrix4f& matrix) const
|
|
{
|
|
int loc;
|
|
if (getUniformLoc(name, loc)) {
|
|
glUniformMatrix4fv(loc, 1, GL_FALSE, matrix.e);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ShaderProgram::setAttribute(const std::string& name, const Matrix4f& matrix) const
|
|
{
|
|
int loc;
|
|
if (getAttribLoc(name, loc)) {
|
|
glVertexAttrib4fv(loc, matrix.e);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ShaderProgram::setUniform(const std::string& name, const Color& color) const
|
|
{
|
|
int loc;
|
|
if (getUniformLoc(name, loc)) {
|
|
Vector4f c = color.toRGBAf();
|
|
|
|
glUniform4f(loc, c.x, c.y, c.z, c.w);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ShaderProgram::getAttribLoc(const std::string& name, int& loc) const
|
|
{
|
|
loc = glGetAttribLocation(m_id, name.c_str());
|
|
if (loc < 0) {
|
|
m_error = "Attribute variable '" + name + "' was not found in shader.";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ShaderProgram::getUniformLoc(const std::string& name, int& loc) const
|
|
{
|
|
loc = glGetUniformLocation(m_id, name.c_str());
|
|
if (loc < 0) {
|
|
m_error = "Uniform variable '" + name + "' was not found in shader.";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::string ShaderProgram::fetchErrorLog()
|
|
{
|
|
GLchar buf[4096] = { '\0' };
|
|
|
|
glGetProgramInfoLog(m_id, sizeof(buf), NULL, buf);
|
|
|
|
return std::string(buf);
|
|
}
|
|
|
|
} // namespace sp
|