154 lines
3.8 KiB
C++
154 lines
3.8 KiB
C++
#include <iostream>
|
|
#include <utility>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
#include "shader.hpp"
|
|
#include "utils.hpp"
|
|
|
|
namespace Fan
|
|
{
|
|
|
|
Rc<Shader> Shader::create(const std::string& vertex_shader_path,
|
|
const std::string& fragment_shader_path)
|
|
{
|
|
auto vertex_shader = compile_shader(vertex_shader_path, GL_VERTEX_SHADER);
|
|
if (!vertex_shader) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto fragment_shader = compile_shader(fragment_shader_path, GL_FRAGMENT_SHADER);
|
|
if (!fragment_shader) {
|
|
glDeleteShader(*vertex_shader);
|
|
return nullptr;
|
|
}
|
|
|
|
GLuint shader_program = glCreateProgram();
|
|
glAttachShader(shader_program, *vertex_shader);
|
|
glAttachShader(shader_program, *fragment_shader);
|
|
glLinkProgram(shader_program);
|
|
|
|
glDeleteShader(*vertex_shader);
|
|
glDeleteShader(*fragment_shader);
|
|
|
|
GLint success;
|
|
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
|
|
if (!success) {
|
|
GLint log_length = 0;
|
|
glGetProgramiv(shader_program, GL_INFO_LOG_LENGTH, &log_length);
|
|
|
|
if (log_length > 0) {
|
|
std::string log(log_length, ' ');
|
|
glGetProgramInfoLog(shader_program, log_length, nullptr, &log[0]);
|
|
std::cerr << "ERROR: SHADER: Could not link shader program: " << log << std::endl;
|
|
}
|
|
|
|
glDeleteProgram(shader_program);
|
|
return nullptr;
|
|
}
|
|
|
|
return make_rc<Shader>(shader_program);
|
|
}
|
|
|
|
Shader::~Shader()
|
|
{
|
|
glDeleteProgram(m_id);
|
|
}
|
|
|
|
Shader::Shader(Shader&& other) noexcept
|
|
: m_id(std::exchange(other.m_id, 0))
|
|
{
|
|
}
|
|
|
|
Shader& Shader::operator=(Shader&& other) noexcept
|
|
{
|
|
if (this == &other) { return *this; }
|
|
|
|
std::swap(m_id, other.m_id);
|
|
|
|
return *this;
|
|
}
|
|
|
|
GLuint Shader::get_id() const
|
|
{
|
|
return m_id;
|
|
}
|
|
|
|
GLint Shader::get_location(const std::string &name)
|
|
{
|
|
GLint location = glGetUniformLocation(m_id, name.c_str());
|
|
if (location == -1) {
|
|
std::cerr << "WARNING: SHADER: uniform " << name << " not found" << std::endl;
|
|
}
|
|
return location;
|
|
}
|
|
|
|
void Shader::set_int(const std::string& name, GLint value)
|
|
{
|
|
glUniform1i(get_location(name), value);
|
|
}
|
|
|
|
void Shader::set_float(const std::string& name, float value)
|
|
{
|
|
glUniform1f(get_location(name), value);
|
|
}
|
|
|
|
void Shader::set_vec3(const std::string& name, float x, float y, float z)
|
|
{
|
|
glUniform3f(get_location(name), x, y, z);
|
|
}
|
|
|
|
void Shader::set_vec3(const std::string& name, const glm::vec3& value)
|
|
{
|
|
glUniform3f(get_location(name), value.x, value.y, value.z);
|
|
}
|
|
|
|
void Shader::set_mat4(const std::string& name, const glm::mat4& value)
|
|
{
|
|
GLint location = get_location(name);
|
|
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
|
|
}
|
|
|
|
Opt<GLuint> Shader::compile_shader(const std::string& source_path,
|
|
GLenum shader_type)
|
|
{
|
|
auto shader_source = read_entire_file(source_path);
|
|
if (!shader_source) {
|
|
std::cerr << "ERROR: SHADER: Could not read shader " << source_path << std::endl;
|
|
return std::nullopt;
|
|
}
|
|
|
|
GLuint shader = glCreateShader(shader_type);
|
|
const char *shader_source_str = shader_source->c_str();
|
|
glShaderSource(shader, 1, &shader_source_str, nullptr);
|
|
glCompileShader(shader);
|
|
|
|
GLint success;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
|
if (!success) {
|
|
GLint log_length = 0;
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
|
|
|
|
if (log_length > 0) {
|
|
std::string log(log_length, ' ');
|
|
glGetShaderInfoLog(shader, log_length, nullptr, &log[0]);
|
|
std::cerr << "ERROR: SHADER: Could not compile shader: " << log << std::endl;
|
|
}
|
|
|
|
glDeleteShader(shader);
|
|
return std::nullopt;
|
|
}
|
|
|
|
return shader;
|
|
}
|
|
|
|
void Shader::use() const
|
|
{
|
|
if (m_id == 0) {
|
|
return;
|
|
}
|
|
|
|
glUseProgram(m_id);
|
|
}
|
|
|
|
} // namespace Fan
|