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