147 lines
4.5 KiB
C++
147 lines
4.5 KiB
C++
#include "shader.h"
|
|
#include "util/Log.h"
|
|
|
|
#include <fmt/format.h>
|
|
#include <fstream>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
Shader::Shader(std::string_view name, std::filesystem::path const &directory)
|
|
: program(glCreateProgram())
|
|
{
|
|
std::filesystem::path vertex_shader_path = directory / name;
|
|
vertex_shader_path.concat(".vert");
|
|
|
|
std::filesystem::path frag_shader_path = directory / name;
|
|
frag_shader_path.concat(".frag");
|
|
|
|
std::string vertex_shader_source = parse(vertex_shader_path);
|
|
std::string fragment_shader_source = parse(frag_shader_path);
|
|
|
|
GLuint vertex_shader = compile(vertex_shader_source, GL_VERTEX_SHADER);
|
|
GLuint fragment_shader = compile(fragment_shader_source, GL_FRAGMENT_SHADER);
|
|
|
|
glAttachShader(program, vertex_shader);
|
|
glAttachShader(program, fragment_shader);
|
|
|
|
glLinkProgram(program);
|
|
|
|
GLint linked = 0;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &linked);
|
|
|
|
if (linked == 0) {
|
|
Log::logger().warn(R"(Failed to link Shader "{}")", name);
|
|
}
|
|
|
|
#ifdef NDEBUG
|
|
glDetachShader(program, vertex_shader);
|
|
glDetachShader(program, fragment_shader);
|
|
|
|
glDeleteShader(vertex_shader);
|
|
glDeleteShader(fragment_shader);
|
|
#endif
|
|
|
|
Log::logger().trace(R"(Loaded Shader "{}")", name);
|
|
}
|
|
|
|
Shader::~Shader()
|
|
{
|
|
glDeleteProgram(program);
|
|
}
|
|
|
|
void Shader::bind() const
|
|
{
|
|
glUseProgram(program);
|
|
}
|
|
|
|
void Shader::unbind()
|
|
{
|
|
glUseProgram(0);
|
|
}
|
|
|
|
auto Shader::parse(const std::filesystem::path &path) -> std::string
|
|
{
|
|
std::fstream file;
|
|
file.open(path, std::ios::in);
|
|
|
|
if (!file.is_open()) {
|
|
Log::logger().critical(R"(Shader "{}" not found!)", path.string());
|
|
std::terminate();
|
|
}
|
|
|
|
return {(std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>())};
|
|
}
|
|
|
|
auto Shader::compile(std::string_view source, GLenum type) -> GLuint
|
|
{
|
|
GLuint program = glCreateShader(type);
|
|
auto const *src = source.data();
|
|
glShaderSource(program, 1, &src, nullptr);
|
|
glCompileShader(program);
|
|
|
|
int result{};
|
|
glGetShaderiv(program, GL_COMPILE_STATUS, &result);
|
|
|
|
if (result != GL_TRUE) {
|
|
int length{};
|
|
glGetShaderiv(program, GL_INFO_LOG_LENGTH, &length);
|
|
|
|
std::string message;
|
|
message.reserve(static_cast<unsigned>(length));
|
|
|
|
glGetShaderInfoLog(program, length, &length, message.data());
|
|
Log::logger().error("Shader compilation failed: {}", message);
|
|
|
|
return 0;
|
|
}
|
|
|
|
return program;
|
|
}
|
|
|
|
auto Shader::retrieveUniformLocation(std::string_view uniform_name) const -> GLint
|
|
{
|
|
if (uniform_location_cache.find(uniform_name.data()) != uniform_location_cache.end()) {
|
|
return uniform_location_cache[uniform_name.data()];
|
|
}
|
|
|
|
GLint location = glGetUniformLocation(program, uniform_name.data());
|
|
|
|
if (location != -1) {
|
|
uniform_location_cache[uniform_name.data()] = location;
|
|
} else {
|
|
Log::logger().warn(R"(Uniform "{}" not found.)", uniform_name);
|
|
}
|
|
|
|
return location;
|
|
}
|
|
|
|
template <typename T>
|
|
void Shader::set_uniform(std::string_view name, T value) const
|
|
{
|
|
GLint location = retrieveUniformLocation(name);
|
|
|
|
if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, int>) {
|
|
glUniform1i(location, (int)value);
|
|
} else if constexpr (std::is_same_v<T, unsigned>) {
|
|
glUniform1ui(location, value);
|
|
} else if constexpr (std::is_same_v<T, float>) {
|
|
glUniform1f(location, value);
|
|
} else if constexpr (std::is_same_v<T, glm::vec2>) {
|
|
glUniform2f(location, value.x, value.y); //NOLINT(cppcoreguidelines-pro-type-union-access)
|
|
} else if constexpr (std::is_same_v<T, glm::vec3>) {
|
|
glUniform3f(location, value.x, value.y, value.z); //NOLINT(cppcoreguidelines-pro-type-union-access)
|
|
} else if constexpr (std::is_same_v<T, glm::mat3>) {
|
|
glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(value));
|
|
} else if constexpr (std::is_same_v<T, glm::mat4>) {
|
|
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
|
|
}
|
|
}
|
|
|
|
template void Shader::set_uniform(std::string_view, bool) const;
|
|
template void Shader::set_uniform(std::string_view, int) const;
|
|
template void Shader::set_uniform(std::string_view, unsigned) const;
|
|
template void Shader::set_uniform(std::string_view, float) const;
|
|
template void Shader::set_uniform(std::string_view, glm::vec2) const;
|
|
template void Shader::set_uniform(std::string_view, glm::vec3) const;
|
|
template void Shader::set_uniform(std::string_view, glm::mat3) const;
|
|
template void Shader::set_uniform(std::string_view, glm::mat4) const;
|