From b99d010faa0d8f92fc72fc7168215d1dfc842112 Mon Sep 17 00:00:00 2001 From: hgn Date: Sun, 26 Sep 2021 01:24:02 +0100 Subject: [PATCH] added visual indicators of.. stuff --- fishladder.c | 348 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 276 insertions(+), 72 deletions(-) diff --git a/fishladder.c b/fishladder.c index 6929cff..8d1443b 100644 --- a/fishladder.c +++ b/fishladder.c @@ -39,6 +39,28 @@ m3x3f m_mdl; #define FLAG_SPLIT 0x20 #define FLAG_MERGER 0x40 #define FLAG_DROP_R 0x80 +#define FLAG_FLIP_FLOP 0x100 + +v3f colour_sets[] = +{ { 0.9f, 0.2f, 0.01f }, + { 0.2f, 0.9f, 0.14f }, + { 0.1f, 0.3f, 0.85f } }; + +static void colour_code_v3( char cc, v3f target ) +{ + if( cc >= 'a' && cc <= 'z' ) + { + int id = cc - 'a'; + + if( id < vg_list_size( colour_sets ) ) + { + v3_copy( colour_sets[ id ], target ); + return; + } + } + + v3_copy( (v3f){0.0f,0.0f,0.0f}, target ); +} struct world { @@ -53,9 +75,16 @@ struct world u32 frame; + u32 sim_frame; + float sim_start; + int simulating; + struct cell_terminal { + // TODO: Split into input/output structures char *conditions; + char recv[12]; + int recv_count; int id; } *io; @@ -68,6 +97,17 @@ struct world GLuint circle_vbo; int selected; + + struct fish + { + v2i pos; + v2i dir; + int alive; + char payload; + } + fishes[16]; + + int num_fishes; } world = {}; static void map_free(void) @@ -206,6 +246,11 @@ static int map_load( const char *str ) return 1; } +static struct cell *pcell( v2i pos ) +{ + return &world.data[ pos[1]*world.w + pos[0] ]; +} + int main( int argc, char *argv[] ) { vg_init( argc, argv, "FishLadder" ); @@ -418,23 +463,65 @@ void vg_update(void) m3x3_mul( m_projection, m_view, vg_pv ); vg_projection_update(); + // Input stuff + v2f tile_pos; v2_copy( vg_mouse_ws, tile_pos ); int tile_x = floorf( tile_pos[0] ); int tile_y = floorf( tile_pos[1] ); - if( cell_interactive( (v2i){ tile_x, tile_y } )) + // Tilemap editing + if( !world.simulating ) { - world.selected = tile_y * world.w + tile_x; - - if( vg_get_button_down("primary") ) + if( cell_interactive( (v2i){ tile_x, tile_y } )) + { + world.selected = tile_y * world.w + tile_x; + + if( vg_get_button_down("primary") ) + { + world.data[ world.selected ].state ^= FLAG_CANAL; + } + } + else + world.selected = -1; + } + + // Simulation stop/start + if( vg_get_button_down("go") ) + { + if( world.simulating ) { - world.data[ world.selected ].state ^= FLAG_CANAL; + world.simulating = 0; + world.num_fishes = 0; + world.sim_frame = 0; + + for( int i = 0; i < arrlen( world.io ); i ++ ) + world.io[i].recv_count = 0; + + vg_info( "Stopping simulation!\n" ); + } + else + { + vg_success( "Starting simulation!\n" ); + + world.simulating = 1; + world.num_fishes = 0; + world.sim_frame = 0; + world.sim_start = vg_time; + + for( int i = 0; i < world.w*world.h; i ++ ) + { + world.data[ i ].state &= ~FLAG_FLIP_FLOP; + } + + for( int i = 0; i < arrlen( world.io ); i ++ ) + world.io[i].recv_count = 0; } } - else - world.selected = -1; + + // Simulation stuff + // ======================================================== // Reclassify world. TODO: Move into own function for( int y = 2; y < world.h-2; y ++ ) @@ -481,68 +568,6 @@ void vg_update(void) } } - /* - canals - x - xxxxx - x x - x xxx - x x x - x xxx - x x - xxxxx - x - x - - configs (Downlevels marked) - x - xDxDx - x x - x DxD - x x x - x xDx - x x - xxxDx - x - x - - Path tracing with min function - 0 - 11011 - 1 . - 1 D.D - 1 . . - 1 .D. - 1 . - 1112. - 2 - 2 - - Path tracing with min function - 0 - 11011 - 1 1 - 1 212 - 1 2 2 - 1 232 - 1 3 - 11143 - 4 - 4 - - L to R fill - 0000000 - 1101111 - 1111111 - 1112122 - 1112222 - 1112322 - 1111333 - 1114333 - 4444444 - 4444444 - */ - // Simulate world static int update_tick = 0; update_tick ++; @@ -608,7 +633,130 @@ void vg_update(void) } } - world.frame ++; + world.frame ^= 0x1; + } + + // Fish ticks + if( world.simulating ) + { + while( world.sim_frame < (int)((vg_time-world.sim_start)*2.0f) ) + { + vg_info( "frame: %u\n", world.sim_frame ); + + for( int i = 0; i < arrlen( world.io ); i ++ ) + { + struct cell_terminal *term = &world.io[ i ]; + int posx = term->id % world.w; + int posy = (term->id - posx)/world.w; + int is_input = world.data[ term->id ].state & FLAG_INPUT; + + if( is_input ) + { + if( world.sim_frame < arrlen( term->conditions ) ) + { + struct fish *fish = &world.fishes[world.num_fishes++]; + fish->pos[0] = posx; + fish->pos[1] = posy; + fish->alive = 1; + fish->payload = term->conditions[world.sim_frame]; + + int can_spawn = 0; + + v2i dirs[] = {{1,0},{-1,0},{0,-1}}; + for( int j = 0; j < vg_list_size(dirs); j ++ ) + { + v2i target; + if( world.data[ (posy+dirs[j][1])*world.w + posx+dirs[j][0] ].water[ world.frame & 0x1 ] ) + { + fish->dir[0] = dirs[j][0]; + fish->dir[1] = dirs[j][1]; + can_spawn = 1; + break; + } + } + + if( !can_spawn ) + world.num_fishes--; + } + } + } + + for( int i = 0; i < world.num_fishes; i ++ ) + { + struct fish *fish = &world.fishes[i]; + struct cell *cell_current = pcell( fish->pos ); + + if( !fish->alive ) + continue; + + // Apply to output + if( cell_current->state & FLAG_OUTPUT ) + { + for( int j = 0; j < arrlen( world.io ); j ++ ) + { + struct cell_terminal *term = &world.io[j]; + + if( term->id == fish->pos[1]*world.w + fish->pos[0] ) + { + term->recv[ term->recv_count ++ ] = fish->payload; + break; + } + } + + fish->alive = 0; + continue; + } + + if( !(cell_current->water[ world.frame & 0x1 ] || cell_current->state & (FLAG_INPUT)) ) + { + fish->alive = 0; + } + else + { + if( cell_current->state & FLAG_SPLIT ) + { + // Flip flop L/R + fish->dir[0] = cell_current->state&FLAG_FLIP_FLOP?1:-1; + fish->dir[1] = 0; + + cell_current->state ^= FLAG_FLIP_FLOP; + } + else if( cell_current->state & FLAG_MERGER ) + { + // Can only move up + fish->dir[0] = 0; + fish->dir[1] = -1; + } + else + { + struct cell *cell_next = pcell( (v2i){ fish->pos[0]+fish->dir[0], fish->pos[1]+fish->dir[1] } ); + if( !cell_next->water[ world.frame & 0x1 ] ) + { + // Try other directions for valid + v2i dirs[] = {{1,0},{-1,0},{0,-1}}; + vg_info( "Trying some other directions...\n" ); + + for( int j = 0; j < vg_list_size(dirs); j ++ ) + { + if( (dirs[j][0] == -fish->dir[0]) && (dirs[j][1] == -fish->dir[1]) ) + continue; + + if( pcell( (v2i){ fish->pos[0]+dirs[j][0], fish->pos[1]+dirs[j][1] } )->water[ world.frame & 0x1 ] ) + { + fish->dir[0] = dirs[j][0]; + fish->dir[1] = dirs[j][1]; + } + } + } + } + + fish->pos[0] += fish->dir[0]; + fish->pos[1] += fish->dir[1]; + } + } + + world.sim_frame ++; + } } } @@ -673,11 +821,67 @@ void vg_render(void) int posy = (term->id - posx)/world.w; int is_input = world.data[ term->id ].state & FLAG_INPUT; + int const filled_start = 0; + int const filled_count = 32*3; + int const empty_start = 32*3; + int const empty_count = 32*6; + + v4f dot_colour = { 0.0f, 0.0f, 0.0f, 1.0f }; + for( int j = 0; j < arrlen( term->conditions ); j ++ ) { glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, (float)posy + 0.2f, 0.1f ); - glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.2f, 0.8f, 0.6f, 1.0f ); - glDrawArrays( GL_TRIANGLES, is_input? 0: 32*3, is_input? 32*3: 32*6 ); + + if( is_input ) + { + colour_code_v3( term->conditions[j], dot_colour ); + glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, dot_colour ); + + // Draw filled if tick not passed, draw empty if empty + if( world.sim_frame > j ) + glDrawArrays( GL_TRIANGLES, empty_start, empty_count ); + else + glDrawArrays( GL_TRIANGLES, filled_start, filled_count ); + } + else + { + if( term->recv_count > j ) + { + colour_code_v3( term->recv[j], dot_colour ); + v3_muls( dot_colour, 0.8f, dot_colour ); + glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, dot_colour ); + + glDrawArrays( GL_TRIANGLES, filled_start, filled_count ); + } + + colour_code_v3( term->conditions[j], dot_colour ); + glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, dot_colour ); + + glDrawArrays( GL_TRIANGLES, empty_start, empty_count ); + } + } + } + + // Draw 'fish' + if( world.simulating ) + { + float scaled_time = (vg_time-world.sim_start)*2.0f; + float lerp = 1.0f-(scaled_time - (float)world.sim_frame); + + v4f dot_colour = { 0.0f, 0.0f, 0.0f, 1.0f }; + + for( int i = 0; i < world.num_fishes; i ++ ) + { + struct fish *fish = &world.fishes[i]; + + if( !fish->alive ) + continue; + + colour_code_v3( fish->payload, dot_colour ); + glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, dot_colour ); + + glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)fish->pos[0] + 0.5f - (float)fish->dir[0]*lerp, (float)fish->pos[1] + 0.5f - (float)fish->dir[1]*lerp, 0.25f ); + glDrawArrays( GL_TRIANGLES, 0, 32*3 ); } } } -- 2.25.1