}
*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;
v2f physics_v;
v2f physics_co;
}
- fishes[16];
+ fishes[64];
int num_fishes;
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);
{
arrfree( world.data );
arrfree( world.io );
+
+ free( world.cmd_buf_tiles );
world.w = 0;
world.h = 0;
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:
{
cell->state &= ~FLAG_FLIP_ROTATING;
}
- if( cell->state & FLAG_IS_TRIGGER )
+ if( cell->state & (FLAG_IS_TRIGGER|FLAG_EMITTER) )
cell->state &= ~FLAG_TRIGGERED;
}
{
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 )
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 );
}
}
-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 };
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 );
}
}
}
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
// ========================================================================================================
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
// ========================================================================================================
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 );
}
}
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 );
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) );
}
}
}
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 );
}
}