#include #include #include #include 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 = Path::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