173 lines
4.3 KiB
C++
173 lines
4.3 KiB
C++
#include "shader.h"
|
|
|
|
Shader::Shader(std::string name, bool useGeom)
|
|
{
|
|
initializeOpenGLFunctions();
|
|
|
|
m_programId = glCreateProgram();
|
|
loadShader(Config::shaderPath() + name + ".vert", GL_VERTEX_SHADER);
|
|
loadShader(Config::shaderPath() + name + ".frag", GL_FRAGMENT_SHADER);
|
|
if (useGeom) {
|
|
loadShader(Config::shaderPath() + name + ".geom", GL_GEOMETRY_SHADER);
|
|
}
|
|
linkProgram();
|
|
}
|
|
|
|
Shader::~Shader()
|
|
{
|
|
glDeleteProgram(m_programId);
|
|
}
|
|
|
|
void Shader::loadShader(std::string name, GLenum shaderType)
|
|
{
|
|
GLuint shader = glCreateShader(shaderType);
|
|
|
|
|
|
std::string shaderSource = loadSource(name);
|
|
const char* shaderSourcePointer = shaderSource.c_str();
|
|
|
|
glShaderSource(shader, 1, &shaderSourcePointer, nullptr);
|
|
glCompileShader(shader);
|
|
|
|
if (checkCompilationStatus(shader)) {
|
|
m_shaders.insert(shader);
|
|
} else {
|
|
std::cerr
|
|
<< "Shader compilation failed" << std::endl
|
|
<< "File: " << name << std::endl
|
|
<< "*** Errors ***" << std::endl;
|
|
logCompilationError(shader);
|
|
|
|
std::cerr
|
|
<< "** Source code ***" << std::endl
|
|
<< shaderSource << std::endl;
|
|
|
|
glDeleteShader(shader);
|
|
|
|
}
|
|
}
|
|
|
|
std::string Shader::loadSource(std::string path)
|
|
{
|
|
std::ifstream shaderSourceFile(path);
|
|
std::string line;
|
|
std::stringstream source;
|
|
QRegularExpression re("^\\s*#\\s*include\\s+\"(.+)\"");
|
|
|
|
if (shaderSourceFile.is_open()) {
|
|
while (getline(shaderSourceFile, line)) {
|
|
QRegularExpressionMatch match = re.match(QString::fromStdString(line));
|
|
if (match.hasMatch()) {
|
|
QString includedFile = match.captured(1);
|
|
source << Shader::loadSource(Config::shaderPath() + includedFile.toStdString());
|
|
} else {
|
|
source << line << std::endl;
|
|
}
|
|
}
|
|
} else {
|
|
std::cerr << "Error while opening file " << path << std::endl;
|
|
}
|
|
|
|
return source.str();
|
|
}
|
|
|
|
|
|
bool Shader::checkCompilationStatus(GLuint shader)
|
|
{
|
|
GLint result;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
|
|
return result == GL_TRUE;
|
|
}
|
|
|
|
void Shader::logCompilationError(GLuint shader)
|
|
{
|
|
GLint maxLength = 0;
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
|
|
char* infoLog = new char[unsigned(maxLength)];
|
|
glGetShaderInfoLog(shader, maxLength, &maxLength, infoLog);
|
|
|
|
std::cerr << infoLog << std::endl;
|
|
|
|
delete[] infoLog;
|
|
}
|
|
|
|
void Shader::linkProgram()
|
|
{
|
|
for (GLuint shader: m_shaders) {
|
|
glAttachShader(m_programId, shader);
|
|
}
|
|
glLinkProgram(m_programId);
|
|
|
|
if (!checkLinkStatus()) {
|
|
std::cerr << "Linking program failed" << std::endl;
|
|
logLinkError();
|
|
glDeleteProgram(m_programId);
|
|
}
|
|
|
|
for (GLuint shader: m_shaders) {
|
|
glDetachShader(m_programId, shader);
|
|
glDeleteShader(shader);
|
|
}
|
|
m_shaders.clear();
|
|
|
|
}
|
|
|
|
bool Shader::checkLinkStatus()
|
|
{
|
|
GLint result;
|
|
glGetProgramiv(m_programId, GL_LINK_STATUS, &result);
|
|
return result == GL_TRUE;
|
|
}
|
|
|
|
void Shader::logLinkError()
|
|
{
|
|
GLint maxLength = 0;
|
|
glGetProgramiv(m_programId, GL_INFO_LOG_LENGTH, &maxLength);
|
|
char* infoLog = new char[unsigned(maxLength)];
|
|
glGetProgramInfoLog(m_programId, maxLength, &maxLength, infoLog);
|
|
|
|
std::cerr << infoLog << std::endl;
|
|
|
|
delete[] infoLog;
|
|
}
|
|
|
|
void Shader::setTexture(std::string location, GLuint slot, GLuint textureId, GLenum target)
|
|
{
|
|
bind();
|
|
glUniform1i(uniformLocation(location), int(slot - GL_TEXTURE0));
|
|
glActiveTexture(slot);
|
|
glBindTexture(target, textureId);
|
|
release();
|
|
}
|
|
|
|
void Shader::bind()
|
|
{
|
|
glUseProgram(m_programId);
|
|
}
|
|
|
|
void Shader::release()
|
|
{
|
|
glUseProgram(0);
|
|
}
|
|
|
|
GLint Shader::uniformLocation(std::string location)
|
|
{
|
|
try {
|
|
return m_uniformLocationMap.at(location);
|
|
} catch (const std::out_of_range&) {
|
|
m_uniformLocationMap[location] = glGetUniformLocation(m_programId, location.c_str());
|
|
return m_uniformLocationMap[location];
|
|
}
|
|
}
|
|
|
|
GLint Shader::attributeLocation(std::string location)
|
|
{
|
|
try {
|
|
return m_attributeLocationMap.at(location);
|
|
} catch (const std::out_of_range&) {
|
|
m_attributeLocationMap[location] = glGetAttribLocation(m_programId, location.c_str());
|
|
return m_attributeLocationMap[location];
|
|
}
|
|
}
|
|
|