6#include <brenta/renderer/opengl/shader.hpp>
7#include <brenta/logger.hpp>
9#include <glm/gtc/type_ptr.hpp>
13using namespace brenta;
17 if (this->
id == 0)
return;
19 glDeleteProgram(this->
id);
21 EVENT(Logger::Event::Lifetime,
"Shader: destroyed {}", this->
id);
27Shader::create(
const tenno::vector<Shader::Object> &objects)
29 tenno::vector<Shader::Id> compiled_shaders = {};
30 if (!compile_shaders(compiled_shaders, objects))
32 ERROR(
"shader: error compiling shader");
36 std::optional<Shader::Id>
id =
37 Shader::link_program(compiled_shaders,
nullptr, 0);
40 Shader::clean_compilation(compiled_shaders);
41 EVENT(Logger::Event::Lifetime,
"Shader: initialized {}", *
id);
46Shader::create(
const GLchar **feedback_varyings,
int num_varyings,
47 const tenno::vector<Shader::Object> &objects)
49 tenno::vector<Shader::Id> compiled_shaders = {};
50 if (!compile_shaders(compiled_shaders, objects))
52 ERROR(
"shader: error compiling shader");
56 std::optional<Shader::Id>
id =
57 Shader::link_program(compiled_shaders, feedback_varyings, num_varyings);
60 Shader::clean_compilation(compiled_shaders);
61 EVENT(Logger::Event::Lifetime,
"Shader: initialized {}", *
id);
65bool Shader::compile_shaders(tenno::vector<Shader::Id> &compiled,
66 const tenno::vector<Shader::Object> &objects)
68 for (
const auto& obj : objects)
70 GLenum shader_type_gl;
73 case Shader::Type::Fragment: shader_type_gl = GL_FRAGMENT_SHADER;
break;
74 case Shader::Type::Vertex: shader_type_gl = GL_VERTEX_SHADER;
break;
75 case Shader::Type::Geometry: shader_type_gl = GL_GEOMETRY_SHADER;
break;
76 case Shader::Type::Compute: shader_type_gl = GL_COMPUTE_SHADER;
break;
77 default: shader_type_gl = 0;
break;
80 unsigned int shader = glCreateShader(shader_type_gl);
81 const GLchar *src = obj.src.c_str();
82 glShaderSource(shader, 1, &src, NULL);
83 glCompileShader(shader);
84 if (!Shader::check_compile_errors(shader))
87 compiled.push_back(shader);
92bool Shader::compile_shaders([[maybe_unused]] tenno::vector<Shader::Id> &compiled)
97std::optional<Shader::Id>
98Shader::link_program(tenno::vector<Shader::Id>& compiled_shaders,
99 const GLchar **feedback_varyings,
int num_varyings)
101 Shader::Id
id = glCreateProgram();
102 std::for_each(compiled_shaders.begin(), compiled_shaders.end(),
103 [&
id](
auto shader) { glAttachShader(id, shader); });
105 if (feedback_varyings !=
nullptr)
106 glTransformFeedbackVaryings(
id, num_varyings, feedback_varyings,
107 GL_INTERLEAVED_ATTRIBS);
110 if (!Shader::check_link_errors(
id))
115void Shader::clean_compilation(tenno::vector<Shader::Id>& compiled_shaders)
117 std::for_each(compiled_shaders.begin(), compiled_shaders.end(),
118 [](
auto shader) { glDeleteShader(shader); });
122Shader::Id Shader::get_id()
const
130 glUseProgram(this->get_id());
133 if ((err = glGetError()) != GL_NO_ERROR)
135 ERROR(
"Shader::use: error using shader: {}", err);
141bool Shader::set_bool(Shader::Id
id,
const std::string& unif_name,
bool value)
143 GLint location = glGetUniformLocation(
id, unif_name.c_str());
147 ERROR(
"Shader::set_bool: uniform '{}' not found in shader",
152 glUniform1i(location, (
int) value);
155 if ((err = glGetError()) != GL_NO_ERROR)
157 ERROR(
"Shader::set_bool: error setting bool value with name {}: {}",
164bool Shader::set_int(Shader::Id
id,
const std::string &unif_name,
int value)
166 GLint location = glGetUniformLocation(
id, unif_name.c_str());
170 ERROR(
"Shader::set_int: uniform '{}' not found in shader",
175 glUniform1i(location, value);
178 if ((err = glGetError()) != GL_NO_ERROR)
180 ERROR(
"Shader::set_int: error setting int value with name '{}'",
187bool Shader::set_float(Shader::Id
id,
const std::string &unif_name,
float value)
189 GLint location = glGetUniformLocation(
id, unif_name.c_str());
193 ERROR(
"Shader::set_float: uniform '{}' not found in shader",
198 glUniform1f(location, value);
201 if ((err = glGetError()) != GL_NO_ERROR)
203 ERROR(
"Shader::set_float: error setting float value with name '{}': {}",
210bool Shader::set_float2(Shader::Id
id,
const std::string &unif_name,
float v1,
float v2)
212 GLint location = glGetUniformLocation(
id, unif_name.c_str());
216 ERROR(
"Shader::set_float2: uniform '{}' not found in shader",
221 glUniform2f(location, v1, v2);
224 if ((err = glGetError()) != GL_NO_ERROR)
226 ERROR(
"Shader::set_float2: error setting float uniform with name '{}': {}",
233bool Shader::set_float3(Shader::Id
id,
const std::string &unif_name,
float v1,
float v2,
float v3)
235 GLint location = glGetUniformLocation(
id, unif_name.c_str());
239 ERROR(
"Shader::set_float3: uniform '{}' not found in shader",
244 glUniform3f(location, v1, v2, v3);
247 if ((err = glGetError()) != GL_NO_ERROR)
249 ERROR(
"Shader::set_float3: error setting float value with name '{}': {}",
256bool Shader::set_mat4(Shader::Id
id,
const std::string &unif_name, glm::mat4 value)
258 GLint location = glGetUniformLocation(
id, unif_name.c_str());
262 ERROR(
"Shader::set_mat4: uniform '{}' not found in shader",
267 glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
270 if ((err = glGetError()) != GL_NO_ERROR)
272 ERROR(
"Shader::set_mat4: error setting mat4 value with name '{}': {}",
279bool Shader::set_vec3(Shader::Id
id,
const std::string &unif_name,
280 float x,
float y,
float z)
282 GLint location = glGetUniformLocation(
id, unif_name.c_str());
286 ERROR(
"Shader::set_vec3: uniform '{}' not found in shader",
291 glUniform3f(location, x, y, z);
294 if ((err = glGetError()) != GL_NO_ERROR)
296 ERROR(
"Shader::set_vec3: error setting vec3 value with name '{}': {}",
303bool Shader::set_vec3(Shader::Id
id,
const std::string& unif_name, glm::vec3 value)
305 GLint location = glGetUniformLocation(
id, unif_name.c_str());
309 ERROR(
"Shader::set_vec3: uniform '{}' not found in shader",
314 glUniform3f(location, value.x, value.y, value.z);
317 if ((err = glGetError()) != GL_NO_ERROR)
319 ERROR(
"Shader::set_vec3: error setting vec3 value with name '{}': {}",
327bool Shader::set_bool(
const std::string &unif_name,
bool value)
328{
return Shader::set_bool(this->
id, unif_name, value); }
329bool Shader::set_int(
const std::string &unif_name,
int value)
330{
return Shader::set_int(this->
id, unif_name, value); }
331bool Shader::set_float(
const std::string &unif_name,
float value)
332{
return Shader::set_float(this->
id, unif_name, value); }
333bool Shader::set_float2(
const std::string &unif_name,
float v1,
float v2)
334{
return Shader::set_float2(this->
id, unif_name, v1, v2); }
335bool Shader::set_float3(
const std::string &unif_name,
float v1,
float v2,
float v3)
336{
return Shader::set_float3(this->
id, unif_name, v1, v2, v3); }
337bool Shader::set_mat4(
const std::string &unif_name, glm::mat4 value)
338{
return Shader::set_mat4(this->
id, unif_name, value); }
339bool Shader::set_vec3(
const std::string &unif_name,
float x,
float y,
float z)
340{
return Shader::set_vec3(this->
id, unif_name, x, y, z); }
341bool Shader::set_vec3(
const std::string &unif_name, glm::vec3 value)
342{
return Shader::set_vec3(this->
id, unif_name, value); }
344bool Shader::check_compile_errors(Shader::Id shader)
348 glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
349 if (success)
return true;
351 std::stringstream out;
352 glGetShaderInfoLog(shader, 1024, NULL, infoLog);
353 out <<
"shader: compilation error: " << infoLog;
354 ERROR(
"{}", out.str());
358bool Shader::check_link_errors(Shader::Id shader)
362 glGetProgramiv(shader, GL_LINK_STATUS, &success);
363 if (success)
return true;
365 std::stringstream out;
366 glGetProgramInfoLog(shader, 1024, NULL, infoLog);
367 out <<
"shader: program linking error: " << infoLog;
368 ERROR(
"{}", out.str());
376Shader::Object::Object(Type type,
const std::filesystem::path &path)
380 auto src = Object::read_file(path);
392std::optional<std::string>
393Shader::Object::read_file(
const std::filesystem::path &path)
397 file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
402 if (!file.is_open())
throw "Cannot open file";
403 std::stringstream stream;
404 stream << file.rdbuf();
408 catch (std::ifstream::failure &e)
410 ERROR(
"shader: error reading shader file: {}", path.string());
416 ERROR(
"shader: file is empty: {}", path.string());
425 this->objs.push_back(obj);
427 this->watch_paths.push_back(*obj.path);
431Shader::Builder &Shader::Builder::objects(
const tenno::vector<Shader::Object> &objs)
433 for (
auto& obj : objs)
435 this->objs.push_back(obj);
437 this->watch_paths.push_back(*obj.path);
442Shader::Builder &Shader::Builder::feedback(
const GLchar **feedback_varyings,
445 this->feedback_varyings = feedback_varyings;
446 this->num_varyings = num_varyings;
451Shader::Builder &Shader::Builder::watch(
const std::filesystem::path &path)
453 this->watch_paths.push_back(path);
457std::optional<Shader> Shader::Builder::build()
459 if (num_varyings == 0)
460 return Shader::create(this->objs);
462 return Shader::create(this->feedback_varyings,
467tenno::vector<std::filesystem::path> Shader::Builder::get_watch_paths()
const
469 return this->watch_paths;