#include #include #include "util.hpp" #include "shaders.hpp" #define MAX_ERR_MSG_LEN 256 // Visit/Variant overload pattern // https://www.modernescpp.com/index.php/visiting-a-std-variant-with-the-overload-pattern/ template struct overload : Ts ... { using Ts::operator() ...; }; template overload(Ts...) -> overload; namespace shader { bool _compile_shader(uint *out_id, const char* filepath, int shader_type); bool load(uint* out_id, const char* vertex_filepath, const char* fragment_filepath) { uint vertex_id; if (!_compile_shader(&vertex_id, vertex_filepath, GL_VERTEX_SHADER)) return false; uint fragment_id; if (!_compile_shader(&fragment_id, fragment_filepath, GL_FRAGMENT_SHADER)) return false; uint program_id = glCreateProgram(); glAttachShader(program_id, vertex_id); glAttachShader(program_id, fragment_id); glLinkProgram(program_id); int status; glGetProgramiv(program_id, GL_LINK_STATUS, &status); if (status == GL_FALSE) { char err_msg[MAX_ERR_MSG_LEN]; glGetProgramInfoLog(program_id, MAX_ERR_MSG_LEN, NULL, err_msg); printf("Error linking shaders %s and %s\n", vertex_filepath, fragment_filepath); printf("Error msg: %s\n", err_msg); return false; } glDeleteShader(vertex_id); glDeleteShader(fragment_id); *out_id = program_id; return true; } void use(uint id) { glUseProgram(id); } void set_uniform(uint id, const char* name, uniform_variant value) { const auto visitor = overload { [id, name](int i) { glUniform1i(glGetUniformLocation(id, name), i); }, [id, name](float f) { glUniform1f(glGetUniformLocation(id, name), f); }, [id, name](bool b) { glUniform1i(glGetUniformLocation(id, name), b); }, [id, name](vec4 v) { glUniform4f(glGetUniformLocation(id, name), v.x, v.y, v.z, v.w); }, [id, name](vec3 v) { glUniform3f(glGetUniformLocation(id, name), v.x, v.y, v.z); }, [id, name](vec2 v) { glUniform2f(glGetUniformLocation(id, name), v.x, v.y); }, [id, name](vec4i v) { glUniform4i(glGetUniformLocation(id, name), v.x, v.y, v.z, v.w); }, [id, name](vec3i v) { glUniform3i(glGetUniformLocation(id, name), v.x, v.y, v.z); }, [id, name](vec2i v) { glUniform2i(glGetUniformLocation(id, name), v.x, v.y); }, }; visit(visitor, value); } // Privates bool _compile_shader(uint *out_id, const char* filepath, int shader_type) { array source; if (!read_file(&source, filepath)) return false; uint id = glCreateShader(shader_type); glShaderSource(id, 1, &source.data, (int*)&source.len); glCompileShader(id); int status; glGetShaderiv(id, GL_COMPILE_STATUS, &status); if (status == GL_FALSE) { char err_msg[MAX_ERR_MSG_LEN]; glGetShaderInfoLog(id, MAX_ERR_MSG_LEN, NULL, err_msg); printf("Error compiling shader %s\n", filepath); printf("%.*s\n", (int)source.len, source.data); printf("Error msg: %s\n", err_msg); } *out_id = id; return status == GL_TRUE; } } // namespace shader