Brenta Engine 1.2
Loading...
Searching...
No Matches
gl.cpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#include <brenta/gl.hpp>
7#include <brenta/logger.hpp>
8#include <brenta/window.hpp>
9#include <brenta/text.hpp>
10
11#include <sstream>
12
13using namespace brenta;
14
15//
16// Static variables
17//
18
19const std::string gl::subsystem_name = "gl";
20const gl::config gl::default_config = {
21 false,
22 false,
23 false,
24 false,
25};
26gl::config gl::init_config = default_config;
27bool gl::initialized = false;
28
29// Forward declaration
30void APIENTRY glDebugOutput([[maybe_unused]] GLenum source,
31 [[maybe_unused]] GLenum type,
32 [[maybe_unused]] GLuint id,
33 [[maybe_unused]] GLenum severity,
34 [[maybe_unused]] GLsizei length,
35 [[maybe_unused]] const GLchar *message,
36 [[maybe_unused]] const void *userParam);
37
38//
39// Subsystem interface
40//
41
42std::expected<void, subsystem::error> gl::initialize()
43{
44 if (this->is_initialized()) return {};
45
46 GLADloadproc loadproc = (GLADloadproc) window::get_proc_address();
47 if (!gladLoadGLLoader(loadproc))
48 {
49 ERROR("{}: failed to initialize GLAD", gl::subsystem_name);
50 return std::unexpected("Failed to initialize GLAD");
51 }
52
53 int width = window::get_width();
54 int height = window::get_height();
55
56 glViewport(0, 0, width, height);
57
58 if (gl::init_config.enable_depth_test)
59 {
60 glEnable(GL_DEPTH_TEST);
61 INFO("{}: enabled GL_DEPTH_TEST", gl::subsystem_name);
62 }
63
64 if (gl::init_config.enable_blending)
65 {
66 glEnable(GL_BLEND);
67 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
68 INFO("{}: enabled GL_BLEND (transparency)", gl::subsystem_name);
69 }
70
71 if (gl::init_config.enable_cull_face)
72 {
73 glEnable(GL_CULL_FACE);
74 INFO("{}: enabled GL_CULL_FACE", gl::subsystem_name);
75 }
76
77 if (gl::init_config.enable_multisample)
78 {
79 glEnable(GL_MULTISAMPLE);
80 INFO("{}: enabled GL_MULTISAMPLE", gl::subsystem_name);
81 }
82
83 int flags;
84 glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
85 if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
86 {
87 // Enable all messages from all sources, of all types, of all severities.
88 glEnable(GL_DEBUG_OUTPUT);
89 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
90 glDebugMessageCallback(glDebugOutput, nullptr);
91 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE,
92 0, nullptr, GL_TRUE);
93 INFO("{}: configured GL_DEBUG_OUTPUT", gl::subsystem_name);
94 }
95
96 GLenum errcode = gl::check_error();
97 if (errcode != GL_NO_ERROR)
98 {
99 return std::unexpected("GL error");
100 }
101
102 gl::initialized = true;
103 INFO("{}: initialized", gl::subsystem_name);
104 return {};
105}
106
107std::expected<void, subsystem::error> gl::terminate()
108{
109 if (!this->is_initialized()) return {};
110
111 gl::initialized = false;
112 INFO("{}: terminated", gl::subsystem_name);
113 return {};
114}
115
116std::string gl::name()
117{
118 return gl::subsystem_name;
119}
120
122{
123 return gl::initialized;
124}
125
126//
127// Member functions
128//
129
130void gl::set_poligon_mode(GLboolean enable)
131{
132 if (enable)
133 {
134 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
135 INFO("{}: enabled GL_POLYGON_MODE (wireframe)", gl::subsystem_name);
136 }
137 else
138 {
139 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
140 INFO("{}: disabled GL_POLYGON_MODE (fill)", gl::subsystem_name);
141 }
142}
143
144gl &gl::instance()
145{
146 static gl _gl;
147 return _gl;
148}
149
150void gl::set_viewport(int x, int y, int width, int height)
151{
152 glViewport(x, y, width, height);
153}
154
155void gl::set_color(float r, float g, float b, float a)
156{
157 glClearColor(r, g, b, a);
158}
159
160void gl::draw_arrays(GLenum mode, int first, int count)
161{
162 glDrawArrays(mode, first, count);
163}
164
165void gl::draw_elements(GLenum mode, int count, GLenum type, const void *indices)
166{
167 glDrawElements(mode, count, type, indices);
168}
169
170void gl::bind_vertex_array(unsigned int n)
171{
172 glBindVertexArray(n);
173}
174
176{
177 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
178}
179
180GLenum gl::_check_error(const char *file, int line)
181{
182 GLenum errorCode;
183 while ((errorCode = glGetError()) != GL_NO_ERROR)
184 {
185 std::string error = "";
186 switch (errorCode)
187 {
188 case GL_INVALID_ENUM: error = "invalid enum"; break;
189 case GL_INVALID_VALUE: error = "invalid value"; break;
190 case GL_INVALID_OPERATION: error = "invalid operation"; break;
191 case GL_STACK_OVERFLOW: error = "stack overflow"; break;
192 case GL_STACK_UNDERFLOW: error = "stack underflow"; break;
193 case GL_OUT_OF_MEMORY: error = "out of memory"; break;
194 case GL_INVALID_FRAMEBUFFER_OPERATION:
195 error = "invalid framebuffer operation"; break;
196 default: error = "unknown error"; break;
197 }
198
199 error += " | " + std::string(file) + " (" + std::to_string(line) + ")";
200 ERROR("{}: {}", gl::subsystem_name, error);
201 }
202 return errorCode;
203}
204
205//
206// Utilities
207//
208
209void APIENTRY glDebugOutput([[maybe_unused]] GLenum source,
210 [[maybe_unused]] GLenum type,
211 [[maybe_unused]] GLuint id,
212 [[maybe_unused]] GLenum severity,
213 [[maybe_unused]] GLsizei length,
214 [[maybe_unused]] const GLchar *message,
215 [[maybe_unused]] const void *userParam)
216{
217 // ignore non-significant error/warning codes
218 if(id == 131169 || id == 131185 || id == 131218 || id == 131204) return;
219
220 std::stringstream out;
221 out << "Debug message (" << id << "): " << message << std::endl;
222
223 switch (source)
224 {
225 case GL_DEBUG_SOURCE_API:
226 out << "Source: API"; break;
227 case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
228 out << "Source: Window System"; break;
229 case GL_DEBUG_SOURCE_SHADER_COMPILER:
230 out << "Source: Shader Compiler"; break;
231 case GL_DEBUG_SOURCE_THIRD_PARTY:
232 out << "Source: Third Party"; break;
233 case GL_DEBUG_SOURCE_APPLICATION:
234 out << "Source: Application"; break;
235 case GL_DEBUG_SOURCE_OTHER:
236 out << "Source: Other"; break;
237 } out << std::endl;
238
239 switch (type)
240 {
241 case GL_DEBUG_TYPE_ERROR:
242 out << "Type: Error"; break;
243 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
244 out << "Type: Deprecated Behaviour"; break;
245 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
246 out << "Type: Undefined Behaviour"; break;
247 case GL_DEBUG_TYPE_PORTABILITY:
248 out << "Type: Portability"; break;
249 case GL_DEBUG_TYPE_PERFORMANCE:
250 out << "Type: Performance"; break;
251 case GL_DEBUG_TYPE_MARKER:
252 out << "Type: Marker"; break;
253 case GL_DEBUG_TYPE_PUSH_GROUP:
254 out << "Type: Push Group"; break;
255 case GL_DEBUG_TYPE_POP_GROUP:
256 out << "Type: Pop Group"; break;
257 case GL_DEBUG_TYPE_OTHER:
258 out << "Type: Other"; break;
259 } out << std::endl;
260
261 switch (severity)
262 {
263 case GL_DEBUG_SEVERITY_HIGH:
264 out << "Severity: high"; break;
265 case GL_DEBUG_SEVERITY_MEDIUM:
266 out << "Severity: medium"; break;
267 case GL_DEBUG_SEVERITY_LOW:
268 out << "Severity: low"; break;
269 case GL_DEBUG_SEVERITY_NOTIFICATION:
270 out << "Severity: notification"; break;
271 } out << std::endl;
272 out << std::endl;
273
274 ERROR("{}: {}", gl::subsystem_name, out.str());
275}
276
277//
278// Builder
279//
280
281gl::builder &gl::builder::blending()
282{
283 this->conf.enable_blending = true;
284 return *this;
285}
286
287gl::builder &gl::builder::cull_face()
288{
289 this->conf.enable_cull_face = true;
290 return *this;
291}
292
293gl::builder &gl::builder::multisample()
294{
295 this->conf.enable_multisample = true;
296 return *this;
297}
298
299gl::builder &gl::builder::depth_test()
300{
301 this->conf.enable_depth_test = true;
302 return *this;
303}
304
305brenta::subsystem &gl::builder::build()
306{
307 gl::init_config = this->conf;
308 return gl::instance();
309}
OpenGL helper functions.
Definition gl.hpp:30
static void set_color(float r, float g, float b, float a)
Set Clear Color.
Definition gl.cpp:155
static GLenum _check_error(const char *file, int line)
Check OpenGL error.
Definition gl.cpp:180
static void clear()
Clear.
Definition gl.cpp:175
std::string name() override
Returns the name of the sybsystem.
Definition gl.cpp:116
static void set_poligon_mode(GLboolean enable)
Set Poligon Mode.
Definition gl.cpp:130
static void draw_elements(GLenum mode, int count, GLenum type, const void *indices)
Draw Elements.
Definition gl.cpp:165
bool is_initialized() override
Returns true if the subsystem is initialized.
Definition gl.cpp:121
static void set_viewport(int x, int y, int width, int height)
Set Viewport.
Definition gl.cpp:150
static void draw_arrays(GLenum mode, int first, int count)
Draw Arrays.
Definition gl.cpp:160
Subsystem interface.
Definition subsystem.hpp:22
static GLFWglproc get_proc_address()
Get the OpenGL function pointer.
Definition window.cpp:152