X-Git-Url: https://harrygodden.com/git/?p=fishladder.git;a=blobdiff_plain;f=fishladder.c;fp=fishladder.c;h=e0cfd67458a364ea41326f5c052916e34509662c;hp=74f972643492666caabd88500d62892708a1f882;hb=3cb144985169da3cea1c21a7b0bfba8d43c28fdb;hpb=aa435c13e7184bcd2034b8af1b20db1063baf9ec diff --git a/fishladder.c b/fishladder.c index 74f9726..e0cfd67 100644 --- a/fishladder.c +++ b/fishladder.c @@ -218,6 +218,15 @@ static struct world } *data; #pragma pack(pop) + + struct render_cmd + { + struct cell *ptr; + v2i pos; + } + *cmd_buf_tiles, *cmd_buf_specials; + + u32 tile_count, tile_special_count, max_commands; int initialzed; int sim_run, max_runs; @@ -275,7 +284,7 @@ static struct world v2f physics_v; v2f physics_co; } - fishes[16]; + fishes[64]; int num_fishes; @@ -351,7 +360,8 @@ static int world_check_pos_ok( v2i co, int dist ); static int cell_interactive( v2i co ); void vg_update(void); -static void render_tiles( v2i start, v2i end, v4f const regular_colour, v4f const selected_colour ); +static void render_tiles( v4f const regular_colour, v4f const selected_colour ); +static void render_tile_block( v2i start, v2i end, v4f const regular_colour, v4f const selected_colour ); void vg_render(void); void vg_ui(void); @@ -510,6 +520,8 @@ static void map_free(void) { arrfree( world.data ); arrfree( world.io ); + + free( world.cmd_buf_tiles ); world.w = 0; world.h = 0; @@ -1112,6 +1124,10 @@ static int map_load( const char *str, const char *name ) btn->position[1] = world.h -i -2; } + // Allocate buffers for render commands + world.cmd_buf_tiles = malloc( world.w*world.h* sizeof( struct render_cmd ) ); + world.max_commands = world.w*world.h; + return 1; IL_REG_ERROR: @@ -1797,7 +1813,7 @@ static void vg_update(void) { cell->state &= ~FLAG_FLIP_ROTATING; } - if( cell->state & FLAG_IS_TRIGGER ) + if( cell->state & (FLAG_IS_TRIGGER|FLAG_EMITTER) ) cell->state &= ~FLAG_TRIGGERED; } @@ -1984,9 +2000,12 @@ static void vg_update(void) { struct fish *fish = &world.fishes[i]; + // Apply movement if( fish->state == k_fish_state_alive ) - { v2i_add( fish->pos, fish->dir, fish->pos ); + + if( fish->state == k_fish_state_alive || fish->state == k_fish_state_soon_alive ) + { struct cell *cell_current = pcell( fish->pos ); if( cell_current->state & FLAG_IS_TRIGGER ) @@ -1995,7 +2014,8 @@ static void vg_update(void) struct cell *target_peice = &world.data[ cell_current->links[trigger_id] ]; - if( target_peice->state & FLAG_EMITTER ) + // Spawn new marble + if( (target_peice->state & FLAG_EMITTER) && !(target_peice->state & FLAG_TRIGGERED)) { struct fish *fish = &world.fishes[ world.num_fishes ]; lcell( cell_current->links[trigger_id], fish->pos ); @@ -2317,7 +2337,42 @@ static void vg_update(void) } } -static void render_tiles( v2i start, v2i end, v4f const regular_colour, v4f const selected_colour ) +static void render_tile( v2i pos, struct cell *ptr, v4f const regular_colour, v4f const selected_colour ) +{ + int selected = world.selected == pos[1]*world.w + pos[0]; + + int tile_offsets[][2] = + { + {2, 0}, {0, 3}, {0, 2}, {2, 2}, + {1, 0}, {2, 3}, {3, 2}, {1, 3}, + {3, 1}, {0, 1}, {1, 2}, {2, 1}, + {1, 1}, {3, 3}, {2, 1}, {2, 1} + }; + + int uv[2]; + + uv[0] = tile_offsets[ ptr->config ][0]; + uv[1] = tile_offsets[ ptr->config ][1]; + + glUniform4f( SHADER_UNIFORM( shader_tile_main, "uOffset" ), + (float)pos[0], + (float)pos[1], + uv[0], + uv[1] + ); + + if( selected ) + { + glUniform4fv( SHADER_UNIFORM( shader_tile_main, "uColour" ), 1, selected_colour ); + draw_mesh( 0, 2 ); + glUniform4fv( SHADER_UNIFORM( shader_tile_main, "uColour" ), 1, regular_colour ); + } + else + draw_mesh( 0, 2 ); +} + +// Renders specific chunk of tiles +static void render_tile_block( v2i start, v2i end, v4f const regular_colour, v4f const selected_colour ) { v2i full_start = { 0,0 }; v2i full_end = { world.w, world.h }; @@ -2327,41 +2382,44 @@ static void render_tiles( v2i start, v2i end, v4f const regular_colour, v4f cons start = full_start; end = full_end; } - - glUniform4fv( SHADER_UNIFORM( shader_tile_main, "uColour" ), 1, regular_colour ); for( int y = start[1]; y < end[1]; y ++ ) { for( int x = start[0]; x < end[0]; x ++ ) { - struct cell *cell = pcell((v2i){x,y}); - int selected = world.selected == y*world.w + x; - - int tile_offsets[][2] = - { - {2, 0}, {0, 3}, {0, 2}, {2, 2}, - {1, 0}, {2, 3}, {3, 2}, {1, 3}, - {3, 1}, {0, 1}, {1, 2}, {2, 1}, - {1, 1}, {3, 3}, {2, 1}, {2, 1} - }; - - int uv[2] = { 3, 0 }; - + v2i pos = { x, y }; + struct cell *cell = pcell( pos ); + if( cell->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT|FLAG_EMITTER) ) - { - uv[0] = tile_offsets[ cell->config ][0]; - uv[1] = tile_offsets[ cell->config ][1]; - } else continue; - - glUniform4f( SHADER_UNIFORM( shader_tile_main, "uOffset" ), (float)x, (float)y, uv[0], uv[1] ); - if( selected ) - { - glUniform4fv( SHADER_UNIFORM( shader_tile_main, "uColour" ), 1, selected_colour ); - draw_mesh( 0, 2 ); - glUniform4fv( SHADER_UNIFORM( shader_tile_main, "uColour" ), 1, regular_colour ); - } - else - draw_mesh( 0, 2 ); + render_tile( pos, cell, regular_colour, selected_colour ); + } + } +} + +// Renders all tiles in the command list +static void render_tiles( v4f const regular_colour, v4f const selected_colour ) +{ + glUniform4fv( SHADER_UNIFORM( shader_tile_main, "uColour" ), 1, regular_colour ); + + struct render_list + { + struct render_cmd *arr; + u32 count; + } + render_lists[] = { + { world.cmd_buf_tiles, world.tile_count }, + { world.cmd_buf_specials, world.tile_special_count } + }; + + for( int i = 0; i < vg_list_size( render_lists ); i ++ ) + { + struct render_list *list = &render_lists[i]; + for( int j = 0; j < list->count; j ++ ) + { + struct render_cmd *cmd = &list->arr[j]; + struct cell *cell = cmd->ptr; + + render_tile( cmd->pos, cell, regular_colour, selected_colour ); } } } @@ -2501,6 +2559,34 @@ void vg_render(void) if( !world.initialzed ) return; + + // Extract render commands + world.tile_count = 0; + world.tile_special_count = 0; + + for( int y = 1; y < world.h-1; y ++ ) + { + for( int x = 1; x < world.w-1; x ++ ) + { + struct cell *cell = pcell((v2i){x,y}); + + if( cell->state & (FLAG_CANAL|FLAG_INPUT|FLAG_OUTPUT|FLAG_EMITTER) ) + { + struct render_cmd *cmd; + + if( cell->config == k_cell_type_split || (cell->state & FLAG_EMITTER ) ) + cmd = &world.cmd_buf_tiles[ world.max_commands - (++ world.tile_special_count) ]; + else + cmd = &world.cmd_buf_tiles[ world.tile_count ++ ]; + + cmd->pos[0] = x; + cmd->pos[1] = y; + cmd->ptr = cell; + } + } + } + + world.cmd_buf_specials = &world.cmd_buf_tiles[ world.max_commands - world.tile_special_count ]; // BACKGROUND // ======================================================================================================== @@ -2547,7 +2633,7 @@ void vg_render(void) vg_tex2d_bind( &tex_wood, 1 ); glUniform1i( SHADER_UNIFORM( shader_tile_main, "uTexWood" ), 1 ); - render_tiles( NULL, NULL, colour_default, colour_default ); + render_tiles( colour_default, colour_default ); // MARBLES // ======================================================================================================== @@ -2607,51 +2693,46 @@ void vg_render(void) glUniform1i( SHADER_UNIFORM( shader_tile_main, "uTexWood" ), 1 ); glUniform1f( SHADER_UNIFORM( shader_tile_main, "uForeground" ), 1.0f ); - render_tiles( NULL, NULL, colour_default, colour_selected ); + render_tiles( colour_default, colour_selected ); // Draw splitters - for( int y = 2; y < world.h-2; y ++ ) + for( int i = 0; i < world.tile_special_count; i ++ ) { - for( int x = 2; x < world.w-2; x ++ ) - { - struct cell *cell = pcell((v2i){x,y}); + struct render_cmd *cmd = &world.cmd_buf_specials[i]; + struct cell *cell = cmd->ptr; - if( cell->state & FLAG_CANAL ) + if( cell->config == k_cell_type_split ) + { + float rotation = cell->state & FLAG_FLIP_FLOP? vg_rad( -45.0f ): vg_rad( 45.0f ); + + if( cell->state & FLAG_FLIP_ROTATING ) { - if( cell->config == k_cell_type_split ) + if( (world.frame_lerp > curve_7_linear_section) ) { - float rotation = cell->state & FLAG_FLIP_FLOP? vg_rad( -45.0f ): vg_rad( 45.0f ); - - if( cell->state & FLAG_FLIP_ROTATING ) + float const rotation_speed = 0.4f; + if( (world.frame_lerp < 1.0f-rotation_speed) ) { - if( (world.frame_lerp > curve_7_linear_section) ) - { - float const rotation_speed = 0.4f; - if( (world.frame_lerp < 1.0f-rotation_speed) ) - { - float t = world.frame_lerp - curve_7_linear_section; - t *= -2.0f * (1.0f/(1.0f-(curve_7_linear_section+rotation_speed))); - t += 1.0f; - - rotation *= t; - } - else - rotation *= -1.0f; - } + float t = world.frame_lerp - curve_7_linear_section; + t *= -2.0f * (1.0f/(1.0f-(curve_7_linear_section+rotation_speed))); + t += 1.0f; + + rotation *= t; } - - m2x2_create_rotation( subtransform, rotation ); - - glUniformMatrix2fv( SHADER_UNIFORM( shader_tile_main, "uSubTransform" ), 1, GL_FALSE, (float *)subtransform ); - glUniform4f( SHADER_UNIFORM( shader_tile_main, "uOffset" ), - (float)x, - (float)y + 0.125f, - cell->state & FLAG_TARGETED? 3.0f: 0.0f, - 0.0f - ); - draw_mesh( 0, 2 ); + else + rotation *= -1.0f; } } + + m2x2_create_rotation( subtransform, rotation ); + + glUniformMatrix2fv( SHADER_UNIFORM( shader_tile_main, "uSubTransform" ), 1, GL_FALSE, (float *)subtransform ); + glUniform4f( SHADER_UNIFORM( shader_tile_main, "uOffset" ), + (float)cmd->pos[0], + (float)cmd->pos[1] + 0.125f, + cell->state & FLAG_TARGETED? 3.0f: 0.0f, + 0.0f + ); + draw_mesh( 0, 2 ); } } @@ -2670,7 +2751,7 @@ void vg_render(void) glUniformMatrix2fv( SHADER_UNIFORM( shader_tile_main, "uSubTransform" ), 1, GL_FALSE, (float *)subtransform ); glUniform2fv( SHADER_UNIFORM( shader_tile_main, "uMousePos" ), 1, world.tile_pos ); - render_tiles( new_begin, new_end, colour_default, colour_default ); + render_tile_block( new_begin, new_end, colour_default, colour_default ); world.data[ world.selected ].state ^= FLAG_CANAL; map_reclassify( new_begin, new_end, 0 ); @@ -2798,54 +2879,53 @@ void vg_render(void) 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 ++ ) + for( int i = 0; i < world.tile_special_count; i ++ ) { - for( int x = 2; x < world.w-2; x ++ ) - { - struct cell *cell = pcell((v2i){x,y}); + struct render_cmd *cmd = &world.cmd_buf_specials[i]; + struct cell *cell = cmd->ptr; - if( cell->state & FLAG_CANAL ) + if( cell->state & FLAG_TARGETED ) + { + for( int j = 0; j < 2; j ++ ) { - if( cell->state & FLAG_IS_TRIGGER ) - { - int trigger_id = cell->links[0]?0:1; - struct cell *other_cell = &world.data[ cell->links[ trigger_id ]]; - - struct cell_description *desc = &cell_descriptions[ cell->config ]; - - int x2 = cell->links[trigger_id] % world.w; - int y2 = (cell->links[trigger_id] - x2) / world.w; - - v2f startpoint; - v2f endpoint; - - startpoint[0] = (float)x2 + (trigger_id? 0.75f: 0.25f); - startpoint[1] = (float)y2 + 0.25f; - - endpoint[0] = x; - endpoint[1] = y; - - v2_add( desc->trigger_pos, endpoint, endpoint ); - - if( other_cell->state & FLAG_EMITTER ) - { - v4f wire_colour; - colour_code_v3( other_cell->cc, wire_colour ); - wire_colour[3] = 1.0f; + if( !cell->links[j] ) + continue; - glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, wire_colour ); - } - else - { - glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, trigger_id? wire_right_colour: wire_left_colour ); - } + struct cell *other_cell = &world.data[ cell->links[ j ]]; + struct cell_description *desc = &cell_descriptions[ other_cell->config ]; + + int x2 = cell->links[j] % world.w; + int y2 = (cell->links[j] - x2) / world.w; + + v2f startpoint; + v2f endpoint; + + endpoint[0] = (float)cmd->pos[0] + (j? 0.75f: 0.25f); + endpoint[1] = (float)cmd->pos[1] + 0.25f; + + startpoint[0] = x2; + startpoint[1] = y2; + + v2_add( desc->trigger_pos, startpoint, startpoint ); + + if( cmd->ptr->state & FLAG_EMITTER ) + { + v4f wire_colour; + colour_code_v3( other_cell->cc, wire_colour ); + wire_colour[3] = 1.0f; - glUniform1f( SHADER_UNIFORM( shader_wire, "uCurve" ), cell->state & FLAG_TRIGGERED? rp_x2 * 0.4f: 0.4f ); - 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) ); + glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, wire_colour ); } + else + { + glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, j? wire_right_colour: wire_left_colour ); + } + + glUniform1f( SHADER_UNIFORM( shader_wire, "uCurve" ), other_cell->state & FLAG_TRIGGERED? rp_x2 * 0.4f: 0.4f ); + glUniform1f( SHADER_UNIFORM( shader_wire, "uGlow" ), other_cell->state & FLAG_TRIGGERED? rp_xa: 0.0f ); + glUniform3f( SHADER_UNIFORM( shader_wire, "uEnd" ), startpoint[0], startpoint[1], 0.18f ); + glUniform3f( SHADER_UNIFORM( shader_wire, "uStart" ), endpoint[0], endpoint[1], 0.18f ); + glDrawElements( GL_TRIANGLES, world.wire.em, GL_UNSIGNED_SHORT, (void*)(0) ); } } } @@ -2857,81 +2937,78 @@ void vg_render(void) glUniformMatrix3fv( SHADER_UNIFORM( shader_tile_colour, "uPv" ), 1, GL_FALSE, (float *)vg_pv ); use_mesh( &world.shapes ); - for( int y = 2; y < world.h-2; y ++ ) + for( int i = 0; i < world.tile_special_count; i ++ ) { - for( int x = 2; x < world.w-2; x ++ ) - { - struct cell *cell = pcell((v2i){x,y}); + struct render_cmd *cmd = &world.cmd_buf_specials[i]; + struct cell *cell = cmd->ptr; - if( cell->state & FLAG_CANAL ) + if( cell->state & FLAG_TARGETED ) + { + for( int j = 0; j < 2; j ++ ) { - if( cell->state & FLAG_IS_TRIGGER ) - { - int trigger_id = cell->links[0]?0:1; - struct cell *other_cell = &world.data[ cell->links[ trigger_id ]]; - - struct cell_description *desc = &cell_descriptions[ cell->config ]; + if( !cell->links[j] ) + continue; + + struct cell *other_cell = &world.data[ cell->links[ j ]]; - 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] ); - - if( other_cell->state & FLAG_EMITTER ) - { - v4f wire_colour; - colour_code_v3( other_cell->cc, wire_colour ); + struct cell_description *desc = &cell_descriptions[ other_cell->config ]; + + int x2 = cell->links[j] % world.w; + int y2 = (cell->links[j] - x2) / world.w; + + v2f pts[2]; + + pts[0][0] = (float)cmd->pos[0] + (j? 0.75f: 0.25f); + pts[0][1] = (float)cmd->pos[1] + 0.25f; + + pts[1][0] = x2; + pts[1][1] = y2; + + v2_add( desc->trigger_pos, pts[1], pts[1] ); + + if( other_cell->state & FLAG_EMITTER ) + { + v4f wire_colour; + colour_code_v3( other_cell->cc, wire_colour ); - v3_muls( wire_colour, 0.8f, wire_colour ); - wire_colour[3] = 1.0f; + v3_muls( wire_colour, 0.8f, wire_colour ); + wire_colour[3] = 1.0f; - glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, wire_colour ); - } - else - { - glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, trigger_id? wire_right_colour: wire_left_colour ); - } - //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 ); - } + glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, wire_colour ); + } + else + { + glUniform4fv( SHADER_UNIFORM( shader_wire, "uColour" ), 1, j? 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 // ======================================================================================================== - + // TODO: Make this sprites probably + 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 i = 0; i < world.tile_special_count; i ++ ) { - for( int x = 2; x < world.w-2; x ++ ) - { - struct cell *cell = pcell((v2i){x,y}); + struct render_cmd *cmd = &world.cmd_buf_specials[i]; + struct cell *cell = cmd->ptr; - 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 ); - } + if( cell->state & FLAG_TARGETED && cell->config == k_cell_type_split ) + { + glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), cmd->pos[0], cmd->pos[1], 1.0f ); + draw_mesh( cell->state & FLAG_FLIP_FLOP? 5: 4, 1 ); } }