poll functions
[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_framebuffer_poll( int argc, char const *argv[] );
596 VG_STATIC void render_init_fs_quad(void)
597 {
598 vg_info( "[render] Allocate quad\n" );
599
600 float quad[] =
601 {
602 0.00f,0.00f, 1.00f,1.00f, 0.00f,1.00f,
603 0.00f,0.00f, 1.00f,0.00f, 1.00f,1.00f,
604
605 0.20f,0.00f, 0.80f,1.00f, 0.20f,1.00f,
606 0.20f,0.00f, 0.80f,0.00f, 0.80f,1.00f,
607
608 /* 9x9 debug grid */
609 /* row0 */
610 0.00f,0.00f, 0.30f,0.30f, 0.00f,0.30f,
611 0.00f,0.00f, 0.30f,0.00f, 0.30f,0.30f,
612 0.30f,0.00f, 0.60f,0.30f, 0.30f,0.30f,
613 0.30f,0.00f, 0.60f,0.00f, 0.60f,0.30f,
614 0.60f,0.00f, 0.90f,0.30f, 0.60f,0.30f,
615 0.60f,0.00f, 0.90f,0.00f, 0.90f,0.30f,
616 /* row1 */
617 0.00f,0.30f, 0.30f,0.60f, 0.00f,0.60f,
618 0.00f,0.30f, 0.30f,0.30f, 0.30f,0.60f,
619 0.30f,0.30f, 0.60f,0.60f, 0.30f,0.60f,
620 0.30f,0.30f, 0.60f,0.30f, 0.60f,0.60f,
621 0.60f,0.30f, 0.90f,0.60f, 0.60f,0.60f,
622 0.60f,0.30f, 0.90f,0.30f, 0.90f,0.60f,
623 /* row2 */
624 0.00f,0.60f, 0.30f,0.90f, 0.00f,0.90f,
625 0.00f,0.60f, 0.30f,0.60f, 0.30f,0.90f,
626 0.30f,0.60f, 0.60f,0.90f, 0.30f,0.90f,
627 0.30f,0.60f, 0.60f,0.60f, 0.60f,0.90f,
628 0.60f,0.60f, 0.90f,0.90f, 0.60f,0.90f,
629 0.60f,0.60f, 0.90f,0.60f, 0.90f,0.90f,
630 };
631
632 vg_function_push( (struct vg_cmd)
633 {
634 .name = "fb",
635 .function = render_framebuffer_control,
636 .poll_suggest = render_framebuffer_poll
637 });
638
639 glGenVertexArrays( 1, &gpipeline.fsquad.vao );
640 glGenBuffers( 1, &gpipeline.fsquad.vbo );
641 glBindVertexArray( gpipeline.fsquad.vao );
642 glBindBuffer( GL_ARRAY_BUFFER, gpipeline.fsquad.vbo );
643 glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW );
644 glBindVertexArray( gpipeline.fsquad.vao );
645 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE,
646 sizeof(float)*2, (void*)0 );
647 glEnableVertexAttribArray( 0 );
648
649 VG_CHECK_GL_ERR();
650 }
651
652 VG_STATIC void render_init_uniform_buffers(void)
653 {
654 vg_info( "[render] Allocate uniform buffer\n" );
655
656 glGenBuffers( 1, &gpipeline.ubo_world_lighting );
657 glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
658 glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting),
659 NULL, GL_DYNAMIC_DRAW );
660
661 render_update_lighting_ub();
662 glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting );
663
664 VG_CHECK_GL_ERR();
665 }
666
667 VG_STATIC void render_init(void)
668 {
669 shader_blit_register();
670 shader_blitblur_register();
671 shader_standard_register();
672 shader_vblend_register();
673
674 vg_acquire_thread_sync();
675 {
676 /*
677 * Complete Framebuffers
678 */
679 for( int i=0; i<vg_list_size(framebuffers); i++ )
680 {
681 struct framebuffer *fb = &framebuffers[i];
682 render_fb_allocate( fb );
683 }
684
685 render_init_fs_quad();
686 render_init_uniform_buffers();
687
688 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
689 gpipeline.ready = 1;
690 }
691
692 vg_release_thread_sync();
693 }
694
695 /*
696 * Utility
697 */
698 VG_STATIC void render_fsquad(void)
699 {
700 glBindVertexArray( gpipeline.fsquad.vao );
701 glDrawArrays( GL_TRIANGLES, 0, 6 );
702 }
703
704 VG_STATIC void render_fsquad1(void)
705 {
706 glBindVertexArray( gpipeline.fsquad.vao );
707 glDrawArrays( GL_TRIANGLES, 6, 6 );
708 }
709
710 /*
711 * Call this inside the UI function
712 */
713 VG_STATIC void render_view_framebuffer_ui(void)
714 {
715 int viewing_count = 0;
716
717 glBindVertexArray( gpipeline.fsquad.vao );
718 shader_blit_use();
719 shader_blit_uTexMain( 0 );
720
721 for( int i=0; i<vg_list_size(framebuffers); i++ )
722 {
723 struct framebuffer *fb = &framebuffers[i];
724
725 for( int j=0; j<vg_list_size(fb->attachments); j++ )
726 {
727 struct framebuffer_attachment *at = &fb->attachments[j];
728
729 if( !at->debug_view )
730 continue;
731
732 v2f corner,
733 window = { vg.window_x, vg.window_y };
734
735 corner[0] = viewing_count % 3;
736 corner[1] = 1 + (viewing_count / 3);
737 v2_mul( corner, window, corner );
738 v2_muls( corner, 0.3f, corner );
739 corner[1] = vg.window_y - corner[1];
740
741 ui_text( (ui_rect){ corner[0], corner[1], 0.0f, 0.0f },
742 fb->display_name, 2, k_text_align_left );
743 ui_text( (ui_rect){ corner[0], corner[1] + 32, 0.0f, 0.0f, },
744 at->display_name, 1, k_text_align_left );
745
746 if( at->purpose == k_framebuffer_attachment_type_renderbuffer )
747 {
748 v2f center;
749 v2_muladds( corner, window, 0.15f, center );
750
751 ui_text( (ui_rect){ center[0], center[1], 0.0f, 0.0f },
752 "<hardware texture>", 1, k_text_align_center );
753 }
754 else
755 {
756 render_fb_bind_texture( fb, j, 0 );
757
758 int start = (viewing_count+2) * 6,
759 count = 6;
760 glDrawArrays( GL_TRIANGLES, start, count );
761 }
762
763 viewing_count ++;
764 }
765 }
766 }
767
768 VG_STATIC void render_framebuffer_show( struct framebuffer *fb,
769 struct framebuffer_attachment *at,
770 int operation )
771 {
772 at->debug_view = operation;
773 vg_info( "%s %s:%s\n", (operation?"shown": "hidden"),
774 fb->display_name, at->display_name );
775 }
776
777 /*
778 * arg0: command "show"/"hide"
779 * arg1: framebuffer name <name>/"all"
780 * arg2: subname <name>/none
781 */
782 VG_STATIC int render_framebuffer_control( int argc, char const *argv[] )
783 {
784 if( argc < 2 )
785 {
786 vg_error( "Usage: fb \"show/hide\" <name>/\"all\" <name>/none\n" );
787 return 0;
788 }
789
790 int modify_all = 0,
791 operation = 0;
792
793 if( !strcmp( argv[0], "show" ) )
794 operation = 1;
795 else if( !strcmp( argv[0], "hide" ) )
796 operation = 0;
797 else
798 {
799 vg_error( "Unknown framebuffer operation: '%s'\n", argv[0] );
800 return 0;
801 }
802
803 if( !strcmp( argv[1], "all" ) )
804 modify_all = 1;
805
806 for( int i=0; i<vg_list_size(framebuffers); i++ )
807 {
808 struct framebuffer *fb = &framebuffers[i];
809
810 for( int j=0; j<vg_list_size(fb->attachments); j++ )
811 {
812 struct framebuffer_attachment *at = &fb->attachments[j];
813
814 if( at->purpose == k_framebuffer_attachment_type_none )
815 continue;
816
817 if( modify_all )
818 {
819 render_framebuffer_show( fb, at, operation );
820 }
821 else
822 {
823 if( !strcmp( fb->display_name, argv[1] ) )
824 {
825 if( argc == 2 )
826 render_framebuffer_show( fb, at, operation );
827 else if( !strcmp( at->display_name, argv[2] ) )
828 render_framebuffer_show( fb, at, operation );
829 }
830 }
831 }
832 }
833
834 return 0;
835 }
836
837 VG_STATIC void render_framebuffer_poll( int argc, char const *argv[] )
838 {
839 const char *term = argv[argc-1];
840
841 if( argc == 1 )
842 {
843 console_suggest_score_text( "show", term, 0 );
844 console_suggest_score_text( "hide", term, 0 );
845 }
846 else if( argc == 2 )
847 {
848 console_suggest_score_text( "all", term, 0 );
849
850 for( int i=0; i<vg_list_size(framebuffers); i++ )
851 {
852 struct framebuffer *fb = &framebuffers[i];
853 console_suggest_score_text( fb->display_name, term, 0 );
854 }
855 }
856 else if( argc == 3 )
857 {
858 int modify_all = 0;
859
860 if( !strcmp( argv[1], "all" ) )
861 modify_all = 1;
862
863 for( int i=0; i<vg_list_size(framebuffers); i++ )
864 {
865 struct framebuffer *fb = &framebuffers[i];
866
867 for( int j=0; j<vg_list_size(fb->attachments); j++ )
868 {
869 struct framebuffer_attachment *at = &fb->attachments[j];
870
871 if( at->purpose == k_framebuffer_attachment_type_none )
872 continue;
873
874 if( modify_all )
875 {
876 console_suggest_score_text( at->display_name, term, 0 );
877 }
878 else if( !strcmp( fb->display_name, argv[1] ) )
879 {
880 console_suggest_score_text( at->display_name, term, 0 );
881 }
882 }
883 }
884 }
885 }
886
887 #endif /* RENDER_H */