perlin-shadows/src/shader.cpp

216 lines
6.2 KiB
C++

#include "shader.h"
#include <iostream>
#include <string>
#include "renderer.h"
using namespace std;
Shader::Shader(const string &vertexShader, const string &fragmentShader,
const string &geometryShader) {
const auto vertexShaderId = CompileShader(vertexShader, GL_VERTEX_SHADER);
const auto fragmentShaderId =
CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
GLuint geometryShaderId{0};
id_ = glCreateProgram();
glAttachShader(id_, vertexShaderId);
CheckGLError("Error in attaching the vertex shader");
glAttachShader(id_, fragmentShaderId);
CheckGLError("Error in attaching the fragment shader");
if (!geometryShader.empty()) {
geometryShaderId = CompileShader(geometryShader, GL_GEOMETRY_SHADER);
glAttachShader(id_, geometryShaderId);
CheckGLError("Error in attaching the geometry shader");
}
glLinkProgram(id_);
CheckProgramivError(id_, GL_LINK_STATUS,
"Error when creating shader program");
glDeleteShader(vertexShaderId);
glDeleteShader(fragmentShaderId);
if (geometryShaderId != 0) {
glDeleteShader(geometryShaderId);
}
glUseProgram(id_);
PrintStatus();
}
Shader::~Shader() { glDeleteProgram(id_); }
bool Shader::CopyDataToUniform(const glm::mat4 &data,
const string &name) const {
const auto location = glGetUniformLocation(id_, name.c_str());
if (location == -1) {
return false;
}
glUniformMatrix4fv(location, 1, GL_FALSE, &data[0][0]);
return true;
}
bool Shader::CopyDataToUniform(const int count, const glm::mat4 *data,
const std::string &name) const {
const auto location = glGetUniformLocation(id_, name.c_str());
if (location == -1) {
return false;
}
glUniformMatrix4fv(location, count, GL_FALSE, &(*data)[0][0]);
return true;
}
bool Shader::CopyDataToUniform(const glm::vec4 &data,
const string &name) const {
const auto location = glGetUniformLocation(id_, name.c_str());
if (location == -1) {
return false;
}
glUniform4fv(location, 1, &data[0]);
return true;
}
bool Shader::CopyDataToUniform(const glm::vec3 &data,
const string &name) const {
const auto location = glGetUniformLocation(id_, name.c_str());
if (location == -1) {
return false;
}
glUniform3fv(location, 1, &data[0]);
return true;
}
bool Shader::CopyDataToUniform(const float data, const string &name) const {
const auto location = glGetUniformLocation(id_, name.c_str());
if (location == -1) {
return false;
}
glUniform1fv(location, 1, &data);
return true;
}
bool Shader::CopyDataToUniform(const int data, const string &name) const {
const auto location = glGetUniformLocation(id_, name.c_str());
if (location == -1) {
return false;
}
glUniform1iv(location, 1, &data);
return true;
}
bool Shader::CopyDataToUniform(const bool data, const string &name) const {
const auto location = glGetUniformLocation(id_, name.c_str());
if (location == -1) {
return false;
}
const int actualData = data;
glUniform1iv(location, 1, &actualData);
return true;
}
GLuint Shader::CompileShader(const std::string &shaderSource,
const GLenum shaderType) {
const GLuint id = glCreateShader(shaderType);
const auto shaderC_str = shaderSource.c_str();
glShaderSource(id, 1, &shaderC_str, nullptr);
glCompileShader(id);
CheckShaderivError(id, GL_COMPILE_STATUS,
"Error when compiling shader file:\n" + shaderSource);
return id;
}
void Shader::PrintStatus() const {
GLint rc;
GLsizei length;
glValidateProgram(id_);
glGetProgramiv(id_, GL_VALIDATE_STATUS, &rc);
if (rc == GL_TRUE) {
cout << "Shader is valid" << endl;
} else {
cerr << "Shader is not valid, status: " << rc << endl;
}
glGetProgramiv(id_, GL_INFO_LOG_LENGTH, &rc);
if (rc == 0) {
cout << "No shader info log";
} else {
auto *log = new GLchar[rc];
glGetProgramInfoLog(id_, rc, &length, log);
cout << "Shader info log: " << log;
delete[] log;
}
cout << endl;
glGetProgramiv(id_, GL_ATTACHED_SHADERS, &rc);
cout << "Number of attached shaders: " << rc << "\n";
glGetProgramiv(id_, GL_ACTIVE_ATTRIBUTES, &rc);
cout << "Number of active attributes: " << rc << "\n";
GLsizei bufSize;
glGetProgramiv(id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &bufSize);
GLint size;
GLenum type;
const auto attributeName = new GLchar[bufSize];
for (int i = 0; i < rc; ++i) {
glGetActiveAttrib(id_, i, bufSize, &length, &size, &type, attributeName);
cout << "\t" << attributeName << ": " << type << "\n";
}
delete[] attributeName;
cout << flush;
glGetProgramiv(id_, GL_ACTIVE_UNIFORMS, &rc);
cout << "Number of active uniforms: " << rc << "\n";
glGetProgramiv(id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &bufSize);
auto *uniformName = new GLchar[bufSize];
for (int i = 0; i < rc; ++i) {
glGetActiveUniform(id_, i, bufSize, &length, &size, &type, uniformName);
cout << "\t" << uniformName << ": " << type << "\n";
}
delete[] uniformName;
cout << flush;
Renderer::CheckGLError();
}
void Shader::CheckGLError(const string &errorMessage) {
const auto rc = glGetError();
if (rc != GL_NO_ERROR) {
cerr << errorMessage << endl;
throw runtime_error(reinterpret_cast<const char *>(gluErrorString(rc)));
}
}
void Shader::CheckProgramivError(const GLuint program, const GLenum pname,
const string &errorMessage) {
GLint rc;
glGetProgramiv(program, pname, &rc);
if (rc != GL_TRUE) {
cerr << errorMessage << endl;
GLsizei length, bufSize;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufSize);
const auto error = new GLchar[bufSize];
glGetProgramInfoLog(program, bufSize, &length, error);
throw runtime_error(error);
}
}
void Shader::CheckShaderivError(const GLuint shader, const GLenum pname,
const string &errorMessage) {
GLint rc;
glGetShaderiv(shader, pname, &rc);
if (rc != GL_TRUE) {
cerr << errorMessage << endl;
GLsizei length, bufSize;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &bufSize);
const auto error = new GLchar[bufSize];
glGetShaderInfoLog(shader, bufSize, &length, error);
throw runtime_error(error);
}
}