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