#include "shader.hpp" #include #include #include #include #include #include "dbc.hpp" #include #include #include namespace fs = std::filesystem; inline std::string read_file(const std::string& filename) { // load the file std::ifstream in_file{filename, std::ios::binary}; // get the size of the file std::stringstream in_str; in_str << in_file.rdbuf(); return in_str.str(); } void check_error(const std::string& what, unsigned int thing, GLenum check_type) { int success = 0; char infoLog[512] = {0}; if(check_type == GL_LINK_STATUS) { glGetProgramiv(thing, check_type, &success); if(!success) { glGetProgramInfoLog(thing, 512, NULL, infoLog); dbc::sentinel(std::format("ERROR: Program {} compile failed: {}", what, infoLog)); } } else { glGetShaderiv(thing, check_type, &success); if(!success) { glGetShaderInfoLog(thing, 512, NULL, infoLog); dbc::sentinel(std::format("ERROR: Shader {} compile failed: {}", what, infoLog)); } } } unsigned int Shader::load_shader(const std::string& filename, GLenum shader_type) { dbc::log($F("Loading shader {}", filename)); dbc::check(fs::exists(filename), std::format("shader file {} does not exist", filename)); // create the shader std::string shader_code = read_file(filename); const char* shader_code_ptr = shader_code.c_str(); int shader_id = glCreateShader(shader_type); glShaderSource(shader_id, 1, &shader_code_ptr, NULL); glCompileShader(shader_id); check_error(filename, shader_id, GL_COMPILE_STATUS); // check compile error return shader_id; } Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) { unsigned int vertex = load_shader(vertexPath, GL_VERTEX_SHADER); unsigned int fragment = load_shader(fragmentPath, GL_FRAGMENT_SHADER); ID = glCreateProgram(); glAttachShader(ID, vertex); glAttachShader(ID, fragment); glLinkProgram(ID); check_error("link", ID, GL_LINK_STATUS); glDeleteShader(vertex); glDeleteShader(fragment); } void Shader::use() const { glUseProgram(ID); } void Shader::cleanup() { glDeleteProgram(ID); } void Shader::setBool(const std::string &name, bool value) const { auto uniform = glGetUniformLocation(ID, name.c_str()); glUniform1i(uniform, (int)value); } void Shader::setInt(const std::string &name, int value) const { auto uniform = glGetUniformLocation(ID, name.c_str()); glUniform1i(uniform, value); } void Shader::setFloat(const std::string &name, float value) const { auto uniform = glGetUniformLocation(ID, name.c_str()); glUniform1f(uniform, value); } void Shader::setVec4(const std::string &name, float v1, float v2, float v3, float v4) const { auto uniform = glGetUniformLocation(ID, name.c_str()); glUniform4f(uniform, v1, v2, v3, v4); } void Shader::setVec4(const std::string &name, const glm::vec4& value) const { auto uniform = glGetUniformLocation(ID, name.c_str()); glUniform4fv(uniform, 1, &value[0]); } void Shader::setVec3(const std::string &name, const glm::vec3& value) const { auto uniform = glGetUniformLocation(ID, name.c_str()); glUniform3fv(uniform, 1, &value[0]); } void Shader::setVec3(const std::string &name, float v1, float v2, float v3) const { auto uniform = glGetUniformLocation(ID, name.c_str()); glUniform3f(uniform, v1, v2, v3); } void Shader::setMat4(const std::string &name, const glm::mat4& mat) const { unsigned int loc = glGetUniformLocation(ID, name.c_str()); glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(mat)); } void Shader::apply_material(const Material& material) { setVec3("material.ambient", material.ambient); setFloat("material.shininess", material.shininess); } void Shader::apply_lighting(const Lighting& lighting) { setInt("pointLightCount", lighting.positioned.size()); setInt("dirLightCount", lighting.directional.size()); for(size_t i = 0; i < lighting.directional.size(); i++) { apply_dir_light(lighting.directional[i], i); } for(size_t i = 0; i < lighting.positioned.size(); i++) { apply_point_light(lighting.positioned[i], i); } // set the first spotlight to the camera light if given size_t i = 0; // camera is optional, so only add if used if(lighting.camera.on) { apply_spot_light(lighting.camera, 0); i++; } // gross but that's fine for now for(; i < lighting.spot.size(); i++) { // need to be off by one because the camera is a spot light if(lighting.spot[i].on) { apply_spot_light(lighting.spot[i], i+1); } } // need +1 for the camera spot light setInt("spotLightCount", (int)i); } void Shader::apply_dir_light(const Light& light, size_t index) { dbc::check(index < MAX_LIGHTS, "too many directional lights"); // nasty, this needs to go setVec3(std::format("dirLights[{}].direction", index), light.direction); setVec3(std::format("dirLights[{}].ambient", index), light.ambient); setVec3(std::format("dirLights[{}].diffuse", index), light.diffuse); setVec3(std::format("dirLights[{}].specular", index), light.specular); } void Shader::apply_point_light(const Light& light, size_t index) { dbc::check(index < MAX_LIGHTS, "too many positioned lights"); // disgusting, crafting a string on every render? setVec3(std::format("pointLights[{}].position", index), light.position); setVec3(std::format("pointLights[{}].ambient", index), light.ambient); setVec3(std::format("pointLights[{}].diffuse", index), light.diffuse); setVec3(std::format("pointLights[{}].specular", index), light.specular); setFloat(std::format("pointLights[{}].constant", index), light.constant); setFloat(std::format("pointLights[{}].linear", index), light.linear); setFloat(std::format("pointLights[{}].quadratic", index), light.quadratic); } void Shader::apply_spot_light(const Light& light, size_t index) { dbc::check(index < MAX_LIGHTS, "too many spot lights"); // find a way to not make strings all the time setVec3(std::format("spotLights[{}].position", index), light.position); setVec3(std::format("spotLights[{}].direction", index), light.direction); setVec3(std::format("spotLights[{}].ambient", index), light.ambient); setVec3(std::format("spotLights[{}].diffuse", index), light.diffuse); setVec3(std::format("spotLights[{}].specular", index), light.specular); setFloat(std::format("spotLights[{}].constant", index), light.constant); setFloat(std::format("spotLights[{}].linear", index), light.linear); setFloat(std::format("spotLights[{}].quadratic", index), light.quadratic); setFloat(std::format("spotLights[{}].cut_off", index), glm::cos(glm::radians(light.cut_off))); setFloat(std::format("spotLights[{}].outer_cut_off", index), glm::cos(glm::radians(light.outer_cut_off))); }