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