94 lines
3.1 KiB
C++
94 lines
3.1 KiB
C++
#include <typeinfo>
|
|
#include <stdio.h>
|
|
|
|
#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<typename ... Ts>
|
|
struct overload : Ts ... {
|
|
using Ts::operator() ...;
|
|
};
|
|
template<class... Ts> overload(Ts...) -> overload<Ts...>;
|
|
|
|
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<char> 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
|