A 3D game engine from scratch.
1// (c) 2020 Vlad-Stefan Harbuz <vlad@vladh.net>
2
3#include "../src_external/pstr.h"
4#include "renderer.hpp"
5#include "engine.hpp"
6#include "mats.hpp"
7#include "debug.hpp"
8#include "util.hpp"
9#include "glutil.hpp"
10#include "logs.hpp"
11#include "debug_ui.hpp"
12#include "debugdraw.hpp"
13#include "intrinsics.hpp"
14
15
16renderer::State *renderer::state = nullptr;
17
18
19GLFWwindow *
20renderer::init_window(WindowSize *window_size)
21{
22 glfwInit();
23
24 logs::info("Using OpenGL 4.1");
25 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
26 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
27 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
28
29#if defined(PLATFORM_MACOS)
30 // macOS requires a forward compatible context
31 // This means the highest OpenGL version will be used that is at least the version
32 // we specified, and that contains no breaking changes from the version we specified
33 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
34#endif
35
36 if (SETTINGS.opengl_debug_on) {
37 logs::info("Using OpenGL debug context");
38 glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true);
39 }
40
41 // Remove window decorations (border etc.)
42 glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
43
44 // For fullscreen windows, do not discard our video mode when minimised
45 glfwWindowHint(GLFW_AUTO_ICONIFY, GLFW_FALSE);
46
47 // Create the window. Right now we're working with screencoord sizes,
48 // not pixels!
49
50 GLFWwindow *window;
51
52 if (SETTINGS.fullscreen_on) {
53 i32 n_monitors;
54 GLFWmonitor **monitors = glfwGetMonitors(&n_monitors);
55 GLFWmonitor *target_monitor = monitors[SETTINGS.target_monitor];
56 const GLFWvidmode *video_mode = glfwGetVideoMode(target_monitor);
57 glfwWindowHint(GLFW_RED_BITS, video_mode->redBits);
58 glfwWindowHint(GLFW_GREEN_BITS, video_mode->greenBits);
59 glfwWindowHint(GLFW_BLUE_BITS, video_mode->blueBits);
60 glfwWindowHint(GLFW_REFRESH_RATE, video_mode->refreshRate);
61
62 window_size->screencoord_width = video_mode->width;
63 window_size->screencoord_height = video_mode->height;
64
65 if (SETTINGS.windowed_fullscreen_on) {
66 window = glfwCreateWindow(
67 window_size->screencoord_width, window_size->screencoord_height,
68 WINDOW_TITLE,
69 nullptr, nullptr);
70 } else {
71 window = glfwCreateWindow(
72 window_size->screencoord_width, window_size->screencoord_height,
73 WINDOW_TITLE,
74 target_monitor, nullptr);
75 }
76 } else {
77 window_size->screencoord_width = 1920;
78 window_size->screencoord_height = 1080;
79
80 window = glfwCreateWindow(
81 window_size->screencoord_width, window_size->screencoord_height,
82 WINDOW_TITLE,
83 nullptr, nullptr);
84
85 glfwSetWindowPos(window, 200, 200);
86 }
87
88 if (!window) {
89 logs::fatal("Failed to create GLFW window");
90 return nullptr;
91 }
92
93 glfwMakeContextCurrent(window);
94
95 if (!SETTINGS.vsync_on) {
96 glfwSwapInterval(0);
97 }
98
99 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
100 logs::fatal("Failed to initialize GLAD");
101 return nullptr;
102 }
103
104 if (!GLAD_GL_ARB_texture_cube_map_array) {
105 logs::fatal("No support for GLAD_GL_ARB_texture_cube_map_array");
106 }
107 if (!GLAD_GL_ARB_texture_storage) {
108 logs::fatal("No support for GLAD_GL_ARB_texture_storage");
109 }
110 if (!GLAD_GL_ARB_buffer_storage) {
111 logs::warning("No support for GLAD_GL_ARB_buffer_storage");
112 }
113
114 // TODO: Remove GL_EXT_debug_marker from GLAD
115 // TODO: Remove GL_EXT_debug_label from GLAD
116 // TODO: Remove GL_ARB_texture_storage_multisample from GLAD
117
118 if (SETTINGS.opengl_debug_on) {
119 if (GLAD_GL_AMD_debug_output || GLAD_GL_ARB_debug_output || GLAD_GL_KHR_debug) {
120 GLint flags;
121 glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
122
123 if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) {
124 glEnable(GL_DEBUG_OUTPUT);
125 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
126 glDebugMessageCallback(glutil::debug_message_callback, nullptr);
127 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
128 } else {
129 logs::fatal("Tried to initialise OpenGL debug output but couldn't");
130 }
131 } else {
132 logs::warning(
133 "Tried to initialise OpenGL debug output but none of "
134 "[GL_AMD_debug_output, GL_ARB_debug_output, GL_KHR_debug] "
135 "are supported on this system. Skipping.");
136 }
137 }
138
139 // Enable multisampling
140 glEnable(GL_MULTISAMPLE);
141 glfwWindowHint(GLFW_SAMPLES, 4);
142
143 glEnable(GL_DEPTH_TEST);
144 glEnable(GL_CULL_FACE);
145 glCullFace(GL_BACK);
146 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
147#if !defined(PLATFORM_MACOS)
148 glLineWidth(2.0f);
149#endif
150 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
151
152 // Get the framebuffer size. This is the actual window size in pixels.
153 glfwGetFramebufferSize(window, &window_size->width, &window_size->height);
154 glViewport(0, 0, window_size->width, window_size->height);
155
156 glfwSetFramebufferSizeCallback(window, core::framebuffer_size_callback);
157 glfwSetCursorPosCallback(window, core::mouse_callback);
158 glfwSetMouseButtonCallback(window, core::mouse_button_callback);
159 glfwSetKeyCallback(window, core::key_callback);
160 glfwSetCharCallback(window, core::char_callback);
161
162 return window;
163}
164
165
166void
167renderer::resize_renderer_buffers(
168 memory::Pool *memory_pool,
169 BuiltinTextures *builtin_textures,
170 u32 width,
171 u32 height
172) {
173 // TODO: Only regenerate once we're done resizing, not for every little bit
174 // of the resize.
175 init_g_buffer(
176 memory_pool,
177 &builtin_textures->g_buffer,
178 &builtin_textures->g_position_texture,
179 &builtin_textures->g_normal_texture,
180 &builtin_textures->g_albedo_texture,
181 &builtin_textures->g_pbr_texture,
182 width, height);
183 init_l_buffer(
184 memory_pool,
185 &builtin_textures->l_buffer,
186 &builtin_textures->l_color_texture,
187 &builtin_textures->l_bright_color_texture,
188 &builtin_textures->l_depth_texture,
189 width, height);
190 init_blur_buffers(
191 memory_pool,
192 &builtin_textures->blur1_buffer,
193 &builtin_textures->blur2_buffer,
194 &builtin_textures->blur1_texture,
195 &builtin_textures->blur2_texture,
196 width, height);
197
198 each (material, *mats::get_materials()) {
199 if (material->n_textures > 0 && material->is_screensize_dependent) {
200 for (u32 idx_texture = 0; idx_texture < material->n_textures; idx_texture++) {
201 mats::Texture *texture = &material->textures[idx_texture];
202 if (texture->type == mats::TextureType::g_position) {
203 material->textures[idx_texture] = *builtin_textures->g_position_texture;
204 } else if (texture->type == mats::TextureType::g_normal) {
205 material->textures[idx_texture] = *builtin_textures->g_normal_texture;
206 } else if (texture->type == mats::TextureType::g_albedo) {
207 material->textures[idx_texture] = *builtin_textures->g_albedo_texture;
208 } else if (texture->type == mats::TextureType::g_pbr) {
209 material->textures[idx_texture] = *builtin_textures->g_pbr_texture;
210 } else if (texture->type == mats::TextureType::l_color) {
211 material->textures[idx_texture] = *builtin_textures->l_color_texture;
212 } else if (texture->type == mats::TextureType::l_bright_color) {
213 material->textures[idx_texture] = *builtin_textures->l_bright_color_texture;
214 } else if (texture->type == mats::TextureType::l_depth) {
215 material->textures[idx_texture] = *builtin_textures->l_depth_texture;
216 } else if (texture->type == mats::TextureType::blur1) {
217 material->textures[idx_texture] = *builtin_textures->blur1_texture;
218 } else if (texture->type == mats::TextureType::blur2) {
219 material->textures[idx_texture] = *builtin_textures->blur2_texture;
220 }
221 }
222 mats::bind_texture_uniforms(material);
223 }
224 }
225}
226
227
228void
229renderer::update_drawing_options(GLFWwindow *window)
230{
231 if (input::is_cursor_enabled()) {
232 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
233 } else {
234 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
235 }
236
237 if (renderer::state->should_use_wireframe) {
238 // This will be handled in the rendering loop.
239 } else {
240 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
241 }
242}
243
244
245void
246renderer::render(GLFWwindow *window)
247{
248 // Block rendering until all previous OpenGL operations have been completed.
249 // This prevents issues where we have multiple frames queued up for drawing on the GPU,
250 // in which case we will get all sorts of unpleasant stutter. This problem will only
251 // realistically happen when the CPU has way less to do than the GPU and so is issuing
252 // a lot of frames.
253 // In the future, we might want to remove this, because it does block our CPU time
254 // until the GPU is done. However, for now, we don't have that much in our scene,
255 // and the stuttering is more of a problem.
256 // If we're using vsync, this is not really a problem, so we don't need to glFinish().
257 // There is an issue that can arise: it might be the case that we think we're using
258 // vsync, but actually a graphics driver has forced it off, in which case we won't be
259 // using glFinish(), but we should be...probably not going to be a real problem,
260 // though.
261 if (!SETTINGS.vsync_on) {
262 glFinish();
263 }
264
265 WindowSize *window_size = core::get_window_size();
266
267 copy_scene_data_to_ubo(0, 0, false);
268
269 // Clear framebuffers
270 {
271 glBindFramebuffer(GL_FRAMEBUFFER, 0);
272 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
273 glBindFramebuffer(GL_FRAMEBUFFER, renderer::state->builtin_textures.g_buffer);
274 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
275 glBindFramebuffer(GL_FRAMEBUFFER, renderer::state->builtin_textures.l_buffer);
276 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
277 if (SETTINGS.bloom_on) {
278 glBindFramebuffer(GL_FRAMEBUFFER, renderer::state->builtin_textures.blur1_buffer);
279 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
280 glBindFramebuffer(GL_FRAMEBUFFER, renderer::state->builtin_textures.blur2_buffer);
281 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
282 }
283 }
284
285 // Render shadow map
286 if (SETTINGS.shadows_on) {
287 // Point lights
288 {
289 f32 ratio = (f32)renderer::state->builtin_textures.shadowmap_3d_width /
290 (f32)renderer::state->builtin_textures.shadowmap_3d_height;
291 m4 perspective_projection = glm::perspective(
292 radians(90.0f), ratio,
293 renderer::state->builtin_textures.shadowmap_near_clip_dist,
294 renderer::state->builtin_textures.shadowmap_far_clip_dist);
295
296 u32 idx_light = 0;
297
298 each (light_component, *lights::get_components()) {
299 if (light_component->entity_handle == entities::NO_ENTITY_HANDLE) {
300 continue;
301 }
302
303 spatial::Component *spatial_component =
304 spatial::get_component(light_component->entity_handle);
305
306 if (!(
307 lights::is_light_component_valid(light_component) &&
308 light_component->type == lights::LightType::point &&
309 spatial::is_spatial_component_valid(spatial_component)
310 )) {
311 continue;
312 }
313
314 v3 position = spatial_component->position;
315
316 for (u32 idx_face = 0; idx_face < 6; idx_face++) {
317 renderer::state->shadowmap_3d_transforms[(idx_light * 6) + idx_face] =
318 perspective_projection * glm::lookAt(
319 position,
320 position + models::CUBEMAP_OFFSETS[idx_face],
321 models::CUBEMAP_UPS[idx_face]);
322 }
323
324 glViewport(0, 0,
325 renderer::state->builtin_textures.shadowmap_3d_width,
326 renderer::state->builtin_textures.shadowmap_3d_height);
327 glBindFramebuffer(GL_FRAMEBUFFER,
328 renderer::state->builtin_textures.shadowmaps_3d_framebuffer);
329 glClear(GL_DEPTH_BUFFER_BIT);
330
331 copy_scene_data_to_ubo(
332 idx_light, lights::light_type_to_int(light_component->type),
333 false);
334 render_scene(drawable::Pass::shadowcaster, drawable::Mode::depth);
335
336 idx_light++;
337 }
338 }
339
340 // Directional lights
341 {
342 f32 ortho_ratio = (
343 (f32)renderer::state->builtin_textures.shadowmap_2d_width /
344 (f32)renderer::state->builtin_textures.shadowmap_2d_height);
345 f32 ortho_width = 100.0f;
346 f32 ortho_height = ortho_width / ortho_ratio;
347 m4 ortho_projection = glm::ortho(
348 -ortho_width, ortho_width, -ortho_height, ortho_height,
349 renderer::state->builtin_textures.shadowmap_near_clip_dist,
350 renderer::state->builtin_textures.shadowmap_far_clip_dist);
351
352 u32 idx_light = 0;
353
354 each (light_component, *lights::get_components()) {
355 if (light_component->entity_handle == entities::NO_ENTITY_HANDLE) {
356 continue;
357 }
358
359 spatial::Component *spatial_component =
360 spatial::get_component(light_component->entity_handle);
361
362 if (!(
363 lights::is_light_component_valid(light_component) &&
364 light_component->type == lights::LightType::directional &&
365 spatial::is_spatial_component_valid(spatial_component)
366 )) {
367 continue;
368 }
369
370 renderer::state->shadowmap_2d_transforms[idx_light] = ortho_projection *
371 glm::lookAt(spatial_component->position,
372 spatial_component->position + light_component->direction,
373 v3(0.0f, -1.0f, 0.0f));
374
375 glViewport(0, 0,
376 renderer::state->builtin_textures.shadowmap_2d_width,
377 renderer::state->builtin_textures.shadowmap_2d_height);
378 glBindFramebuffer(GL_FRAMEBUFFER,
379 renderer::state->builtin_textures.shadowmaps_2d_framebuffer);
380 glClear(GL_DEPTH_BUFFER_BIT);
381
382 copy_scene_data_to_ubo(
383 idx_light, lights::light_type_to_int(light_component->type),
384 false);
385 render_scene(drawable::Pass::shadowcaster, drawable::Mode::depth);
386
387 idx_light++;
388 }
389 }
390 }
391
392 glViewport(0, 0, window_size->width, window_size->height);
393
394 // Geometry pass
395 {
396 if (renderer::state->should_use_wireframe) {
397 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
398 }
399 glBindFramebuffer(GL_FRAMEBUFFER, renderer::state->builtin_textures.g_buffer);
400 render_scene(drawable::Pass::deferred, drawable::Mode::regular);
401 if (renderer::state->should_use_wireframe) {
402 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
403 }
404 }
405
406 // Copy depth from geometry pass to lighting pass
407 {
408 glBindFramebuffer(GL_READ_FRAMEBUFFER, renderer::state->builtin_textures.g_buffer);
409 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, renderer::state->builtin_textures.l_buffer);
410 glBlitFramebuffer(0, 0, window_size->width, window_size->height,
411 0, 0, window_size->width, window_size->height,
412 GL_DEPTH_BUFFER_BIT, GL_NEAREST);
413 }
414
415 glBindFramebuffer(GL_FRAMEBUFFER, renderer::state->builtin_textures.l_buffer);
416
417 // Lighting pass
418 {
419 glDisable(GL_DEPTH_TEST);
420 render_scene(drawable::Pass::lighting, drawable::Mode::regular);
421 glEnable(GL_DEPTH_TEST);
422 }
423
424
425 // Forward pass
426 {
427 // Skysphere
428 {
429 // Cull outside, not inside, of sphere.
430 glCullFace(GL_FRONT);
431 // Do not write to depth buffer.
432 glDepthMask(GL_FALSE);
433 // Draw at the very back of our depth range, so as to be behind everything.
434 glDepthRange(0.9999f, 1.0f);
435
436 render_scene(drawable::Pass::forward_skybox, drawable::Mode::regular);
437
438 glDepthRange(0.0f, 1.0f);
439 glDepthMask(GL_TRUE);
440 glCullFace(GL_BACK);
441 }
442
443 // Forward
444 {
445 if (renderer::state->should_use_wireframe) {
446 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
447 }
448 render_scene(drawable::Pass::forward_depth, drawable::Mode::regular);
449 glDisable(GL_DEPTH_TEST);
450 render_scene(drawable::Pass::forward_nodepth, drawable::Mode::regular);
451 glEnable(GL_DEPTH_TEST);
452 if (renderer::state->should_use_wireframe) {
453 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
454 }
455 }
456
457 // Debug draw pass
458 {
459 debugdraw::render();
460 }
461 }
462
463 glDisable(GL_DEPTH_TEST);
464
465 // Blur pass
466 if (SETTINGS.bloom_on) {
467 glBindFramebuffer(GL_FRAMEBUFFER, renderer::state->builtin_textures.blur1_buffer);
468 copy_scene_data_to_ubo(0, 0, true);
469 render_scene(drawable::Pass::preblur, drawable::Mode::regular);
470
471 glBindFramebuffer(GL_FRAMEBUFFER, renderer::state->builtin_textures.blur2_buffer);
472 copy_scene_data_to_ubo(0, 0, false);
473 render_scene(drawable::Pass::blur2, drawable::Mode::regular);
474
475 for (u32 idx = 0; idx < 3; idx++) {
476 glBindFramebuffer(GL_FRAMEBUFFER, renderer::state->builtin_textures.blur1_buffer);
477 copy_scene_data_to_ubo(0, 0, true);
478 render_scene(drawable::Pass::blur1, drawable::Mode::regular);
479
480 glBindFramebuffer(GL_FRAMEBUFFER, renderer::state->builtin_textures.blur2_buffer);
481 copy_scene_data_to_ubo(0, 0, false);
482 render_scene(drawable::Pass::blur2, drawable::Mode::regular);
483 }
484 }
485
486 glBindFramebuffer(GL_FRAMEBUFFER, 0);
487
488 // Postprocessing pass
489 {
490 render_scene(drawable::Pass::postprocessing, drawable::Mode::regular);
491 }
492
493 // Render debug pass
494 {
495 render_scene(drawable::Pass::renderdebug, drawable::Mode::regular);
496 }
497
498 // UI pass
499 {
500 if (!renderer::state->should_hide_ui) {
501 glEnable(GL_BLEND);
502 debug_ui::render_debug_ui();
503 glDisable(GL_BLEND);
504 }
505 }
506
507 glEnable(GL_DEPTH_TEST);
508
509 START_TIMER(swap_buffers);
510 glfwSwapBuffers(window);
511 END_TIMER_MIN(swap_buffers, 10);
512
513 // Do any needed post-render cleanup
514 debugdraw::clear();
515 clear_gui_vertices();
516}
517
518
519void
520renderer::init(
521 renderer::State *renderer_state,
522 memory::Pool *memory_pool,
523 u32 width,
524 u32 height,
525 GLFWwindow *window
526) {
527 renderer::state = renderer_state;
528 BuiltinTextures *builtin_textures = &renderer::state->builtin_textures;
529 if (SETTINGS.graphics_quality == GraphicsQuality::high) {
530 *builtin_textures = {
531 .shadowmap_3d_width = min((u32)width, (u32)2000),
532 .shadowmap_3d_height = min((u32)width, (u32)2000),
533 .shadowmap_2d_width = 2560 * 2,
534 .shadowmap_2d_height = 1440 * 2,
535 .shadowmap_near_clip_dist = 0.05f,
536 .shadowmap_far_clip_dist = 200.0f,
537 };
538 } else if (SETTINGS.graphics_quality == GraphicsQuality::low) {
539 *builtin_textures = {
540 .shadowmap_3d_width = 500,
541 .shadowmap_3d_height = 500,
542 .shadowmap_2d_width = 800,
543 .shadowmap_2d_height = 600,
544 .shadowmap_near_clip_dist = 0.05f,
545 .shadowmap_far_clip_dist = 200.0f,
546 };
547 }
548 init_g_buffer(memory_pool,
549 &builtin_textures->g_buffer,
550 &builtin_textures->g_position_texture,
551 &builtin_textures->g_normal_texture,
552 &builtin_textures->g_albedo_texture,
553 &builtin_textures->g_pbr_texture,
554 width, height);
555 init_l_buffer(memory_pool,
556 &builtin_textures->l_buffer,
557 &builtin_textures->l_color_texture,
558 &builtin_textures->l_bright_color_texture,
559 &builtin_textures->l_depth_texture,
560 width, height);
561 init_blur_buffers(memory_pool,
562 &builtin_textures->blur1_buffer,
563 &builtin_textures->blur2_buffer,
564 &builtin_textures->blur1_texture,
565 &builtin_textures->blur2_texture,
566 width, height);
567 init_3d_shadowmaps(memory_pool,
568 &builtin_textures->shadowmaps_3d_framebuffer,
569 &builtin_textures->shadowmaps_3d,
570 &builtin_textures->shadowmaps_3d_texture,
571 builtin_textures->shadowmap_3d_width,
572 builtin_textures->shadowmap_3d_height);
573 init_2d_shadowmaps(memory_pool,
574 &builtin_textures->shadowmaps_2d_framebuffer,
575 &builtin_textures->shadowmaps_2d,
576 &builtin_textures->shadowmaps_2d_texture,
577 builtin_textures->shadowmap_2d_width,
578 builtin_textures->shadowmap_2d_height);
579 init_ubo(&renderer::state->ubo_shader_common);
580 update_drawing_options(window);
581 init_gui(memory_pool);
582}
583
584
585void
586renderer::start_drawing_gui()
587{
588 glBindVertexArray(renderer::state->gui_vao);
589 glBindBuffer(GL_ARRAY_BUFFER, renderer::state->gui_vbo);
590}
591
592
593void
594renderer::push_gui_vertices(f32 *vertices, u32 n_vertices)
595{
596 // VAO/VBO must have been bound by start_drawing()
597 if (renderer::state->gui_n_vertices_pushed + n_vertices > GUI_MAX_N_VERTICES) {
598 logs::error("Pushed too many GUI vertices, did you forget to call renderer::clear_gui_vertices()?");
599 return;
600 }
601 glBufferSubData(GL_ARRAY_BUFFER,
602 GUI_VERTEX_SIZE * renderer::state->gui_n_vertices_pushed,
603 GUI_VERTEX_SIZE * n_vertices, vertices);
604
605 renderer::state->gui_n_vertices_pushed += n_vertices;
606}
607
608
609void
610renderer::clear_gui_vertices()
611{
612 renderer::state->gui_n_vertices_pushed = 0;
613}
614
615
616void
617renderer::render_gui()
618{
619 glUseProgram(renderer::state->gui_shader_asset.program);
620
621 glActiveTexture(GL_TEXTURE0);
622 glBindTexture(GL_TEXTURE_2D, renderer::state->gui_texture_atlas.texture_name);
623
624 if (!renderer::state->gui_shader_asset.did_set_texture_uniforms) {
625 shaders::set_int(&renderer::state->gui_shader_asset, "atlas_texture", 0);
626 renderer::state->gui_shader_asset.did_set_texture_uniforms = true;
627 }
628
629 glDrawArrays(GL_TRIANGLES, 0, renderer::state->gui_n_vertices_pushed);
630}
631
632
633bool
634renderer::should_use_wireframe()
635{
636 return renderer::state->should_use_wireframe;
637}
638
639
640void
641renderer::set_should_use_wireframe(bool val)
642{
643 renderer::state->should_use_wireframe = val;
644}
645
646
647renderer::BuiltinTextures *
648renderer::get_builtin_textures()
649{
650 return &renderer::state->builtin_textures;
651}
652
653
654shaders::Asset *
655renderer::get_standard_depth_shader_asset()
656{
657 return &renderer::state->standard_depth_shader_asset;
658}
659
660
661iv2
662renderer::get_gui_texture_atlas_size()
663{
664 return renderer::state->gui_texture_atlas.size;
665}
666
667
668Array<fonts::FontAsset> *
669renderer::get_gui_font_assets()
670{
671 return &renderer::state->gui_font_assets;
672}
673
674
675void
676renderer::set_renderdebug_displayed_texture_type(mats::TextureType val)
677{
678 renderer::state->renderdebug_displayed_texture_type = val;
679}
680
681
682bool
683renderer::should_hide_ui()
684{
685 return renderer::state->should_hide_ui;
686}
687
688
689void
690renderer::set_should_hide_ui(bool val)
691{
692 renderer::state->should_hide_ui = val;
693}
694
695
696void
697renderer::init_g_buffer(
698 memory::Pool *memory_pool,
699 u32 *g_buffer,
700 mats::Texture **g_position_texture,
701 mats::Texture **g_normal_texture,
702 mats::Texture **g_albedo_texture,
703 mats::Texture **g_pbr_texture,
704 u32 width,
705 u32 height
706) {
707 glGenFramebuffers(1, g_buffer);
708 glBindFramebuffer(GL_FRAMEBUFFER, *g_buffer);
709
710 u32 g_position_texture_name;
711 u32 g_normal_texture_name;
712 u32 g_albedo_texture_name;
713 u32 g_pbr_texture_name;
714
715 glGenTextures(1, &g_position_texture_name);
716 glGenTextures(1, &g_normal_texture_name);
717 glGenTextures(1, &g_albedo_texture_name);
718 glGenTextures(1, &g_pbr_texture_name);
719
720 *g_position_texture = mats::init_texture(
721 MEMORY_PUSH(memory_pool, mats::Texture, "g_position_texture"),
722 GL_TEXTURE_2D, mats::TextureType::g_position, g_position_texture_name, width, height, 4);
723 (*g_position_texture)->is_builtin = true;
724
725 *g_normal_texture = mats::init_texture(
726 MEMORY_PUSH(memory_pool, mats::Texture, "g_normal_texture"),
727 GL_TEXTURE_2D, mats::TextureType::g_normal, g_normal_texture_name, width, height, 4);
728 (*g_normal_texture)->is_builtin = true;
729
730 *g_albedo_texture = mats::init_texture(
731 MEMORY_PUSH(memory_pool, mats::Texture, "g_albedo_texture"),
732 GL_TEXTURE_2D, mats::TextureType::g_albedo, g_albedo_texture_name, width, height, 4);
733 (*g_albedo_texture)->is_builtin = true;
734
735 *g_pbr_texture = mats::init_texture(
736 MEMORY_PUSH(memory_pool, mats::Texture, "g_pbr_texture"),
737 GL_TEXTURE_2D, mats::TextureType::g_pbr, g_pbr_texture_name, width, height, 4);
738 (*g_pbr_texture)->is_builtin = true;
739
740 glBindTexture(GL_TEXTURE_2D, (*g_position_texture)->texture_name);
741 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
742 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
743 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F,
744 (*g_position_texture)->width, (*g_position_texture)->height,
745 0, GL_RGBA, GL_FLOAT, NULL);
746 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
747 (*g_position_texture)->texture_name, 0);
748
749 glBindTexture(GL_TEXTURE_2D, (*g_normal_texture)->texture_name);
750 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
751 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
752 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F,
753 (*g_normal_texture)->width, (*g_normal_texture)->height,
754 0, GL_RGBA, GL_FLOAT, NULL);
755 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D,
756 (*g_normal_texture)->texture_name, 0);
757
758 glBindTexture(GL_TEXTURE_2D, (*g_albedo_texture)->texture_name);
759 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
760 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
761 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
762 (*g_albedo_texture)->width, (*g_albedo_texture)->height,
763 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
764 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D,
765 (*g_albedo_texture)->texture_name, 0);
766
767 glBindTexture(GL_TEXTURE_2D, (*g_pbr_texture)->texture_name);
768 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
769 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
770 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
771 (*g_pbr_texture)->width, (*g_pbr_texture)->height,
772 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
773 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D,
774 (*g_pbr_texture)->texture_name, 0);
775
776 u32 attachments[4] = {
777 GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
778 GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3
779 };
780 glDrawBuffers(4, attachments);
781
782 u32 rbo_depth;
783 glGenRenderbuffers(1, &rbo_depth);
784 glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
785 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
786 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
787 rbo_depth);
788
789 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
790 logs::fatal("Framebuffer not complete!");
791 }
792}
793
794
795void
796renderer::init_l_buffer(
797 memory::Pool *memory_pool,
798 u32 *l_buffer,
799 mats::Texture **l_color_texture,
800 mats::Texture **l_bright_color_texture,
801 mats::Texture **l_depth_texture,
802 u32 width,
803 u32 height
804) {
805 glGenFramebuffers(1, l_buffer);
806 glBindFramebuffer(GL_FRAMEBUFFER, *l_buffer);
807
808 // l_color_texture
809 {
810 u32 l_color_texture_name;
811 glGenTextures(1, &l_color_texture_name);
812
813 *l_color_texture = mats::init_texture(
814 MEMORY_PUSH(memory_pool, mats::Texture, "l_color_texture"),
815 GL_TEXTURE_2D, mats::TextureType::l_color, l_color_texture_name,
816 width, height, 4);
817 (*l_color_texture)->is_builtin = true;
818
819 glBindTexture(GL_TEXTURE_2D, (*l_color_texture)->texture_name);
820 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
821 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
822 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
823 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
824 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F,
825 (*l_color_texture)->width, (*l_color_texture)->height,
826 0, GL_RGBA, GL_FLOAT, NULL);
827 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
828 (*l_color_texture)->texture_name, 0);
829 }
830
831 // l_bright_color_texture
832 {
833 u32 l_bright_color_texture_name;
834 glGenTextures(1, &l_bright_color_texture_name);
835
836 *l_bright_color_texture = mats::init_texture(
837 MEMORY_PUSH(memory_pool, mats::Texture, "l_bright_color_texture"),
838 GL_TEXTURE_2D, mats::TextureType::l_bright_color, l_bright_color_texture_name,
839 width, height, 4);
840 (*l_bright_color_texture)->is_builtin = true;
841
842 glBindTexture(GL_TEXTURE_2D, (*l_bright_color_texture)->texture_name);
843 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
844 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
845 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
846 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
847 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F,
848 (*l_bright_color_texture)->width,
849 (*l_bright_color_texture)->height,
850 0, GL_RGBA, GL_FLOAT, NULL);
851 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D,
852 (*l_bright_color_texture)->texture_name, 0);
853 }
854
855 // Attach textures
856 {
857 u32 attachments[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
858 glDrawBuffers(2, attachments);
859 }
860
861 if (SETTINGS.fog_on) {
862 // l_depth_texture
863 // NOTE: Either this or the depth buffer should be enabled, not both
864 // NOTE: This does not work on macOS. The most likely reason is that in
865 // the render() function, we copy the depth framebuffer from the
866 // g_buffer to the "depth framebuffer" of the l_buffer (this one). Of
867 // course, the l_buffer does not have a depth framebuffer, but it has a
868 // depth texture. It looks like some machines are capable of doing the
869 // right thing, but we can't rely on being able to do this. The solution
870 // would probably be to use a depth texture for the g_buffer as well.
871 // That way, we know we can copy the depth from one to the other without
872 // issues. For the moment, we're not using fog, so this is just
873 // commented out.
874 u32 l_depth_texture_name;
875 glGenTextures(1, &l_depth_texture_name);
876
877 *l_depth_texture = mats::init_texture(
878 MEMORY_PUSH(memory_pool, mats::Texture, "l_depth_texture"),
879 GL_TEXTURE_2D, mats::TextureType::l_depth, l_depth_texture_name,
880 width, height, 1);
881 (*l_depth_texture)->is_builtin = true;
882
883 glBindTexture(GL_TEXTURE_2D, (*l_depth_texture)->texture_name);
884 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
885 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
886 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
887 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
888 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
889 (*l_depth_texture)->width, (*l_depth_texture)->height,
890 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
891 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
892 (*l_depth_texture)->texture_name, 0);
893 } else {
894 // Depth buffer
895 // NOTE: Either this or the l_depth_texure should be enabled, not both
896 u32 rbo_depth;
897 glGenRenderbuffers(1, &rbo_depth);
898 glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
899 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
900 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
901 rbo_depth);
902 }
903
904 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
905 logs::fatal("Framebuffer not complete!");
906 }
907}
908
909
910void
911renderer::init_blur_buffers(
912 memory::Pool *memory_pool,
913 u32 *blur1_buffer,
914 u32 *blur2_buffer,
915 mats::Texture **blur1_texture,
916 mats::Texture **blur2_texture,
917 u32 width,
918 u32 height
919) {
920 if (!SETTINGS.bloom_on) {
921 return;
922 }
923 glGenFramebuffers(1, blur1_buffer);
924 glBindFramebuffer(GL_FRAMEBUFFER, *blur1_buffer);
925 u32 blur1_texture_name;
926 glGenTextures(1, &blur1_texture_name);
927
928 *blur1_texture = mats::init_texture(
929 MEMORY_PUSH(memory_pool, mats::Texture, "blur1_texture"),
930 GL_TEXTURE_2D, mats::TextureType::blur1, blur1_texture_name,
931 width, height, 4);
932 (*blur1_texture)->is_builtin = true;
933
934 glBindTexture(GL_TEXTURE_2D, (*blur1_texture)->texture_name);
935 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
936 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
937 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
938 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
939 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F,
940 (*blur1_texture)->width, (*blur1_texture)->height,
941 0, GL_RGBA, GL_FLOAT, NULL);
942 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
943 (*blur1_texture)->texture_name, 0);
944
945 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
946 logs::fatal("Framebuffer not complete!");
947 }
948
949 glGenFramebuffers(1, blur2_buffer);
950 glBindFramebuffer(GL_FRAMEBUFFER, *blur2_buffer);
951 u32 blur2_texture_name;
952 glGenTextures(1, &blur2_texture_name);
953
954 *blur2_texture = mats::init_texture(
955 MEMORY_PUSH(memory_pool, mats::Texture, "blur2_texture"),
956 GL_TEXTURE_2D, mats::TextureType::blur2, blur2_texture_name,
957 width, height, 4);
958 (*blur2_texture)->is_builtin = true;
959
960 glBindTexture(GL_TEXTURE_2D, (*blur2_texture)->texture_name);
961 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
962 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
963 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
964 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
965 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F,
966 (*blur2_texture)->width, (*blur2_texture)->height,
967 0, GL_RGBA, GL_FLOAT, NULL);
968 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
969 (*blur2_texture)->texture_name, 0);
970
971 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
972 logs::fatal("Framebuffer not complete!");
973 }
974}
975
976
977void
978renderer::init_ubo(u32 *ubo_shader_common)
979{
980 glGenBuffers(1, ubo_shader_common);
981 glBindBuffer(GL_UNIFORM_BUFFER, *ubo_shader_common);
982 glBufferData(GL_UNIFORM_BUFFER, sizeof(ShaderCommon), NULL, GL_STATIC_DRAW);
983 glBindBuffer(GL_UNIFORM_BUFFER, 0);
984 glBindBufferRange(GL_UNIFORM_BUFFER, 0, *ubo_shader_common, 0, sizeof(ShaderCommon));
985}
986
987
988void
989renderer::init_3d_shadowmaps(
990 memory::Pool *memory_pool,
991 u32 *shadowmaps_3d_framebuffer,
992 u32 *shadowmaps_3d,
993 mats::Texture **shadowmaps_3d_texture,
994 u32 shadowmap_3d_width,
995 u32 shadowmap_3d_height
996) {
997 glGenFramebuffers(1, shadowmaps_3d_framebuffer);
998 glGenTextures(1, shadowmaps_3d);
999 glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, *shadowmaps_3d);
1000
1001 glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 1, GL_DEPTH_COMPONENT32F,
1002 shadowmap_3d_width, shadowmap_3d_height,
1003 6 * MAX_N_LIGHTS);
1004
1005 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1006 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1007 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1008 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1009 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
1010 glBindFramebuffer(GL_FRAMEBUFFER, *shadowmaps_3d_framebuffer);
1011 glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, *shadowmaps_3d, 0);
1012
1013 // #slow
1014 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
1015 logs::fatal("Framebuffer not complete!");
1016 }
1017
1018 *shadowmaps_3d_texture = mats::init_texture(
1019 MEMORY_PUSH(memory_pool, mats::Texture, "shadowmaps_3d_texture"),
1020 GL_TEXTURE_CUBE_MAP_ARRAY,
1021 mats::TextureType::shadowmaps_3d, *shadowmaps_3d,
1022 shadowmap_3d_width, shadowmap_3d_height, 1);
1023 (*shadowmaps_3d_texture)->is_builtin = true;
1024}
1025
1026
1027void
1028renderer::init_2d_shadowmaps(
1029 memory::Pool *memory_pool,
1030 u32 *shadowmaps_2d_framebuffer,
1031 u32 *shadowmaps_2d,
1032 mats::Texture **shadowmaps_2d_texture,
1033 u32 shadowmap_2d_width,
1034 u32 shadowmap_2d_height
1035) {
1036 glGenFramebuffers(1, shadowmaps_2d_framebuffer);
1037 glGenTextures(1, shadowmaps_2d);
1038 glBindTexture(GL_TEXTURE_2D_ARRAY, *shadowmaps_2d);
1039
1040 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_DEPTH_COMPONENT32F,
1041 shadowmap_2d_width, shadowmap_2d_height, MAX_N_LIGHTS);
1042
1043 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1044 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1045 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1046 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1047 f32 border_color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
1048 glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, border_color);
1049 glBindFramebuffer(GL_FRAMEBUFFER, *shadowmaps_2d_framebuffer);
1050 glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, *shadowmaps_2d, 0);
1051
1052 // #slow
1053 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
1054 logs::fatal("Framebuffer not complete!");
1055 }
1056
1057 *shadowmaps_2d_texture = mats::init_texture(
1058 MEMORY_PUSH(memory_pool, mats::Texture, "shadowmaps_2d_texture"),
1059 GL_TEXTURE_2D_ARRAY,
1060 mats::TextureType::shadowmaps_2d, *shadowmaps_2d,
1061 shadowmap_2d_width,
1062 shadowmap_2d_height, 1);
1063 (*shadowmaps_2d_texture)->is_builtin = true;
1064}
1065
1066
1067void
1068renderer::init_gui(memory::Pool *memory_pool)
1069{
1070 memory::Pool temp_memory_pool = {};
1071
1072 // VAO
1073 {
1074 glGenVertexArrays(1, &renderer::state->gui_vao);
1075 glGenBuffers(1, &renderer::state->gui_vbo);
1076 glBindVertexArray(renderer::state->gui_vao);
1077 glBindBuffer(GL_ARRAY_BUFFER, renderer::state->gui_vbo);
1078 glBufferData(GL_ARRAY_BUFFER, GUI_VERTEX_SIZE * GUI_MAX_N_VERTICES, NULL, GL_DYNAMIC_DRAW);
1079 u32 location;
1080
1081 // position (vec2)
1082 location = 0;
1083 glEnableVertexAttribArray(location);
1084 glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, GUI_VERTEX_SIZE,
1085 (void*)(0));
1086
1087 // tex_coords (vec2)
1088 location = 1;
1089 glEnableVertexAttribArray(location);
1090 glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, GUI_VERTEX_SIZE,
1091 (void*)(2 * sizeof(f32)));
1092
1093 // color (vec4)
1094 location = 2;
1095 glEnableVertexAttribArray(location);
1096 glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, GUI_VERTEX_SIZE,
1097 (void*)(4 * sizeof(f32)));
1098 }
1099
1100 // Shaders
1101 shaders::init_shader_asset(&renderer::state->gui_shader_asset, &temp_memory_pool,
1102 "gui_generic", shaders::Type::standard, "gui_generic.vert", "gui_generic.frag", "");
1103
1104 // Materials
1105 mats::init_texture_atlas(&renderer::state->gui_texture_atlas, iv2(2000, 2000));
1106
1107 // Fonts
1108 {
1109 renderer::state->gui_font_assets = Array<fonts::FontAsset>(memory_pool, 8, "gui_font_assets");
1110 FT_Library ft_library;
1111 if (FT_Init_FreeType(&ft_library)) {
1112 logs::error("Could not init FreeType");
1113 return;
1114 }
1115 fonts::init_font_asset(renderer::state->gui_font_assets.push(),
1116 memory_pool, &renderer::state->gui_texture_atlas,
1117 &ft_library, "body", gui::MAIN_FONT_REGULAR, 18);
1118 fonts::init_font_asset(renderer::state->gui_font_assets.push(),
1119 memory_pool, &renderer::state->gui_texture_atlas,
1120 &ft_library, "body-bold", gui::MAIN_FONT_BOLD, 18);
1121 fonts::init_font_asset(renderer::state->gui_font_assets.push(),
1122 memory_pool, &renderer::state->gui_texture_atlas,
1123 &ft_library, "heading", gui::MAIN_FONT_REGULAR, 42);
1124 fonts::init_font_asset(renderer::state->gui_font_assets.push(),
1125 memory_pool, &renderer::state->gui_texture_atlas,
1126 &ft_library, "title", gui::MAIN_FONT_REGULAR, 64);
1127 FT_Done_FreeType(ft_library);
1128 }
1129
1130 memory::destroy_memory_pool(&temp_memory_pool);
1131}
1132
1133
1134void
1135renderer::copy_scene_data_to_ubo(
1136 u32 current_shadow_light_idx,
1137 u32 current_shadow_light_type,
1138 bool is_blur_horizontal
1139) {
1140 WindowSize *window_size = core::get_window_size();
1141 ShaderCommon *shader_common = &renderer::state->shader_common;
1142 cameras::Camera *camera = cameras::get_main();
1143
1144 shader_common->view = camera->view;
1145 shader_common->projection = camera->projection;
1146 shader_common->ui_projection = camera->ui_projection;
1147 memcpy(shader_common->shadowmap_3d_transforms,
1148 renderer::state->shadowmap_3d_transforms,
1149 sizeof(renderer::state->shadowmap_3d_transforms));
1150 memcpy(shader_common->shadowmap_2d_transforms,
1151 renderer::state->shadowmap_2d_transforms,
1152 sizeof(renderer::state->shadowmap_2d_transforms));
1153
1154 shader_common->camera_position = v4(camera->position, 1.0f);
1155 shader_common->camera_pitch = (float)camera->pitch;
1156
1157 shader_common->camera_horizontal_fov = camera->horizontal_fov;
1158 shader_common->camera_vertical_fov = camera->vertical_fov;
1159 shader_common->camera_near_clip_dist = camera->near_clip_dist;
1160 shader_common->camera_far_clip_dist = camera->far_clip_dist;
1161
1162 shader_common->current_shadow_light_idx = current_shadow_light_idx;
1163 shader_common->current_shadow_light_type = current_shadow_light_type;
1164
1165 shader_common->shadow_far_clip_dist =
1166 renderer::state->builtin_textures.shadowmap_far_clip_dist;
1167 shader_common->is_blur_horizontal = is_blur_horizontal;
1168 shader_common->renderdebug_displayed_texture_type =
1169 renderer::state->renderdebug_displayed_texture_type;
1170 shader_common->unused_pad = 0;
1171
1172 shader_common->exposure = camera->exposure;
1173 shader_common->t = (float)(engine::get_t());
1174 shader_common->window_width = window_size->width;
1175 shader_common->window_height = window_size->height;
1176
1177 u32 n_point_lights = 0;
1178 u32 n_directional_lights = 0;
1179
1180 each (light_component, *lights::get_components()) {
1181 if (light_component->entity_handle == entities::NO_ENTITY_HANDLE) {
1182 continue;
1183 }
1184
1185 spatial::Component *spatial_component =
1186 spatial::get_component(light_component->entity_handle);
1187
1188 if (!(
1189 lights::is_light_component_valid(light_component) &&
1190 spatial::is_spatial_component_valid(spatial_component)
1191 )) {
1192 continue;
1193 }
1194
1195 if (light_component->type == lights::LightType::point) {
1196 shader_common->point_light_position[n_point_lights] = v4(
1197 spatial_component->position, 1.0f
1198 );
1199 shader_common->point_light_color[n_point_lights] =
1200 light_component->color;
1201 shader_common->point_light_attenuation[n_point_lights] =
1202 light_component->attenuation;
1203 n_point_lights++;
1204 } else if (light_component->type == lights::LightType::directional) {
1205 shader_common->directional_light_position[n_directional_lights] =
1206 v4(spatial_component->position, 1.0f);
1207 shader_common->directional_light_direction[n_directional_lights] =
1208 v4(light_component->direction, 1.0f);
1209 shader_common->directional_light_color[n_directional_lights] =
1210 light_component->color;
1211 shader_common->directional_light_attenuation[n_directional_lights] =
1212 light_component->attenuation;
1213 n_directional_lights++;
1214 }
1215 }
1216
1217 shader_common->n_point_lights = n_point_lights;
1218 shader_common->n_directional_lights = n_directional_lights;
1219
1220 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(ShaderCommon), shader_common);
1221}
1222
1223
1224void
1225renderer::draw(
1226 drawable::Mode render_mode,
1227 drawable::Component *drawable_component,
1228 mats::Material *material,
1229 m4 *model_matrix,
1230 m3 *model_normal_matrix,
1231 m4 *bone_matrices,
1232 shaders::Asset *standard_depth_shader_asset
1233) {
1234 shaders::Asset *shader_asset = nullptr;
1235
1236 if (render_mode == drawable::Mode::regular) {
1237 shader_asset = &material->shader_asset;
1238 } else if (render_mode == drawable::Mode::depth) {
1239 if (shaders::is_shader_asset_valid(&material->depth_shader_asset)) {
1240 shader_asset = &material->depth_shader_asset;
1241 } else {
1242 shader_asset = standard_depth_shader_asset;
1243 }
1244 }
1245
1246 assert(shader_asset);
1247
1248 // If our shader program has changed since our last mesh, tell OpenGL about it.
1249 if (shader_asset->program != drawable::get_last_drawn_shader_program()) {
1250 glUseProgram(shader_asset->program);
1251 drawable::set_last_drawn_shader_program(shader_asset->program);
1252
1253 if (render_mode == drawable::Mode::regular) {
1254 for (
1255 u32 texture_idx = 1;
1256 texture_idx < shader_asset->n_texture_units + 1; texture_idx++
1257 ) {
1258 if (shader_asset->texture_units[texture_idx] != 0) {
1259 glActiveTexture(GL_TEXTURE0 + texture_idx);
1260 glBindTexture(shader_asset->texture_unit_types[texture_idx],
1261 shader_asset->texture_units[texture_idx]);
1262 }
1263 }
1264 }
1265 }
1266
1267 for (
1268 u32 uniform_idx = 0;
1269 uniform_idx < shader_asset->n_intrinsic_uniforms;
1270 uniform_idx++
1271 ) {
1272 const char *uniform_name = shader_asset->intrinsic_uniform_names[uniform_idx];
1273 if (pstr_eq(uniform_name, "model_matrix")) {
1274 shaders::set_mat4(shader_asset, "model_matrix", model_matrix);
1275 } else if (pstr_eq(uniform_name, "model_normal_matrix")) {
1276 shaders::set_mat3(shader_asset, "model_normal_matrix", model_normal_matrix);
1277 } else if (bone_matrices && pstr_eq(uniform_name, "bone_matrices[0]")) {
1278 shaders::set_mat4_multiple(shader_asset, MAX_N_BONES,
1279 "bone_matrices[0]", bone_matrices);
1280 }
1281 }
1282
1283 geom::Mesh *mesh = &drawable_component->mesh;
1284 glBindVertexArray(mesh->vao);
1285 if (mesh->n_indices > 0) {
1286 glDrawElements(mesh->mode, mesh->n_indices, GL_UNSIGNED_INT, 0);
1287 } else {
1288 glDrawArrays(mesh->mode, 0, mesh->n_vertices);
1289 }
1290}
1291
1292
1293void
1294renderer::draw_all(
1295 drawable::Pass render_pass,
1296 drawable::Mode render_mode,
1297 shaders::Asset *standard_depth_shader_asset
1298) {
1299 spatial::ModelMatrixCache cache = { m4(1.0f), nullptr };
1300
1301 each (drawable_component, *drawable::get_components()) {
1302 if (!drawable::is_component_valid(drawable_component)) {
1303 continue;
1304 }
1305
1306 if (!((u32)render_pass & (u32)drawable_component->target_render_pass)) {
1307 continue;
1308 }
1309
1310#if 0
1311 logs::info("Drawing %s",
1312 engine::get_entity(drawable_component->entity_handle)->debug_name);
1313#endif
1314
1315 mats::Material *material = mats::get_material_by_name(
1316 drawable_component->mesh.material_name);
1317
1318 if (!material || material->state != mats::MaterialState::complete) {
1319 material = mats::get_material_by_name("unknown");
1320 }
1321
1322 spatial::Component *spatial_component = spatial::get_component(drawable_component->entity_handle);
1323
1324 m4 model_matrix = m4(1.0f);
1325 m3 model_normal_matrix = m3(1.0f);
1326 m4 *bone_matrices = nullptr;
1327
1328 if (spatial::is_spatial_component_valid(spatial_component)) {
1329 // We only need to calculate the normal matrix if we have non-uniform
1330 // scaling.
1331 model_matrix = spatial::make_model_matrix(spatial_component, &cache);
1332
1333 // TODO: Even though we have a uniform scaling in the transformation for
1334 // our spatial component itself, when accumulating it with the parent
1335 // spatial components, we might (possibly) get non-uniform scaling,
1336 // in which case we want to calculate the model normal matrix!
1337 // Oops! We should be looking at the model_matrix and not at
1338 // spatial_component->scale.
1339 if (
1340 spatial_component->scale.x == spatial_component->scale.y &&
1341 spatial_component->scale.y == spatial_component->scale.z
1342 ) {
1343 model_normal_matrix = m3(model_matrix);
1344 } else {
1345 model_normal_matrix = m3(transpose(inverse(model_matrix)));
1346 }
1347
1348 // Animations
1349 anim::Component *animation_component = anim::find_animation_component(
1350 spatial_component);
1351 if (animation_component) {
1352 bone_matrices = animation_component->bone_matrices;
1353 }
1354 }
1355
1356 draw(render_mode, drawable_component, material,
1357 &model_matrix, &model_normal_matrix, bone_matrices, standard_depth_shader_asset);
1358 }
1359}
1360
1361
1362void
1363renderer::render_scene(drawable::Pass render_pass, drawable::Mode render_mode)
1364{
1365#if 0
1366 logs::info("drawable::Pass: %s", render_pass_to_string(render_pass));
1367#endif
1368 draw_all(render_pass, render_mode,
1369 &renderer::state->standard_depth_shader_asset);
1370}