See More

#include "GLSLProgram.h" #include "BengineErrors.h" #include #include namespace Bengine { //The : _numAttributes(0) ect. is an initialization list. It is a better way to initialize variables, since it avoids an extra copy. GLSLProgram::GLSLProgram() : _numAttributes(0), _programID(0), _vertexShaderID(0), _fragmentShaderID(0) { } GLSLProgram::~GLSLProgram() { } //Compiles the shaders into a form that your GPU can understand void GLSLProgram::compileShaders(const std::string& vertexShaderFilePath, const std::string& fragmentShaderFilepath) { //Vertex and fragment shaders are successfully compiled. //Now time to link them together into a program. //Get a program object. _programID = glCreateProgram(); //Create the vertex shader object, and store its ID _vertexShaderID = glCreateShader(GL_VERTEX_SHADER); if (_vertexShaderID == 0) { fatalError("Vertex shader failed to be created!"); } //Create the fragment shader object, and store its ID _fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); if (_fragmentShaderID == 0) { fatalError("Fragment shader failed to be created!"); } //Compile each shader compileShader(vertexShaderFilePath, _vertexShaderID); compileShader(fragmentShaderFilepath, _fragmentShaderID); } void GLSLProgram::linkShaders() { //Attach our shaders to our program glAttachShader(_programID, _vertexShaderID); glAttachShader(_programID, _fragmentShaderID); //Link our program glLinkProgram(_programID); //Note the different functions here: glGetProgram* instead of glGetShader*. GLint isLinked = 0; glGetProgramiv(_programID, GL_LINK_STATUS, (int *)&isLinked); if (isLinked == GL_FALSE) { GLint maxLength = 0; glGetProgramiv(_programID, GL_INFO_LOG_LENGTH, &maxLength); //The maxLength includes the NULL character std::vector errorLog(maxLength); glGetProgramInfoLog(_programID, maxLength, &maxLength, &errorLog[0]); //We don't need the program anymore. glDeleteProgram(_programID); //Don't leak shaders either. glDeleteShader(_vertexShaderID); glDeleteShader(_fragmentShaderID); //print the error log and quit std::printf("%s\n", &(errorLog[0])); fatalError("Shaders failed to link!"); } //Always detach shaders after a successful link. glDetachShader(_programID, _vertexShaderID); glDetachShader(_programID, _fragmentShaderID); glDeleteShader(_vertexShaderID); glDeleteShader(_fragmentShaderID); } //Adds an attribute to our shader. SHould be called between compiling and linking. void GLSLProgram::addAttribute(const std::string& attributeName) { glBindAttribLocation(_programID, _numAttributes++, attributeName.c_str()); } GLint GLSLProgram::getUniformLocation(const std::string& uniformName) { GLint location = glGetUniformLocation(_programID, uniformName.c_str()); if (location == GL_INVALID_INDEX) { fatalError("Uniform " + uniformName + " not found in shader!"); } return location; } //enable the shader, and all its attributes void GLSLProgram::use() { glUseProgram(_programID); //enable all the attributes we added with addAttribute for (int i = 0; i < _numAttributes; i++) { glEnableVertexAttribArray(i); } } //disable the shader void GLSLProgram::unuse() { glUseProgram(0); for (int i = 0; i < _numAttributes; i++) { glDisableVertexAttribArray(i); } } //Compiles a single shader file void GLSLProgram::compileShader(const std::string& filePath, GLuint id) { //Open the file std::ifstream shaderFile(filePath); if (shaderFile.fail()) { perror(filePath.c_str()); fatalError("Failed to open " + filePath); } //File contents stores all the text in the file std::string fileContents = ""; //line is used to grab each line of the file std::string line; //Get all the lines in the file and add it to the contents while (std::getline(shaderFile, line)) { fileContents += line + "\n"; } shaderFile.close(); //get a pointer to our file contents c string; const char* contentsPtr = fileContents.c_str(); //tell opengl that we want to use fileContents as the contents of the shader file glShaderSource(id, 1, &contentsPtr, nullptr); //compile the shader glCompileShader(id); //check for errors GLint success = 0; glGetShaderiv(id, GL_COMPILE_STATUS, &success); if (success == GL_FALSE) { GLint maxLength = 0; glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength); //The maxLength includes the NULL character std::vector errorLog(maxLength); glGetShaderInfoLog(id, maxLength, &maxLength, &errorLog[0]); //Provide the infolog in whatever manor you deem best. //Exit with failure. glDeleteShader(id); //Don't leak the shader. //Print error log and quit std::printf("%s\n", &(errorLog[0])); fatalError("Shader " + filePath + " failed to compile"); } } }