216 lines
6.2 KiB
C++
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);
|
|
}
|
|
}
|