#include #include #include #include "shader.hpp" #include "utils.hpp" namespace Fan { Rc 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_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 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