#ifndef SHADER_CPP #define SHADER_CPP #include "shader.hpp" #include "misc.hpp" #include // include glad to get all the required OpenGL headers #include #include #include #include Shader::Shader(const std::string vertexPath, const std::string fragmentPath) { const char* vertexSource = this->readFile(vertexPath); const char* shaderSource = this->readFile(fragmentPath); const std::pair shaders = this->compileShaders(vertexSource, shaderSource); this->ID = this->linkShaderObjectsShaderProgram(shaders.first, shaders.second); } // use/activate the shader void Shader::use() { glUseProgram(ID); } // utility uniform functions 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::shaderFailedMessage(const unsigned int shader, const bool compilation) const { char infoLog[512]; const size_t sizeOfInfoLog = sizeof(infoLog) / sizeof(infoLog[0]); compilation ? glGetShaderInfoLog(shader, sizeOfInfoLog, NULL, infoLog) : glGetProgramInfoLog(shader, sizeOfInfoLog, NULL, infoLog); std::cout << "ERROR vertex shader compilation failed \n" << infoLog << std::endl; } int Shader::shaderSuccessful(const unsigned int shader, const bool compilation) const { // check if compilation was successful // int because glGetShaderiv requires int int success; // here we store info about compilation // check if compilation was successful compilation ? glGetShaderiv(shader, GL_COMPILE_STATUS, &success) : glGetProgramiv(shader, GL_LINK_STATUS, &success); // if not display compilation log if (!success) { shaderFailedMessage(shader, compilation); } return success; } unsigned int Shader::compileShader(const GLenum shaderType, const char *shaderSource) const { // we create vertex shader and assign its id to shader variable const unsigned int shaderID = glCreateShader(shaderType); // attach shader source code to shader object // from left: shader object to compile, how many strings as source code, actual source code (we leave the 4th as NULL) glShaderSource(shaderID, 1, &shaderSource, NULL); // compile shader glCompileShader(shaderID); if (!shaderSuccessful(shaderID, true)) return 0; return shaderID; } const char* Shader::readFile(const std::string fileName) const { // 1. retrieve the vertex/fragment source code from filePath std::string shaderCode; std::ifstream shaderFile; // ensure ifstream objects can throw exceptions: shaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); try { // open file shaderFile.open(fileName); std::stringstream shaderStream; // read file buffer contents into streams shaderStream << shaderFile.rdbuf(); // close file handlers shaderFile.close(); // convert stream into string shaderCode = shaderStream.str(); } catch(std::ifstream::failure const& e) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << std::endl; } const char* vShaderCode = shaderCode.c_str(); return vShaderCode; } unsigned int Shader::linkShaderObjectsShaderProgram(const unsigned int vertexShaders, const unsigned int fragmentShader) const { // link shader objects into shader program // will store shader program id // creates program const unsigned int programID = glCreateProgram(); // attachShaders glAttachShader(programID, vertexShaders); glAttachShader(programID, fragmentShader); // link shaders glLinkProgram(programID); if (!shaderSuccessful(programID, false)) return 0; // activate program // after that every shader and rendering call will use this program object glUseProgram(programID); // delete shaders (they are linked into shaderProgram and we do not need them anymore) glDeleteShader(vertexShaders); glDeleteShader(fragmentShader); if (programID == 0) print("Shader Program Linking Failed"); return programID; } std::pair Shader::compileShaders(const char* vertexShaderSource, const char* fragmentShaderSource) const { const unsigned int vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource); if (vertexShader == 0) { print("Vertex Shader Compilation Failed"); return std::make_pair(0, 0); } const unsigned int fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); if (fragmentShader == 0) { print("Fragment Shader Compilation Failed"); return std::make_pair(0, 0); } return std::make_pair(vertexShader, fragmentShader); } #endif