#include "Shader.hpp" namespace d2 { /*explicit*/ Shader::Shader() { m_program = glCreateProgram(); load_shader(GL_VERTEX_SHADER, DUCK_ASSETS / "shaders" / "vertex.glsl"); load_shader(GL_FRAGMENT_SHADER, DUCK_ASSETS / "shaders" / "fragment.glsl"); glLinkProgram(m_program); GLint status = GL_FALSE; glGetProgramiv(m_program, GL_LINK_STATUS, &status); if (status == GL_FALSE) { size_t const SZ = 1024; char msg[SZ]; glGetProgramInfoLog(m_program, SZ, nullptr, msg); throw shader_error {"Cannot link program."}; } } /*virtual*/ Shader::~Shader() { glDeleteProgram(m_program); } void Shader::use() const { glUseProgram(m_program); } GLint Shader::attr(std::string const& name) const { use(); return glGetAttribLocation(m_program, name.c_str()); } GLint Shader::uniform(std::string const& name) const { use(); return glGetUniformLocation(m_program, name.c_str()); } void Shader::set_matrix(std::string const& name, glm::mat4 matrix) const { use(); glUniformMatrix4fv(uniform(name), 1, false, glm::value_ptr(matrix)); } GLuint Shader::load_shader(GLenum type, std::filesystem::path source_path) { // Load source // ----------- if (!std::filesystem::is_regular_file(source_path)) { throw shader_error {"Cannot find shader '" + source_path.string() + "'."}; } std::stringstream ss; std::ifstream file { source_path }; if (!file) { throw shader_error {"Cannot open shader '" + source_path.string() + "'"}; } ss << file.rdbuf(); // Compile source // -------------- std::string source = ss.str(); char const* c_source[] = {source.c_str()}; GLuint shader = glCreateShader(type); glShaderSource(shader, 1, c_source, nullptr); glCompileShader(shader); // check compilation status // ------------------------ GLint status = GL_FALSE; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); if (status == GL_FALSE) { size_t const SZ = 1024; char msg[SZ]; glGetShaderInfoLog(shader, SZ, nullptr, msg); std::stringstream ss; ss << "Cannot compile shader '" << source_path.string() << "'" << std::endl; ss << msg << std::endl; throw shader_error {ss.str()}; } glAttachShader(m_program, shader); return shader; } }