X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=render.h;h=22c05726ddd0222a7b567e6b47c1c87ddea18540;hb=859178c6d4b2a9b9a95f8b01b113f589ce0f197f;hp=cac188d07dcbdf3fc258bcbb4a5ab45256567e50;hpb=b9dedb4dd2a1e94ae76a3986716ee3c57e568213;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/render.h b/render.h index cac188d..22c0572 100644 --- a/render.h +++ b/render.h @@ -1,385 +1,807 @@ +/* + * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved + */ + #include "common.h" #include "model.h" +#include "camera.h" +#include "world.h" #include "shaders/blit.h" -#include "shaders/standard.h" -#include "shaders/vblend.h" -#include "shaders/unlit.h" - -static void render_water_texture( m4x3f camera ); -static void render_water_surface( m4x4f pv, m4x3f camera ); -static void render_world( m4x4f projection, m4x3f camera ); -static void shader_link_standard_ub( GLuint shader, int texture_id ); -static void render_world_depth( m4x4f projection, m4x3f camera ); +#include "shaders/blitblur.h" +#include "shaders/blitcolour.h" +#include "shaders/blit_transition.h" +#define WORKSHOP_PREVIEW_WIDTH 504 +#define WORKSHOP_PREVIEW_HEIGHT 336 #ifndef RENDER_H #define RENDER_H -struct framebuffer -{ - GLuint fb, colour, rb; - int div; - GLuint format; +static f32 k_render_scale = 1.0f; +static i32 k_blur_effect = 1; +static f32 k_blur_strength = 0.3f; +static f32 k_fov = 0.86f; +static f32 k_cam_height = 0.8f; - int allocated; -}; +typedef struct framebuffer framebuffer; -static struct pipeline -{ - float fov; +/* + * All standard buffers used in rendering + */ +static struct pipeline{ glmesh fsquad; - GLuint fb_background, - rgb_background; + framebuffer *fb_main, + *fb_water_reflection, + *fb_water_beneath, + *fb_workshop_preview, + *fb_network_status; + int ready; +} +gpipeline; + +struct framebuffer{ + const char *display_name; + int resolution_div, /* definition */ + fixed_w, + fixed_h, + + render_w, /* runtime */ + render_h; + + struct framebuffer_attachment{ + const char *display_name; + + enum framebuffer_attachment_type{ + k_framebuffer_attachment_type_none, + k_framebuffer_attachment_type_texture, + k_framebuffer_attachment_type_renderbuffer, + k_framebuffer_attachment_type_texture_depth + } + purpose; - /* STD140 */ - struct ub_world_lighting - { - /* v3f (padded) */ - v4f g_light_colours[3], - g_light_directions[3], - g_ambient_colour; + enum framebuffer_quality_profile{ + k_framebuffer_quality_all, + k_framebuffer_quality_high_only + } + quality; + + GLenum internalformat, + format, + type, + attachment; - v4f g_water_plane, - g_depth_bounds; + GLuint id; - float g_water_fog; - int g_light_count; - int g_light_preview; + /* Runtime */ + int debug_view; } - ub_world_lighting; - - struct light_widget - { - int enabled; - v2f dir; - v3f colour; - } - widgets[3]; - - float shadow_spread, shadow_length; - - GLuint fb_depthmap, rgb_depthmap; - GLuint ubo_world_lighting, - ubo_world; - - int ready; + attachments[5]; + GLuint fb; + framebuffer **link; } -gpipeline = +framebuffers[] = { - .widgets = { + /* + * The primary draw target + */ + "main", + .link = &gpipeline.fb_main, + .resolution_div = 1, + .attachments = + { + { + "colour", k_framebuffer_attachment_type_texture, + + .internalformat = GL_RGB, + .format = GL_RGB, + .type = GL_UNSIGNED_BYTE, + .attachment = GL_COLOR_ATTACHMENT0 + }, + { + "motion", k_framebuffer_attachment_type_texture, + + .quality = k_framebuffer_quality_high_only, + .internalformat = GL_RG16F, + .format = GL_RG, + .type = GL_FLOAT, + .attachment = GL_COLOR_ATTACHMENT1 + }, + { +#if 0 + "depth_stencil", k_framebuffer_attachment_type_renderbuffer, + + .internalformat = GL_DEPTH24_STENCIL8, +#else + "depth_stencil", k_framebuffer_attachment_type_texture_depth, + .internalformat = GL_DEPTH24_STENCIL8, + .format = GL_DEPTH_STENCIL, + .type = GL_UNSIGNED_INT_24_8, +#endif + .attachment = GL_DEPTH_STENCIL_ATTACHMENT + } + } + }, + { + /* + * Second rendered view from the perspective of the water reflection + */ + "water_reflection", + .link = &gpipeline.fb_water_reflection, + .resolution_div = 2, + .attachments = { - .enabled = 1, - .colour = { 1.36f, 1.35f, 1.01f }, - .dir = { 0.63f, -0.08f } - }, + { + "colour", k_framebuffer_attachment_type_texture, + .internalformat = GL_RGB, + .format = GL_RGB, + .type = GL_UNSIGNED_BYTE, + .attachment = GL_COLOR_ATTACHMENT0 + }, + { + "depth_stencil", k_framebuffer_attachment_type_renderbuffer, + + .internalformat = GL_DEPTH24_STENCIL8, + .attachment = GL_DEPTH_STENCIL_ATTACHMENT + } + } + }, + { + /* + * Thid rendered view from the perspective of the camera, but just + * captures stuff thats under the water + */ + "water_beneath", + .link = &gpipeline.fb_water_beneath, + .resolution_div = 2, + .attachments = { - .enabled = 1, - .colour = { 0.33f, 0.56f, 0.64f }, - .dir = { -2.60f, -0.13f } - }, + { + "colour", k_framebuffer_attachment_type_texture, + .internalformat = GL_RED, + .format = GL_RED, + .type = GL_UNSIGNED_BYTE, + .attachment = GL_COLOR_ATTACHMENT0 + }, + { + "depth_stencil", k_framebuffer_attachment_type_renderbuffer, + + .internalformat = GL_DEPTH24_STENCIL8, + .attachment = GL_DEPTH_STENCIL_ATTACHMENT + } + } + }, + { + "workshop_preview", + .link = &gpipeline.fb_workshop_preview, + .resolution_div = 0, + .fixed_w = WORKSHOP_PREVIEW_WIDTH, .fixed_h = WORKSHOP_PREVIEW_HEIGHT, + .attachments = { - .enabled = 1, - .colour = { 0.05f, 0.05f, 0.23f }, - .dir = { 2.60f, -0.84f } + { + "colour", k_framebuffer_attachment_type_texture, + .internalformat = GL_RGB, + .format = GL_RGB, + .type = GL_UNSIGNED_BYTE, + .attachment = GL_COLOR_ATTACHMENT0 + }, + { + "depth_stencil", k_framebuffer_attachment_type_renderbuffer, + .internalformat = GL_DEPTH24_STENCIL8, + .attachment = GL_DEPTH_STENCIL_ATTACHMENT + } } }, - .shadow_spread = 0.65f, - .shadow_length = 9.50f, - - .ub_world_lighting = { - .g_ambient_colour = { 0.09f, 0.03f, 0.07f } + "network_status_ui", + .link = &gpipeline.fb_network_status, + .resolution_div = 0, + .fixed_w = 128, .fixed_h = 48, + .attachments = + { + { + "colour", k_framebuffer_attachment_type_texture, + .internalformat = GL_RGB, + .format = GL_RGB, + .type = GL_UNSIGNED_BYTE, + .attachment = GL_COLOR_ATTACHMENT0 + } + } } }; /* - * Matrix Projections + * Get the current (automatically scaled or fixed) resolution of framebuffer */ -/* - * http://www.terathon.com/lengyel/Lengyel-Oblique.pdf - */ -static void plane_clip_projection( m4x4f mat, v4f plane ) +static void render_fb_get_current_res( struct framebuffer *fb, + int *x, int *y ) { - v4f c = - { - (vg_signf(plane[0]) + mat[2][0]) / mat[0][0], - (vg_signf(plane[1]) + mat[2][1]) / mat[1][1], - -1.0f, - (1.0f + mat[2][2]) / mat[3][2] - }; - - v4_muls( plane, 2.0f / v4_dot(plane,c), c ); - - mat[0][2] = c[0]; - mat[1][2] = c[1]; - mat[2][2] = c[2] + 1.0f; - mat[3][2] = c[3]; + if( fb->resolution_div ){ + *x = vg.window_x / fb->resolution_div; + *y = vg.window_y / fb->resolution_div; + } + else{ + *x = fb->fixed_w; + *y = fb->fixed_h; + } } -static void pipeline_projection( m4x4f mat, float nearz, float farz ) +static void render_fb_inverse_ratio( framebuffer *fb, v2f inverse ) { - m4x4_projection( mat, - gpipeline.fov, - (float)vg_window_x / (float)vg_window_y, - nearz, farz ); + if( fb ){ + int x, y; + render_fb_get_current_res( fb, &x, &y ); + + v2f render = { fb->render_w, fb->render_h }, + original = { x, y }; + + v2_div( render, original, inverse ); + } + else{ + v2_div( (v2f){1.0f,1.0f}, (v2f){ vg.window_x, vg.window_y }, inverse ); + } } /* - * Shaders + * Bind framebuffer for drawing to */ -static void shader_link_standard_ub( GLuint shader, int texture_id ) +static void render_fb_bind( framebuffer *fb, int use_scaling ) { - GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" ); - glUniformBlockBinding( shader, idx, 0 ); + int x, y; + render_fb_get_current_res( fb, &x, &y ); + + if( use_scaling ){ + x = k_render_scale*(float)x; + y = k_render_scale*(float)y; + + x = VG_MAX( 16, x ); + y = VG_MAX( 16, y ); + + fb->render_w = x; + fb->render_h = y; + } - glActiveTexture( GL_TEXTURE0 + texture_id ); - glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_depthmap ); - glUniform1i( glGetUniformLocation( shader, "g_world_depth" ), texture_id ); + glBindFramebuffer( GL_FRAMEBUFFER, fb->fb ); + glViewport( 0, 0, x, y ); } -static void render_update_lighting_ub(void) +/* + * Bind framebuffer attachment's texture + */ +static void render_fb_bind_texture( framebuffer *fb, + int attachment, int slot ) { - struct ub_world_lighting *winf = &gpipeline.ub_world_lighting; - int c = 0; + struct framebuffer_attachment *at = &fb->attachments[attachment]; - for( int i=0; i<3; i++ ) + if( (at->purpose != k_framebuffer_attachment_type_texture) && + (at->purpose != k_framebuffer_attachment_type_texture_depth) ) { - struct light_widget *lw = &gpipeline.widgets[i]; + vg_fatal_error( "illegal operation: bind non-texture framebuffer" + " attachment to texture slot" ); + } - if( lw->enabled ) - { - float pitch = lw->dir[0], - yaw = lw->dir[1], - xz = cosf( pitch ); - - v3_copy( (v3f){ xz*cosf(yaw), sinf(pitch), xz*sinf(yaw) }, - winf->g_light_directions[c] ); - v3_copy( lw->colour, winf->g_light_colours[c] ); + glActiveTexture( GL_TEXTURE0 + slot ); + glBindTexture( GL_TEXTURE_2D, fb->attachments[attachment].id ); +} - c ++; - } - } - winf->g_light_count = c; - winf->g_light_directions[0][3] = gpipeline.shadow_length; - winf->g_light_colours[0][3] = gpipeline.shadow_spread; +/* + * Shaders + */ - glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting ); - glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting), - &gpipeline.ub_world_lighting ); -} +#define FB_FORMAT_STR( E ) { E, #E }, /* - * Framebuffers + * Convert OpenGL attachment ID enum to string + */ +static const char *render_fb_attachment_str( GLenum e ) +{ + struct { GLenum e; const char *str; } + formats[] = + { + FB_FORMAT_STR(GL_COLOR_ATTACHMENT0) + FB_FORMAT_STR(GL_COLOR_ATTACHMENT1) + FB_FORMAT_STR(GL_COLOR_ATTACHMENT2) + FB_FORMAT_STR(GL_COLOR_ATTACHMENT3) + FB_FORMAT_STR(GL_COLOR_ATTACHMENT4) + FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT) + }; + + for( int i=0; ipurpose == k_framebuffer_attachment_type_renderbuffer ){ + glBindRenderbuffer( GL_RENDERBUFFER, a->id ); + glRenderbufferStorage( GL_RENDERBUFFER, a->internalformat, rx, ry ); } - else + else if( a->purpose == k_framebuffer_attachment_type_texture || + a->purpose == k_framebuffer_attachment_type_texture_depth ) { - glBindFramebuffer( GL_FRAMEBUFFER, fb->fb ); - glViewport( 0, 0, vg_window_x / fb->div, vg_window_y / fb->div ); + glBindTexture( GL_TEXTURE_2D, a->id ); + glTexImage2D( GL_TEXTURE_2D, 0, a->internalformat, rx, ry, + 0, a->format, a->type, NULL ); } } -static void fb_init( struct framebuffer *fb ) +/* + * Full allocation of a framebuffer + */ +static void render_fb_allocate( struct framebuffer *fb ) { - i32 ix = vg_window_x / fb->div, - iy = vg_window_y / fb->div; - glGenFramebuffers( 1, &fb->fb ); glBindFramebuffer( GL_FRAMEBUFFER, fb->fb ); - glGenTextures( 1, &fb->colour ); - glBindTexture( GL_TEXTURE_2D, fb->colour ); - glTexImage2D( GL_TEXTURE_2D, 0, fb->format, ix, iy, - 0, fb->format, GL_UNSIGNED_BYTE, NULL); + int rx, ry; + render_fb_get_current_res( fb, &rx, &ry ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, fb->colour, 0); + vg_info( "allocate_framebuffer( %s, %dx%d )\n", fb->display_name, rx, ry ); + vg_info( "{\n" ); - glGenRenderbuffers( 1, &fb->rb ); - glBindRenderbuffer( GL_RENDERBUFFER, fb->rb ); - glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy ); + GLenum colour_attachments[4]; + u32 colour_count = 0; - glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, fb->rb ); - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + for( int j=0; jattachments); j++ ){ + struct framebuffer_attachment *attachment = &fb->attachments[j]; - VG_CHECK_GL_ERR(); - fb->allocated = 1; -} + if( attachment->purpose == k_framebuffer_attachment_type_none ) + continue; -static void fb_free( struct framebuffer *fb ) -{ - glDeleteTextures( 1, &fb->colour ); - glDeleteFramebuffers( 1, &fb->fb ); -} + vg_info( " %s: %s\n", + render_fb_attachment_str( attachment->attachment ), + render_fb_format_str( attachment->internalformat ) ); -static void fb_bindtex( struct framebuffer *fb, int texture ) -{ - glActiveTexture( GL_TEXTURE0 + texture ); - glBindTexture( GL_TEXTURE_2D, fb->colour ); -} + if( attachment->purpose == k_framebuffer_attachment_type_renderbuffer ){ + glGenRenderbuffers( 1, &attachment->id ); + render_fb_allocate_texture( fb, attachment ); + glFramebufferRenderbuffer( GL_FRAMEBUFFER, + GL_DEPTH_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, attachment->id ); + } + else if( attachment->purpose == k_framebuffer_attachment_type_texture || + attachment->purpose == k_framebuffer_attachment_type_texture_depth ) + { + glGenTextures( 1, &attachment->id ); + render_fb_allocate_texture( fb, attachment ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + + glFramebufferTexture2D( GL_FRAMEBUFFER, attachment->attachment, + GL_TEXTURE_2D, attachment->id, 0 ); + + if( attachment->purpose == k_framebuffer_attachment_type_texture ) + colour_attachments[ colour_count ++ ] = attachment->attachment; + } + } -static void fb_resize( struct framebuffer *fb ) -{ - if( !fb->allocated ) - return; + glDrawBuffers( colour_count, colour_attachments ); - i32 ix = vg_window_x / fb->div, - iy = vg_window_y / fb->div; + /* + * Check result + */ + GLenum result = glCheckFramebufferStatus( GL_FRAMEBUFFER ); - glBindTexture( GL_TEXTURE_2D, fb->colour ); - glTexImage2D( GL_TEXTURE_2D, 0, fb->format, ix, iy, 0, - fb->format, GL_UNSIGNED_BYTE, NULL ); + if( result == GL_FRAMEBUFFER_COMPLETE ){ + /* + * Attatch to gpipeline + */ + if( fb->link ) + *fb->link = fb; - glBindRenderbuffer( GL_RENDERBUFFER, fb->rb ); - glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy ); + vg_success( " status: complete\n" ); + vg_info( "}\n" ); + } + else{ + if( result == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ) + vg_error( " status: Incomplete attachment" ); + else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT ) + vg_error( " status: Missing attachment" ); + else if( result == GL_FRAMEBUFFER_UNSUPPORTED ) + vg_error( " status: Unsupported framebuffer format" ); + else + vg_error( " status: Generic Error" ); + + vg_info( "}\n" ); + vg_fatal_error( "Incomplete framebuffer (see logs)" ); + } } +/* + * Resize/Update all framebuffers(we know about) + */ static void render_fb_resize(void) { - if( gpipeline.ready ) - { - glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y, 0, - GL_RGB, GL_UNSIGNED_BYTE, NULL ); + if( !gpipeline.ready ) return; + + for( int i=0; iattachments); j++ ){ + struct framebuffer_attachment *attachment = &fb->attachments[j]; + render_fb_allocate_texture( fb, attachment ); + } } } -/* used for drawing player onto */ -static void render_init_temp_buffer(void) -{ - vg_info( "[render] Allocate temporary framebuffer\n" ); +static int render_framebuffer_control( int argc, char const *argv[] ); +static void render_framebuffer_poll( int argc, char const *argv[] ); - glGenFramebuffers( 1, &gpipeline.fb_background ); - glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_background ); +static void async_render_init( void *payload, u32 size ) +{ + /* + * Complete Framebuffers + */ + for( int i=0; iattachments); j++ ){ + struct framebuffer_attachment *at = &fb->attachments[j]; -static void render_init(void) -{ - shader_blit_register(); - shader_standard_register(); - shader_vblend_register(); - shader_unlit_register(); + if( !at->debug_view ) + continue; - vg_acquire_thread_sync(); - { - render_init_temp_buffer(); - render_init_depthmap_buffer(); - render_init_fs_quad(); - render_init_uniform_buffers(); + v2f corner, + window = { vg.window_x, vg.window_y }; - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - gpipeline.ready = 1; + corner[0] = viewing_count % 3; + corner[1] = 1 + (viewing_count / 3); + v2_mul( corner, window, corner ); + v2_muls( corner, 0.3f, corner ); + corner[1] = vg.window_y - corner[1]; + + ui_text( (ui_rect){ corner[0], corner[1], 0.0f, 0.0f }, + fb->display_name, 2, k_text_align_left ); + ui_text( (ui_rect){ corner[0], corner[1] + 32, 0.0f, 0.0f, }, + at->display_name, 1, k_text_align_left ); + + if( at->purpose == k_framebuffer_attachment_type_renderbuffer ){ + v2f center; + v2_muladds( corner, window, 0.15f, center ); + + ui_text( (ui_rect){ center[0], center[1], 0.0f, 0.0f }, + "", 1, k_text_align_center ); + } + else{ + render_fb_bind_texture( fb, j, 0 ); + + int start = (viewing_count+2) * 6, + count = 6; + glDrawArrays( GL_TRIANGLES, start, count ); + } + + viewing_count ++; + } } +#endif +} - vg_release_thread_sync(); +static void render_framebuffer_show( struct framebuffer *fb, + struct framebuffer_attachment *at, + int operation ) +{ + at->debug_view = operation; + vg_info( "%s %s:%s\n", (operation?"shown": "hidden"), + fb->display_name, at->display_name ); } -static void render_free(void *_) +/* + * arg0: command "show"/"hide" + * arg1: framebuffer name /"all" + * arg2: subname /none + */ +static int render_framebuffer_control( int argc, char const *argv[] ) { - glDeleteBuffers( 1, &gpipeline.ubo_world_lighting ); + if( argc < 2 ){ + vg_error( "Usage: fb \"show/hide\" /\"all\" /none\n" ); + return 0; + } + + int modify_all = 0, + operation = 0; - glDeleteVertexArrays( 1, &gpipeline.fsquad.vao ); - glDeleteBuffers( 1, &gpipeline.fsquad.vbo ); + if( !strcmp( argv[0], "show" ) ) + operation = 1; + else if( !strcmp( argv[0], "hide" ) ) + operation = 0; + else{ + vg_error( "Unknown framebuffer operation: '%s'\n", argv[0] ); + return 0; + } - glDeleteFramebuffers( 1, &gpipeline.fb_depthmap ); - glDeleteTextures( 1, &gpipeline.rgb_depthmap ); + if( !strcmp( argv[1], "all" ) ) + modify_all = 1; + + for( int i=0; iattachments); j++ ){ + struct framebuffer_attachment *at = &fb->attachments[j]; + + if( at->purpose == k_framebuffer_attachment_type_none ) + continue; + + if( modify_all ){ + render_framebuffer_show( fb, at, operation ); + } + else{ + if( !strcmp( fb->display_name, argv[1] ) ){ + if( argc == 2 ) + render_framebuffer_show( fb, at, operation ); + else if( !strcmp( at->display_name, argv[2] ) ) + render_framebuffer_show( fb, at, operation ); + } + } + } + } - glDeleteFramebuffers( 1, &gpipeline.fb_background ); - glDeleteTextures( 1, &gpipeline.rgb_background ); + return 0; } -/* - * Utility - */ -static void render_fsquad(void) +static void render_framebuffer_poll( int argc, char const *argv[] ) { - glBindVertexArray( gpipeline.fsquad.vao ); - glDrawArrays( GL_TRIANGLES, 0, 6 ); + const char *term = argv[argc-1]; + + if( argc == 1 ){ + console_suggest_score_text( "show", term, 0 ); + console_suggest_score_text( "hide", term, 0 ); + } + else if( argc == 2 ){ + console_suggest_score_text( "all", term, 0 ); + + for( int i=0; idisplay_name, term, 0 ); + } + } + else if( argc == 3 ){ + int modify_all = 0; + + if( !strcmp( argv[1], "all" ) ) + modify_all = 1; + + for( int i=0; iattachments); j++ ){ + struct framebuffer_attachment *at = &fb->attachments[j]; + + if( at->purpose == k_framebuffer_attachment_type_none ) + continue; + + if( modify_all ){ + console_suggest_score_text( at->display_name, term, 0 ); + } + else if( !strcmp( fb->display_name, argv[1] ) ){ + console_suggest_score_text( at->display_name, term, 0 ); + } + } + } + } } #endif /* RENDER_H */