diff --git a/J/shader.h b/J/shader.h index 423e2b0..78eee00 100644 --- a/J/shader.h +++ b/J/shader.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #import "basic.h" @@ -21,28 +22,25 @@ // TODO: add error checking at set_uniforms? // TODO: use an uniform map? (benchmark first!) // TODO: allow arrays is uniforms (now all counts are 1) +// TODO: matrix attributes are not handled well (they take up 4 indices in the attributes) namespace J { - -enum { - ATTRIB_VERTEX, - ATTRIB_COLOR, - NUM_ATTRIBUTES -}; class shader { - // NOTE: it could be hardcoded to use vertex_shader and fragment_shader. - typedef std::map ShaderMap; + // NOTE: it could be hardcoded to use vertex_shader and fragment_shader, for ShaderMap. + typedef std::map ShaderMap; // shader_type -> shader_name + typedef std::map AttributeMap; // attribute_name -> attribute_index GLuint program; ShaderMap shaders; + AttributeMap attributes; public: // *********** // constructor - shader(std::string vertex_shader_filename, std::string fragment_shader_filename) : - program(0), shaders() { + shader(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename, const std::vector& attributes_to_use = std::vector()) : + program(0), shaders(), attributes() { program = glCreateProgram(); if(program == 0) { throw std::runtime_error("Program couldn't be created"); @@ -61,11 +59,9 @@ public: throw std::runtime_error(fragment_shader_filename + " couldn't be opened"); compile_shader(fragment_shader, GL_FRAGMENT_SHADER); } - { // TODO: think of a nice way to implement this - // Bind attribute locations. - // This needs to be done prior to linking. - glBindAttribLocation(program, ATTRIB_VERTEX, "position"); - glBindAttribLocation(program, ATTRIB_COLOR, "color"); + for (unsigned int i = 0; i < attributes_to_use.size(); ++i) { + glBindAttribLocation(program, i, attributes_to_use[i].c_str()); + attributes[attributes_to_use[i]] = i; } link_program(); @@ -95,6 +91,14 @@ public: void end() { glUseProgram(0); } + + // ***************** + // attribute setters + void set_attribute(const std::string& name, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr){ + const GLuint index = attributes[name]; + glVertexAttribPointer(index, size, type, normalized, stride, ptr); + glEnableVertexAttribArray(index); + } // *************** // uniform setters @@ -168,15 +172,15 @@ public: } // matrices (in ES2 only square matrices) - void set_uniform(char const* name, const GLfloat (&value)[16], GLboolean trans = GL_FALSE) const { + void set_uniform(char const* name, const GLfloat (&value)[16], GLboolean trans) const { glUniformMatrix4fv(glGetUniformLocation(program, name), 1, trans, value); } - void set_uniform(char const* name, const GLfloat (&value)[9], GLboolean trans = GL_FALSE) const { + void set_uniform(char const* name, const GLfloat (&value)[9], GLboolean trans) const { glUniformMatrix3fv(glGetUniformLocation(program, name), 1, trans, value); } - void set_uniform(char const* name, const GLfloat (&value)[4], GLboolean trans = GL_FALSE) const { + void set_uniform(char const* name, const GLfloat (&value)[4], GLboolean trans) const { glUniformMatrix2fv(glGetUniformLocation(program, name), 1, trans, value); } @@ -198,7 +202,7 @@ public: glGetProgramiv(program, GL_VALIDATE_STATUS, &status); if(status == GL_FALSE){ std::cerr << "validator reports:" << std::endl; - show_log(); + show_program_log(); throw std::runtime_error("Program not valid"); } #endif @@ -248,7 +252,7 @@ private: if(status == GL_FALSE || shader == 0) { std::cerr << "source:\n" << source << std::endl; std::cerr << "shader reports:" << std::endl; - show_log(); + show_shader_log(shader); throw std::runtime_error("Shader failed to compile"); } #endif @@ -260,17 +264,26 @@ private: glGetProgramiv(program, GL_LINK_STATUS, &status); if(status == GL_FALSE) { std::cerr << "linker reports:" << std::endl; - show_log(); + show_program_log(); throw std::runtime_error("Shader failed to link"); } #endif } - void show_log(std::ostream& out = std::cerr) { - GLsizei infoLength = 0; + void show_program_log(std::ostream& out = std::cerr) { + GLint infoLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLength); - char* infoBuffer = new GLchar[infoLength]; - glGetProgramInfoLog(program, infoLength, &infoLength, infoBuffer); + char* infoBuffer = new GLchar[infoLength+10]; + glGetProgramInfoLog(program, infoLength+10, &infoLength, infoBuffer); + out << infoBuffer << std::endl; + delete [] infoBuffer; + } + + void show_shader_log(GLuint shader, std::ostream& out = std::cerr) { + GLint infoLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength); + char* infoBuffer = new GLchar[infoLength+10]; + glGetShaderInfoLog(shader, infoLength+10, &infoLength, infoBuffer); out << infoBuffer << std::endl; delete [] infoBuffer; }