switched to command based rendering
[fishladder.git] / fishladder.c
index 74f972643492666caabd88500d62892708a1f882..e0cfd67458a364ea41326f5c052916e34509662c 100644 (file)
@@ -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 );
                }
        }