#include #include #include #include Shader::Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath, const char* TCSPath, const char* TESPath) { // 1. Retrieve the shader source code from file paths std::string vertexCode; std::string fragmentCode; std::string geometryCode; std::string TCSCode; std::string TESCode; std::ifstream vShaderFile; std::ifstream fShaderFile; std::ifstream gShaderFile; std::ifstream tcsShaderFile; std::ifstream tesShaderFile; // Ensure ifstream objects can throw exceptions: vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); tcsShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); tesShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try { // open files vShaderFile.open(vertexPath); fShaderFile.open(fragmentPath); std::stringstream vShaderStream, fShaderStream; // read file's buffer contents into streams vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); // close file handlers vShaderFile.close(); fShaderFile.close(); // convert stream into string vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); if (geometryPath != nullptr) { gShaderFile.open(geometryPath); std::stringstream gShaderStream; gShaderStream << gShaderFile.rdbuf(); gShaderFile.close(); geometryCode = gShaderStream.str(); } if (TCSPath != nullptr) { tcsShaderFile.open(TCSPath); std::stringstream tcsShaderStream; tcsShaderStream << tcsShaderFile.rdbuf(); tcsShaderFile.close(); TCSCode = tcsShaderStream.str(); } if (TESPath != nullptr) { tesShaderFile.open(TESPath); std::stringstream tesShaderStream; tesShaderStream << tesShaderFile.rdbuf(); tesShaderFile.close(); TESCode = tesShaderStream.str(); } } catch (std::ifstream::failure e) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; } const char* vShaderCode = vertexCode.c_str(); const char* fShaderCode = fragmentCode.c_str(); const char* gShaderCode = geometryPath != nullptr ? geometryCode.c_str() : nullptr; const char* tcsShaderCode = TCSPath != nullptr ? TCSCode.c_str() : nullptr; const char* tesShaderCode = TESPath != nullptr ? TESCode.c_str() : nullptr; // 2. compile shaders unsigned int vertex, fragment, geometry, tessControl, tessEval; // vertex shader vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &vShaderCode, NULL); glCompileShader(vertex); checkCompileErrors(vertex, "VERTEX"); // fragment Shader fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &fShaderCode, NULL); glCompileShader(fragment); checkCompileErrors(fragment, "FRAGMENT"); // Geometry Shader if (geometryPath != nullptr) { const char* gShaderCode = geometryCode.c_str(); geometry = glCreateShader(GL_GEOMETRY_SHADER); glShaderSource(geometry, 1, &gShaderCode, NULL); glCompileShader(geometry); checkCompileErrors(geometry, "GEOMETRY"); std::cout << "loaded GEO" << std::endl; } // Tessellation Control Shader if (TCSPath != nullptr) { tessControl = glCreateShader(GL_TESS_CONTROL_SHADER); glShaderSource(tessControl, 1, &tcsShaderCode, NULL); glCompileShader(tessControl); checkCompileErrors(tessControl, "TESS_CONTROL"); } if (TESPath != nullptr) { tessEval = glCreateShader(GL_TESS_EVALUATION_SHADER); glShaderSource(tessEval, 1, &tesShaderCode, NULL); glCompileShader(tessEval); checkCompileErrors(tessEval, "TESS_EVALUATION"); } // shader Program ID = glCreateProgram(); glAttachShader(ID, vertex); glAttachShader(ID, fragment); if (geometryPath != nullptr) glAttachShader(ID, geometry); if (TCSPath != nullptr) glAttachShader(ID, tessControl); if (TESPath != nullptr) glAttachShader(ID, tessEval); glLinkProgram(ID); checkCompileErrors(ID, "PROGRAM"); // delete the shaders as they're linked into our program now and no longer necessery glDeleteShader(vertex); glDeleteShader(fragment); if (geometryPath != nullptr) glDeleteShader(geometry); if (TCSPath != nullptr) glDeleteShader(tessControl); if (TESPath != nullptr) glDeleteShader(tessEval); } void Shader::use() { glUseProgram(ID); } // ------------------------------------------------------------------------ void Shader::setBool(const std::string& name, bool value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); } // ------------------------------------------------------------------------ void Shader::setInt(const std::string& name, int value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), value); } // ------------------------------------------------------------------------ void Shader::setFloat(const std::string& name, float value) const { glUniform1f(glGetUniformLocation(ID, name.c_str()), value); } // ------------------------------------------------------------------------ void Shader::setVec2(const std::string& name, const glm::vec2& value) const { glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); } void Shader::setVec2(const std::string& name, float x, float y) const { glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); } // ------------------------------------------------------------------------ void Shader::setVec3(const std::string& name, const glm::vec3& value) const { glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); } void Shader::setVec3(const std::string& name, float x, float y, float z) const { glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); } // ------------------------------------------------------------------------ void Shader::setVec4(const std::string& name, const glm::vec4& value) const { glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); } void Shader::setVec4(const std::string& name, float x, float y, float z, float w) { glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); } // ------------------------------------------------------------------------ void Shader::setMat2(const std::string& name, const glm::mat2& mat) const { glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); } // ------------------------------------------------------------------------ void Shader::setMat3(const std::string& name, const glm::mat3& mat) const { glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); } // ------------------------------------------------------------------------ void Shader::setMat4(const std::string& name, const glm::mat4& mat) const { glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); } // -------------------------------------------------------------------------- void Shader::setUniformBlock(const std::string& name, unsigned int uniformBlock) const { unsigned int uniformBlockIndex = glGetUniformBlockIndex(ID, name.c_str()); glUniformBlockBinding(ID, uniformBlockIndex, uniformBlock); } void Shader::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; } } }