diff --git a/J/fbo.h b/J/fbo.h index caa74b4..42fb2ca 100644 --- a/J/fbo.h +++ b/J/fbo.h @@ -12,6 +12,7 @@ // TODO: more error checking in debug build. // TODO: make texture class? for easier switching between linear/nearest interpolation for example +// NOTE: stencil attachment is not supported namespace J { @@ -31,16 +32,12 @@ public: // generate texture glGenTextures(1, &texture_id); - glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture_id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0); // attach depth - create_attach_renderbuffer(GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT); - - // attach stencil - //create_attach_renderbuffer(GL_STENCIL_INDEX, GL_STENCIL_ATTACHMENT); + create_attach_renderbuffer(GL_DEPTH_COMPONENT16, GL_DEPTH_ATTACHMENT); check_status(); @@ -84,9 +81,7 @@ private: void bind(){ glBindFramebuffer(GL_FRAMEBUFFER, fbo_number); - GLenum status = glGetError(); - if(status != GL_NO_ERROR) - throw std::runtime_error("i has error" + std::to_string(status) + "with fbo: " + std::to_string(fbo_number)); + check_error(); } void unbind(){ @@ -125,7 +120,7 @@ private: std::cout << "UNKNOWN FRAMEBUFFER ERROR" << std::endl; break; } - //throw std::runtime_error("I will not continu.."); + throw std::runtime_error("I will not continu.."); } void check_error(){ diff --git a/J/shader.h b/J/shader.h index fcbfafb..5852e82 100644 --- a/J/shader.h +++ b/J/shader.h @@ -13,6 +13,7 @@ // TODO: do glValidateProgram, like in the OpenGL template (see bottom) // TODO: add error checking at set_uniforms? // TODO: use an uniform map? (benchmark first!) +// TODO: allow arrays is uniforms (now all counts are 1) namespace J { @@ -23,6 +24,7 @@ enum { }; class shader { + // NOTE: it could be hardcoded to use vertex_shader and fragment_shader. typedef std::map ShaderMap; GLuint program; @@ -30,6 +32,8 @@ class shader { public: + // *********** + // constructor shader(std::string vertex_shader_filename, std::string fragment_shader_filename) : program(0), shaders() { program = glCreateProgram(); @@ -42,13 +46,13 @@ public: std::ifstream vertex_shader(vertex_shader_filename.c_str()); if(!vertex_shader) throw std::runtime_error(vertex_shader_filename + " couldn't be opened"); - read_shader(vertex_shader, GL_VERTEX_SHADER); + compile_shader(vertex_shader, GL_VERTEX_SHADER); } { // fragment shader std::ifstream fragment_shader(fragment_shader_filename.c_str()); if(!fragment_shader) throw std::runtime_error(fragment_shader_filename + " couldn't be opened"); - read_shader(fragment_shader, GL_FRAGMENT_SHADER); + compile_shader(fragment_shader, GL_FRAGMENT_SHADER); } { // TODO: think of a nice way to implement this // Bind attribute locations. @@ -69,12 +73,13 @@ public: glDeleteShader(shader); // NOTE: If a shader object to be deleted is attached to a program object, it will be flagged for deletion, but it will not be deleted until it is no longer attached to any program object } - - glDeleteProgram(program); - + end(); + glDeleteProgram(program); } + // ***** + // usage void begin() { glUseProgram(program); } @@ -83,6 +88,10 @@ public: glUseProgram(0); } + // *************** + // uniform setters + + // float vectors (multiple values) void set_uniform(char const* name, float x) const { glUniform1f(glGetUniformLocation(program, name), x); } @@ -99,6 +108,7 @@ public: glUniform4f(glGetUniformLocation(program, name), x, y, z, w); } + // integer vectors (multiple values) void set_uniform(char const* name, int x) const { glUniform1i(glGetUniformLocation(program, name), x); } @@ -114,32 +124,79 @@ public: void set_uniform(char const* name, int x, int y, int z, int w) const { glUniform4i(glGetUniformLocation(program, name), x, y, z, w); } + + // Float vectors (array) + void set_uniform(char const* name, const GLfloat (&value)[4]) const { + glUniform4fv(glGetUniformLocation(program, name), 1, value); + } + + void set_uniform(char const* name, const GLfloat (&value)[3]) const { + glUniform3fv(glGetUniformLocation(program, name), 1, value); + } + + void set_uniform(char const* name, const GLfloat (&value)[2]) const { + glUniform2fv(glGetUniformLocation(program, name), 1, value); + } + + void set_uniform(char const* name, const GLfloat (&value)[1]) const { + glUniform1fv(glGetUniformLocation(program, name), 1, value); + } + + // Integer vectors (array) + void set_uniform(char const* name, const GLint (&value)[4]) const { + glUniform4iv(glGetUniformLocation(program, name), 1, value); + } + + void set_uniform(char const* name, const GLint (&value)[3]) const { + glUniform3iv(glGetUniformLocation(program, name), 1, value); + } + + void set_uniform(char const* name, const GLint (&value)[2]) const { + glUniform2iv(glGetUniformLocation(program, name), 1, value); + } + + void set_uniform(char const* name, const GLint (&value)[1]) const { + glUniform1iv(glGetUniformLocation(program, name), 1, value); + } - // TODO: add support for other matrices (not only 4x4), in ES2 only square matrices - void set_matrix(char const* name, bool trans, const GLfloat* value) const { + // matrices (in ES2 only square matrices) + void set_uniform(char const* name, const GLfloat (&value)[16], GLboolean trans = GL_FALSE) const { glUniformMatrix4fv(glGetUniformLocation(program, name), 1, trans, value); } - // TODO: add support for other vectors (not only length 4) - void set_uniform(char const* name, const GLfloat* value, GLsizei count = 1) const { - glUniform4fv(glGetUniformLocation(program, name), count, value); + void set_uniform(char const* name, const GLfloat (&value)[9], GLboolean trans = GL_FALSE) const { + glUniformMatrix3fv(glGetUniformLocation(program, name), 1, trans, value); } - - // TODO: add support for other vectors (not only length 4) - void set_uniform(char const* name, const GLint* value, GLsizei count = 1) const { - glUniform4iv(glGetUniformLocation(program, name), count, value); + + void set_uniform(char const* name, const GLfloat (&value)[4], GLboolean trans = GL_FALSE) const { + glUniformMatrix2fv(glGetUniformLocation(program, name), 1, trans, value); } + // textures (see todo above) void set_texture(const char* name, GLenum target, GLuint tex, int textureLocation) const { glActiveTexture(GL_TEXTURE0 + textureLocation); glBindTexture(target, tex); set_uniform(name, textureLocation); } + + // ********* + // validator + void validate() { + GLint status; + glValidateProgram(program); + glGetProgramiv(program, GL_VALIDATE_STATUS, &status); + if(status == GL_FALSE){ + std::cerr << "validator reports:" << std::endl; + show_log(); + throw std::runtime_error("Program not valid"); + } + } private: - // FIXME: this also compiles, bad name - void read_shader(std::istream& file, GLenum type) { + // ******************* + // compiling / linking + void compile_shader(std::istream& file, GLenum type) { // get the c-string, the shortest way (not fastest) std::string buffer((std::istreambuf_iterator(file)), std::istreambuf_iterator()); const char* sptr = buffer.c_str(); @@ -150,21 +207,9 @@ private: glShaderSource(shader, 1, &sptr, &ssize); glCompileShader(shader); -#if defined(DEBUG) - // check compile status - GLint status = GL_FALSE; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if(status == GL_FALSE || shader == 0) { - GLsizei infoLength = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength); - char* infoBuffer = new GLchar[infoLength]; - glGetShaderInfoLog(shader, infoLength, &infoLength, infoBuffer); - std::cerr << "source:\n" << buffer << std::endl; - std::cerr << "shader reports:\n" << infoBuffer << std::endl; - delete [] infoBuffer; - throw std::runtime_error("Shader failed to compile"); - } -#endif + #if defined(DEBUG) + check_compile_status(shader, buffer); + #endif // put it in tha map shaders[type] = shader; @@ -181,47 +226,42 @@ private: // link glLinkProgram(program); -#if defined(DEBUG) - // check link status + #if defined(DEBUG) + check_link_status(); + #endif + } + + // *************** + // status checking + void check_compile_status(GLint shader, std::string source = "") { + GLint status = GL_FALSE; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if(status == GL_FALSE || shader == 0) { + std::cerr << "source:\n" << source << std::endl; + std::cerr << "shader reports:" << std::endl; + show_log(); + throw std::runtime_error("Shader failed to compile"); + } + } + + void check_link_status() { GLint status; glGetProgramiv(program, GL_LINK_STATUS, &status); if(status == GL_FALSE) { - GLsizei infoLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLength); - char* infoBuffer = new GLchar[infoLength]; - glGetProgramInfoLog(program, infoLength, &infoLength, infoBuffer); - std::cerr << "linker reports:\n" << infoBuffer << std::endl; - delete [] infoBuffer; + std::cerr << "linker reports:" << std::endl; + show_log(); throw std::runtime_error("Shader failed to link"); } -#endif - } - - /* - // Validate program before drawing. This is a good check, but only really necessary in a debug build. - - (BOOL)validateProgram:(GLuint)prog - { - GLint logLength, status; - - glValidateProgram(prog); - glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength); - if (logLength > 0) - { - GLchar *log = (GLchar *)malloc(logLength); - glGetProgramInfoLog(prog, logLength, &logLength, log); - NSLog(@"Program validate log:\n%s", log); - free(log); - } - - glGetProgramiv(prog, GL_VALIDATE_STATUS, &status); - if (status == 0) - return FALSE; - - return TRUE; - } - - */ - + } + + void show_log(std::ostream& out = std::cerr) { + GLsizei infoLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLength); + char* infoBuffer = new GLchar[infoLength]; + glGetProgramInfoLog(program, infoLength, &infoLength, infoBuffer); + out << infoBuffer << std::endl; + delete [] infoBuffer; + } }; } // namespace J