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