176 lines
5.3 KiB
C++
176 lines
5.3 KiB
C++
#include "ShaderLoader.h"
|
|
#include <vector>
|
|
#include <fstream>
|
|
#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<std::string, std::string> 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<char> 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<char> 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<char> 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<std::string, std::string> 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++;
|
|
}
|
|
}
|