#include "ShaderLoader.h" #include #include #include "../inc/gl/glew.h" #include "../Renderer.h" #include "../PropertyLoader.h" ShaderLoader* ShaderLoader::mInstance = NULL; void ShaderLoader::Create() { if (mInstance == NULL) mInstance = new ShaderLoader(); } void ShaderLoader::Destroy() { if (mInstance != NULL) delete mInstance; mInstance = NULL; } ShaderLoader* ShaderLoader::Instance() { return mInstance; } void ShaderLoader::SetShaderPath(std::string shaderPath) { mShaderPath = shaderPath; } std::string ShaderLoader::GetShaderPath() { return mShaderPath; } // Load shader unsigned ShaderLoader::LoadShader(const char* vertexFileName, const char* fragmentFileName, std::map additionalProperties) { // Create the shaders unsigned vertexShaderID = glCreateShader(GL_VERTEX_SHADER); unsigned fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); std::string vertexPath = mShaderPath; std::string fragmentPath = mShaderPath; vertexPath.append(vertexFileName); fragmentPath.append(fragmentFileName); // Read the vertex shader code from the file std::string vertexShaderCode; std::ifstream vertexShaderStream(vertexPath, std::ios::in); if (vertexShaderStream.is_open()) { std::string line; while (getline(vertexShaderStream, line)) { ParseProperties(line, '$', additionalProperties); ParseProperties(line, '%', additionalProperties); vertexShaderCode += "\n" + line; } vertexShaderStream.close(); } // Read the fragment shader code from the file std::string fragmentShaderCode; std::ifstream fragmentShaderStream(fragmentPath, std::ios::in); if (fragmentShaderStream.is_open()) { std::string line = ""; while (getline(fragmentShaderStream, line)) { ParseProperties(line, '$', additionalProperties); ParseProperties(line, '%', additionalProperties); fragmentShaderCode += "\n" + line; } fragmentShaderStream.close(); } int result = GL_FALSE; int infoLogLength; // Compile vertex shader if (verbose) printf("Compiling shader : %s\n", vertexFileName); char const* vertexSourcePointer = vertexShaderCode.c_str(); glShaderSource(vertexShaderID, 1, &vertexSourcePointer, NULL); glCompileShader(vertexShaderID); // Check vertex shader glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &result); glGetShaderiv(vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength); if (infoLogLength > 0) { std::vector vertexShaderErrorMessage(infoLogLength); glGetShaderInfoLog(vertexShaderID, infoLogLength, NULL, &vertexShaderErrorMessage[0]); fprintf(stdout, "%s\n", &vertexShaderErrorMessage[0]); } // Compile fragment shader if (verbose) printf("Compiling shader : %s\n", fragmentFileName); char const * fragmentSourcePointer = fragmentShaderCode.c_str(); glShaderSource(fragmentShaderID, 1, &fragmentSourcePointer, NULL); glCompileShader(fragmentShaderID); // Check fragment shader glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &result); glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength); if (infoLogLength > 0) { std::vector fragmentShaderErrorMessage(infoLogLength); glGetShaderInfoLog(fragmentShaderID, infoLogLength, NULL, &fragmentShaderErrorMessage[0]); if (fragmentShaderErrorMessage.size() > 1) fprintf(stdout, "%s\n", &fragmentShaderErrorMessage[0]); } // Link the program if (verbose) fprintf(stdout, "Linking program\n"); unsigned programID = glCreateProgram(); glAttachShader(programID, vertexShaderID); glAttachShader(programID, fragmentShaderID); glLinkProgram(programID); // Check the program glGetProgramiv(programID, GL_LINK_STATUS, &result); glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength); std::vector programErrorMessage(glm::max(infoLogLength, int(1))); glGetProgramInfoLog(programID, infoLogLength, NULL, &programErrorMessage[0]); if (programErrorMessage.size() > 1) fprintf(stdout, "%s\n", &programErrorMessage[0]); glDeleteShader(vertexShaderID); glDeleteShader(fragmentShaderID); return programID; } ShaderLoader::ShaderLoader() { PropertyLoader::Create(); mShaderPath = "../Research/shaders/"; } ShaderLoader::~ShaderLoader() { } //************************************ // Parse shader properties, i.e. text between delimiters //************************************ void ShaderLoader::ParseProperties(std::string &line, char delimiter, std::map additionalProperties) { size_t open = 0, close = 0; bool inProperty = false; size_t i = 0; while(i < line.size()) { // Whenever a delimiter is found, toggle between in and out of property if (line[i] == delimiter) { if (inProperty) { // If we were in a property, this delimiter marks the end of it. // Replace all text between open and close by an additional property close = i; std::string identifier = line.substr(open + 1, close - open - 1); auto addProp = additionalProperties.find(identifier); std::string value; if (addProp != additionalProperties.end()) value = addProp->second; else value = PropertyLoader::Instance()->GetProperty("shader_" + identifier); if (value.empty()) return; line.replace(open, close - open + 1, value); i = open + value.size(); } else { // If we were NOT in a property, this is the start of one open = i; } inProperty = !inProperty; } i++; } }