Brenta Engine 1.2
Loading...
Searching...
No Matches
shader.hpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#pragma once
7
8#include <algorithm>
9#include <brenta/logger.hpp>
10#include <fstream>
11#include <glad/glad.h>
12#include <glm/glm.hpp>
13#include <glm/gtc/matrix_transform.hpp>
14#include <glm/gtc/type_ptr.hpp>
15#include <iostream>
16#include <sstream>
17#include <string>
18#include <unordered_map>
19#include <vector>
20
21namespace brenta
22{
23
35class shader
36{
37public:
38
39 using name_t = std::string;
40
41 enum type
42 {
43 vertex,
44 fragment,
45 geometry,
46 compute,
47 };
48
56 static std::unordered_map<shader::name_t, unsigned int> shaders;
57
74 template <typename... Args>
75 static bool create(const std::string &shader_name,
76 shader::type type, const std::string &path,
77 Args... args)
78 {
79 std::vector<unsigned int> compiled_shaders = {};
80 if (!compile_shaders(compiled_shaders, type, path, args...))
81 {
82 ERROR("shader: error compiling shader {}", path);
83 return false;
84 }
85
86 /* shader Program */
87 unsigned int ID = glCreateProgram();
88 std::for_each(compiled_shaders.begin(), compiled_shaders.end(),
89 [&ID](auto shader) { glAttachShader(ID, shader); });
90
91 glLinkProgram(ID);
92 if (!shader::check_compile_errors(ID, "PROGRAM"))
93 {
94 return false;
95 }
96
97 shader::shaders.insert({shader_name, ID});
98 std::for_each(compiled_shaders.begin(), compiled_shaders.end(),
99 [](auto shader) { glDeleteShader(shader); });
100 return true;
101 }
102
119 template <typename... Args>
120 static bool create(const GLchar **feedback_varyings, int num_varyings,
121 const std::string &shader_name,
122 shader::type type, const std::string &path,
123 Args... args)
124 {
125 std::vector<unsigned int> compiled_shaders = {};
126 if (!compile_shaders(compiled_shaders, type, path, args...))
127 {
128 ERROR("shader: error compiling shader {}", path)
129 return false;
130 }
131
132 /* shader Program */
133 unsigned int ID = glCreateProgram();
134 std::for_each(compiled_shaders.begin(), compiled_shaders.end(),
135 [&ID](auto shader) { glAttachShader(ID, shader); });
136
137 if (feedback_varyings != nullptr)
138 {
139 glTransformFeedbackVaryings(ID, num_varyings, feedback_varyings,
140 GL_INTERLEAVED_ATTRIBS);
141 }
142
143 glLinkProgram(ID);
144 if (!shader::check_compile_errors(ID, "PROGRAM"))
145 {
146 return false;
147 }
148
149 shader::shaders.insert({shader_name, ID});
150 std::for_each(compiled_shaders.begin(), compiled_shaders.end(),
151 [](auto shader) { glDeleteShader(shader); });
152
153 return true;
154 }
155
156 static bool
157 compile_shaders([[maybe_unused]] std::vector<unsigned int> &compiled)
158 {
159 return true;
160 }
161
162 template <typename... Args>
163 static bool compile_shaders(std::vector<unsigned int> &compiled,
164 shader::type type, const std::string &path,
165 Args... args)
166 {
167 std::string code;
168 std::ifstream file;
169 file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
170
171 try
172 {
173 file.open(path);
174 if (!file.is_open()) throw "Cannot open file";
175 std::stringstream stream;
176 stream << file.rdbuf();
177 file.close();
178 code = stream.str();
179 }
180 catch (std::ifstream::failure &e)
181 {
182 ERROR("shader: error reading shader file: {}", path);
183 return false;
184 }
185
186 if (code.empty())
187 {
188 ERROR("shader: file is empty: {}", path);
189 return false;
190 }
191
192 const char *shader_code = code.c_str();
193
194 GLenum shader_type_gl;
195 switch(type)
196 {
197 case fragment: shader_type_gl = GL_FRAGMENT_SHADER; break;
198 case vertex: shader_type_gl = GL_VERTEX_SHADER; break;
199 case geometry: shader_type_gl = GL_GEOMETRY_SHADER; break;
200 case compute: shader_type_gl = GL_COMPUTE_SHADER; break;
201 default: shader_type_gl = 0; break;
202 }
203
204 unsigned int shader = glCreateShader(shader_type_gl);
205 glShaderSource(shader, 1, &shader_code, NULL);
206 glCompileShader(shader);
207 if (!shader::check_compile_errors(shader, "SHADER"))
208 {
209 return false;
210 }
211
212 compiled.push_back(shader);
213 return compile_shaders(compiled, args...);
214 }
215
222 static unsigned int get_id(shader::name_t shader_name);
223
234 static bool use(shader::name_t shader_name);
235
236 // Utility uniform functions
237
246 static bool set_bool(shader::name_t shader_name,
247 const GLchar *name, bool value);
256 static bool set_int(shader::name_t shader_name, const GLchar *name,
257 int value);
266 static bool set_float(shader::name_t shader_name,
267 const GLchar *name, float value);
276 static bool set_mat4(shader::name_t shader_name, const GLchar *name,
277 glm::mat4 value);
288 static bool set_vec3(shader::name_t shader_name, const GLchar *name,
289 float x, float y, float z);
298 static bool set_vec3(shader::name_t shader_name, const GLchar *name,
299 glm::vec3 value);
300
301private:
302
303 static bool check_compile_errors(unsigned int shader, std::string type);
304
305};
306
307} // namespace brenta
Shader class.
Definition shader.hpp:36
static bool use(shader::name_t shader_name)
Use the shader.
Definition shader.cpp:24
static bool set_mat4(shader::name_t shader_name, const GLchar *name, glm::mat4 value)
Set a 4x4 matrix in the shader.
Definition shader.cpp:114
static bool set_float(shader::name_t shader_name, const GLchar *name, float value)
Set a float in the shader.
Definition shader.cpp:89
static std::unordered_map< shader::name_t, unsigned int > shaders
Map of shaders.
Definition shader.hpp:56
static bool set_vec3(shader::name_t shader_name, const GLchar *name, float x, float y, float z)
Set a 3D vector in the shader.
Definition shader.cpp:140
static unsigned int get_id(shader::name_t shader_name)
Get the ID of a shader.
Definition shader.cpp:14
static bool create(const std::string &shader_name, shader::type type, const std::string &path, Args... args)
Create a new shader.
Definition shader.hpp:75
static bool set_bool(shader::name_t shader_name, const GLchar *name, bool value)
Set a boolean in the shader.
Definition shader.cpp:37
static bool create(const GLchar **feedback_varyings, int num_varyings, const std::string &shader_name, shader::type type, const std::string &path, Args... args)
Create a new shader with feedback varyings.
Definition shader.hpp:120
static bool set_int(shader::name_t shader_name, const GLchar *name, int value)
Set an integer in the shader.
Definition shader.cpp:63