From: hgn Date: Sun, 5 Dec 2021 16:57:05 +0000 (+0000) Subject: ui gpu clipping X-Git-Url: https://harrygodden.com/git/?p=fishladder.git;a=commitdiff_plain;h=42fc2b14afbe5a37bdd469b9bac5f642bc50ccc4 ui gpu clipping --- diff --git a/fishladder.c b/fishladder.c index 74a39ce..842bb64 100644 --- a/fishladder.c +++ b/fishladder.c @@ -23,9 +23,9 @@ Reverse order New things to program: - UI text element renderer (SDF) - Particle system thing for ball collision - Level descriptions / titles + UI text element renderer (SDF) DONE(sorta) + Particle system thing for ball collision + Level descriptions / titles HALF Row Gridlines for I/O Play button / Speed controller @@ -355,7 +355,7 @@ struct world int num_fishes; - char map_name[128]; + char map_name[64]; struct career_level *ptr_career_level; u32 score; @@ -402,9 +402,9 @@ static int map_load( const char *str, const char *name ) // Scan for width for(;; world.w ++) { - if( str[world.w] == ';' ) + if( c[world.w] == ';' ) break; - else if( !str[world.w] ) + else if( !c[world.w] ) { vg_error( "Unexpected EOF when parsing level\n" ); return 0; @@ -1965,6 +1965,27 @@ void vg_render(void) } + // Level title + ui_begin( &ui_global_ctx, 512, 256 ); + + ui_global_ctx.override_colour = 0xff9a8a89; + //ui_text( &ui_global_ctx, world.map_title, 6, 0 ); + ui_global_ctx.override_colour = 0xffffffff; + + ui_resolve( &ui_global_ctx ); + + m3x3f world_text; + m3x3_copy( vg_pv, world_text ); + m3x3_translate( world_text, (v3f){ 1.55f, 1.9f, 0.0f } ); + m3x3_rotate( world_text, VG_PIf*0.5f ); + m3x3_scale( world_text, (v3f){0.01f,-0.01f,0.01f} ); + + ui_draw( &ui_global_ctx, world_text ); + + // Main + // ========================================================================================= + + use_mesh( &world.tile ); SHADER_USE( shader_tile_main ); m2x2f subtransform; @@ -2311,12 +2332,49 @@ void vg_render(void) level_ui_space[1] -= 0.01f; draw_numbers( level_ui_space, i ); } - - //use_mesh( &world.numbers ); - //draw_numbers( (v3f){ 0.0f, -0.5f, 0.1f }, 128765 ); } void vg_ui(void) { + ui_global_ctx.cursor[0] = 0; + ui_global_ctx.cursor[1] = 0; + ui_global_ctx.cursor[2] = 256; + + ui_fill_y( &ui_global_ctx ); + ui_new_node( &ui_global_ctx ); + { + ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0xff5577ff ); + + ui_text( &ui_global_ctx, "MARBLE COMPUTING", 4, 0 ); + + ui_global_ctx.cursor[1] += 45; + ui_global_ctx.cursor[3] = 709; + + // Level scroll view + ui_new_node( &ui_global_ctx ); + { + ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0xffff7729 ); + ui_set_clip( &ui_global_ctx, ui_global_ctx.cursor ); + + ui_global_ctx.cursor[3] = 50; + ui_global_ctx.cursor[2] = 240; + + for( int i = 0; i < vg_list_size(cmp_levels_basic); i ++ ) + { + struct cmp_level *lvl_info = &cmp_levels_basic[i]; + + ui_new_node( &ui_global_ctx ); + { + ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, i&0x1?0xff23fce45:0xff8722f8 ); + ui_text( &ui_global_ctx, lvl_info->title, 3, 0 ); + } + ui_end_down( &ui_global_ctx ); + } + + ui_release_clip( &ui_global_ctx ); + } + ui_end_down( &ui_global_ctx ); + } + ui_end( &ui_global_ctx ); } diff --git a/fishladder_resources.h b/fishladder_resources.h index 023c329..da8b8ea 100644 --- a/fishladder_resources.h +++ b/fishladder_resources.h @@ -6,7 +6,7 @@ vg_tex2d tex_tile_detail = { .path = "textures/tile_overlays.qoi" }; vg_tex2d tex_wood = { .path = "textures/wood.qoi" }; vg_tex2d tex_background = { .path = "textures/background.qoi" }; vg_tex2d tex_ball_noise = { .path = "textures/bnoise.qoi" }; -vg_tex2d tex_monofur = { .path = "textures/ascii.qoi" }; +vg_tex2d tex_monofur = { .path = "textures/ascii.qoi", .flags = VG_TEXTURE_NO_MIP }; vg_tex2d *texture_list[] = { &tex_tile_detail, &tex_tile_data, &tex_wood, &tex_background, &tex_ball_noise, &tex_monofur }; @@ -95,7 +95,7 @@ static void resource_load_main(void) // Textures vg_tex2d_init( texture_list, vg_list_size( texture_list ) ); - ui_override_font( tex_monofur.name, 3 ); + ui_override_font( tex_monofur.name, 7 ); // Audio sfx_set_init( &audio_tile_mod, NULL ); @@ -543,3 +543,224 @@ u32 const MESH_NUMBERS_OFFSETS[][2] = vg_list_size( MESH_NUMBER_9 ) / MESH_NUMBER_DIVISOR } }; + +struct cmp_level +{ + const char *map_name; + const char *title; + const char *description; + + int serial_id; +}; + +struct cmp_level cmp_levels_tutorials[] = +{ + { + .title = "PRINCIPLE 1", + .map_name = "cmp_t01", + .description = "Utilize basic transport methods", + + .serial_id = 0 + }, + { + .title = "PRINCIPLE 2", + .map_name = "cmp_t02", + .description = "Utilize the twisty turny(TM) piece", + + .serial_id = 1 + }, + { + .title = "PRINCIPLE 3", + .map_name = "cmp_t03", + .description = "Merge transport into one", + + .serial_id = 2 + }, + { + .title = "PRINCIPLE 4", + .map_name = "cmp_t04", + .description = "Some stages require multiple runs to succeed in order to pass", + + .serial_id = 12 + } +}; + +struct cmp_level cmp_levels_basic[] = +{ + { + .title = "SUBDIVISION 1", + .map_name = "cmp_b01", + .description = "Simple maths, branching required.", + + .serial_id = 3 + }, + { + .title = "SUBDIVISION 2", + .map_name = "cmp_b02", + .description = "Simple maths. Futher.", + + .serial_id = 4 + }, + { + .title = "RESTRUCTURE", + .map_name = "cmp_b03", + .description = "Not so simple swap", + + .serial_id = 5 + }, + { + .title = "SERIALIZE", + .map_name = "cmp_b04", + .description = "Merge and sort", + + .serial_id = 6 + }, + { + .title = "PATTERNS 1", + .map_name = "cmp_b05", + .description = "Replicate", + + .serial_id = 7 + }, + { + .title = "PATTERNS 2", + .map_name = "cmp_b06", + .description = "Replicate MORE", + + .serial_id = 8 + }, + { + .title = "MIGHTY CONSUMER", + .map_name = "cmp_b07", + .description = "Build a greedy system", + + .serial_id = 9 + }, + { + .title = "ENCRYPTED 1", + .map_name = "cmp_b08", + .description = "Some configurations may not be valid", + + .serial_id = 10 + }, + { + .title = "REVERSE", + .map_name = "cmp_b09", + .description = "Reverse the incoming order. Always length 4", + + .serial_id = 11 + }, + { + .title = "PRINCIPLE 5", + .map_name = "cmp_b10", + .description = + "The competent engineers among you may have already\n" + "spotted and utilized these parts of the system\n" + "\n" + "We forgot to include the relevant principle tasks\n" + "as part of your training package, you will now be\n" + "tasked to complete them", + + .serial_id = 15 + }, + { + .title = "ROUTING PROBLEM", + .map_name = "cmp_routing", + .description = + "Things can get a little chaotic on tight boards,\n" + "Do your best to utilize principle 5 to get the job\n" + "done.", + + .serial_id = 16 + }, + { + .title = "PRINCIPLE 6", + .map_name = "cmp_b11", + .description = + "While hovering over a simple tile peice, right click\n" + "and drag to start creating a wire. These can be\n" + "connected to the left, or right recieving pins of a\n" + "Twisty Turny(TM) peice.\n" + "\n" + "Once connected, the Twisty Turny(TM) will no longer\n" + "'flip flop' as marbles run through them, but instead\n" + "be set to left or right rotating only. As indicated\n" + "by the status arrow beneath them\n" + "\n" + "When the left or right slot is triggered, the Twisty\n" + "Turny(TM) will switch modes according to that input.\n" + "\n" + "Trigger wires apply instantaneously, however if both\n" + "the left and right inputs are recieved at the same\n" + "time, this results in no operation being performed,\n" + "and no state changes take place in the Twisty Turny(TM)\n", + + .serial_id = 17 + }, + { + .title = "NOT GATE", + .map_name = "cmp_not", + .description = + "Test your knowledge of triggers, build an 'NOT GATE'\n" + "emulated by marble logic.", + + .serial_id = 18 + }, + { + .title = "AND GATE", + .map_name = "cmp_and", + .description = + "A slightly more complicated gate, but shouldn't be\n" + "too difficult for your skillset.", + + .serial_id = 19 + }, + { + .title = "QUALIFICATION PROJECT", + .map_name = "cmp_grad", + .description = + "There's no instructions here, resolve and complete this\n" + "task to qualify yourself as an official marble engineer", + .serial_id = 20 + } +}; + +struct cmp_level cmp_levels_grad[] = +{ + { + .title = "SORT", + .map_name = "cmp_i01", + .description = + "Device a scheme to filter and sort the inputs. If you\n" + "believe you lack the tools required to solve this one,\n" + "take a harder look at the inputs.", + + .serial_id = 13 + }, + { + .title = "THIRDS", + .map_name = "cmp_i02", + .description = + "Spit your inputs up into a third of its value\n" + "Is this possible? -HG", + + .serial_id = 14 + }, + { + .title = "XOR CHIP", + .map_name = "cmp_xor", + .description = + "Significantly more complicated than an AND or NOT gate,\n" + "but possible.", + .serial_id = 21 + }, + { + .title = "SECRET CODE", + .map_name = "cmp_secret", + .description = + "Only one input should send an unlock signal marble to\n" + "the output.\n" + "The code: 100110", + .serial_id = 22 + } +}; diff --git a/maps/level0.map b/maps/level0.map index e5dc410..a30aab9 100644 --- a/maps/level0.map +++ b/maps/level0.map @@ -1,3 +1,4 @@ +PRINCIPLE 1 #########; ###-#####;acac ## ##; diff --git a/textures/ascii.png b/textures/ascii.png index 523184d..adf296e 100644 Binary files a/textures/ascii.png and b/textures/ascii.png differ diff --git a/vg/vg.h b/vg/vg.h index c792527..cdcf431 100644 --- a/vg/vg.h +++ b/vg/vg.h @@ -255,7 +255,7 @@ static void vg_init( int argc, char *argv[], const char *window_name ) vg_debugtools_draw(); ui_resolve( &ui_global_ctx ); - ui_draw( &ui_global_ctx ); + ui_draw( &ui_global_ctx, NULL ); } glfwSwapBuffers( vg_window ); diff --git a/vg/vg_console.h b/vg/vg_console.h index 48dee1a..febe54a 100644 --- a/vg/vg_console.h +++ b/vg/vg_console.h @@ -177,6 +177,9 @@ static void execute_console_input( const char *cmd ) { temp[i] = '\0'; in_token = 0; + + if( arg_count == vg_list_size( args ) ) + break; } else { diff --git a/vg/vg_ui.h b/vg/vg_ui.h index 56ece6b..a2cc770 100644 --- a/vg/vg_ui.h +++ b/vg/vg_ui.h @@ -6,16 +6,22 @@ SHADER_DEFINE( shader_ui, "layout (location=0) in vec2 a_co;" // i16, i16, .. ? "layout (location=1) in vec2 a_uv;" // i8, i8 "layout (location=2) in vec4 a_colour;" // u32 + "layout (location=3) in vec4 a_clip;" // i16, i16, i16, i16 "uniform mat3 uPv;" "" "out vec2 aTexCoords;" "out vec4 aColour;" + "out vec2 aWsp;" + "out vec4 aClip;" "" "void main()" "{" "gl_Position = vec4( uPv * vec3( a_co, 1.0 ), 1.0 );" - "aTexCoords = a_uv * 0.01388888888;" + "aTexCoords = a_uv * 0.0078125;" "aColour = a_colour;" + + "aWsp = a_co;" + "aClip = a_clip;" "}", // FRAGMENT @@ -25,10 +31,15 @@ SHADER_DEFINE( shader_ui, "in vec2 aTexCoords;" "in vec4 aColour;" "" + "in vec2 aWsp;" + "in vec4 aClip;" + "" "void main()" "{" + "float clip_blend = step( aWsp.x, aClip.z ) * step( aWsp.y, aClip.w ) * step( aClip.x, aWsp.x ) * step( aClip.y, aWsp.y );" + "vec4 glyph = texture( uTexGlyphs, aTexCoords );" - "FragColor = aColour * vec4( 1.0, 1.0, 1.0, glyph.r );" + "FragColor = aColour * vec4( 1.0, 1.0, 1.0, glyph.r * clip_blend );" "}" , UNIFORMS({ "uPv", "uTexGlyphs" }) @@ -61,17 +72,21 @@ struct ui_ctx #pragma pack(push,1) struct ui_vert { - ui_px co[2]; - u8 uv[2]; - u32 colour; + ui_px co[2]; //32 4 + u8 uv[2]; //16 2 + u32 colour; //32 4 + ui_rect clip; //64 8 } *verts; #pragma pack(pop) + u32 override_colour; + u32 num_verts; u16 *indices; u32 num_indices; + ui_rect clipping; ui_rect cursor; u32 stack_count; u32 capture_mouse_id; @@ -172,7 +187,7 @@ static void ui_default_init(void) u32 const stride = sizeof( struct ui_vert ); // XY - glVertexAttribPointer( 0, 2, GL_UNSIGNED_SHORT, GL_FALSE, stride, (void *)offsetof( struct ui_vert, co ) ); + glVertexAttribPointer( 0, 2, GL_SHORT, GL_FALSE, stride, (void *)offsetof( struct ui_vert, co ) ); glEnableVertexAttribArray( 0 ); // UV @@ -182,6 +197,10 @@ static void ui_default_init(void) // COLOUR glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void *)offsetof( struct ui_vert, colour ) ); glEnableVertexAttribArray( 2 ); + + // CLIPPING + glVertexAttribPointer( 3, 4, GL_SHORT, GL_FALSE, stride, (void *)offsetof( struct ui_vert, clip ) ); + glEnableVertexAttribArray( 3 ); } // Initialize default context @@ -204,7 +223,7 @@ static void ui_default_free(void) free( ui_global_ctx.indices ); } -static void ui_draw( ui_ctx *ctx ) +static void ui_draw( ui_ctx *ctx, m3x3f view_override ) { glBindVertexArray( ui_vao ); @@ -221,9 +240,16 @@ static void ui_draw( ui_ctx *ctx ) SHADER_USE( shader_ui ); m3x3f view = M3X3_IDENTITY; - m3x3_translate( view, (v3f){ -1.0f, 1.0f, 0.0f } ); - m3x3_scale( view, (v3f){ 1.0f/((float)vg_window_x*0.5f), -1.0f/((float)vg_window_y*0.5f), 1.0f } ); - glUniformMatrix3fv( SHADER_UNIFORM( shader_ui, "uPv" ), 1, GL_FALSE, (float *)view ); + + if( !view_override ) + { + view_override = view; + + m3x3_translate( view, (v3f){ -1.0f, 1.0f, 0.0f } ); + m3x3_scale( view, (v3f){ 1.0f/((float)vg_window_x*0.5f), -1.0f/((float)vg_window_y*0.5f), 1.0f } ); + } + + glUniformMatrix3fv( SHADER_UNIFORM( shader_ui, "uPv" ), 1, GL_FALSE, (float *)view_override ); glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, ui_glyph_texture ); @@ -394,6 +420,22 @@ static void ui_capture_mouse( ui_ctx *ctx, u32 id ) } } +static void ui_set_clip( ui_ctx *ctx, ui_rect clip ) +{ + ctx->clipping[0] = clip[0]; + ctx->clipping[1] = clip[1]; + ctx->clipping[2] = clip[0] + clip[2]; + ctx->clipping[3] = clip[1] + clip[3]; +} + +static void ui_release_clip( ui_ctx *ctx ) +{ + ctx->clipping[0] = -32000; + ctx->clipping[1] = -32000; + ctx->clipping[2] = 32000; + ctx->clipping[3] = 32000; +} + // Drawing // =========================================================================================================== @@ -423,6 +465,11 @@ static struct ui_vert *ui_fill_rect_uv( ui_ctx *ctx, ui_rect rect, u32 colour, u u16 ind_start = ctx->num_verts; u16 *indices = &ctx->indices[ ctx->num_indices ]; + ui_rect_copy( ctx->clipping, vertices[0].clip ); + ui_rect_copy( ctx->clipping, vertices[1].clip ); + ui_rect_copy( ctx->clipping, vertices[2].clip ); + ui_rect_copy( ctx->clipping, vertices[3].clip ); + indices[0] = ind_start+0; indices[1] = ind_start+2; indices[2] = ind_start+1; @@ -439,7 +486,7 @@ static struct ui_vert *ui_fill_rect_uv( ui_ctx *ctx, ui_rect rect, u32 colour, u static struct ui_vert *ui_fill_rect( ui_ctx *ctx, ui_rect rect, u32 colour ) { - return ui_fill_rect_uv( ctx, rect, colour, (ui_px[4]){ 66, 72-66, 66, 72-66 } ); + return ui_fill_rect_uv( ctx, rect, colour, (ui_px[4]){ 4,124,4,124 } ); } static void ui_text( ui_ctx *ctx, const char *str, ui_px scale, int alignment ) @@ -448,10 +495,10 @@ static void ui_text( ui_ctx *ctx, const char *str, ui_px scale, int alignment ) text_cursor[0] = ctx->cursor[0]; text_cursor[1] = ctx->cursor[1]; - text_cursor[2] = 7*scale; - text_cursor[3] = 7*scale; + text_cursor[2] = scale*8; + text_cursor[3] = scale*8; - u32 current_colour = 0xffffffff; + u32 current_colour = ctx->override_colour; const char *_c = str; char c; @@ -467,13 +514,19 @@ static void ui_text( ui_ctx *ctx, const char *str, ui_px scale, int alignment ) { u8 glyph_base[2]; u8 glyph_index = c - 32; - glyph_base[0] = glyph_index%10; - glyph_base[1] = (glyph_index-glyph_base[0])/10; + glyph_base[0] = glyph_index&0xf; + glyph_base[1] = (glyph_index-glyph_base[0])>>4; - glyph_base[0] *= 7; - glyph_base[1] *= 7; + glyph_base[0] *= 8; + glyph_base[1] *= 8; - ui_fill_rect_uv( ctx, text_cursor, current_colour, (ui_px[4]){glyph_base[0],72-glyph_base[1],glyph_base[0]+7,72-(glyph_base[1]+7)} ); + ui_fill_rect_uv( ctx, text_cursor, current_colour, + (ui_px[4]){ + glyph_base[0], + 128-glyph_base[1], + glyph_base[0]+8, + 128-(glyph_base[1]+8) + }); } else if( c == '\x1B' ) { @@ -510,9 +563,10 @@ static void ui_text( ui_ctx *ctx, const char *str, ui_px scale, int alignment ) break; } } + continue; } - text_cursor[0] += ui_glyph_spacing_x*scale; + text_cursor[0] += (ui_glyph_spacing_x*scale)/2; } } @@ -533,6 +587,8 @@ static void ui_begin( ui_ctx *ctx, ui_px res_x, ui_px res_y ) ctx->num_verts = 0; ctx->num_indices = 0; + + ui_release_clip( ctx ); } static void ui_resolve( ui_ctx *ctx )