3 struct framebuffer framebuffers
[] =
7 * The primary draw target
10 .link
= &gpipeline
.fb_main
,
15 "colour", k_framebuffer_attachment_type_texture
,
17 .internalformat
= GL_RGB
,
19 .type
= GL_UNSIGNED_BYTE
,
20 .attachment
= GL_COLOR_ATTACHMENT0
23 "motion", k_framebuffer_attachment_type_texture
,
25 .quality
= k_framebuffer_quality_high_only
,
26 .internalformat
= GL_RG16F
,
29 .attachment
= GL_COLOR_ATTACHMENT1
33 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
35 .internalformat
= GL_DEPTH24_STENCIL8
,
37 "depth_stencil", k_framebuffer_attachment_type_texture_depth
,
38 .internalformat
= GL_DEPTH24_STENCIL8
,
39 .format
= GL_DEPTH_STENCIL
,
40 .type
= GL_UNSIGNED_INT_24_8
,
42 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
48 * Second rendered view from the perspective of the water reflection
51 .link
= &gpipeline
.fb_water_reflection
,
56 "colour", k_framebuffer_attachment_type_texture
,
57 .internalformat
= GL_RGB
,
59 .type
= GL_UNSIGNED_BYTE
,
60 .attachment
= GL_COLOR_ATTACHMENT0
63 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
65 .internalformat
= GL_DEPTH24_STENCIL8
,
66 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
72 * Thid rendered view from the perspective of the camera, but just
73 * captures stuff thats under the water
76 .link
= &gpipeline
.fb_water_beneath
,
81 "colour", k_framebuffer_attachment_type_texture
,
82 .internalformat
= GL_RED
,
84 .type
= GL_UNSIGNED_BYTE
,
85 .attachment
= GL_COLOR_ATTACHMENT0
88 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
90 .internalformat
= GL_DEPTH24_STENCIL8
,
91 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
97 .link
= &gpipeline
.fb_workshop_preview
,
99 .fixed_w
= WORKSHOP_PREVIEW_WIDTH
, .fixed_h
= WORKSHOP_PREVIEW_HEIGHT
,
103 "colour", k_framebuffer_attachment_type_texture
,
104 .internalformat
= GL_RGB
,
106 .type
= GL_UNSIGNED_BYTE
,
107 .attachment
= GL_COLOR_ATTACHMENT0
110 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
111 .internalformat
= GL_DEPTH24_STENCIL8
,
112 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
118 .link
= &gpipeline
.fb_network_status
,
120 .fixed_w
= 128, .fixed_h
= 48,
124 "colour", k_framebuffer_attachment_type_texture
,
125 .internalformat
= GL_RGB
,
127 .type
= GL_UNSIGNED_BYTE
,
128 .attachment
= GL_COLOR_ATTACHMENT0
135 * Get the current (automatically scaled or fixed) resolution of framebuffer
137 void render_fb_get_current_res( struct framebuffer
*fb
, int *x
, int *y
)
139 if( fb
->resolution_div
){
140 *x
= vg
.window_x
/ fb
->resolution_div
;
141 *y
= vg
.window_y
/ fb
->resolution_div
;
149 void render_fb_inverse_ratio( framebuffer
*fb
, v2f inverse
)
153 render_fb_get_current_res( fb
, &x
, &y
);
155 v2f render
= { fb
->render_w
, fb
->render_h
},
158 v2_div( render
, original
, inverse
);
161 v2_div( (v2f
){1.0f
,1.0f
}, (v2f
){ vg
.window_x
, vg
.window_y
}, inverse
);
166 * Bind framebuffer for drawing to
168 void render_fb_bind( framebuffer
*fb
, int use_scaling
)
171 render_fb_get_current_res( fb
, &x
, &y
);
174 x
= k_render_scale
*(float)x
;
175 y
= k_render_scale
*(float)y
;
184 glBindFramebuffer( GL_FRAMEBUFFER
, fb
->fb
);
185 glViewport( 0, 0, x
, y
);
189 * Bind framebuffer attachment's texture
191 void render_fb_bind_texture( framebuffer
*fb
, int attachment
, int slot
)
193 struct framebuffer_attachment
*at
= &fb
->attachments
[attachment
];
195 if( (at
->purpose
!= k_framebuffer_attachment_type_texture
) &&
196 (at
->purpose
!= k_framebuffer_attachment_type_texture_depth
) )
198 vg_fatal_error( "illegal operation: bind non-texture framebuffer"
199 " attachment to texture slot" );
202 glActiveTexture( GL_TEXTURE0
+ slot
);
203 glBindTexture( GL_TEXTURE_2D
, fb
->attachments
[attachment
].id
);
211 #define FB_FORMAT_STR( E ) { E, #E },
214 * Convert OpenGL attachment ID enum to string
216 static const char *render_fb_attachment_str( GLenum e
)
218 struct { GLenum e
; const char *str
; }
221 FB_FORMAT_STR(GL_COLOR_ATTACHMENT0
)
222 FB_FORMAT_STR(GL_COLOR_ATTACHMENT1
)
223 FB_FORMAT_STR(GL_COLOR_ATTACHMENT2
)
224 FB_FORMAT_STR(GL_COLOR_ATTACHMENT3
)
225 FB_FORMAT_STR(GL_COLOR_ATTACHMENT4
)
226 FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT
)
229 for( int i
=0; i
<vg_list_size(formats
); i
++ )
230 if( formats
[i
].e
== e
)
231 return formats
[i
].str
;
237 * Convert OpenGL texture format enums from TexImage2D table 1,2 &
238 * RenderBufferStorage Table 1, into strings
240 static const char *render_fb_format_str( GLenum format
)
242 struct { GLenum e
; const char *str
; }
246 FB_FORMAT_STR(GL_DEPTH_COMPONENT
)
247 FB_FORMAT_STR(GL_DEPTH_STENCIL
)
248 FB_FORMAT_STR(GL_RED
)
250 FB_FORMAT_STR(GL_RGB
)
251 FB_FORMAT_STR(GL_RGBA
)
253 /* Render buffer formats */
254 FB_FORMAT_STR(GL_DEPTH_COMPONENT16
)
255 FB_FORMAT_STR(GL_DEPTH_COMPONENT24
)
256 FB_FORMAT_STR(GL_DEPTH_COMPONENT32F
)
257 FB_FORMAT_STR(GL_DEPTH24_STENCIL8
)
258 FB_FORMAT_STR(GL_DEPTH32F_STENCIL8
)
259 FB_FORMAT_STR(GL_STENCIL_INDEX8
)
263 FB_FORMAT_STR(GL_R8_SNORM
)
264 FB_FORMAT_STR(GL_R16
)
265 FB_FORMAT_STR(GL_R16_SNORM
)
266 FB_FORMAT_STR(GL_RG8
)
267 FB_FORMAT_STR(GL_RG8_SNORM
)
268 FB_FORMAT_STR(GL_RG16
)
269 FB_FORMAT_STR(GL_RG16_SNORM
)
270 FB_FORMAT_STR(GL_R3_G3_B2
)
271 FB_FORMAT_STR(GL_RGB4
)
272 FB_FORMAT_STR(GL_RGB5
)
273 FB_FORMAT_STR(GL_RGB8
)
274 FB_FORMAT_STR(GL_RGB8_SNORM
)
275 FB_FORMAT_STR(GL_RGB10
)
276 FB_FORMAT_STR(GL_RGB12
)
277 FB_FORMAT_STR(GL_RGB16_SNORM
)
278 FB_FORMAT_STR(GL_RGBA2
)
279 FB_FORMAT_STR(GL_RGBA4
)
280 FB_FORMAT_STR(GL_RGB5_A1
)
281 FB_FORMAT_STR(GL_RGBA8
)
282 FB_FORMAT_STR(GL_RGBA8_SNORM
)
283 FB_FORMAT_STR(GL_RGB10_A2
)
284 FB_FORMAT_STR(GL_RGB10_A2UI
)
285 FB_FORMAT_STR(GL_RGBA12
)
286 FB_FORMAT_STR(GL_RGBA16
)
287 FB_FORMAT_STR(GL_SRGB8
)
288 FB_FORMAT_STR(GL_SRGB8_ALPHA8
)
289 FB_FORMAT_STR(GL_R16F
)
290 FB_FORMAT_STR(GL_RG16F
)
291 FB_FORMAT_STR(GL_RGB16F
)
292 FB_FORMAT_STR(GL_RGBA16F
)
293 FB_FORMAT_STR(GL_R32F
)
294 FB_FORMAT_STR(GL_RG32F
)
295 FB_FORMAT_STR(GL_RGB32F
)
296 FB_FORMAT_STR(GL_RGBA32F
)
297 FB_FORMAT_STR(GL_R11F_G11F_B10F
)
298 FB_FORMAT_STR(GL_RGB9_E5
)
299 FB_FORMAT_STR(GL_R8I
)
300 FB_FORMAT_STR(GL_R8UI
)
301 FB_FORMAT_STR(GL_R16I
)
302 FB_FORMAT_STR(GL_R16UI
)
303 FB_FORMAT_STR(GL_R32I
)
304 FB_FORMAT_STR(GL_R32UI
)
305 FB_FORMAT_STR(GL_RG8I
)
306 FB_FORMAT_STR(GL_RG8UI
)
307 FB_FORMAT_STR(GL_RG16I
)
308 FB_FORMAT_STR(GL_RG16UI
)
309 FB_FORMAT_STR(GL_RG32I
)
310 FB_FORMAT_STR(GL_RG32UI
)
311 FB_FORMAT_STR(GL_RGB8I
)
312 FB_FORMAT_STR(GL_RGB8UI
)
313 FB_FORMAT_STR(GL_RGB16I
)
314 FB_FORMAT_STR(GL_RGB16UI
)
315 FB_FORMAT_STR(GL_RGB32I
)
316 FB_FORMAT_STR(GL_RGB32UI
)
317 FB_FORMAT_STR(GL_RGBA8I
)
318 FB_FORMAT_STR(GL_RGBA8UI
)
319 FB_FORMAT_STR(GL_RGBA16I
)
320 FB_FORMAT_STR(GL_RGBA16UI
)
321 FB_FORMAT_STR(GL_RGBA32I
)
322 FB_FORMAT_STR(GL_RGBA32UI
)
325 for( int i
=0; i
<vg_list_size(formats
); i
++ )
326 if( formats
[i
].e
== format
)
327 return formats
[i
].str
;
333 * Bind and allocate texture for framebuffer attachment
335 static void render_fb_allocate_texture( struct framebuffer
*fb
,
336 struct framebuffer_attachment
*a
)
339 render_fb_get_current_res( fb
, &rx
, &ry
);
341 if( a
->purpose
== k_framebuffer_attachment_type_renderbuffer
){
342 glBindRenderbuffer( GL_RENDERBUFFER
, a
->id
);
343 glRenderbufferStorage( GL_RENDERBUFFER
, a
->internalformat
, rx
, ry
);
345 else if( a
->purpose
== k_framebuffer_attachment_type_texture
||
346 a
->purpose
== k_framebuffer_attachment_type_texture_depth
)
348 glBindTexture( GL_TEXTURE_2D
, a
->id
);
349 glTexImage2D( GL_TEXTURE_2D
, 0, a
->internalformat
, rx
, ry
,
350 0, a
->format
, a
->type
, NULL
);
355 * Full allocation of a framebuffer
357 void render_fb_allocate( struct framebuffer
*fb
)
359 glGenFramebuffers( 1, &fb
->fb
);
360 glBindFramebuffer( GL_FRAMEBUFFER
, fb
->fb
);
363 render_fb_get_current_res( fb
, &rx
, &ry
);
365 vg_info( "allocate_framebuffer( %s, %dx%d )\n", fb
->display_name
, rx
, ry
);
368 GLenum colour_attachments
[4];
369 u32 colour_count
= 0;
371 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ ){
372 struct framebuffer_attachment
*attachment
= &fb
->attachments
[j
];
374 if( attachment
->purpose
== k_framebuffer_attachment_type_none
)
377 vg_info( " %s: %s\n",
378 render_fb_attachment_str( attachment
->attachment
),
379 render_fb_format_str( attachment
->internalformat
) );
381 if( attachment
->purpose
== k_framebuffer_attachment_type_renderbuffer
){
382 glGenRenderbuffers( 1, &attachment
->id
);
383 render_fb_allocate_texture( fb
, attachment
);
384 glFramebufferRenderbuffer( GL_FRAMEBUFFER
,
385 GL_DEPTH_STENCIL_ATTACHMENT
,
386 GL_RENDERBUFFER
, attachment
->id
);
388 else if( attachment
->purpose
== k_framebuffer_attachment_type_texture
||
389 attachment
->purpose
== k_framebuffer_attachment_type_texture_depth
)
391 glGenTextures( 1, &attachment
->id
);
392 render_fb_allocate_texture( fb
, attachment
);
393 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
394 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
395 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
396 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
398 glFramebufferTexture2D( GL_FRAMEBUFFER
, attachment
->attachment
,
399 GL_TEXTURE_2D
, attachment
->id
, 0 );
401 if( attachment
->purpose
== k_framebuffer_attachment_type_texture
)
402 colour_attachments
[ colour_count
++ ] = attachment
->attachment
;
406 glDrawBuffers( colour_count
, colour_attachments
);
411 GLenum result
= glCheckFramebufferStatus( GL_FRAMEBUFFER
);
413 if( result
== GL_FRAMEBUFFER_COMPLETE
){
415 * Attatch to gpipeline
420 vg_success( " status: complete\n" );
424 if( result
== GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
)
425 vg_error( " status: Incomplete attachment" );
426 else if( result
== GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
)
427 vg_error( " status: Missing attachment" );
428 else if( result
== GL_FRAMEBUFFER_UNSUPPORTED
)
429 vg_error( " status: Unsupported framebuffer format" );
431 vg_error( " status: Generic Error" );
434 vg_fatal_error( "Incomplete framebuffer (see logs)" );
439 * Resize/Update all framebuffers(we know about)
441 void render_fb_resize(void)
443 if( !gpipeline
.ready
) return;
445 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
446 struct framebuffer
*fb
= &framebuffers
[i
];
447 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ ){
448 struct framebuffer_attachment
*attachment
= &fb
->attachments
[j
];
449 render_fb_allocate_texture( fb
, attachment
);
454 static int render_framebuffer_control( int argc
, char const *argv
[] );
455 static void render_framebuffer_poll( int argc
, char const *argv
[] );
457 static void async_render_init( void *payload
, u32 size
)
460 * Complete Framebuffers
462 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
463 struct framebuffer
*fb
= &framebuffers
[i
];
464 render_fb_allocate( fb
);
467 f32 rh
= 0x1p
-4f
, ih
= 0.3f
;
470 0.00f
,0.00f
, 1.00f
,1.00f
, 0.00f
,1.00f
, /* fsquad */
471 0.00f
,0.00f
, 1.00f
,0.00f
, 1.00f
,1.00f
,
473 0.00f
,0.00f
, 1.00f
,rh
, 0.00f
,rh
, /* fsquad1 */
474 0.00f
,0.00f
, 1.00f
,0.00f
, 1.00f
,rh
,
475 0.00f
,1.00f
, 0.00f
,1.0f
-rh
,1.00f
,1.0f
-rh
,
476 0.00f
,1.00f
, 1.00f
,1.0f
-rh
,1.00f
,1.0f
,
480 0.00f
,0.00f
, 0.30f
,0.30f
, 0.00f
,0.30f
,
481 0.00f
,0.00f
, 0.30f
,0.00f
, 0.30f
,0.30f
,
482 0.30f
,0.00f
, 0.60f
,0.30f
, 0.30f
,0.30f
,
483 0.30f
,0.00f
, 0.60f
,0.00f
, 0.60f
,0.30f
,
484 0.60f
,0.00f
, 0.90f
,0.30f
, 0.60f
,0.30f
,
485 0.60f
,0.00f
, 0.90f
,0.00f
, 0.90f
,0.30f
,
487 0.00f
,0.30f
, 0.30f
,0.60f
, 0.00f
,0.60f
,
488 0.00f
,0.30f
, 0.30f
,0.30f
, 0.30f
,0.60f
,
489 0.30f
,0.30f
, 0.60f
,0.60f
, 0.30f
,0.60f
,
490 0.30f
,0.30f
, 0.60f
,0.30f
, 0.60f
,0.60f
,
491 0.60f
,0.30f
, 0.90f
,0.60f
, 0.60f
,0.60f
,
492 0.60f
,0.30f
, 0.90f
,0.30f
, 0.90f
,0.60f
,
494 0.00f
,0.60f
, 0.30f
,0.90f
, 0.00f
,0.90f
,
495 0.00f
,0.60f
, 0.30f
,0.60f
, 0.30f
,0.90f
,
496 0.30f
,0.60f
, 0.60f
,0.90f
, 0.30f
,0.90f
,
497 0.30f
,0.60f
, 0.60f
,0.60f
, 0.60f
,0.90f
,
498 0.60f
,0.60f
, 0.90f
,0.90f
, 0.60f
,0.90f
,
499 0.60f
,0.60f
, 0.90f
,0.60f
, 0.90f
,0.90f
,
501 0.00f
,ih
, 1.00f
,ih
+rh
, 0.00f
,ih
+rh
, /* fsquad2 */
502 0.00f
,ih
, 1.00f
,ih
, 1.00f
,ih
+rh
,
505 glGenVertexArrays( 1, &gpipeline
.fsquad
.vao
);
506 glGenBuffers( 1, &gpipeline
.fsquad
.vbo
);
507 glBindVertexArray( gpipeline
.fsquad
.vao
);
508 glBindBuffer( GL_ARRAY_BUFFER
, gpipeline
.fsquad
.vbo
);
509 glBufferData( GL_ARRAY_BUFFER
, sizeof(quad
), quad
, GL_STATIC_DRAW
);
510 glBindVertexArray( gpipeline
.fsquad
.vao
);
511 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
,
512 sizeof(float)*2, (void*)0 );
513 glEnableVertexAttribArray( 0 );
517 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
521 void render_init(void)
523 vg_console_reg_var( "blur_strength", &k_blur_strength
, k_var_dtype_f32
, 0 );
524 vg_console_reg_var( "render_scale", &k_render_scale
,
525 k_var_dtype_f32
, VG_VAR_PERSISTENT
);
526 vg_console_reg_var( "fov", &k_fov
, k_var_dtype_f32
, VG_VAR_PERSISTENT
);
527 vg_console_reg_var( "cam_height", &k_cam_height
,
528 k_var_dtype_f32
, VG_VAR_PERSISTENT
);
529 vg_console_reg_var( "blur_effect", &k_blur_effect
,
530 k_var_dtype_i32
, VG_VAR_PERSISTENT
);
532 vg_console_reg_cmd( "fb", render_framebuffer_control
,
533 render_framebuffer_poll
);
535 vg_async_call( async_render_init
, NULL
, 0 );
541 void render_fsquad(void)
543 glBindVertexArray( gpipeline
.fsquad
.vao
);
544 glDrawArrays( GL_TRIANGLES
, 0, 6 );
547 void render_fsquad1(void)
549 glBindVertexArray( gpipeline
.fsquad
.vao
);
550 glDrawArrays( GL_TRIANGLES
, 6, 6+6 );
553 void render_fsquad2(void)
555 glBindVertexArray( gpipeline
.fsquad
.vao
);
556 glDrawArrays( GL_TRIANGLES
, 66+6,6 );
560 * Call this inside the UI function
562 void render_view_framebuffer_ui(void)
565 int viewing_count
= 0;
567 glBindVertexArray( gpipeline
.fsquad
.vao
);
569 shader_blit_uTexMain( 0 );
571 v2f identity
= { 1.0f
, 1.0f
};
572 shader_blit_uInverseRatio( identity
);
574 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
575 struct framebuffer
*fb
= &framebuffers
[i
];
577 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ ){
578 struct framebuffer_attachment
*at
= &fb
->attachments
[j
];
580 if( !at
->debug_view
)
584 window
= { vg
.window_x
, vg
.window_y
};
586 corner
[0] = viewing_count
% 3;
587 corner
[1] = 1 + (viewing_count
/ 3);
588 v2_mul( corner
, window
, corner
);
589 v2_muls( corner
, 0.3f
, corner
);
590 corner
[1] = vg
.window_y
- corner
[1];
592 ui_text( (ui_rect
){ corner
[0], corner
[1], 0.0f
, 0.0f
},
593 fb
->display_name
, 2, k_text_align_left
);
594 ui_text( (ui_rect
){ corner
[0], corner
[1] + 32, 0.0f
, 0.0f
, },
595 at
->display_name
, 1, k_text_align_left
);
597 if( at
->purpose
== k_framebuffer_attachment_type_renderbuffer
){
599 v2_muladds( corner
, window
, 0.15f
, center
);
601 ui_text( (ui_rect
){ center
[0], center
[1], 0.0f
, 0.0f
},
602 "<hardware texture>", 1, k_text_align_center
);
605 render_fb_bind_texture( fb
, j
, 0 );
607 int start
= (viewing_count
+2) * 6,
609 glDrawArrays( GL_TRIANGLES
, start
, count
);
618 static void render_framebuffer_show( struct framebuffer
*fb
,
619 struct framebuffer_attachment
*at
,
622 at
->debug_view
= operation
;
623 vg_info( "%s %s:%s\n", (operation
?"shown": "hidden"),
624 fb
->display_name
, at
->display_name
);
628 * arg0: command "show"/"hide"
629 * arg1: framebuffer name <name>/"all"
630 * arg2: subname <name>/none
632 static int render_framebuffer_control( int argc
, char const *argv
[] )
635 vg_error( "Usage: fb \"show/hide\" <name>/\"all\" <name>/none\n" );
642 if( !strcmp( argv
[0], "show" ) )
644 else if( !strcmp( argv
[0], "hide" ) )
647 vg_error( "Unknown framebuffer operation: '%s'\n", argv
[0] );
651 if( !strcmp( argv
[1], "all" ) )
654 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
655 struct framebuffer
*fb
= &framebuffers
[i
];
657 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ ){
658 struct framebuffer_attachment
*at
= &fb
->attachments
[j
];
660 if( at
->purpose
== k_framebuffer_attachment_type_none
)
664 render_framebuffer_show( fb
, at
, operation
);
667 if( !strcmp( fb
->display_name
, argv
[1] ) ){
669 render_framebuffer_show( fb
, at
, operation
);
670 else if( !strcmp( at
->display_name
, argv
[2] ) )
671 render_framebuffer_show( fb
, at
, operation
);
680 static void render_framebuffer_poll( int argc
, char const *argv
[] )
682 const char *term
= argv
[argc
-1];
685 console_suggest_score_text( "show", term
, 0 );
686 console_suggest_score_text( "hide", term
, 0 );
688 else if( argc
== 2 ){
689 console_suggest_score_text( "all", term
, 0 );
691 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
692 struct framebuffer
*fb
= &framebuffers
[i
];
693 console_suggest_score_text( fb
->display_name
, term
, 0 );
696 else if( argc
== 3 ){
699 if( !strcmp( argv
[1], "all" ) )
702 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ ){
703 struct framebuffer
*fb
= &framebuffers
[i
];
705 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ ){
706 struct framebuffer_attachment
*at
= &fb
->attachments
[j
];
708 if( at
->purpose
== k_framebuffer_attachment_type_none
)
712 console_suggest_score_text( at
->display_name
, term
, 0 );
714 else if( !strcmp( fb
->display_name
, argv
[1] ) ){
715 console_suggest_score_text( at
->display_name
, term
, 0 );