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