From: hgn Date: Fri, 10 Dec 2021 02:06:54 +0000 (+0000) Subject: world buttons X-Git-Url: https://harrygodden.com/git/?p=fishladder.git;a=commitdiff_plain;h=a7f8fe92814d85e52a564b8a8f93db6ca682bf25 world buttons --- diff --git a/fishladder.c b/fishladder.c index 19e3fb4..13f3623 100644 --- a/fishladder.c +++ b/fishladder.c @@ -26,8 +26,8 @@ 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 + Row Gridlines for I/O DONE + Play button / Speed controller ( play buttern, pause, speed control, step button ) After release: @@ -148,7 +148,9 @@ float const curve_7_linear_section = 0.1562f; v3f colour_sets[] = { { 1.0f, 0.9f, 0.3f }, { 0.2f, 0.9f, 0.14f }, - { 0.4f, 0.8f, 1.00f } }; + { 0.4f, 0.8f, 1.00f }, + { 0.882f, 0.204f, 0.922f } +}; static void colour_code_v3( char cc, v3f target ) { @@ -213,6 +215,14 @@ enum e_fish_state k_fish_state_soon_alive }; +enum e_world_button +{ + k_world_button_none = -1, + k_world_button_sim = 0, + k_world_button_ff = 1, + k_world_button_wire_mode = 2 +}; + struct world { #pragma pack(push,1) @@ -232,7 +242,6 @@ struct world int sim_frame; float sim_start; - int simulating; int sim_run, max_runs; float sim_speed; @@ -258,9 +267,16 @@ struct world } *io; + struct cell_button + { + float light_target, light; + int pressed; + } + buttons[4]; + int w, h; - struct mesh tile, circle, numbers; + struct mesh shapes, numbers; struct mesh_wire { GLuint vao, vbo, ebo; @@ -298,6 +314,11 @@ struct world u32 time; } world; +static struct cell_button *get_wbutton( enum e_world_button btn ) +{ + return &world.buttons[ btn ]; +} + void leaderboard_set_score( struct cmp_level *cmp_level, u32 score ); static void map_free(void) @@ -367,6 +388,11 @@ static int hash21i( v2i p, u32 umod ) return random_noise[ (random_noise[p[1] & 1023] + p[0]) & 1023 ] & umod; } +static struct cell *pcell( v2i pos ) +{ + return &world.data[ pos[1]*world.w + pos[0] ]; +} + static void map_reclassify( v2i start, v2i end, int update_texbuffer ); static int map_load( const char *str, const char *name ) { @@ -397,7 +423,7 @@ static int map_load( const char *str, const char *name ) char link_id_buffer[32]; int link_id_n = 0; - + for(;;) { if( !*c ) @@ -601,7 +627,7 @@ static int map_load( const char *str, const char *name ) turtle[1] = 16+posy; turtle_dir[0] = 0; - turtle_dir[1] = posy <= 4? -1: 1; + turtle_dir[1] = pcell((v2i){ posx,posy })->state & FLAG_INPUT? 1: -1; original_y = turtle_dir[1]; for( int i = 0; i < 100; i ++ ) @@ -694,11 +720,6 @@ IL_REG_ERROR: return 0; } -static struct cell *pcell( v2i pos ) -{ - return &world.data[ pos[1]*world.w + pos[0] ]; -} - static void map_serialize( FILE *stream ) { for( int y = 0; y < world.h; y ++ ) @@ -861,7 +882,9 @@ static int console_load_map( int argc, char const *argv[] ) static void simulation_stop(void) { - world.simulating = 0; + get_wbutton( k_world_button_sim )->pressed = 0; + get_wbutton( k_world_button_ff )->pressed = 0; + world.num_fishes = 0; world.sim_frame = 0; world.sim_run = 0; @@ -873,6 +896,64 @@ static void simulation_stop(void) vg_info( "Stopping simulation!\n" ); } +static void wbutton_run( enum e_world_button btn_name ) +{ + struct cell_button *btn = &world.buttons[btn_name]; + + // Interaction + + int is_hovering = (world.tile_x == world.w-1 && world.tile_y == world.h-btn_name-2)?1:0; + if( vg_get_button_up( "primary" ) && is_hovering ) + { + // Click event + btn->pressed ^= 0x1; + + if( btn_name == k_world_button_sim ) + { + if( btn->pressed ) + { + vg_success( "Starting simulation!\n" ); + + sfx_set_playrnd( &audio_rolls, &audio_system_balls_rolling, 0, 1 ); + + world.num_fishes = 0; + world.sim_frame = 0; + world.sim_start = vg_time; + world.sim_run = 0; + world.sim_speed = 2.5f; + + for( int i = 0; i < world.w*world.h; i ++ ) + world.data[ i ].state &= ~FLAG_FLIP_FLOP; + + io_reset(); + } + else + { + simulation_stop(); + } + } + } + + // Drawing + if( btn->pressed ) btn->light_target = is_hovering? 0.9f: 0.8f; + else btn->light_target = is_hovering? 0.2f: 0.0f; + + if( vg_get_button( "primary" ) && is_hovering ) + btn->light_target = 1.0f; + + btn->light = vg_lerpf( btn->light, btn->light_target, vg_time_delta*26.0f ); + + glUniform4f( SHADER_UNIFORM( shader_buttons, "uOffset" ), + world.w-1, + world.h-btn_name-2, + (float)btn_name, + 3.0f + ); + glUniform4f( SHADER_UNIFORM( shader_buttons, "uColour" ), 0.204f, 0.345f, 0.553f, btn->light ); + + draw_mesh( 0, 2 ); +} + static int console_changelevel( int argc, char const *argv[] ) { if( argc >= 1 ) @@ -1064,24 +1145,18 @@ void vg_start(void) .function = console_credits }); - // Quad mesh + // Combined quad, long quad / empty circle / filled circle mesh { - float quad_mesh[] = - { + float combined_mesh[6*8 + 32*6*3] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 4.0f, 1.0f, - 0.0f, 0.0f, 4.0f, 1.0f, 4.0f, 0.0f + 0.0f, 0.0f, 0.0f, 0.2f, 1.0f, 0.2f, + 0.0f, 0.0f, 1.0f, 0.2f, 1.0f, 0.0f }; - init_mesh( &world.tile, quad_mesh, vg_list_size(quad_mesh) ); - } - - // Circle mesh - { - float circle_mesh[32*6*3]; - int res = vg_list_size( circle_mesh ) / (6*3); + float *circle_mesh = combined_mesh + 6*4; + int const res = 32; for( int i = 0; i < res; i ++ ) { @@ -1105,7 +1180,7 @@ void vg_start(void) v2_copy( v1, circle_mesh+i*6+2 ); } - init_mesh( &world.circle, circle_mesh, vg_list_size( circle_mesh ) ); + init_mesh( &world.shapes, combined_mesh, vg_list_size( combined_mesh ) ); } // Numbers mesh @@ -1215,8 +1290,7 @@ void vg_free(void) glDeleteBuffers( 1, &world.wire.vbo ); glDeleteBuffers( 1, &world.wire.ebo ); - free_mesh( &world.tile ); - free_mesh( &world.circle ); + free_mesh( &world.shapes ); free_mesh( &world.numbers ); map_free(); @@ -1435,7 +1509,7 @@ void vg_update(void) world.tile_y = floorf( world.tile_pos[1] ); // Tilemap editing - if( !world.simulating && !gui_want_mouse() ) + if( !get_wbutton( k_world_button_sim )->pressed && !gui_want_mouse() ) { v2_copy( vg_mouse_ws, drag_to_co ); @@ -1528,7 +1602,9 @@ void vg_update(void) } } else + { world.selected = -1; + } if( !(vg_get_button("secondary") && id_drag_from) ) id_drag_from = 0; @@ -1539,35 +1615,8 @@ void vg_update(void) id_drag_from = 0; } - // Simulation stop/start - if( vg_get_button_down("go") ) - { - if( world.simulating ) - { - simulation_stop(); - } - else - { - vg_success( "Starting simulation!\n" ); - - sfx_set_playrnd( &audio_rolls, &audio_system_balls_rolling, 0, 1 ); - - world.simulating = 1; - world.num_fishes = 0; - world.sim_frame = 0; - world.sim_start = vg_time; - world.sim_run = 0; - world.sim_speed = 2.5f; - - for( int i = 0; i < world.w*world.h; i ++ ) - world.data[ i ].state &= ~FLAG_FLIP_FLOP; - - io_reset(); - } - } - // Fish ticks - if( world.simulating ) + if( get_wbutton( k_world_button_sim )->pressed ) { while( world.sim_frame < (int)((vg_time-world.sim_start)*world.sim_speed) ) { @@ -1930,8 +1979,7 @@ void vg_update(void) vg_error( "Level failed :(\n" ); } - - simulation_stop(); // TODO: Async? + simulation_stop(); break; } @@ -2108,7 +2156,7 @@ void vg_render(void) // NOTE: this is for final optimisations ONLY! // ====================================================================== - use_mesh( &world.tile ); + use_mesh( &world.shapes ); // Draw background @@ -2156,7 +2204,7 @@ void vg_render(void) // Main // ========================================================================================= - use_mesh( &world.tile ); + use_mesh( &world.shapes ); SHADER_USE( shader_tile_main ); m2x2f subtransform; @@ -2188,7 +2236,7 @@ void vg_render(void) glUniform1i( SHADER_UNIFORM( shader_ball, "uTexMain" ), 0 ); // Draw 'fish' - if( world.simulating ) + if( get_wbutton( k_world_button_sim )->pressed ) { for( int i = 0; i < world.num_fishes; i ++ ) { @@ -2285,6 +2333,16 @@ void vg_render(void) //glDisable(GL_BLEND); + SHADER_USE( shader_buttons ); + glUniformMatrix3fv( SHADER_UNIFORM( shader_buttons, "uPv" ), 1, GL_FALSE, (float *)vg_pv ); + + vg_tex2d_bind( &tex_buttons, 0 ); + glUniform1i( SHADER_UNIFORM( shader_buttons, "uTexMain" ), 0 ); + + wbutton_run( k_world_button_sim ); + wbutton_run( k_world_button_ff ); + + // Draw connecting wires glDisable(GL_BLEND); @@ -2340,12 +2398,15 @@ void vg_render(void) SHADER_USE( shader_tile_colour ); glUniformMatrix3fv( SHADER_UNIFORM( shader_tile_colour, "uPv" ), 1, GL_FALSE, (float *)vg_pv ); - use_mesh( &world.circle ); + use_mesh( &world.shapes ); - int const filled_start = 0; - int const filled_count = 32; - int const empty_start = 32; - int const empty_count = 32*2; + int const circle_base = 4; + int const filled_start = circle_base+0; + int const filled_count = circle_base+32; + int const empty_start = circle_base+32; + int const empty_count = circle_base+32*2; + + glEnable(GL_BLEND); // Draw i/o arrays for( int i = 0; i < arrlen( world.io ); i ++ ) @@ -2359,15 +2420,24 @@ void vg_render(void) for( int k = 0; k < term->run_count; k ++ ) { + float y_offset = is_input? 1.2f: -0.2f; + float y_h = (is_input? 0.2f: -0.2f) * (float)k; + float y_row = is_input? + (y_offset + (float)posy + (float)(term->run_count-1)*0.2f) - y_h: + (float)posy + y_offset + y_h; + + if( k & 0x1 ) + { + glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1.0f, 1.0f, 1.0f, 0.1f ); + glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx, y_row - 0.1f, 1.0f ); + draw_mesh( 2, 2 ); + } + for( int j = 0; j < term->runs[k].condition_count; j ++ ) { - float y_offset = is_input? 1.2f: -0.2f; - float y_h = (is_input? 0.2f: -0.2f) * (float)k; - if( is_input ) { - glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, - (y_offset + (float)posy + (float)(term->run_count-1)*0.2f) - y_h, 0.1f ); + glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, y_row, 0.1f ); colour_code_v3( term->runs[k].conditions[j], dot_colour ); glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, dot_colour ); @@ -2380,7 +2450,7 @@ void vg_render(void) } else { - glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, (float)posy + y_offset + y_h, 0.1f ); + glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, y_row, 0.1f ); if( term->runs[k].recv_count > j ) { @@ -2400,12 +2470,7 @@ void vg_render(void) } } - if( world.simulating ) - { - glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.0f, 0.0f, 0.0f, 1.0f ); - glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), -0.5f + cosf( vg_time * 4.0f ) * 0.2f, sinf( vg_time * 4.0f ) * 0.2f + (float)world.h * 0.5f, 0.05f ); - draw_mesh( filled_start, filled_count ); - } + glDisable(GL_BLEND); // Draw score float const score_bright = 1.25f; @@ -2614,7 +2679,7 @@ void vg_ui(void) ui_global_ctx.override_colour = 0xffffffff; gui_text( lvl_info->title, 6, 0 ); ui_global_ctx.cursor[1] += 18; - gui_text( "incomplete", 4, 0 ); + gui_text( lvl_info->completed_score>0? "passed": "incomplete", 4, 0 ); } else { diff --git a/fishladder_resources.h b/fishladder_resources.h index 8c8ee3b..f5b392a 100644 --- a/fishladder_resources.h +++ b/fishladder_resources.h @@ -8,8 +8,9 @@ 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", .flags = VG_TEXTURE_NO_MIP }; vg_tex2d tex_unkown = { .path = "textures/unkown.qoi" }; +vg_tex2d tex_buttons = { .path = "textures/buttons.qoi" }; -vg_tex2d *texture_list[] = { &tex_tile_detail, &tex_tile_data, &tex_wood, &tex_background, &tex_ball_noise, &tex_monofur, &tex_unkown }; +vg_tex2d *texture_list[] = { &tex_tile_detail, &tex_tile_data, &tex_wood, &tex_background, &tex_ball_noise, &tex_monofur, &tex_unkown, &tex_buttons }; // AUDIO // =========================================================================================================== @@ -379,6 +380,43 @@ SHADER_DEFINE( shader_wire, UNIFORMS({ "uPv", "uColour", "uTexMain", "uStart", "uEnd", "uCurve" }) ) +SHADER_DEFINE( shader_buttons, + // VERTEX + "layout (location=0) in vec2 a_co;" + "uniform vec4 uOffset;" // Tile x/y, uv x/y + "uniform mat3 uPv;" + "" + "out vec2 aTexCoords;" + "" + "void main()" + "{" + // Vertex transform + "vec3 worldpos = vec3( a_co + uOffset.xy, 1.0 );" + "gl_Position = vec4( uPv * worldpos, 1.0 );" + + // Create texture coords + "vec2 edge_safe_coords = a_co * 0.98 + 0.01;" + "aTexCoords = (edge_safe_coords + uOffset.zw) * 0.25;" + "}", + + // FRAGMENT + "out vec4 FragColor;" + "" + "uniform sampler2D uTexMain;" + "uniform vec4 uColour;" // rgb, light amount + "" + "in vec2 aTexCoords;" + "" + "void main()" + "{" + "vec4 glyph = texture( uTexMain, aTexCoords.xy );" + + "FragColor = vec4( uColour.rgb * (mix(glyph.r, glyph.g, uColour.a)+0.02)*2.6 + glyph.b * 0.4, glyph.a );" + "}" + , + UNIFORMS({ "uPv", "uOffset", "uTexMain", "uColour" }) +) + void vg_register(void) { @@ -387,6 +425,7 @@ void vg_register(void) SHADER_INIT( shader_ball ); SHADER_INIT( shader_background ); SHADER_INIT( shader_wire ); + SHADER_INIT( shader_buttons ); } /* @@ -580,6 +619,7 @@ struct cmp_level static struct cmp_level cmp_levels_tutorials[] = { + // r1 { .serial_id = 0, .title = "PRINCIPLE 1", @@ -589,6 +629,7 @@ static struct cmp_level cmp_levels_tutorials[] = ._unlock = 1, .is_tutorial = 1 }, + // r1 { .serial_id = 1, .title = "PRINCIPLE 2", @@ -599,6 +640,7 @@ static struct cmp_level cmp_levels_tutorials[] = ._unlock = 2, .is_tutorial = 1, }, + // r1 { .serial_id = 2, .title = "PRINCIPLE 3", @@ -608,6 +650,7 @@ static struct cmp_level cmp_levels_tutorials[] = ._unlock = 12, .is_tutorial = 1 }, + // r1 { .serial_id = 12, .title = "PRINCIPLE 4", @@ -622,29 +665,34 @@ static struct cmp_level cmp_levels_tutorials[] = static struct cmp_level cmp_levels_basic[] = { + // r1 { .serial_id = 3, .title = "SUBDIVISION 1", .map_name = "cmp_b01", - .description = "Simple maths, branching required.", + .description = "Sometimes getting the desired amount takes\n" + "dividing up the input and recombining it.", ._linked = 4, ._unlock = 6 }, + // r1 { .serial_id = 4, .title = "SUBDIVISION 2", .map_name = "cmp_b02", - .description = "Simple maths, except more.", + .description = "", ._linked = 5, ._unlock = 7 }, + // r1 { .serial_id = 5, .title = "RESTRUCTURE", .map_name = "cmp_b03", - .description = "Not so simple swap", + .description = "It is possible to swap these values using\n" + "simple division and addition.", ._unlock = 8 }, @@ -697,20 +745,23 @@ static struct cmp_level cmp_levels_basic[] = ._unlock = 15 }, + // r2 { .serial_id = 15, .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" + "The eager engineers among you may have already spotted\n" + "and utilized these parts of the system\n" "\n" "We forgot to include the relevant principle tasks as\n" "of your training package, you will now be tasked to\n" "complete them", - ._unlock = 16 + ._unlock = 16, + .is_tutorial = 1 }, + // r2 { .serial_id = 16, .title = "ROUTING PROBLEM", @@ -743,7 +794,8 @@ static struct cmp_level cmp_levels_basic[] = "this results in no operation being performed, and no\n" "state changes take place in the Twisty Turny(TM)\n", - ._unlock = 18 + ._unlock = 18, + .is_tutorial = 1 }, { .serial_id = 18, diff --git a/maps/cmp_b01.map b/maps/cmp_b01.map new file mode 100644 index 0000000..ccb9765 --- /dev/null +++ b/maps/cmp_b01.map @@ -0,0 +1,10 @@ +#############; +###-#####-##$;a,aaa +## #$; +## #$; +## ##; +## ##; +## ##; +## ##; +######+######;aaaa +#############; diff --git a/maps/cmp_b02.map b/maps/cmp_b02.map new file mode 100644 index 0000000..013f900 --- /dev/null +++ b/maps/cmp_b02.map @@ -0,0 +1,13 @@ +###############; +####-##-##-####;aaaaaa,a,a +## ##; +## ##; +## ##; +#### ##### ####; +### ###; +### ###; +### ###; +### ###; +### ###; +#######+#######;aaaaaaaa +###############; diff --git a/maps/cmp_b03.map b/maps/cmp_b03.map new file mode 100644 index 0000000..3fa19dc --- /dev/null +++ b/maps/cmp_b03.map @@ -0,0 +1,10 @@ +#############; +###-#####-###;aaa,aa +## ##; +## ##; +## ##; +## ##; +## ##; +## ##; +###+#####+###;aa,aaa +#############; diff --git a/maps/cmp_b10.map b/maps/cmp_b10.map new file mode 100644 index 0000000..dcdf667 --- /dev/null +++ b/maps/cmp_b10.map @@ -0,0 +1,7 @@ +###########; +##-########;ab +## # ##; +## # ##; +## # ##; +########+##;ab +###########; diff --git a/maps/cmp_routing.map b/maps/cmp_routing.map new file mode 100644 index 0000000..ead3b05 --- /dev/null +++ b/maps/cmp_routing.map @@ -0,0 +1,16 @@ +###################; +####-#########-####;bbbb,aaaa +## # ####### ##; +## ####### # ##; +## # ## ## # ##; +## #### #### ##; +## # #### # ####; +#### ##-#+## #-##;dddd,dddd,cccc +## # #### ##; +## # # ##; +##+##### ########;cccc +#### ##### # ##; +## # ##; +## # # ##; +#####+#######+#####;aaaa,bbbb +###################; diff --git a/maps/level3.map b/maps/level3.map deleted file mode 100644 index 9c548b3..0000000 --- a/maps/level3.map +++ /dev/null @@ -1,10 +0,0 @@ -#############; -###-#####-###;a,aaa -## ##; -## ##; -## ##; -## ##; -## ##; -## ##; -######+######;aaaa -#############; diff --git a/maps/level4.map b/maps/level4.map deleted file mode 100644 index 3fa19dc..0000000 --- a/maps/level4.map +++ /dev/null @@ -1,10 +0,0 @@ -#############; -###-#####-###;aaa,aa -## ##; -## ##; -## ##; -## ##; -## ##; -## ##; -###+#####+###;aa,aaa -#############; diff --git a/textures/buttons.png b/textures/buttons.png new file mode 100644 index 0000000..52e9001 Binary files /dev/null and b/textures/buttons.png differ diff --git a/vg/vg_m.h b/vg/vg_m.h index a0c0107..3b7feb4 100644 --- a/vg/vg_m.h +++ b/vg/vg_m.h @@ -227,7 +227,7 @@ static inline void v3_normalize( v3f a ) v3_muls( a, 1.f / v3_length( a ), a ); } -static inline float csr_lerpf( float a, float b, float t ) +static inline float vg_lerpf( float a, float b, float t ) { return a + t*(b-a); }