X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=fishladder.c;h=7520c2c86a0ae261868484d14e84642ed3ea44fc;hb=b2ed006db6dc46c57b163f572391ac74a94f4a4f;hp=d4640be4b2f08e27c15113af77bd07bfe819f5e8;hpb=aacc3fa98842a475c5fd6d0f102a341ec6ed4b69;p=fishladder.git diff --git a/fishladder.c b/fishladder.c index d4640be..7520c2c 100644 --- a/fishladder.c +++ b/fishladder.c @@ -1,38 +1,12 @@ // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved +//#define VG_CAPTURE_MODE #define VG_STEAM #define VG_STEAM_APPID 1218140U #include "vg/vg.h" #include "fishladder_resources.h" -/* - Todo for release: - Tutorial levels: - 1. Transport - 2. Split - 3. Merge (and explode) - 4. Principle 1 (divide colours) - 5. Principle 2 (combine colours) - - Trainee levels: - Simple maths (x3) - Colour ordering (x2) - Routing problems (x2) - - Medium levels: - Reverse order - - New things to program: - UI text element renderer (SDF) DONE(sorta) - Particle system thing for ball collision - Level descriptions / titles HALF - Row Gridlines for I/O DONE - Play button / Speed controller PLAY/PAUSED.. todo: speed, wire connecty - - - After release: - -*/ +// #define STEAM_LEADERBOARDS // CONSTANTS // =========================================================================================================== @@ -923,8 +897,13 @@ struct dcareer_state }; #pragma pack(pop) +static int career_load_success = 0; + static void career_serialize(void) { + if( !career_load_success ) + return; + struct dcareer_state encoded; encoded.version = 2; encoded.in_map = world.pCmpLevel? world.pCmpLevel->serial_id: -1; @@ -1003,7 +982,6 @@ static void career_load(void) { vg_warn( "This save file is too small to have a header. Creating a blank one\n" ); free( cr ); - return; } memcpy( (void*)&encoded, cr, VG_MIN( sizeof( struct dcareer_state ), sz ) ); @@ -1045,6 +1023,8 @@ static void career_load(void) } } } + + career_load_success = 1; } // MAIN GAMEPLAY @@ -1054,6 +1034,12 @@ static int is_simulation_running(void) return world.buttons[ k_world_button_sim ].pressed; } +static void clear_animation_flags(void) +{ + for( int i = 0; i < world.w*world.h; i ++ ) + world.data[ i ].state &= ~(FLAG_FLIP_FLOP|FLAG_FLIP_ROTATING); +} + static void simulation_stop(void) { world.buttons[ k_world_button_sim ].pressed = 0; @@ -1062,14 +1048,40 @@ static void simulation_stop(void) world.num_fishes = 0; world.sim_frame = 0; world.sim_run = 0; + world.frame_lerp = 0.0f; io_reset(); sfx_system_fadeout( &audio_system_balls_rolling, 44100 ); + clear_animation_flags(); + vg_info( "Stopping simulation!\n" ); } +static void simulation_start(void) +{ + 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_run = 0; + + world.sim_delta_speed = 2.5f; + world.sim_delta_ref = vg_time; + world.sim_internal_ref = 0.0f; + world.sim_internal_time = 0.0f; + world.pause_offset_target = 0.0f; + + world.sim_target = 0; + + clear_animation_flags(); + + io_reset(); +} + static int world_check_pos_ok( v2i co ) { return (co[0] < 2 || co[0] >= world.w-2 || co[1] < 2 || co[1] >= world.h-2)? 0: 1; @@ -1241,7 +1253,7 @@ void vg_update(void) if( vg_get_button_up("secondary") && world.id_drag_from == world.selected ) { - u32 link_id = local_x > 0.5f? 1: 0; + u32 link_id = cell_ptr->links[ 0 ]? 0: 1; // break existing connection off if( cell_ptr->links[ link_id ] ) @@ -1259,7 +1271,7 @@ void vg_update(void) world.id_drag_from = 0; } - if( world.id_drag_from && (cell_ptr->state & FLAG_CANAL) && (cell_ptr->config == k_cell_type_split) ) + else if( world.id_drag_from && (cell_ptr->state & FLAG_CANAL) && (cell_ptr->config == k_cell_type_split) ) { world.drag_to_co[0] = (float)world.tile_x + (local_x > 0.5f? 0.75f: 0.25f); world.drag_to_co[1] = (float)world.tile_y + 0.25f; @@ -1527,11 +1539,6 @@ void vg_update(void) if( cell_current->state & FLAG_IS_TRIGGER ) { int trigger_id = cell_current->links[0]?0:1; - int connection_id = cell_current->links[trigger_id]; - int target_px = connection_id % world.w; - int target_py = (connection_id - target_px)/world.w; - - vg_line2( (v2f){ fish->pos[0], fish->pos[1] }, (v2f){ target_px, target_py }, 0xffffffff, 0xffffffff ); struct cell *target_peice = &world.data[ cell_current->links[trigger_id] ]; @@ -1887,30 +1894,6 @@ static void draw_numbers( v3f coord, int number ) } }*/ -static void simulation_start(void) -{ - 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_run = 0; - - world.sim_delta_speed = 2.5f; - world.sim_delta_ref = vg_time; - world.sim_internal_ref = 0.0f; - world.sim_internal_time = 0.0f; - world.pause_offset_target = 0.0f; - - world.sim_target = 0; - - for( int i = 0; i < world.w*world.h; i ++ ) - world.data[ i ].state &= ~FLAG_FLIP_FLOP; - - io_reset(); -} - static void wbutton_run( enum e_world_button btn_name ) { static v3f button_colours[] = { @@ -2028,12 +2011,15 @@ void vg_render(void) v4f const colour_default = {1.0f, 1.0f, 1.0f, 1.0f}; v4f const colour_selected = {0.90f, 0.92f, 1.0f, 1.0f}; - int const circle_base = 4; + int const circle_base = 6; 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; + if( !world.initialzed ) + return; + // BACKGROUND // ======================================================================================================== use_mesh( &world.shapes ); @@ -2220,25 +2206,33 @@ void vg_render(void) // WIRES // ======================================================================================================== - glDisable(GL_BLEND); + //glDisable(GL_BLEND); SHADER_USE( shader_wire ); glBindVertexArray( world.wire.vao ); glUniformMatrix3fv( SHADER_UNIFORM( shader_wire, "uPv" ), 1, GL_FALSE, (float *)vg_pv ); - glUniform4f( SHADER_UNIFORM( shader_wire, "uColour" ), 0.2f, 0.2f, 0.2f, 1.0f ); + + v4f const wire_left_colour = { 0.5f, 0.5f, 0.5f, 1.0f }; + v4f const wire_right_colour = { 0.2f, 0.2f, 0.2f, 1.0f }; + v4f const wire_drag_colour = { 0.2f, 0.2f, 0.2f, 0.6f }; + + glUniform1f( SHADER_UNIFORM( shader_wire, "uTime" ), world.frame_lerp ); + glUniform1f( SHADER_UNIFORM( shader_wire, "uGlow" ), 0.0f ); if( world.id_drag_from ) - { + { + glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, wire_drag_colour ); glUniform1f( SHADER_UNIFORM( shader_wire, "uCurve" ), 0.4f ); - glUniform3f( SHADER_UNIFORM( shader_wire, "uStart" ), world.drag_from_co[0], world.drag_from_co[1], 0.06f ); - glUniform3f( SHADER_UNIFORM( shader_wire, "uEnd" ), world.drag_to_co[0], world.drag_to_co[1], 0.06f ); + glUniform3f( SHADER_UNIFORM( shader_wire, "uStart" ), world.drag_from_co[0], world.drag_from_co[1], 0.20f ); + glUniform3f( SHADER_UNIFORM( shader_wire, "uEnd" ), world.drag_to_co[0], world.drag_to_co[1], 0.20f ); glDrawElements( GL_TRIANGLES, world.wire.em, GL_UNSIGNED_SHORT, (void*)(0) ); } // Pulling animation float rp_x1 = world.frame_lerp*9.0f; - float rp_x2 = 1.0f-rp_x1*expf(1.0f-rp_x1)* 0.36f; + float rp_xa = rp_x1*expf(1.0f-rp_x1)* 0.36f; + float rp_x2 = 1.0f-rp_xa; for( int y = 2; y < world.h-2; y ++ ) { @@ -2268,23 +2262,91 @@ void vg_render(void) v2_add( desc->trigger_pos, endpoint, endpoint ); + glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, trigger_id? wire_right_colour: wire_left_colour ); glUniform1f( SHADER_UNIFORM( shader_wire, "uCurve" ), cell->state & FLAG_TRIGGERED? rp_x2 * 0.4f: 0.4f ); - glUniform3f( SHADER_UNIFORM( shader_wire, "uStart" ), startpoint[0], startpoint[1], 0.04f ); - glUniform3f( SHADER_UNIFORM( shader_wire, "uEnd" ), endpoint[0], endpoint[1], 0.04f ); + glUniform1f( SHADER_UNIFORM( shader_wire, "uGlow" ), cell->state & FLAG_TRIGGERED? rp_xa: 0.0f ); + glUniform3f( SHADER_UNIFORM( shader_wire, "uStart" ), startpoint[0], startpoint[1], 0.18f ); + glUniform3f( SHADER_UNIFORM( shader_wire, "uEnd" ), endpoint[0], endpoint[1], 0.18f ); glDrawElements( GL_TRIANGLES, world.wire.em, GL_UNSIGNED_SHORT, (void*)(0) ); } } } } - // I/O ARRAYS + // WIRE ENDPOINTS // ======================================================================================================== SHADER_USE( shader_tile_colour ); glUniformMatrix3fv( SHADER_UNIFORM( shader_tile_colour, "uPv" ), 1, GL_FALSE, (float *)vg_pv ); use_mesh( &world.shapes ); - glEnable(GL_BLEND); + for( int y = 2; y < world.h-2; y ++ ) + { + for( int x = 2; x < world.w-2; x ++ ) + { + struct cell *cell = pcell((v2i){x,y}); + + if( cell->state & FLAG_CANAL ) + { + if( cell->state & FLAG_IS_TRIGGER ) + { + struct cell_description *desc = &cell_descriptions[ cell->config ]; + + int trigger_id = cell->links[0]?0:1; + + int x2 = cell->links[trigger_id] % world.w; + int y2 = (cell->links[trigger_id] - x2) / world.w; + + v2f pts[2]; + + pts[0][0] = (float)x2 + (trigger_id? 0.75f: 0.25f); + pts[0][1] = (float)y2 + 0.25f; + + pts[1][0] = x; + pts[1][1] = y; + + v2_add( desc->trigger_pos, pts[1], pts[1] ); + + glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), + 1, trigger_id? wire_right_colour: wire_left_colour ); + + for( int i = 0; i < 2; i ++ ) + { + glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), + pts[i][0], + pts[i][1], + 0.08f + ); + draw_mesh( filled_start, filled_count ); + } + } + } + } + } + + // SUB SPLITTER DIRECTION + // ======================================================================================================== + + glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.9f, 0.35f, 0.1f, 0.75f ); + + for( int y = 2; y < world.h-2; y ++ ) + { + for( int x = 2; x < world.w-2; x ++ ) + { + struct cell *cell = pcell((v2i){x,y}); + + if( cell->state & FLAG_CANAL && cell->state & FLAG_TARGETED && cell->config == k_cell_type_split ) + { + glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), x, y, 1.0f ); + draw_mesh( cell->state & FLAG_FLIP_FLOP? 5: 4, 1 ); + } + } + } + + // I/O ARRAYS + // ======================================================================================================== + + //glEnable(GL_BLEND); for( int i = 0; i < arrlen( world.io ); i ++ ) { @@ -2767,6 +2829,7 @@ void vg_ui(void) void leaderboard_dispatch_score(void) { +#if STEAM_LEADERBOARDS sw_upload_leaderboard_score( ui_data.upload_request.level->steam_leaderboard, k_ELeaderboardUploadScoreMethodKeepBest, @@ -2778,10 +2841,12 @@ void leaderboard_dispatch_score(void) ui_data.upload_request.is_waiting = 0; vg_success( "Dispatched leaderboard score\n" ); +#endif } void leaderboard_found( LeaderboardFindResult_t *pCallback ) { +#ifdef STEAM_LEADERBOARDS if( !pCallback->m_bLeaderboardFound ) { vg_error( "Leaderboard could not be found\n" ); @@ -2811,10 +2876,12 @@ void leaderboard_found( LeaderboardFindResult_t *pCallback ) } } } +#endif } void leaderboard_downloaded( LeaderboardScoresDownloaded_t *pCallback ) { +#ifdef STEAM_LEADERBOARDS // Update UI if this leaderboard matches what we currently have in view if( ui_data.level_selected->steam_leaderboard == pCallback->m_hSteamLeaderboard ) { @@ -2849,10 +2916,12 @@ void leaderboard_downloaded( LeaderboardScoresDownloaded_t *pCallback ) ui_data.leaderboard_show = 0; } else vg_warn( "Downloaded leaderboard does not match requested!\n" ); +#endif } void leaderboard_set_score( struct cmp_level *cmp_level, u32 score ) { +#ifdef STEAM_LEADERBOARDS if( ui_data.upload_request.is_waiting ) vg_warn( "You are uploading leaderboard entries too quickly!\n" ); @@ -2865,6 +2934,7 @@ void leaderboard_set_score( struct cmp_level *cmp_level, u32 score ) leaderboard_dispatch_score(); else sw_find_leaderboard( cmp_level->map_name ); +#endif } // CONSOLE COMMANDS @@ -2982,11 +3052,16 @@ static int console_changelevel( int argc, char const *argv[] ) // START UP / SHUTDOWN // =========================================================================================================== +#define TRANSFORM_TRI_2D( S, OX, OY, X1, Y1, X2, Y2, X3, Y3 ) \ + X1*S+OX, Y1*S+OY, X2*S+OX, Y2*S+OY, X3*S+OX, Y3*S+OY + void vg_start(void) { // Steamworks callbacks + #ifdef STEAM_LEADERBOARDS sw_leaderboard_found = &leaderboard_found; sw_leaderboard_downloaded = &leaderboard_downloaded; + #endif vg_function_push( (struct vg_cmd){ .name = "_map_write", @@ -3010,15 +3085,18 @@ void vg_start(void) // Combined quad, long quad / empty circle / filled circle mesh { - float combined_mesh[6*8 + 32*6*3] = { + float combined_mesh[6*6 + 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, 0.2f, 1.0f, 0.2f, - 0.0f, 0.0f, 1.0f, 0.2f, 1.0f, 0.0f + 0.0f, 0.0f, 1.0f, 0.2f, 1.0f, 0.0f, + + TRANSFORM_TRI_2D( 0.15f,0.05f,0.4f, 0.0f, 1.0f, 1.0f, 2.0f, 1.0f, 0.0f ), + TRANSFORM_TRI_2D( 0.15f,0.80f,0.4f, 0.0f, 0.0f, 0.0f, 2.0f, 1.0f, 1.0f ) }; - float *circle_mesh = combined_mesh + 6*4; + float *circle_mesh = combined_mesh + 6*6; int const res = 32; for( int i = 0; i < res; i ++ )