#pragma once // Adapted from LearnOpenGL // Must be the first include #include "Gedeng/Logger.h" #include // Other includes #include #include #include #include #include #include namespace Gedeng { class Shader { private: unsigned int load_shader(const char *path, GLuint type) { std::string code; std::ifstream file; file.open(path); std::stringstream shader_stream; shader_stream << file.rdbuf(); file.close(); code = shader_stream.str(); const char *code_charptr = code.c_str(); unsigned int shader = glCreateShader(type); glShaderSource(shader, 1, &code_charptr, NULL); glCompileShader(shader); checkCompileErrors(shader, "ANY"); return shader; } public: unsigned int ID; Shader() : ID(glCreateProgram()) { } Shader(const char *vertex_path, const char *fragment_path, const char *geometry_path = nullptr) : Shader() { add_vertex_shader(vertex_path); add_fragment_shader(fragment_path); if (geometry_path) add_geometry_shader(geometry_path); link(); } void add_vertex_shader(const char *path) { unsigned int shader = load_shader(path, GL_VERTEX_SHADER); glAttachShader(ID, shader); glDeleteShader(shader); } void add_fragment_shader(const char *path) { unsigned int shader = load_shader(path, GL_FRAGMENT_SHADER); glAttachShader(ID, shader); glDeleteShader(shader); } void add_geometry_shader(const char *path) { unsigned int shader = load_shader(path, GL_GEOMETRY_SHADER); glAttachShader(ID, shader); glDeleteShader(shader); } void add_tessellation_control_shader(const char *path) { unsigned int shader = load_shader(path, GL_TESS_CONTROL_SHADER); glAttachShader(ID, shader); glDeleteShader(shader); } void add_tessellation_evaluation_shader(const char *path) { unsigned int shader = load_shader(path, GL_TESS_EVALUATION_SHADER); glAttachShader(ID, shader); glDeleteShader(shader); } void add_transform_feedback(const char **varyings, size_t varying_count) { for (size_t i = 0; i < varying_count; i++) { // TODO: Is this loop required? glTransformFeedbackVaryings(ID, varying_count, varyings, GL_INTERLEAVED_ATTRIBS); } } void link() { glLinkProgram(ID); checkCompileErrors(ID, "PROGRAM"); } // activate the shader // ------------------------------------------------------------------------ void use() { glUseProgram(ID); } // utility uniform functions // ------------------------------------------------------------------------ void setBool(const std::string &name, bool value) const { glUniform1i(getUniformLocation(name), (int)value); } // ------------------------------------------------------------------------ void setInt(const std::string &name, int value) const { glUniform1i(getUniformLocation(name), value); } // ------------------------------------------------------------------------ void setFloat(const std::string &name, float value) const { glUniform1f(getUniformLocation(name), value); } // ------------------------------------------------------------------------ void setVec2(const std::string &name, const glm::vec2 &value) const { glUniform2fv(getUniformLocation(name), 1, &value[0]); } void setVec2(const std::string &name, float x, float y) const { glUniform2f(getUniformLocation(name), x, y); } // ------------------------------------------------------------------------ void setVec3(const std::string &name, const glm::vec3 &value) const { glUniform3fv(getUniformLocation(name), 1, &value[0]); } void setVec3(const std::string &name, float x, float y, float z) const { glUniform3f(getUniformLocation(name), x, y, z); } // ------------------------------------------------------------------------ void setVec4(const std::string &name, const glm::vec4 &value) const { glUniform4fv(getUniformLocation(name), 1, &value[0]); } void setVec4(const std::string &name, float x, float y, float z, float w) { glUniform4f(getUniformLocation(name), x, y, z, w); } // ------------------------------------------------------------------------ void setMat2(const std::string &name, const glm::mat2 &mat) const { glUniformMatrix2fv(getUniformLocation(name), 1, GL_FALSE, &mat[0][0]); } // ------------------------------------------------------------------------ void setMat3(const std::string &name, const glm::mat3 &mat) const { glUniformMatrix3fv(getUniformLocation(name), 1, GL_FALSE, &mat[0][0]); } // ------------------------------------------------------------------------ void setMat4(const std::string &name, const glm::mat4 &mat) const { glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &mat[0][0]); } private: GLint getUniformLocation(const std::string &name) const { GLint location = glGetUniformLocation(ID, name.c_str()); if (location == -1) { GG_CORE_ERROR("Invalid uniform location: " + name); } return location; } // utility function for checking shader compilation/linking errors. // ------------------------------------------------------------------------ void checkCompileErrors(GLuint shader, std::string type) { GLint success; GLchar infoLog[1024]; if (type != "PROGRAM") { glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader, 1024, NULL, infoLog); std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; } } else { glGetProgramiv(shader, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shader, 1024, NULL, infoLog); std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; } } } }; } // namespace Gedeng