UI text element renderer (SDF) DONE(sorta)
Particle system thing for ball collision
Level descriptions / titles HALF
- Row Gridlines for I/O
- Play button / Speed controller
+ Row Gridlines for I/O DONE
+ Play button / Speed controller ( play buttern, pause, speed control, step button )
After release:
v3f colour_sets[] =
{ { 1.0f, 0.9f, 0.3f },
{ 0.2f, 0.9f, 0.14f },
- { 0.4f, 0.8f, 1.00f } };
+ { 0.4f, 0.8f, 1.00f },
+ { 0.882f, 0.204f, 0.922f }
+};
static void colour_code_v3( char cc, v3f target )
{
k_fish_state_soon_alive
};
+enum e_world_button
+{
+ k_world_button_none = -1,
+ k_world_button_sim = 0,
+ k_world_button_ff = 1,
+ k_world_button_wire_mode = 2
+};
+
struct world
{
#pragma pack(push,1)
int sim_frame;
float sim_start;
- int simulating;
int sim_run, max_runs;
float sim_speed;
}
*io;
+ struct cell_button
+ {
+ float light_target, light;
+ int pressed;
+ }
+ buttons[4];
+
int w, h;
- struct mesh tile, circle, numbers;
+ struct mesh shapes, numbers;
struct mesh_wire
{
GLuint vao, vbo, ebo;
u32 time;
} world;
+static struct cell_button *get_wbutton( enum e_world_button btn )
+{
+ return &world.buttons[ btn ];
+}
+
void leaderboard_set_score( struct cmp_level *cmp_level, u32 score );
static void map_free(void)
return random_noise[ (random_noise[p[1] & 1023] + p[0]) & 1023 ] & umod;
}
+static struct cell *pcell( v2i pos )
+{
+ return &world.data[ pos[1]*world.w + pos[0] ];
+}
+
static void map_reclassify( v2i start, v2i end, int update_texbuffer );
static int map_load( const char *str, const char *name )
{
char link_id_buffer[32];
int link_id_n = 0;
-
+
for(;;)
{
if( !*c )
turtle[1] = 16+posy;
turtle_dir[0] = 0;
- turtle_dir[1] = posy <= 4? -1: 1;
+ turtle_dir[1] = pcell((v2i){ posx,posy })->state & FLAG_INPUT? 1: -1;
original_y = turtle_dir[1];
for( int i = 0; i < 100; i ++ )
return 0;
}
-static struct cell *pcell( v2i pos )
-{
- return &world.data[ pos[1]*world.w + pos[0] ];
-}
-
static void map_serialize( FILE *stream )
{
for( int y = 0; y < world.h; y ++ )
static void simulation_stop(void)
{
- world.simulating = 0;
+ get_wbutton( k_world_button_sim )->pressed = 0;
+ get_wbutton( k_world_button_ff )->pressed = 0;
+
world.num_fishes = 0;
world.sim_frame = 0;
world.sim_run = 0;
vg_info( "Stopping simulation!\n" );
}
+static void wbutton_run( enum e_world_button btn_name )
+{
+ struct cell_button *btn = &world.buttons[btn_name];
+
+ // Interaction
+
+ int is_hovering = (world.tile_x == world.w-1 && world.tile_y == world.h-btn_name-2)?1:0;
+ if( vg_get_button_up( "primary" ) && is_hovering )
+ {
+ // Click event
+ btn->pressed ^= 0x1;
+
+ if( btn_name == k_world_button_sim )
+ {
+ if( btn->pressed )
+ {
+ 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_start = vg_time;
+ world.sim_run = 0;
+ world.sim_speed = 2.5f;
+
+ for( int i = 0; i < world.w*world.h; i ++ )
+ world.data[ i ].state &= ~FLAG_FLIP_FLOP;
+
+ io_reset();
+ }
+ else
+ {
+ simulation_stop();
+ }
+ }
+ }
+
+ // Drawing
+ if( btn->pressed ) btn->light_target = is_hovering? 0.9f: 0.8f;
+ else btn->light_target = is_hovering? 0.2f: 0.0f;
+
+ if( vg_get_button( "primary" ) && is_hovering )
+ btn->light_target = 1.0f;
+
+ btn->light = vg_lerpf( btn->light, btn->light_target, vg_time_delta*26.0f );
+
+ glUniform4f( SHADER_UNIFORM( shader_buttons, "uOffset" ),
+ world.w-1,
+ world.h-btn_name-2,
+ (float)btn_name,
+ 3.0f
+ );
+ glUniform4f( SHADER_UNIFORM( shader_buttons, "uColour" ), 0.204f, 0.345f, 0.553f, btn->light );
+
+ draw_mesh( 0, 2 );
+}
+
static int console_changelevel( int argc, char const *argv[] )
{
if( argc >= 1 )
.function = console_credits
});
- // Quad mesh
+ // Combined quad, long quad / empty circle / filled circle mesh
{
- float quad_mesh[] =
- {
+ float combined_mesh[6*8 + 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, 1.0f, 4.0f, 1.0f,
- 0.0f, 0.0f, 4.0f, 1.0f, 4.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
};
- init_mesh( &world.tile, quad_mesh, vg_list_size(quad_mesh) );
- }
-
- // Circle mesh
- {
- float circle_mesh[32*6*3];
- int res = vg_list_size( circle_mesh ) / (6*3);
+ float *circle_mesh = combined_mesh + 6*4;
+ int const res = 32;
for( int i = 0; i < res; i ++ )
{
v2_copy( v1, circle_mesh+i*6+2 );
}
- init_mesh( &world.circle, circle_mesh, vg_list_size( circle_mesh ) );
+ init_mesh( &world.shapes, combined_mesh, vg_list_size( combined_mesh ) );
}
// Numbers mesh
glDeleteBuffers( 1, &world.wire.vbo );
glDeleteBuffers( 1, &world.wire.ebo );
- free_mesh( &world.tile );
- free_mesh( &world.circle );
+ free_mesh( &world.shapes );
free_mesh( &world.numbers );
map_free();
world.tile_y = floorf( world.tile_pos[1] );
// Tilemap editing
- if( !world.simulating && !gui_want_mouse() )
+ if( !get_wbutton( k_world_button_sim )->pressed && !gui_want_mouse() )
{
v2_copy( vg_mouse_ws, drag_to_co );
}
}
else
+ {
world.selected = -1;
+ }
if( !(vg_get_button("secondary") && id_drag_from) )
id_drag_from = 0;
id_drag_from = 0;
}
- // Simulation stop/start
- if( vg_get_button_down("go") )
- {
- if( world.simulating )
- {
- simulation_stop();
- }
- else
- {
- vg_success( "Starting simulation!\n" );
-
- sfx_set_playrnd( &audio_rolls, &audio_system_balls_rolling, 0, 1 );
-
- world.simulating = 1;
- world.num_fishes = 0;
- world.sim_frame = 0;
- world.sim_start = vg_time;
- world.sim_run = 0;
- world.sim_speed = 2.5f;
-
- for( int i = 0; i < world.w*world.h; i ++ )
- world.data[ i ].state &= ~FLAG_FLIP_FLOP;
-
- io_reset();
- }
- }
-
// Fish ticks
- if( world.simulating )
+ if( get_wbutton( k_world_button_sim )->pressed )
{
while( world.sim_frame < (int)((vg_time-world.sim_start)*world.sim_speed) )
{
vg_error( "Level failed :(\n" );
}
-
- simulation_stop(); // TODO: Async?
+ simulation_stop();
break;
}
// NOTE: this is for final optimisations ONLY!
// ======================================================================
- use_mesh( &world.tile );
+ use_mesh( &world.shapes );
// Draw background
// Main
// =========================================================================================
- use_mesh( &world.tile );
+ use_mesh( &world.shapes );
SHADER_USE( shader_tile_main );
m2x2f subtransform;
glUniform1i( SHADER_UNIFORM( shader_ball, "uTexMain" ), 0 );
// Draw 'fish'
- if( world.simulating )
+ if( get_wbutton( k_world_button_sim )->pressed )
{
for( int i = 0; i < world.num_fishes; i ++ )
{
//glDisable(GL_BLEND);
+ SHADER_USE( shader_buttons );
+ glUniformMatrix3fv( SHADER_UNIFORM( shader_buttons, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
+
+ vg_tex2d_bind( &tex_buttons, 0 );
+ glUniform1i( SHADER_UNIFORM( shader_buttons, "uTexMain" ), 0 );
+
+ wbutton_run( k_world_button_sim );
+ wbutton_run( k_world_button_ff );
+
+
// Draw connecting wires
glDisable(GL_BLEND);
SHADER_USE( shader_tile_colour );
glUniformMatrix3fv( SHADER_UNIFORM( shader_tile_colour, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
- use_mesh( &world.circle );
+ use_mesh( &world.shapes );
- int const filled_start = 0;
- int const filled_count = 32;
- int const empty_start = 32;
- int const empty_count = 32*2;
+ int const circle_base = 4;
+ 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;
+
+ glEnable(GL_BLEND);
// Draw i/o arrays
for( int i = 0; i < arrlen( world.io ); i ++ )
for( int k = 0; k < term->run_count; k ++ )
{
+ float y_offset = is_input? 1.2f: -0.2f;
+ float y_h = (is_input? 0.2f: -0.2f) * (float)k;
+ float y_row = is_input?
+ (y_offset + (float)posy + (float)(term->run_count-1)*0.2f) - y_h:
+ (float)posy + y_offset + y_h;
+
+ if( k & 0x1 )
+ {
+ glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1.0f, 1.0f, 1.0f, 0.1f );
+ glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx, y_row - 0.1f, 1.0f );
+ draw_mesh( 2, 2 );
+ }
+
for( int j = 0; j < term->runs[k].condition_count; j ++ )
{
- float y_offset = is_input? 1.2f: -0.2f;
- float y_h = (is_input? 0.2f: -0.2f) * (float)k;
-
if( is_input )
{
- glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j,
- (y_offset + (float)posy + (float)(term->run_count-1)*0.2f) - y_h, 0.1f );
+ glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, y_row, 0.1f );
colour_code_v3( term->runs[k].conditions[j], dot_colour );
glUniform4fv( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 1, dot_colour );
}
else
{
- glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, (float)posy + y_offset + y_h, 0.1f );
+ glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), (float)posx + 0.2f + 0.2f * (float)j, y_row, 0.1f );
if( term->runs[k].recv_count > j )
{
}
}
- if( world.simulating )
- {
- glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.0f, 0.0f, 0.0f, 1.0f );
- glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), -0.5f + cosf( vg_time * 4.0f ) * 0.2f, sinf( vg_time * 4.0f ) * 0.2f + (float)world.h * 0.5f, 0.05f );
- draw_mesh( filled_start, filled_count );
- }
+ glDisable(GL_BLEND);
// Draw score
float const score_bright = 1.25f;
ui_global_ctx.override_colour = 0xffffffff;
gui_text( lvl_info->title, 6, 0 );
ui_global_ctx.cursor[1] += 18;
- gui_text( "incomplete", 4, 0 );
+ gui_text( lvl_info->completed_score>0? "passed": "incomplete", 4, 0 );
}
else
{