2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
10 #include "shaders/blit.h"
11 #include "shaders/blitblur.h"
12 #include "shaders/blitcolour.h"
13 #include "shaders/blit_transition.h"
15 #define WORKSHOP_PREVIEW_WIDTH 504
16 #define WORKSHOP_PREVIEW_HEIGHT 336
20 static f32 k_render_scale
= 1.0f
;
21 static i32 k_blur_effect
= 1;
22 static f32 k_blur_strength
= 0.3f
;
23 static f32 k_fov
= 0.86f
;
24 static f32 k_cam_height
= 0.8f
;
26 typedef struct framebuffer framebuffer
;
29 * All standard buffers used in rendering
31 static struct pipeline
{
43 const char *display_name
;
44 int resolution_div
, /* definition */
48 render_w
, /* runtime */
51 struct framebuffer_attachment
{
52 const char *display_name
;
54 enum framebuffer_attachment_type
{
55 k_framebuffer_attachment_type_none
,
56 k_framebuffer_attachment_type_texture
,
57 k_framebuffer_attachment_type_renderbuffer
,
58 k_framebuffer_attachment_type_texture_depth
62 enum framebuffer_quality_profile
{
63 k_framebuffer_quality_all
,
64 k_framebuffer_quality_high_only
68 GLenum internalformat
,
86 * The primary draw target
89 .link
= &gpipeline
.fb_main
,
94 "colour", k_framebuffer_attachment_type_texture
,
96 .internalformat
= GL_RGB
,
98 .type
= GL_UNSIGNED_BYTE
,
99 .attachment
= GL_COLOR_ATTACHMENT0
102 "motion", k_framebuffer_attachment_type_texture
,
104 .quality
= k_framebuffer_quality_high_only
,
105 .internalformat
= GL_RG16F
,
108 .attachment
= GL_COLOR_ATTACHMENT1
112 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
114 .internalformat
= GL_DEPTH24_STENCIL8
,
116 "depth_stencil", k_framebuffer_attachment_type_texture_depth
,
117 .internalformat
= GL_DEPTH24_STENCIL8
,
118 .format
= GL_DEPTH_STENCIL
,
119 .type
= GL_UNSIGNED_INT_24_8
,
121 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
127 * Second rendered view from the perspective of the water reflection
130 .link
= &gpipeline
.fb_water_reflection
,
135 "colour", k_framebuffer_attachment_type_texture
,
136 .internalformat
= GL_RGB
,
138 .type
= GL_UNSIGNED_BYTE
,
139 .attachment
= GL_COLOR_ATTACHMENT0
142 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
144 .internalformat
= GL_DEPTH24_STENCIL8
,
145 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
151 * Thid rendered view from the perspective of the camera, but just
152 * captures stuff thats under the water
155 .link
= &gpipeline
.fb_water_beneath
,
160 "colour", k_framebuffer_attachment_type_texture
,
161 .internalformat
= GL_RED
,
163 .type
= GL_UNSIGNED_BYTE
,
164 .attachment
= GL_COLOR_ATTACHMENT0
167 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
169 .internalformat
= GL_DEPTH24_STENCIL8
,
170 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
176 .link
= &gpipeline
.fb_workshop_preview
,
178 .fixed_w
= WORKSHOP_PREVIEW_WIDTH
, .fixed_h
= WORKSHOP_PREVIEW_HEIGHT
,
182 "colour", k_framebuffer_attachment_type_texture
,
183 .internalformat
= GL_RGB
,
185 .type
= GL_UNSIGNED_BYTE
,
186 .attachment
= GL_COLOR_ATTACHMENT0
189 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
190 .internalformat
= GL_DEPTH24_STENCIL8
,
191 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
198 * Get the current (automatically scaled or fixed) resolution of framebuffer
200 static void render_fb_get_current_res( struct framebuffer
*fb
,
203 if( fb
->resolution_div
){
204 *x
= vg
.window_x
/ fb
->resolution_div
;
205 *y
= vg
.window_y
/ fb
->resolution_div
;
213 static void render_fb_inverse_ratio( framebuffer
*fb
, v2f inverse
)
217 render_fb_get_current_res( fb
, &x
, &y
);
219 v2f render
= { fb
->render_w
, fb
->render_h
},
222 v2_div( render
, original
, inverse
);
225 v2_div( (v2f
){1.0f
,1.0f
}, (v2f
){ vg
.window_x
, vg
.window_y
}, inverse
);
230 * Bind framebuffer for drawing to
232 static void render_fb_bind( framebuffer
*fb
, int use_scaling
)
235 render_fb_get_current_res( fb
, &x
, &y
);
238 x
= k_render_scale
*(float)x
;
239 y
= k_render_scale
*(float)y
;
248 glBindFramebuffer( GL_FRAMEBUFFER
, fb
->fb
);
249 glViewport( 0, 0, x
, y
);
253 * Bind framebuffer attachment's texture
255 static void render_fb_bind_texture( framebuffer
*fb
,
256 int attachment
, int slot
)
258 struct framebuffer_attachment
*at
= &fb
->attachments
[attachment
];
260 if( (at
->purpose
!= k_framebuffer_attachment_type_texture
) &&
261 (at
->purpose
!= k_framebuffer_attachment_type_texture_depth
) )
263 vg_fatal_error( "illegal operation: bind non-texture framebuffer"
264 " attachment to texture slot" );
267 glActiveTexture( GL_TEXTURE0
+ slot
);
268 glBindTexture( GL_TEXTURE_2D
, fb
->attachments
[attachment
].id
);
276 #define FB_FORMAT_STR( E ) { E, #E },
279 * Convert OpenGL attachment ID enum to string
281 static const char *render_fb_attachment_str( GLenum e
)
283 struct { GLenum e
; const char *str
; }
286 FB_FORMAT_STR(GL_COLOR_ATTACHMENT0
)
287 FB_FORMAT_STR(GL_COLOR_ATTACHMENT1
)
288 FB_FORMAT_STR(GL_COLOR_ATTACHMENT2
)
289 FB_FORMAT_STR(GL_COLOR_ATTACHMENT3
)
290 FB_FORMAT_STR(GL_COLOR_ATTACHMENT4
)
291 FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT
)
294 for( int i
=0; i
<vg_list_size(formats
); i
++ )
295 if( formats
[i
].e
== e
)
296 return formats
[i
].str
;
302 * Convert OpenGL texture format enums from TexImage2D table 1,2 &
303 * RenderBufferStorage Table 1, into strings
305 static const char *render_fb_format_str( GLenum format
)
307 struct { GLenum e
; const char *str
; }
311 FB_FORMAT_STR(GL_DEPTH_COMPONENT
)
312 FB_FORMAT_STR(GL_DEPTH_STENCIL
)
313 FB_FORMAT_STR(GL_RED
)
315 FB_FORMAT_STR(GL_RGB
)
316 FB_FORMAT_STR(GL_RGBA
)
318 /* Render buffer formats */
319 FB_FORMAT_STR(GL_DEPTH_COMPONENT16
)
320 FB_FORMAT_STR(GL_DEPTH_COMPONENT24
)
321 FB_FORMAT_STR(GL_DEPTH_COMPONENT32F
)
322 FB_FORMAT_STR(GL_DEPTH24_STENCIL8
)
323 FB_FORMAT_STR(GL_DEPTH32F_STENCIL8
)
324 FB_FORMAT_STR(GL_STENCIL_INDEX8
)
328 FB_FORMAT_STR(GL_R8_SNORM
)
329 FB_FORMAT_STR(GL_R16
)
330 FB_FORMAT_STR(GL_R16_SNORM
)
331 FB_FORMAT_STR(GL_RG8
)
332 FB_FORMAT_STR(GL_RG8_SNORM
)
333 FB_FORMAT_STR(GL_RG16
)
334 FB_FORMAT_STR(GL_RG16_SNORM
)
335 FB_FORMAT_STR(GL_R3_G3_B2
)
336 FB_FORMAT_STR(GL_RGB4
)
337 FB_FORMAT_STR(GL_RGB5
)
338 FB_FORMAT_STR(GL_RGB8
)
339 FB_FORMAT_STR(GL_RGB8_SNORM
)
340 FB_FORMAT_STR(GL_RGB10
)
341 FB_FORMAT_STR(GL_RGB12
)
342 FB_FORMAT_STR(GL_RGB16_SNORM
)
343 FB_FORMAT_STR(GL_RGBA2
)
344 FB_FORMAT_STR(GL_RGBA4
)
345 FB_FORMAT_STR(GL_RGB5_A1
)
346 FB_FORMAT_STR(GL_RGBA8
)
347 FB_FORMAT_STR(GL_RGBA8_SNORM
)
348 FB_FORMAT_STR(GL_RGB10_A2
)
349 FB_FORMAT_STR(GL_RGB10_A2UI
)
350 FB_FORMAT_STR(GL_RGBA12
)
351 FB_FORMAT_STR(GL_RGBA16
)
352 FB_FORMAT_STR(GL_SRGB8
)
353 FB_FORMAT_STR(GL_SRGB8_ALPHA8
)
354 FB_FORMAT_STR(GL_R16F
)
355 FB_FORMAT_STR(GL_RG16F
)
356 FB_FORMAT_STR(GL_RGB16F
)
357 FB_FORMAT_STR(GL_RGBA16F
)
358 FB_FORMAT_STR(GL_R32F
)
359 FB_FORMAT_STR(GL_RG32F
)
360 FB_FORMAT_STR(GL_RGB32F
)
361 FB_FORMAT_STR(GL_RGBA32F
)
362 FB_FORMAT_STR(GL_R11F_G11F_B10F
)
363 FB_FORMAT_STR(GL_RGB9_E5
)
364 FB_FORMAT_STR(GL_R8I
)
365 FB_FORMAT_STR(GL_R8UI
)
366 FB_FORMAT_STR(GL_R16I
)
367 FB_FORMAT_STR(GL_R16UI
)
368 FB_FORMAT_STR(GL_R32I
)
369 FB_FORMAT_STR(GL_R32UI
)
370 FB_FORMAT_STR(GL_RG8I
)
371 FB_FORMAT_STR(GL_RG8UI
)
372 FB_FORMAT_STR(GL_RG16I
)
373 FB_FORMAT_STR(GL_RG16UI
)
374 FB_FORMAT_STR(GL_RG32I
)
375 FB_FORMAT_STR(GL_RG32UI
)
376 FB_FORMAT_STR(GL_RGB8I
)
377 FB_FORMAT_STR(GL_RGB8UI
)
378 FB_FORMAT_STR(GL_RGB16I
)
379 FB_FORMAT_STR(GL_RGB16UI
)
380 FB_FORMAT_STR(GL_RGB32I
)
381 FB_FORMAT_STR(GL_RGB32UI
)
382 FB_FORMAT_STR(GL_RGBA8I
)
383 FB_FORMAT_STR(GL_RGBA8UI
)
384 FB_FORMAT_STR(GL_RGBA16I
)
385 FB_FORMAT_STR(GL_RGBA16UI
)
386 FB_FORMAT_STR(GL_RGBA32I
)
387 FB_FORMAT_STR(GL_RGBA32UI
)
390 for( int i
=0; i
<vg_list_size(formats
); i
++ )
391 if( formats
[i
].e
== format
)
392 return formats
[i
].str
;
398 * Bind and allocate texture for framebuffer attachment
400 static void render_fb_allocate_texture( struct framebuffer
*fb
,
401 struct framebuffer_attachment
*a
)
404 render_fb_get_current_res( fb
, &rx
, &ry
);
406 if( a
->purpose
== k_framebuffer_attachment_type_renderbuffer
){
407 glBindRenderbuffer( GL_RENDERBUFFER
, a
->id
);
408 glRenderbufferStorage( GL_RENDERBUFFER
, a
->internalformat
, rx
, ry
);
410 else if( a
->purpose
== k_framebuffer_attachment_type_texture
||
411 a
->purpose
== k_framebuffer_attachment_type_texture_depth
)
413 glBindTexture( GL_TEXTURE_2D
, a
->id
);
414 glTexImage2D( GL_TEXTURE_2D
, 0, a
->internalformat
, rx
, ry
,
415 0, a
->format
, a
->type
, NULL
);
420 * Full allocation of a framebuffer
422 static void render_fb_allocate( struct framebuffer
*fb
)
424 glGenFramebuffers( 1, &fb
->fb
);
425 glBindFramebuffer( GL_FRAMEBUFFER
, fb
->fb
);
428 render_fb_get_current_res( fb
, &rx
, &ry
);
430 vg_info( "allocate_framebuffer( %s, %dx%d )\n", fb
->display_name
, rx
, ry
);
433 GLenum colour_attachments
[4];
434 u32 colour_count
= 0;
436 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ ){
437 struct framebuffer_attachment
*attachment
= &fb
->attachments
[j
];
439 if( attachment
->purpose
== k_framebuffer_attachment_type_none
)
442 vg_info( " %s: %s\n",
443 render_fb_attachment_str( attachment
->attachment
),
444 render_fb_format_str( attachment
->internalformat
) );
446 if( attachment
->purpose
== k_framebuffer_attachment_type_renderbuffer
){
447 glGenRenderbuffers( 1, &attachment
->id
);
448 render_fb_allocate_texture( fb
, attachment
);
449 glFramebufferRenderbuffer( GL_FRAMEBUFFER
,
450 GL_DEPTH_STENCIL_ATTACHMENT
,
451 GL_RENDERBUFFER
, attachment
->id
);
453 else if( attachment
->purpose
== k_framebuffer_attachment_type_texture
||
454 attachment
->purpose
== k_framebuffer_attachment_type_texture_depth
)
456 glGenTextures( 1, &attachment
->id
);
457 render_fb_allocate_texture( fb
, attachment
);
458 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
459 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
460 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
461 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
463 glFramebufferTexture2D( GL_FRAMEBUFFER
, attachment
->attachment
,
464 GL_TEXTURE_2D
, attachment
->id
, 0 );
466 if( attachment
->purpose
== k_framebuffer_attachment_type_texture
)
467 colour_attachments
[ colour_count
++ ] = attachment
->attachment
;
471 glDrawBuffers( colour_count
, colour_attachments
);
476 GLenum result
= glCheckFramebufferStatus( GL_FRAMEBUFFER
);
478 if( result
== GL_FRAMEBUFFER_COMPLETE
){
480 * Attatch to gpipeline
485 vg_success( " status: complete\n" );
489 if( result
== GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
)
490 vg_error( " status: Incomplete attachment" );
491 else if( result
== GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
)
492 vg_error( " status: Missing attachment" );
493 else if( result
== GL_FRAMEBUFFER_UNSUPPORTED
)
494 vg_error( " status: Unsupported framebuffer format" );
496 vg_error( " status: Generic Error" );
499 vg_fatal_error( "Incomplete framebuffer (see logs)" );
504 * Resize/Update all framebuffers(we know about)
506 static void render_fb_resize(void)
508 if( !gpipeline
.ready
) return;
510 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
511 struct framebuffer
*fb
= &framebuffers
[i
];
512 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ ){
513 struct framebuffer_attachment
*attachment
= &fb
->attachments
[j
];
514 render_fb_allocate_texture( fb
, attachment
);
519 static int render_framebuffer_control( int argc
, char const *argv
[] );
520 static void render_framebuffer_poll( int argc
, char const *argv
[] );
522 static void async_render_init( void *payload
, u32 size
)
525 * Complete Framebuffers
527 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
528 struct framebuffer
*fb
= &framebuffers
[i
];
529 render_fb_allocate( fb
);
532 f32 rh
= 0x1p
-4f
, ih
= 0.3f
;
535 0.00f
,0.00f
, 1.00f
,1.00f
, 0.00f
,1.00f
, /* fsquad */
536 0.00f
,0.00f
, 1.00f
,0.00f
, 1.00f
,1.00f
,
538 0.00f
,0.00f
, 1.00f
,rh
, 0.00f
,rh
, /* fsquad1 */
539 0.00f
,0.00f
, 1.00f
,0.00f
, 1.00f
,rh
,
543 0.00f
,0.00f
, 0.30f
,0.30f
, 0.00f
,0.30f
,
544 0.00f
,0.00f
, 0.30f
,0.00f
, 0.30f
,0.30f
,
545 0.30f
,0.00f
, 0.60f
,0.30f
, 0.30f
,0.30f
,
546 0.30f
,0.00f
, 0.60f
,0.00f
, 0.60f
,0.30f
,
547 0.60f
,0.00f
, 0.90f
,0.30f
, 0.60f
,0.30f
,
548 0.60f
,0.00f
, 0.90f
,0.00f
, 0.90f
,0.30f
,
550 0.00f
,0.30f
, 0.30f
,0.60f
, 0.00f
,0.60f
,
551 0.00f
,0.30f
, 0.30f
,0.30f
, 0.30f
,0.60f
,
552 0.30f
,0.30f
, 0.60f
,0.60f
, 0.30f
,0.60f
,
553 0.30f
,0.30f
, 0.60f
,0.30f
, 0.60f
,0.60f
,
554 0.60f
,0.30f
, 0.90f
,0.60f
, 0.60f
,0.60f
,
555 0.60f
,0.30f
, 0.90f
,0.30f
, 0.90f
,0.60f
,
557 0.00f
,0.60f
, 0.30f
,0.90f
, 0.00f
,0.90f
,
558 0.00f
,0.60f
, 0.30f
,0.60f
, 0.30f
,0.90f
,
559 0.30f
,0.60f
, 0.60f
,0.90f
, 0.30f
,0.90f
,
560 0.30f
,0.60f
, 0.60f
,0.60f
, 0.60f
,0.90f
,
561 0.60f
,0.60f
, 0.90f
,0.90f
, 0.60f
,0.90f
,
562 0.60f
,0.60f
, 0.90f
,0.60f
, 0.90f
,0.90f
,
564 0.00f
,ih
, 1.00f
,ih
+rh
, 0.00f
,ih
+rh
, /* fsquad2 */
565 0.00f
,ih
, 1.00f
,ih
, 1.00f
,ih
+rh
,
568 vg_console_reg_cmd( "fb", render_framebuffer_control
,
569 render_framebuffer_poll
);
570 glGenVertexArrays( 1, &gpipeline
.fsquad
.vao
);
571 glGenBuffers( 1, &gpipeline
.fsquad
.vbo
);
572 glBindVertexArray( gpipeline
.fsquad
.vao
);
573 glBindBuffer( GL_ARRAY_BUFFER
, gpipeline
.fsquad
.vbo
);
574 glBufferData( GL_ARRAY_BUFFER
, sizeof(quad
), quad
, GL_STATIC_DRAW
);
575 glBindVertexArray( gpipeline
.fsquad
.vao
);
576 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
,
577 sizeof(float)*2, (void*)0 );
578 glEnableVertexAttribArray( 0 );
582 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
586 static void render_init(void)
588 vg_console_reg_var( "blur_strength", &k_blur_strength
, k_var_dtype_f32
, 0 );
589 vg_console_reg_var( "render_scale", &k_render_scale
,
590 k_var_dtype_f32
, VG_VAR_PERSISTENT
);
591 vg_console_reg_var( "fov", &k_fov
, k_var_dtype_f32
, VG_VAR_PERSISTENT
);
592 vg_console_reg_var( "cam_height", &k_cam_height
,
593 k_var_dtype_f32
, VG_VAR_PERSISTENT
);
594 vg_console_reg_var( "blur_effect", &k_blur_effect
,
595 k_var_dtype_i32
, VG_VAR_PERSISTENT
);
598 shader_blit_register();
599 shader_blitblur_register();
600 shader_blitcolour_register();
601 shader_blit_transition_register();
603 vg_async_call( async_render_init
, NULL
, 0 );
609 static void render_fsquad(void)
611 glBindVertexArray( gpipeline
.fsquad
.vao
);
612 glDrawArrays( GL_TRIANGLES
, 0, 6 );
615 static void render_fsquad1(void)
617 glBindVertexArray( gpipeline
.fsquad
.vao
);
618 glDrawArrays( GL_TRIANGLES
, 6, 6 );
621 static void render_fsquad2(void)
623 glBindVertexArray( gpipeline
.fsquad
.vao
);
624 glDrawArrays( GL_TRIANGLES
, 66,6 );
628 * Call this inside the UI function
630 static void render_view_framebuffer_ui(void)
633 int viewing_count
= 0;
635 glBindVertexArray( gpipeline
.fsquad
.vao
);
637 shader_blit_uTexMain( 0 );
639 v2f identity
= { 1.0f
, 1.0f
};
640 shader_blit_uInverseRatio( identity
);
642 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
643 struct framebuffer
*fb
= &framebuffers
[i
];
645 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ ){
646 struct framebuffer_attachment
*at
= &fb
->attachments
[j
];
648 if( !at
->debug_view
)
652 window
= { vg
.window_x
, vg
.window_y
};
654 corner
[0] = viewing_count
% 3;
655 corner
[1] = 1 + (viewing_count
/ 3);
656 v2_mul( corner
, window
, corner
);
657 v2_muls( corner
, 0.3f
, corner
);
658 corner
[1] = vg
.window_y
- corner
[1];
660 ui_text( (ui_rect
){ corner
[0], corner
[1], 0.0f
, 0.0f
},
661 fb
->display_name
, 2, k_text_align_left
);
662 ui_text( (ui_rect
){ corner
[0], corner
[1] + 32, 0.0f
, 0.0f
, },
663 at
->display_name
, 1, k_text_align_left
);
665 if( at
->purpose
== k_framebuffer_attachment_type_renderbuffer
){
667 v2_muladds( corner
, window
, 0.15f
, center
);
669 ui_text( (ui_rect
){ center
[0], center
[1], 0.0f
, 0.0f
},
670 "<hardware texture>", 1, k_text_align_center
);
673 render_fb_bind_texture( fb
, j
, 0 );
675 int start
= (viewing_count
+2) * 6,
677 glDrawArrays( GL_TRIANGLES
, start
, count
);
686 static void render_framebuffer_show( struct framebuffer
*fb
,
687 struct framebuffer_attachment
*at
,
690 at
->debug_view
= operation
;
691 vg_info( "%s %s:%s\n", (operation
?"shown": "hidden"),
692 fb
->display_name
, at
->display_name
);
696 * arg0: command "show"/"hide"
697 * arg1: framebuffer name <name>/"all"
698 * arg2: subname <name>/none
700 static int render_framebuffer_control( int argc
, char const *argv
[] )
703 vg_error( "Usage: fb \"show/hide\" <name>/\"all\" <name>/none\n" );
710 if( !strcmp( argv
[0], "show" ) )
712 else if( !strcmp( argv
[0], "hide" ) )
715 vg_error( "Unknown framebuffer operation: '%s'\n", argv
[0] );
719 if( !strcmp( argv
[1], "all" ) )
722 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
723 struct framebuffer
*fb
= &framebuffers
[i
];
725 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ ){
726 struct framebuffer_attachment
*at
= &fb
->attachments
[j
];
728 if( at
->purpose
== k_framebuffer_attachment_type_none
)
732 render_framebuffer_show( fb
, at
, operation
);
735 if( !strcmp( fb
->display_name
, argv
[1] ) ){
737 render_framebuffer_show( fb
, at
, operation
);
738 else if( !strcmp( at
->display_name
, argv
[2] ) )
739 render_framebuffer_show( fb
, at
, operation
);
748 static void render_framebuffer_poll( int argc
, char const *argv
[] )
750 const char *term
= argv
[argc
-1];
753 console_suggest_score_text( "show", term
, 0 );
754 console_suggest_score_text( "hide", term
, 0 );
756 else if( argc
== 2 ){
757 console_suggest_score_text( "all", term
, 0 );
759 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
760 struct framebuffer
*fb
= &framebuffers
[i
];
761 console_suggest_score_text( fb
->display_name
, term
, 0 );
764 else if( argc
== 3 ){
767 if( !strcmp( argv
[1], "all" ) )
770 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
771 struct framebuffer
*fb
= &framebuffers
[i
];
773 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ ){
774 struct framebuffer_attachment
*at
= &fb
->attachments
[j
];
776 if( at
->purpose
== k_framebuffer_attachment_type_none
)
780 console_suggest_score_text( at
->display_name
, term
, 0 );
782 else if( !strcmp( fb
->display_name
, argv
[1] ) ){
783 console_suggest_score_text( at
->display_name
, term
, 0 );
790 #endif /* RENDER_H */