#ifndef SHADER_H #define SHADER_H #include #include #include #include #include #include #include class shader { GLuint program; std::map shaders; public: shader(std::string vertex_shader_filename, std::string fragment_shader_filename) : program(0), shaders() { program = glCreateProgram(); if(program == 0) { throw std::runtime_error("Program couldn't be created"); } { std::ifstream vertex_shader(vertex_shader_filename); if(!vertex_shader) throw std::runtime_error(vertex_shader_filename + " couldn't be opened"); read_shader(vertex_shader, GL_VERTEX_SHADER); } { std::ifstream fragment_shader(fragment_shader_filename); if(!fragment_shader) throw std::runtime_error(fragment_shader_filename + " couldn't be opened"); read_shader(fragment_shader, GL_FRAGMENT_SHADER); } link_program(); } ~shader(){ begin(); for(auto & it : shaders){ GLuint shader = it.second; glDetachShader(program, shader); glDeleteShader(shader); } glDeleteProgram(program); end(); } void begin() { glUseProgram(program); } void end() { glUseProgram(0); } void set_uniform(char const* name, float x) const { glUniform1f(glGetUniformLocation(program, name), x); } void set_uniform(char const* name, float x, float y) const { glUniform2f(glGetUniformLocation(program, name), x, y); } void set_uniform(char const* name, float x, float y, float z) const { glUniform3f(glGetUniformLocation(program, name), x, y, z); } void set_uniform(char const* name, float x, float y, float z, float w) const { glUniform4f(glGetUniformLocation(program, name), x, y, z, w); } void set_uniform(char const* name, int x) const { glUniform1i(glGetUniformLocation(program, name), x); } void set_uniform(char const* name, int x, int y) const { glUniform2i(glGetUniformLocation(program, name), x, y); } void set_uniform(char const* name, int x, int y, int z) const { glUniform3i(glGetUniformLocation(program, name), x, y, z); } void set_uniform(char const* name, int x, int y, int z, int w) const { glUniform4i(glGetUniformLocation(program, name), x, y, z, w); } void set_matrix(char const* name, bool trans, const GLfloat* value) const { glUniformMatrix4fv(glGetUniformLocation(program, name), 1, trans, value); } void set_vector(char const* name, const GLfloat* value) const { glUniform4fv(glGetUniformLocation(program, name), 1, value); } void set_texture(const char* name, GLenum target, GLuint tex, int textureLocation) const { glActiveTexture(GL_TEXTURE0 + textureLocation); glBindTexture(target, tex); set_uniform(name, textureLocation); } private: void read_shader(std::istream& file, GLenum type) { // get the c-string std::string buffer((std::istreambuf_iterator(file)), std::istreambuf_iterator()); const char* sptr = buffer.c_str(); int ssize = buffer.size(); // create and compile shader GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &sptr, &ssize); glCompileShader(shader); // 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 << buffer << std::endl; std::cerr << "shader reports:\n" << infoBuffer << std::endl; delete [] infoBuffer; throw std::runtime_error("Shader failed to compile"); } // put it in tha map shaders[type] = shader; } void link_program() { // attach all shaders for(auto & it : shaders) { GLuint shader = it.second; glAttachShader(program, shader); } // link glLinkProgram(program); // check link status GLint status; glGetProgramiv(program, GL_LINK_STATUS, &status); if(status == GL_FALSE) { throw std::runtime_error("Shader failed to link"); } } }; #endif // SHADER_H