|
|
@ -13,6 +13,7 @@ |
|
|
|
#include <fstream> |
|
|
|
#include <stdexcept> |
|
|
|
#include <map> |
|
|
|
#include <vector> |
|
|
|
#include <iterator> |
|
|
|
|
|
|
|
#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<GLenum, GLuint> ShaderMap; |
|
|
|
// NOTE: it could be hardcoded to use vertex_shader and fragment_shader, for ShaderMap.
|
|
|
|
typedef std::map<GLenum, GLuint> ShaderMap; // shader_type -> shader_name
|
|
|
|
typedef std::map<std::string, GLuint> 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<std::string>& attributes_to_use = std::vector<std::string>()) : |
|
|
|
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(); |
|
|
@ -96,6 +92,14 @@ public: |
|
|
|
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; |
|
|
|
} |
|
|
|