|
From: Tapio V. <aa...@us...> - 2010-11-08 22:24:42
|
Module: performous
Branch: opengl2
Commit: e39aa0aeb2e35ee146bbb09f4ed8af191dfb5b9f
Author: Tapio Vierros <tap...@gm...>
Date: Tue Nov 9 00:15:52 2010 +0200
Shader class refactoring.
* loadFromMemory() split into compile() and link().
* Supports linking together arbitrary number of shaders.
* Program id is now private, accessible through dereference or cast to GLuint.
---
game/glshader.cc | 67 +++++++++++++++++++++++++++--------------------------
game/glshader.hh | 27 +++++++++++++--------
2 files changed, 51 insertions(+), 43 deletions(-)
diff --git a/game/glshader.cc b/game/glshader.cc
index 69f3928..083fca5 100644
--- a/game/glshader.cc
+++ b/game/glshader.cc
@@ -3,6 +3,7 @@
#include <fstream>
#include <stdexcept>
+#include <algorithm>
namespace {
@@ -39,20 +40,19 @@ namespace {
}
}
-Shader::ShaderMap Shader::shaders;
+Shader::ShaderMap Shader::shader_progs;
-Shader::Shader(): program(0), vert_shader(), frag_shader() {}
+Shader::Shader(): program(0) {}
-Shader::Shader(const std::string& vert_path, const std::string& frag_path, bool use) {
+Shader::Shader(const std::string& vert_path, const std::string& frag_path, bool use): program(0) {
loadFromFile(vert_path, frag_path, use);
}
Shader::~Shader() {
- shaders[program] = NULL;
+ shader_progs[program] = NULL;
glDeleteProgram(program);
- glDeleteShader(vert_shader);
- glDeleteShader(frag_shader);
+ std::for_each(shader_ids.begin(), shader_ids.end(), glDeleteShader);
//std::clog << "shader/info: Shader program " << (unsigned)program << " deleted." << std::endl;
}
@@ -62,53 +62,54 @@ void Shader::loadFromFile(const std::string& vert_path, const std::string& frag_
std::string fragstr = loadFile(frag_path);
const char* vert = vertstr.c_str();
const char* frag = fragstr.c_str();
- loadFromMemory(vert, frag, use);
+ compile(vert, GL_VERTEX_SHADER);
+ compile(frag, GL_FRAGMENT_SHADER);
+ link();
+ if (use) bind();
}
-void Shader::loadFromMemory(const char* vert_source, const char* frag_source, bool use) {
+void Shader::compile(const char* source, GLenum type) {
glutil::GLErrorChecker::reset();
- vert_shader = glCreateShader(GL_VERTEX_SHADER);
- frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
- glutil::GLErrorChecker shadererror("Shader::loadFromMemory - glCreateShader");
+ GLenum new_shader = glCreateShader(type);
+ glutil::GLErrorChecker shadererror("Shader::compile - glCreateShader");
- glShaderSource(vert_shader, 1, &vert_source, NULL);
- glShaderSource(frag_shader, 1, &frag_source, NULL);
- glutil::GLErrorChecker shadersourceerror("Shader::loadFromMemory - glShaderSource");
+ glShaderSource(new_shader, 1, &source, NULL);
+ glutil::GLErrorChecker shadersourceerror("Shader::compile - glShaderSource");
- glCompileShader(vert_shader);
- glGetShaderiv(vert_shader, GL_COMPILE_STATUS, &gl_response);
+ glCompileShader(new_shader);
+ glGetShaderiv(new_shader, GL_COMPILE_STATUS, &gl_response);
if (gl_response != GL_TRUE) {
- dumpInfoLog(vert_shader);
- throw std::runtime_error("Something went wrong compiling the vertex shader.");
+ dumpInfoLog(new_shader);
+ throw std::runtime_error("Something went wrong compiling the shader.");
}
- glCompileShader(frag_shader);
- glGetShaderiv(frag_shader, GL_COMPILE_STATUS, &gl_response);
- if (gl_response != GL_TRUE) {
- dumpInfoLog(frag_shader);
- throw std::runtime_error("Something went wrong compiling the fragment shader.");
- }
+ shader_ids.push_back(new_shader);
+}
+
+void Shader::link() {
glutil::GLErrorChecker::reset();
+ if (program) throw std::runtime_error("Shader already linked.");
+ // Create the program id
program = glCreateProgram();
- glutil::GLErrorChecker createprogramerror("Shader::loadFromMemory - glCreateProgram");
+ glutil::GLErrorChecker createprogramerror("Shader::link - glCreateProgram");
- glAttachShader(program, vert_shader);
- glAttachShader(program, frag_shader);
- glutil::GLErrorChecker attachshadererror("Shader::loadFromMemory - glAttachShader");
+ // Attach all compiled shaders to it
+ for (ShaderObjects::const_iterator it = shader_ids.begin(); it != shader_ids.end(); ++it)
+ glAttachShader(program, *it);
+ glutil::GLErrorChecker attachshadererror("Shader::link - glAttachShader");
+ // Link and check status
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &gl_response);
if (gl_response != GL_TRUE) {
dumpInfoLog(program);
- throw std::runtime_error("Something went wrong linking shader program.");
+ throw std::runtime_error("Something went wrong linking the shader program.");
}
- glutil::GLErrorChecker linkerror("Shader::loadFromMemory - glLinkProgram");
-
- shaders[program] = this;
+ glutil::GLErrorChecker linkerror("Shader::link - glLinkProgram");
- if (use) bind();
+ shader_progs[program] = this;
}
diff --git a/game/glshader.hh b/game/glshader.hh
index 73e0a11..57587e9 100644
--- a/game/glshader.hh
+++ b/game/glshader.hh
@@ -2,6 +2,7 @@
#include <string>
#include <map>
+#include <vector>
#include <GL/glew.h>
#include <boost/noncopyable.hpp>
@@ -13,15 +14,14 @@ struct Shader: public boost::noncopyable {
/** Loads the shader from files. */
void loadFromFile(const std::string& vert_path, const std::string& frag_path, bool use = false);
- /** Loads the shader from memory. */
- void loadFromMemory(const char* vert_source, const char* frag_source, bool use = false);
+ /** Compiles a shader of a given type. */
+ void compile(const char* source, GLenum type);
+ /** Links all compiled shaders to a shader program. */
+ void link();
/** Binds the shader into use. */
void bind();
- /** Get uniform location. Uses caching internally. */
- GLint operator[](const std::string& uniform);
-
/** Allow setting uniforms in a chain. Shader needs to be in use.*/
Shader& setUniform(const std::string& uniform, int value) {
@@ -49,28 +49,35 @@ struct Shader: public boost::noncopyable {
glUniform4f((*this)[uniform], x, y, z, w); return *this;
}
+ /** Get uniform location. Uses caching internally. */
+ GLint operator[](const std::string& uniform);
+
// Some operators
+ GLuint operator*() { return program; }
+ operator GLuint() { return program; }
operator bool() const { return program != 0; }
bool operator==(const Shader& rhs) const { return program == rhs.program; }
bool operator!=(const Shader& rhs) const { return program != rhs.program; }
- GLuint program, vert_shader, frag_shader; ///< shader object ids
-
/** Returns pointer to the currently used shader. */
static Shader* current() {
GLint i;
glGetIntegerv(GL_CURRENT_PROGRAM, &i);
- return shaders[i];
+ return shader_progs[i];
}
private:
- int gl_response;
+ GLuint program; ///< shader program object id
+ int gl_response; ///< save last return state
+
+ typedef std::vector<GLuint> ShaderObjects;
+ ShaderObjects shader_ids;
typedef std::map<std::string, GLint> UniformMap;
UniformMap uniforms; ///< Cached uniform locations, use operator[] to access
typedef std::map<GLint, Shader*> ShaderMap;
- static ShaderMap shaders; ///< Shader objects for reverse look-up by id
+ static ShaderMap shader_progs; ///< Shader objects for reverse look-up by id
};
|