a fairly major physics update
[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 /* Runtime */
133 int debug_view;
134 }
135 attachments[5];
136 GLuint fb;
137 framebuffer **link;
138 }
139 framebuffers[] =
140 {
141 {
142 /*
143 * The primary draw target
144 */
145 "main",
146 .link = &gpipeline.fb_main,
147 .resolution_div = 1,
148 .attachments =
149 {
150 {
151 "colour", k_framebuffer_attachment_type_colour,
152
153 .internalformat = GL_RGB,
154 .format = GL_RGB,
155 .type = GL_UNSIGNED_BYTE,
156 .attachment = GL_COLOR_ATTACHMENT0
157 },
158 {
159 "motion", k_framebuffer_attachment_type_colour,
160
161 .quality = k_framebuffer_quality_high_only,
162 .internalformat = GL_RG16F,
163 .format = GL_RG,
164 .type = GL_FLOAT,
165 .attachment = GL_COLOR_ATTACHMENT1
166 },
167 {
168 "depth_stencil", k_framebuffer_attachment_type_renderbuffer,
169
170 .internalformat = GL_DEPTH24_STENCIL8,
171 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
172 }
173 }
174 },
175 {
176 /*
177 * A ortho projection of the world, used for shadows and ocean colouring.
178 * Note: it does not have a render buffer attachement because it's
179 * intended to be drawn to in a MAX blending mode
180 */
181 "heightmap",
182 .link = &gpipeline.fb_heightmap,
183 .fixed_w = 1024,
184 .fixed_h = 1024,
185
186 .attachments =
187 {
188 {
189 "depth", k_framebuffer_attachment_type_colour,
190
191 .internalformat = GL_R32F,
192 .format = GL_RED,
193 .type = GL_FLOAT,
194 .attachment = GL_COLOR_ATTACHMENT0
195 }
196 }
197 },
198 {
199 /*
200 * Second rendered view from the perspective of the water reflection
201 */
202 "water_reflection",
203 .link = &gpipeline.fb_water_reflection,
204 .resolution_div = 3,
205 .attachments =
206 {
207 {
208 "colour", k_framebuffer_attachment_type_colour,
209 .internalformat = GL_RGB,
210 .format = GL_RGB,
211 .type = GL_UNSIGNED_BYTE,
212 .attachment = GL_COLOR_ATTACHMENT0
213 },
214 {
215 "depth_stencil", k_framebuffer_attachment_type_renderbuffer,
216
217 .internalformat = GL_DEPTH24_STENCIL8,
218 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
219 }
220 }
221 },
222 {
223 /*
224 * Thid rendered view from the perspective of the camera, but just
225 * captures stuff thats under the water
226 */
227 "water_beneath",
228 .link = &gpipeline.fb_water_beneath,
229 .resolution_div = 4,
230 .attachments =
231 {
232 {
233 "colour", k_framebuffer_attachment_type_colour,
234 .internalformat = GL_RGBA,
235 .format = GL_RGBA,
236 .type = GL_UNSIGNED_BYTE,
237 .attachment = GL_COLOR_ATTACHMENT0
238 },
239 {
240 "depth_stencil", k_framebuffer_attachment_type_renderbuffer,
241
242 .internalformat = GL_DEPTH24_STENCIL8,
243 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
244 }
245 }
246 }
247 };
248
249 /*
250 * Get the current (automatically scaled or fixed) resolution of framebuffer
251 */
252 VG_STATIC void render_fb_get_current_res( struct framebuffer *fb,
253 int *x, int *y )
254 {
255 if( fb->resolution_div )
256 {
257 *x = vg.window_x / fb->resolution_div;
258 *y = vg.window_y / fb->resolution_div;
259 }
260 else
261 {
262 *x = fb->fixed_w;
263 *y = fb->fixed_h;
264 }
265 }
266
267 /*
268 * Bind framebuffer for drawing to
269 */
270 VG_STATIC void render_fb_bind( framebuffer *fb )
271 {
272 int x, y;
273 render_fb_get_current_res( fb, &x, &y );
274 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
275 glViewport( 0, 0, x, y );
276 }
277
278 /*
279 * Bind framebuffer attachment's texture
280 */
281 VG_STATIC void render_fb_bind_texture( framebuffer *fb,
282 int attachment, int slot )
283 {
284 struct framebuffer_attachment *at = &fb->attachments[attachment];
285
286 if( at->purpose != k_framebuffer_attachment_type_colour )
287 {
288 vg_fatal_exit_loop( "illegal operation: bind non-colour framebuffer"
289 " attachment to texture slot" );
290 }
291
292 glActiveTexture( GL_TEXTURE0 + slot );
293 glBindTexture( GL_TEXTURE_2D, fb->attachments[attachment].id );
294 }
295
296
297 /*
298 * Shaders
299 */
300 VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id )
301 {
302 GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" );
303 glUniformBlockBinding( shader, idx, 0 );
304
305 render_fb_bind_texture( gpipeline.fb_heightmap, 0, texture_id );
306 glUniform1i( glGetUniformLocation( shader, "g_world_depth" ), texture_id );
307 }
308
309 VG_STATIC void render_update_lighting_ub(void)
310 {
311 struct ub_world_lighting *winf = &gpipeline.ub_world_lighting;
312 int c = 0;
313
314 for( int i=0; i<3; i++ )
315 {
316 struct light_widget *lw = &gpipeline.widgets[i];
317
318 if( lw->enabled )
319 {
320 float pitch = lw->dir[0],
321 yaw = lw->dir[1],
322 xz = cosf( pitch );
323
324 v3_copy( (v3f){ xz*cosf(yaw), sinf(pitch), xz*sinf(yaw) },
325 winf->g_light_directions[c] );
326 v3_copy( lw->colour, winf->g_light_colours[c] );
327
328 c ++;
329 }
330 }
331
332 winf->g_light_count = c;
333 winf->g_light_directions[0][3] = gpipeline.shadow_length;
334 winf->g_light_colours[0][3] = gpipeline.shadow_spread;
335
336 if( vg.quality_profile == k_quality_profile_low )
337 winf->g_shadow_samples = 0;
338 else
339 winf->g_shadow_samples = 8;
340
341 glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
342 glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting),
343 &gpipeline.ub_world_lighting );
344 }
345
346 #define FB_FORMAT_STR( E ) { E, #E },
347
348 /*
349 * Convert OpenGL attachment ID enum to string
350 */
351 VG_STATIC const char *render_fb_attachment_str( GLenum e )
352 {
353 struct { GLenum e; const char *str; }
354 formats[] =
355 {
356 FB_FORMAT_STR(GL_COLOR_ATTACHMENT0)
357 FB_FORMAT_STR(GL_COLOR_ATTACHMENT1)
358 FB_FORMAT_STR(GL_COLOR_ATTACHMENT2)
359 FB_FORMAT_STR(GL_COLOR_ATTACHMENT3)
360 FB_FORMAT_STR(GL_COLOR_ATTACHMENT4)
361 FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT)
362 };
363
364 for( int i=0; i<vg_list_size(formats); i++ )
365 if( formats[i].e == e )
366 return formats[i].str;
367
368 return "UNDEFINED";
369 }
370
371 /*
372 * Convert OpenGL texture format enums from TexImage2D table 1,2 &
373 * RenderBufferStorage Table 1, into strings
374 */
375 VG_STATIC const char *render_fb_format_str( GLenum format )
376 {
377 struct { GLenum e; const char *str; }
378 formats[] =
379 {
380 /* Table 1 */
381 FB_FORMAT_STR(GL_DEPTH_COMPONENT)
382 FB_FORMAT_STR(GL_DEPTH_STENCIL)
383 FB_FORMAT_STR(GL_RED)
384 FB_FORMAT_STR(GL_RG)
385 FB_FORMAT_STR(GL_RGB)
386 FB_FORMAT_STR(GL_RGBA)
387
388 /* Render buffer formats */
389 FB_FORMAT_STR(GL_DEPTH_COMPONENT16)
390 FB_FORMAT_STR(GL_DEPTH_COMPONENT24)
391 FB_FORMAT_STR(GL_DEPTH_COMPONENT32F)
392 FB_FORMAT_STR(GL_DEPTH24_STENCIL8)
393 FB_FORMAT_STR(GL_DEPTH32F_STENCIL8)
394 FB_FORMAT_STR(GL_STENCIL_INDEX8)
395
396 /* Table 2 */
397 FB_FORMAT_STR(GL_R8)
398 FB_FORMAT_STR(GL_R8_SNORM)
399 FB_FORMAT_STR(GL_R16)
400 FB_FORMAT_STR(GL_R16_SNORM)
401 FB_FORMAT_STR(GL_RG8)
402 FB_FORMAT_STR(GL_RG8_SNORM)
403 FB_FORMAT_STR(GL_RG16)
404 FB_FORMAT_STR(GL_RG16_SNORM)
405 FB_FORMAT_STR(GL_R3_G3_B2)
406 FB_FORMAT_STR(GL_RGB4)
407 FB_FORMAT_STR(GL_RGB5)
408 FB_FORMAT_STR(GL_RGB8)
409 FB_FORMAT_STR(GL_RGB8_SNORM)
410 FB_FORMAT_STR(GL_RGB10)
411 FB_FORMAT_STR(GL_RGB12)
412 FB_FORMAT_STR(GL_RGB16_SNORM)
413 FB_FORMAT_STR(GL_RGBA2)
414 FB_FORMAT_STR(GL_RGBA4)
415 FB_FORMAT_STR(GL_RGB5_A1)
416 FB_FORMAT_STR(GL_RGBA8)
417 FB_FORMAT_STR(GL_RGBA8_SNORM)
418 FB_FORMAT_STR(GL_RGB10_A2)
419 FB_FORMAT_STR(GL_RGB10_A2UI)
420 FB_FORMAT_STR(GL_RGBA12)
421 FB_FORMAT_STR(GL_RGBA16)
422 FB_FORMAT_STR(GL_SRGB8)
423 FB_FORMAT_STR(GL_SRGB8_ALPHA8)
424 FB_FORMAT_STR(GL_R16F)
425 FB_FORMAT_STR(GL_RG16F)
426 FB_FORMAT_STR(GL_RGB16F)
427 FB_FORMAT_STR(GL_RGBA16F)
428 FB_FORMAT_STR(GL_R32F)
429 FB_FORMAT_STR(GL_RG32F)
430 FB_FORMAT_STR(GL_RGB32F)
431 FB_FORMAT_STR(GL_RGBA32F)
432 FB_FORMAT_STR(GL_R11F_G11F_B10F)
433 FB_FORMAT_STR(GL_RGB9_E5)
434 FB_FORMAT_STR(GL_R8I)
435 FB_FORMAT_STR(GL_R8UI)
436 FB_FORMAT_STR(GL_R16I)
437 FB_FORMAT_STR(GL_R16UI)
438 FB_FORMAT_STR(GL_R32I)
439 FB_FORMAT_STR(GL_R32UI)
440 FB_FORMAT_STR(GL_RG8I)
441 FB_FORMAT_STR(GL_RG8UI)
442 FB_FORMAT_STR(GL_RG16I)
443 FB_FORMAT_STR(GL_RG16UI)
444 FB_FORMAT_STR(GL_RG32I)
445 FB_FORMAT_STR(GL_RG32UI)
446 FB_FORMAT_STR(GL_RGB8I)
447 FB_FORMAT_STR(GL_RGB8UI)
448 FB_FORMAT_STR(GL_RGB16I)
449 FB_FORMAT_STR(GL_RGB16UI)
450 FB_FORMAT_STR(GL_RGB32I)
451 FB_FORMAT_STR(GL_RGB32UI)
452 FB_FORMAT_STR(GL_RGBA8I)
453 FB_FORMAT_STR(GL_RGBA8UI)
454 FB_FORMAT_STR(GL_RGBA16I)
455 FB_FORMAT_STR(GL_RGBA16UI)
456 FB_FORMAT_STR(GL_RGBA32I)
457 FB_FORMAT_STR(GL_RGBA32UI)
458 };
459
460 for( int i=0; i<vg_list_size(formats); i++ )
461 if( formats[i].e == format )
462 return formats[i].str;
463
464 return "UNDEFINED";
465 }
466
467 /*
468 * Bind and allocate texture for framebuffer attachment
469 */
470 VG_STATIC void render_fb_allocate_texture( struct framebuffer *fb,
471 struct framebuffer_attachment *a )
472 {
473 int rx, ry;
474 render_fb_get_current_res( fb, &rx, &ry );
475
476 if( a->purpose == k_framebuffer_attachment_type_renderbuffer )
477 {
478 glBindRenderbuffer( GL_RENDERBUFFER, a->id );
479 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, rx, ry );
480 }
481 else if( a->purpose == k_framebuffer_attachment_type_colour )
482 {
483 glBindTexture( GL_TEXTURE_2D, a->id );
484 glTexImage2D( GL_TEXTURE_2D, 0, a->internalformat, rx, ry,
485 0, a->format, a->type, NULL );
486 }
487 }
488
489 /*
490 * Full allocation of a framebuffer
491 */
492 VG_STATIC void render_fb_allocate( struct framebuffer *fb )
493 {
494 glGenFramebuffers( 1, &fb->fb );
495 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
496
497 int rx, ry;
498 render_fb_get_current_res( fb, &rx, &ry );
499
500 vg_info( "allocate_framebuffer( %s, %dx%d )\n", fb->display_name, rx, ry );
501 vg_info( "{\n" );
502
503 GLenum colour_attachments[4];
504 u32 colour_count = 0;
505
506 for( int j=0; j<vg_list_size(fb->attachments); j++ )
507 {
508 struct framebuffer_attachment *attachment = &fb->attachments[j];
509
510 if( attachment->purpose == k_framebuffer_attachment_type_none )
511 continue;
512
513 vg_info( " %s: %s\n",
514 render_fb_attachment_str( attachment->attachment ),
515 render_fb_format_str( attachment->internalformat ) );
516
517 if( attachment->purpose == k_framebuffer_attachment_type_renderbuffer )
518 {
519 glGenRenderbuffers( 1, &attachment->id );
520 render_fb_allocate_texture( fb, attachment );
521 glFramebufferRenderbuffer( GL_FRAMEBUFFER,
522 GL_DEPTH_STENCIL_ATTACHMENT,
523 GL_RENDERBUFFER, attachment->id );
524 }
525 else if( attachment->purpose == k_framebuffer_attachment_type_colour )
526 {
527 glGenTextures( 1, &attachment->id );
528 render_fb_allocate_texture( fb, attachment );
529 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
530 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
531 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
532 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
533
534 glFramebufferTexture2D( GL_FRAMEBUFFER, attachment->attachment,
535 GL_TEXTURE_2D, attachment->id, 0 );
536
537 colour_attachments[ colour_count ++ ] = attachment->attachment;
538 }
539 }
540
541 glDrawBuffers( colour_count, colour_attachments );
542
543 /*
544 * Check result
545 */
546 GLenum result = glCheckFramebufferStatus( GL_FRAMEBUFFER );
547
548 if( result == GL_FRAMEBUFFER_COMPLETE )
549 {
550 /*
551 * Attatch to gpipeline
552 */
553 if( fb->link )
554 *fb->link = fb;
555
556 vg_success( " status: complete\n" );
557 vg_info( "}\n" );
558 }
559 else
560 {
561 if( result == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT )
562 vg_error( " status: Incomplete attachment" );
563 else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT )
564 vg_error( " status: Missing attachment" );
565 else if( result == GL_FRAMEBUFFER_UNSUPPORTED )
566 vg_error( " status: Unsupported framebuffer format" );
567 else
568 vg_error( " status: Generic Error" );
569
570 vg_info( "}\n" );
571 vg_fatal_exit_loop( "Incomplete framebuffer (see logs)" );
572 }
573 }
574
575 /*
576 * Resize/Update all framebuffers(we know about)
577 */
578 VG_STATIC void render_fb_resize(void)
579 {
580 if( !gpipeline.ready )
581 return;
582
583 for( int i=0; i<vg_list_size(framebuffers); i++ )
584 {
585 struct framebuffer *fb = &framebuffers[i];
586 for( int j=0; j<vg_list_size(fb->attachments); j++ )
587 {
588 struct framebuffer_attachment *attachment = &fb->attachments[j];
589 render_fb_allocate_texture( fb, attachment );
590 }
591 }
592 }
593
594 VG_STATIC int render_framebuffer_control( int argc, char const *argv[] );
595 VG_STATIC void render_init_fs_quad(void)
596 {
597 vg_info( "[render] Allocate quad\n" );
598
599 float quad[] =
600 {
601 0.00f,0.00f, 1.00f,1.00f, 0.00f,1.00f,
602 0.00f,0.00f, 1.00f,0.00f, 1.00f,1.00f,
603
604 0.20f,0.00f, 0.80f,1.00f, 0.20f,1.00f,
605 0.20f,0.00f, 0.80f,0.00f, 0.80f,1.00f,
606
607 /* 9x9 debug grid */
608 /* row0 */
609 0.00f,0.00f, 0.30f,0.30f, 0.00f,0.30f,
610 0.00f,0.00f, 0.30f,0.00f, 0.30f,0.30f,
611 0.30f,0.00f, 0.60f,0.30f, 0.30f,0.30f,
612 0.30f,0.00f, 0.60f,0.00f, 0.60f,0.30f,
613 0.60f,0.00f, 0.90f,0.30f, 0.60f,0.30f,
614 0.60f,0.00f, 0.90f,0.00f, 0.90f,0.30f,
615 /* row1 */
616 0.00f,0.30f, 0.30f,0.60f, 0.00f,0.60f,
617 0.00f,0.30f, 0.30f,0.30f, 0.30f,0.60f,
618 0.30f,0.30f, 0.60f,0.60f, 0.30f,0.60f,
619 0.30f,0.30f, 0.60f,0.30f, 0.60f,0.60f,
620 0.60f,0.30f, 0.90f,0.60f, 0.60f,0.60f,
621 0.60f,0.30f, 0.90f,0.30f, 0.90f,0.60f,
622 /* row2 */
623 0.00f,0.60f, 0.30f,0.90f, 0.00f,0.90f,
624 0.00f,0.60f, 0.30f,0.60f, 0.30f,0.90f,
625 0.30f,0.60f, 0.60f,0.90f, 0.30f,0.90f,
626 0.30f,0.60f, 0.60f,0.60f, 0.60f,0.90f,
627 0.60f,0.60f, 0.90f,0.90f, 0.60f,0.90f,
628 0.60f,0.60f, 0.90f,0.60f, 0.90f,0.90f,
629 };
630
631 vg_function_push( (struct vg_cmd)
632 {
633 .name = "fb",
634 .function = render_framebuffer_control
635 });
636
637 glGenVertexArrays( 1, &gpipeline.fsquad.vao );
638 glGenBuffers( 1, &gpipeline.fsquad.vbo );
639 glBindVertexArray( gpipeline.fsquad.vao );
640 glBindBuffer( GL_ARRAY_BUFFER, gpipeline.fsquad.vbo );
641 glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW );
642 glBindVertexArray( gpipeline.fsquad.vao );
643 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE,
644 sizeof(float)*2, (void*)0 );
645 glEnableVertexAttribArray( 0 );
646
647 VG_CHECK_GL_ERR();
648 }
649
650 VG_STATIC void render_init_uniform_buffers(void)
651 {
652 vg_info( "[render] Allocate uniform buffer\n" );
653
654 glGenBuffers( 1, &gpipeline.ubo_world_lighting );
655 glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
656 glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting),
657 NULL, GL_DYNAMIC_DRAW );
658
659 render_update_lighting_ub();
660 glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting );
661
662 VG_CHECK_GL_ERR();
663 }
664
665 VG_STATIC void render_init(void)
666 {
667 shader_blit_register();
668 shader_blitblur_register();
669 shader_standard_register();
670 shader_vblend_register();
671
672 vg_acquire_thread_sync();
673 {
674 /*
675 * Complete Framebuffers
676 */
677 for( int i=0; i<vg_list_size(framebuffers); i++ )
678 {
679 struct framebuffer *fb = &framebuffers[i];
680 render_fb_allocate( fb );
681 }
682
683 render_init_fs_quad();
684 render_init_uniform_buffers();
685
686 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
687 gpipeline.ready = 1;
688 }
689
690 vg_release_thread_sync();
691 }
692
693 /*
694 * Utility
695 */
696 VG_STATIC void render_fsquad(void)
697 {
698 glBindVertexArray( gpipeline.fsquad.vao );
699 glDrawArrays( GL_TRIANGLES, 0, 6 );
700 }
701
702 VG_STATIC void render_fsquad1(void)
703 {
704 glBindVertexArray( gpipeline.fsquad.vao );
705 glDrawArrays( GL_TRIANGLES, 6, 6 );
706 }
707
708 /*
709 * Call this inside the UI function
710 */
711 VG_STATIC void render_view_framebuffer_ui(void)
712 {
713 int viewing_count = 0;
714
715 glBindVertexArray( gpipeline.fsquad.vao );
716 shader_blit_use();
717 shader_blit_uTexMain( 0 );
718
719 for( int i=0; i<vg_list_size(framebuffers); i++ )
720 {
721 struct framebuffer *fb = &framebuffers[i];
722
723 for( int j=0; j<vg_list_size(fb->attachments); j++ )
724 {
725 struct framebuffer_attachment *at = &fb->attachments[j];
726
727 if( !at->debug_view )
728 continue;
729
730 v2f corner,
731 window = { vg.window_x, vg.window_y };
732
733 corner[0] = viewing_count % 3;
734 corner[1] = 1 + (viewing_count / 3);
735 v2_mul( corner, window, corner );
736 v2_muls( corner, 0.3f, corner );
737 corner[1] = vg.window_y - corner[1];
738
739 ui_text( (ui_rect){ corner[0], corner[1], 0.0f, 0.0f },
740 fb->display_name, 2, k_text_align_left );
741 ui_text( (ui_rect){ corner[0], corner[1] + 32, 0.0f, 0.0f, },
742 at->display_name, 1, k_text_align_left );
743
744 if( at->purpose == k_framebuffer_attachment_type_renderbuffer )
745 {
746 v2f center;
747 v2_muladds( corner, window, 0.15f, center );
748
749 ui_text( (ui_rect){ center[0], center[1], 0.0f, 0.0f },
750 "<hardware texture>", 1, k_text_align_center );
751 }
752 else
753 {
754 render_fb_bind_texture( fb, j, 0 );
755
756 int start = (viewing_count+2) * 6,
757 count = 6;
758 glDrawArrays( GL_TRIANGLES, start, count );
759 }
760
761 viewing_count ++;
762 }
763 }
764 }
765
766 VG_STATIC void render_framebuffer_show( struct framebuffer *fb,
767 struct framebuffer_attachment *at,
768 int operation )
769 {
770 at->debug_view = operation;
771 vg_info( "%s %s:%s\n", (operation?"shown": "hidden"),
772 fb->display_name, at->display_name );
773 }
774
775 /*
776 * arg0: command "show"/"hide"
777 * arg1: framebuffer name <name>/"all"
778 * arg2: subname <name>/none
779 */
780 VG_STATIC int render_framebuffer_control( int argc, char const *argv[] )
781 {
782 if( argc < 2 )
783 {
784 vg_error( "Usage: fb \"show/hide\" <name>/\"all\" <name>/none\n" );
785 return 0;
786 }
787
788 int modify_all = 0,
789 operation = 0;
790
791 if( !strcmp( argv[0], "show" ) )
792 operation = 1;
793 else if( !strcmp( argv[0], "hide" ) )
794 operation = 0;
795 else
796 {
797 vg_error( "Unknown framebuffer operation: '%s'\n", argv[0] );
798 return 0;
799 }
800
801 if( !strcmp( argv[1], "all" ) )
802 modify_all = 1;
803
804 for( int i=0; i<vg_list_size(framebuffers); i++ )
805 {
806 struct framebuffer *fb = &framebuffers[i];
807
808 for( int j=0; j<vg_list_size(fb->attachments); j++ )
809 {
810 struct framebuffer_attachment *at = &fb->attachments[j];
811
812 if( at->purpose == k_framebuffer_attachment_type_none )
813 continue;
814
815 if( modify_all )
816 {
817 render_framebuffer_show( fb, at, operation );
818 }
819 else
820 {
821 if( !strcmp( fb->display_name, argv[1] ) )
822 {
823 if( argc == 2 )
824 render_framebuffer_show( fb, at, operation );
825 else if( !strcmp( at->display_name, argv[2] ) )
826 render_framebuffer_show( fb, at, operation );
827 }
828 }
829 }
830 }
831
832 return 0;
833 }
834
835 #endif /* RENDER_H */