remove junk
[carveJwlIkooP6JGAAIwe30JlM.git] / render.h
1 /*
2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #include "common.h"
6 #include "model.h"
7 #include "camera.h"
8
9 #include "shaders/blit.h"
10 #include "shaders/blitblur.h"
11 #include "shaders/standard.h"
12 #include "shaders/vblend.h"
13
14 VG_STATIC void render_water_texture( camera *cam );
15 VG_STATIC void render_water_surface( camera *cam );
16 VG_STATIC void render_world( camera *cam );
17 VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id );
18 VG_STATIC void render_world_depth( camera *cam );
19
20 #ifndef RENDER_H
21 #define RENDER_H
22
23 typedef struct framebuffer framebuffer;
24
25
26 /*
27 * All standard buffers used in rendering
28 */
29 VG_STATIC struct pipeline
30 {
31 glmesh fsquad;
32
33 framebuffer *fb_main,
34 *fb_heightmap,
35 *fb_water_reflection,
36 *fb_water_beneath;
37
38 /* STD140 */
39 struct ub_world_lighting
40 {
41 /* v3f (padded) */
42 v4f g_light_colours[3],
43 g_light_directions[3],
44 g_ambient_colour;
45
46 v4f g_water_plane,
47 g_depth_bounds;
48
49 float g_water_fog;
50 int g_light_count;
51 int g_light_preview;
52 int g_shadow_samples;
53 }
54 ub_world_lighting;
55
56 struct light_widget
57 {
58 int enabled;
59 v2f dir;
60 v3f colour;
61 }
62 widgets[3];
63
64 float shadow_spread, shadow_length;
65 GLuint ubo_world_lighting,
66 ubo_world;
67
68 int ready;
69 }
70 gpipeline =
71 {
72 .widgets =
73 {
74 {
75 .enabled = 1,
76 .colour = { 1.36f, 1.35f, 1.01f },
77 .dir = { 0.63f, -0.08f }
78 },
79 {
80 .enabled = 1,
81 .colour = { 0.33f, 0.56f, 0.64f },
82 .dir = { -2.60f, -0.13f }
83 },
84 {
85 .enabled = 1,
86 .colour = { 0.05f, 0.05f, 0.23f },
87 .dir = { 2.60f, -0.84f }
88 }
89 },
90 .shadow_spread = 0.65f,
91 .shadow_length = 9.50f,
92
93 .ub_world_lighting =
94 {
95 .g_ambient_colour = { 0.09f, 0.03f, 0.07f }
96 }
97 };
98
99 struct framebuffer
100 {
101 const char *display_name;
102 int resolution_div,
103 fixed_w,
104 fixed_h;
105
106 struct framebuffer_attachment
107 {
108 const char *display_name;
109
110 enum framebuffer_attachment_type
111 {
112 k_framebuffer_attachment_type_none,
113 k_framebuffer_attachment_type_colour,
114 k_framebuffer_attachment_type_renderbuffer
115 }
116 purpose;
117
118 enum framebuffer_quality_profile
119 {
120 k_framebuffer_quality_all,
121 k_framebuffer_quality_high_only
122 }
123 quality;
124
125 GLenum internalformat,
126 format,
127 type,
128 attachment;
129
130 GLuint id;
131 }
132 attachments[5];
133 GLuint fb;
134 framebuffer **link;
135 }
136 framebuffers[] =
137 {
138 {
139 /*
140 * The primary draw target
141 */
142 "Main",
143 .link = &gpipeline.fb_main,
144 .resolution_div = 1,
145 .attachments =
146 {
147 {
148 "Colour", k_framebuffer_attachment_type_colour,
149
150 .internalformat = GL_RGB,
151 .format = GL_RGB,
152 .type = GL_UNSIGNED_BYTE,
153 .attachment = GL_COLOR_ATTACHMENT0
154 },
155 {
156 "Motion Vectors", k_framebuffer_attachment_type_colour,
157
158 .quality = k_framebuffer_quality_high_only,
159 .internalformat = GL_RG16F,
160 .format = GL_RG,
161 .type = GL_FLOAT,
162 .attachment = GL_COLOR_ATTACHMENT1
163 },
164 {
165 "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
166
167 .internalformat = GL_DEPTH24_STENCIL8,
168 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
169 }
170 }
171 },
172 {
173 /*
174 * A ortho projection of the world, used for shadows and ocean colouring.
175 * Note: it does not have a render buffer attachement because it's
176 * intended to be drawn to in a MAX blending mode
177 */
178 "Heightmap",
179 .link = &gpipeline.fb_heightmap,
180 .fixed_w = 1024,
181 .fixed_h = 1024,
182
183 .attachments =
184 {
185 {
186 "Depth", k_framebuffer_attachment_type_colour,
187
188 .internalformat = GL_R32F,
189 .format = GL_RED,
190 .type = GL_FLOAT,
191 .attachment = GL_COLOR_ATTACHMENT0
192 }
193 }
194 },
195 {
196 /*
197 * Second rendered view from the perspective of the water reflection
198 */
199 "Water reflection",
200 .link = &gpipeline.fb_water_reflection,
201 .resolution_div = 3,
202 .attachments =
203 {
204 {
205 "Colour", k_framebuffer_attachment_type_colour,
206 .internalformat = GL_RGB,
207 .format = GL_RGB,
208 .type = GL_UNSIGNED_BYTE,
209 .attachment = GL_COLOR_ATTACHMENT0
210 },
211 {
212 "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
213
214 .internalformat = GL_DEPTH24_STENCIL8,
215 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
216 }
217 }
218 },
219 {
220 /*
221 * Thid rendered view from the perspective of the camera, but just
222 * captures stuff thats under the water
223 */
224 "Water Beneath",
225 .link = &gpipeline.fb_water_beneath,
226 .resolution_div = 4,
227 .attachments =
228 {
229 {
230 "Colour", k_framebuffer_attachment_type_colour,
231 .internalformat = GL_RGBA,
232 .format = GL_RGBA,
233 .type = GL_UNSIGNED_BYTE,
234 .attachment = GL_COLOR_ATTACHMENT0
235 },
236 {
237 "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
238
239 .internalformat = GL_DEPTH24_STENCIL8,
240 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
241 }
242 }
243 }
244 };
245
246 /*
247 * Get the current (automatically scaled or fixed) resolution of framebuffer
248 */
249 VG_STATIC void render_fb_get_current_res( struct framebuffer *fb,
250 int *x, int *y )
251 {
252 if( fb->resolution_div )
253 {
254 *x = vg.window_x / fb->resolution_div;
255 *y = vg.window_y / fb->resolution_div;
256 }
257 else
258 {
259 *x = fb->fixed_w;
260 *y = fb->fixed_h;
261 }
262 }
263
264 /*
265 * Bind framebuffer for drawing to
266 */
267 VG_STATIC void render_fb_bind( framebuffer *fb )
268 {
269 int x, y;
270 render_fb_get_current_res( fb, &x, &y );
271 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
272 glViewport( 0, 0, x, y );
273 }
274
275 /*
276 * Bind framebuffer attachment's texture
277 */
278 VG_STATIC void render_fb_bind_texture( framebuffer *fb,
279 int attachment, int slot )
280 {
281 struct framebuffer_attachment *at = &fb->attachments[attachment];
282
283 if( at->purpose != k_framebuffer_attachment_type_colour )
284 {
285 vg_fatal_exit_loop( "illegal operation: bind non-colour framebuffer"
286 " attachment to texture slot" );
287 }
288
289 glActiveTexture( GL_TEXTURE0 + slot );
290 glBindTexture( GL_TEXTURE_2D, fb->attachments[attachment].id );
291 }
292
293
294 /*
295 * Shaders
296 */
297 VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id )
298 {
299 GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" );
300 glUniformBlockBinding( shader, idx, 0 );
301
302 render_fb_bind_texture( gpipeline.fb_heightmap, 0, texture_id );
303 glUniform1i( glGetUniformLocation( shader, "g_world_depth" ), texture_id );
304 }
305
306 VG_STATIC void render_update_lighting_ub(void)
307 {
308 struct ub_world_lighting *winf = &gpipeline.ub_world_lighting;
309 int c = 0;
310
311 for( int i=0; i<3; i++ )
312 {
313 struct light_widget *lw = &gpipeline.widgets[i];
314
315 if( lw->enabled )
316 {
317 float pitch = lw->dir[0],
318 yaw = lw->dir[1],
319 xz = cosf( pitch );
320
321 v3_copy( (v3f){ xz*cosf(yaw), sinf(pitch), xz*sinf(yaw) },
322 winf->g_light_directions[c] );
323 v3_copy( lw->colour, winf->g_light_colours[c] );
324
325 c ++;
326 }
327 }
328
329 winf->g_light_count = c;
330 winf->g_light_directions[0][3] = gpipeline.shadow_length;
331 winf->g_light_colours[0][3] = gpipeline.shadow_spread;
332
333 if( vg.quality_profile == k_quality_profile_low )
334 winf->g_shadow_samples = 0;
335 else
336 winf->g_shadow_samples = 8;
337
338 glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
339 glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting),
340 &gpipeline.ub_world_lighting );
341 }
342
343 #define FB_FORMAT_STR( E ) { E, #E },
344
345 /*
346 * Convert OpenGL attachment ID enum to string
347 */
348 VG_STATIC const char *render_fb_attachment_str( GLenum e )
349 {
350 struct { GLenum e; const char *str; }
351 formats[] =
352 {
353 FB_FORMAT_STR(GL_COLOR_ATTACHMENT0)
354 FB_FORMAT_STR(GL_COLOR_ATTACHMENT1)
355 FB_FORMAT_STR(GL_COLOR_ATTACHMENT2)
356 FB_FORMAT_STR(GL_COLOR_ATTACHMENT3)
357 FB_FORMAT_STR(GL_COLOR_ATTACHMENT4)
358 FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT)
359 };
360
361 for( int i=0; i<vg_list_size(formats); i++ )
362 if( formats[i].e == e )
363 return formats[i].str;
364
365 return "UNDEFINED";
366 }
367
368 /*
369 * Convert OpenGL texture format enums from TexImage2D table 1,2 &
370 * RenderBufferStorage Table 1, into strings
371 */
372 VG_STATIC const char *render_fb_format_str( GLenum format )
373 {
374 struct { GLenum e; const char *str; }
375 formats[] =
376 {
377 /* Table 1 */
378 FB_FORMAT_STR(GL_DEPTH_COMPONENT)
379 FB_FORMAT_STR(GL_DEPTH_STENCIL)
380 FB_FORMAT_STR(GL_RED)
381 FB_FORMAT_STR(GL_RG)
382 FB_FORMAT_STR(GL_RGB)
383 FB_FORMAT_STR(GL_RGBA)
384
385 /* Render buffer formats */
386 FB_FORMAT_STR(GL_DEPTH_COMPONENT16)
387 FB_FORMAT_STR(GL_DEPTH_COMPONENT24)
388 FB_FORMAT_STR(GL_DEPTH_COMPONENT32F)
389 FB_FORMAT_STR(GL_DEPTH24_STENCIL8)
390 FB_FORMAT_STR(GL_DEPTH32F_STENCIL8)
391 FB_FORMAT_STR(GL_STENCIL_INDEX8)
392
393 /* Table 2 */
394 FB_FORMAT_STR(GL_R8)
395 FB_FORMAT_STR(GL_R8_SNORM)
396 FB_FORMAT_STR(GL_R16)
397 FB_FORMAT_STR(GL_R16_SNORM)
398 FB_FORMAT_STR(GL_RG8)
399 FB_FORMAT_STR(GL_RG8_SNORM)
400 FB_FORMAT_STR(GL_RG16)
401 FB_FORMAT_STR(GL_RG16_SNORM)
402 FB_FORMAT_STR(GL_R3_G3_B2)
403 FB_FORMAT_STR(GL_RGB4)
404 FB_FORMAT_STR(GL_RGB5)
405 FB_FORMAT_STR(GL_RGB8)
406 FB_FORMAT_STR(GL_RGB8_SNORM)
407 FB_FORMAT_STR(GL_RGB10)
408 FB_FORMAT_STR(GL_RGB12)
409 FB_FORMAT_STR(GL_RGB16_SNORM)
410 FB_FORMAT_STR(GL_RGBA2)
411 FB_FORMAT_STR(GL_RGBA4)
412 FB_FORMAT_STR(GL_RGB5_A1)
413 FB_FORMAT_STR(GL_RGBA8)
414 FB_FORMAT_STR(GL_RGBA8_SNORM)
415 FB_FORMAT_STR(GL_RGB10_A2)
416 FB_FORMAT_STR(GL_RGB10_A2UI)
417 FB_FORMAT_STR(GL_RGBA12)
418 FB_FORMAT_STR(GL_RGBA16)
419 FB_FORMAT_STR(GL_SRGB8)
420 FB_FORMAT_STR(GL_SRGB8_ALPHA8)
421 FB_FORMAT_STR(GL_R16F)
422 FB_FORMAT_STR(GL_RG16F)
423 FB_FORMAT_STR(GL_RGB16F)
424 FB_FORMAT_STR(GL_RGBA16F)
425 FB_FORMAT_STR(GL_R32F)
426 FB_FORMAT_STR(GL_RG32F)
427 FB_FORMAT_STR(GL_RGB32F)
428 FB_FORMAT_STR(GL_RGBA32F)
429 FB_FORMAT_STR(GL_R11F_G11F_B10F)
430 FB_FORMAT_STR(GL_RGB9_E5)
431 FB_FORMAT_STR(GL_R8I)
432 FB_FORMAT_STR(GL_R8UI)
433 FB_FORMAT_STR(GL_R16I)
434 FB_FORMAT_STR(GL_R16UI)
435 FB_FORMAT_STR(GL_R32I)
436 FB_FORMAT_STR(GL_R32UI)
437 FB_FORMAT_STR(GL_RG8I)
438 FB_FORMAT_STR(GL_RG8UI)
439 FB_FORMAT_STR(GL_RG16I)
440 FB_FORMAT_STR(GL_RG16UI)
441 FB_FORMAT_STR(GL_RG32I)
442 FB_FORMAT_STR(GL_RG32UI)
443 FB_FORMAT_STR(GL_RGB8I)
444 FB_FORMAT_STR(GL_RGB8UI)
445 FB_FORMAT_STR(GL_RGB16I)
446 FB_FORMAT_STR(GL_RGB16UI)
447 FB_FORMAT_STR(GL_RGB32I)
448 FB_FORMAT_STR(GL_RGB32UI)
449 FB_FORMAT_STR(GL_RGBA8I)
450 FB_FORMAT_STR(GL_RGBA8UI)
451 FB_FORMAT_STR(GL_RGBA16I)
452 FB_FORMAT_STR(GL_RGBA16UI)
453 FB_FORMAT_STR(GL_RGBA32I)
454 FB_FORMAT_STR(GL_RGBA32UI)
455 };
456
457 for( int i=0; i<vg_list_size(formats); i++ )
458 if( formats[i].e == format )
459 return formats[i].str;
460
461 return "UNDEFINED";
462 }
463
464 /*
465 * Bind and allocate texture for framebuffer attachment
466 */
467 VG_STATIC void render_fb_allocate_texture( struct framebuffer *fb,
468 struct framebuffer_attachment *a )
469 {
470 int rx, ry;
471 render_fb_get_current_res( fb, &rx, &ry );
472
473 if( a->purpose == k_framebuffer_attachment_type_renderbuffer )
474 {
475 glBindRenderbuffer( GL_RENDERBUFFER, a->id );
476 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, rx, ry );
477 }
478 else if( a->purpose == k_framebuffer_attachment_type_colour )
479 {
480 glBindTexture( GL_TEXTURE_2D, a->id );
481 glTexImage2D( GL_TEXTURE_2D, 0, a->internalformat, rx, ry,
482 0, a->format, a->type, NULL );
483 }
484 }
485
486 /*
487 * Full allocation of a framebuffer
488 */
489 VG_STATIC void render_fb_allocate( struct framebuffer *fb )
490 {
491 glGenFramebuffers( 1, &fb->fb );
492 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
493
494 int rx, ry;
495 render_fb_get_current_res( fb, &rx, &ry );
496
497 vg_info( "allocate_framebuffer( %s, %dx%d )\n", fb->display_name, rx, ry );
498 vg_info( "{\n" );
499
500 GLenum colour_attachments[4];
501 u32 colour_count = 0;
502
503 for( int j=0; j<vg_list_size(fb->attachments); j++ )
504 {
505 struct framebuffer_attachment *attachment = &fb->attachments[j];
506
507 if( attachment->purpose == k_framebuffer_attachment_type_none )
508 continue;
509
510 vg_info( " %s: %s\n",
511 render_fb_attachment_str( attachment->attachment ),
512 render_fb_format_str( attachment->internalformat ) );
513
514 if( attachment->purpose == k_framebuffer_attachment_type_renderbuffer )
515 {
516 glGenRenderbuffers( 1, &attachment->id );
517 render_fb_allocate_texture( fb, attachment );
518 glFramebufferRenderbuffer( GL_FRAMEBUFFER,
519 GL_DEPTH_STENCIL_ATTACHMENT,
520 GL_RENDERBUFFER, attachment->id );
521 }
522 else if( attachment->purpose == k_framebuffer_attachment_type_colour )
523 {
524 glGenTextures( 1, &attachment->id );
525 render_fb_allocate_texture( fb, attachment );
526 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
527 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
528 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
529 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
530
531 glFramebufferTexture2D( GL_FRAMEBUFFER, attachment->attachment,
532 GL_TEXTURE_2D, attachment->id, 0 );
533
534 colour_attachments[ colour_count ++ ] = attachment->attachment;
535 }
536 }
537
538 glDrawBuffers( colour_count, colour_attachments );
539
540 /*
541 * Check result
542 */
543 GLenum result = glCheckFramebufferStatus( GL_FRAMEBUFFER );
544
545 if( result == GL_FRAMEBUFFER_COMPLETE )
546 {
547 /*
548 * Attatch to gpipeline
549 */
550 if( fb->link )
551 *fb->link = fb;
552
553 vg_success( " status: complete\n" );
554 vg_info( "}\n" );
555 }
556 else
557 {
558 if( result == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT )
559 vg_error( " status: Incomplete attachment" );
560 else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT )
561 vg_error( " status: Missing attachment" );
562 else if( result == GL_FRAMEBUFFER_UNSUPPORTED )
563 vg_error( " status: Unsupported framebuffer format" );
564 else
565 vg_error( " status: Generic Error" );
566
567 vg_info( "}\n" );
568 vg_fatal_exit_loop( "Incomplete framebuffer (see logs)" );
569 }
570 }
571
572 /*
573 * Resize/Update all framebuffers(we know about)
574 */
575 VG_STATIC void render_fb_resize(void)
576 {
577 if( !gpipeline.ready )
578 return;
579
580 for( int i=0; i<vg_list_size(framebuffers); i++ )
581 {
582 struct framebuffer *fb = &framebuffers[i];
583 for( int j=0; j<vg_list_size(fb->attachments); j++ )
584 {
585 struct framebuffer_attachment *attachment = &fb->attachments[j];
586 render_fb_allocate_texture( fb, attachment );
587 }
588 }
589 }
590
591 VG_STATIC void render_init_fs_quad(void)
592 {
593 vg_info( "[render] Allocate quad\n" );
594
595 float quad[] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
596 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
597
598 0.2f, 0.0f, 0.8f, 1.0f, 0.2f, 1.0f,
599 0.2f, 0.0f, 0.8f, 0.0f, 0.8f, 1.0f};
600
601 glGenVertexArrays( 1, &gpipeline.fsquad.vao );
602 glGenBuffers( 1, &gpipeline.fsquad.vbo );
603 glBindVertexArray( gpipeline.fsquad.vao );
604 glBindBuffer( GL_ARRAY_BUFFER, gpipeline.fsquad.vbo );
605 glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW );
606 glBindVertexArray( gpipeline.fsquad.vao );
607 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE,
608 sizeof(float)*2, (void*)0 );
609 glEnableVertexAttribArray( 0 );
610
611 VG_CHECK_GL_ERR();
612 }
613
614 VG_STATIC void render_init_uniform_buffers(void)
615 {
616 vg_info( "[render] Allocate uniform buffer\n" );
617
618 glGenBuffers( 1, &gpipeline.ubo_world_lighting );
619 glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
620 glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting),
621 NULL, GL_DYNAMIC_DRAW );
622
623 render_update_lighting_ub();
624 glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting );
625
626 VG_CHECK_GL_ERR();
627 }
628
629 VG_STATIC void render_init(void)
630 {
631 shader_blit_register();
632 shader_blitblur_register();
633 shader_standard_register();
634 shader_vblend_register();
635
636 vg_acquire_thread_sync();
637 {
638 /*
639 * Complete Framebuffers
640 */
641 for( int i=0; i<vg_list_size(framebuffers); i++ )
642 {
643 struct framebuffer *fb = &framebuffers[i];
644 render_fb_allocate( fb );
645 }
646
647 render_init_fs_quad();
648 render_init_uniform_buffers();
649
650 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
651 gpipeline.ready = 1;
652 }
653
654 vg_release_thread_sync();
655 }
656
657 /*
658 * Utility
659 */
660 VG_STATIC void render_fsquad(void)
661 {
662 glBindVertexArray( gpipeline.fsquad.vao );
663 glDrawArrays( GL_TRIANGLES, 0, 6 );
664 }
665
666 VG_STATIC void render_fsquad1(void)
667 {
668 glBindVertexArray( gpipeline.fsquad.vao );
669 glDrawArrays( GL_TRIANGLES, 6, 6 );
670 }
671
672 #endif /* RENDER_H */