use_mesh( &world.numbers );
draw_numbers( (v3f){ 2.0f, (float)world.h-1.875f, 0.3333f }, world.score );
-
- // Level selection UI
- use_mesh( &world.circle );
- float ratio = ((float)vg_window_x/(float)vg_window_y);
-
- m3x3f ui_view = M3X3_IDENTITY;
- m3x3_scale( ui_view, (v3f){ 1.0f, ratio, 1.0f } );
- glUniformMatrix3fv( SHADER_UNIFORM( shader_tile_colour, "uPv" ), 1, GL_FALSE, (float *)ui_view );
+}
- // Calculate mouse in UIsp
- v3f mouse_ui_space = { ((float)vg_mouse[0] / (float)(vg_window_x)) * 2.0f - 1.0f,
- (((float)vg_mouse[1] / (float)(vg_window_y)) * 2.0f - 1.0f)*(-1.0f/ratio), 0.0125f };
+static ui_colourset flcol_list_a = {
+ .main = 0xff877979,
+ .hover = 0xffa09393,
+ .active = 0xffbfb1b0
+};
+static ui_colourset flcol_list_b = {
+ .main = 0xff7c6e6e,
+ .hover = 0xffa09393,
+ .active = 0xffbfb1b0
+};
- // Get selected level
- const float selection_scale = 0.05f;
- int const level_count = vg_list_size( level_pack_1 );
- int level_select = -1;
-
- if( mouse_ui_space[0] <= -0.8f )
- {
- float levels_range = (float)level_count*selection_scale*0.6f;
- float level_offset = ((-mouse_ui_space[1] + levels_range) / levels_range) * 0.5f * (float)level_count;
- level_select = ceilf( level_offset );
+static ui_colourset flcol_list_complete_a = {
+ .main = 0xff62a064,
+ .hover = 0xff8dc18f,
+ .active = 0xffb2ddb3
+};
- // Draw selector
- if( level_select >= 0 && level_select < vg_list_size( level_pack_1 ) )
- {
- glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.369768f, 0.3654f, 0.42f, 1.0f );
-
- use_mesh( &world.tile );
- glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ),
- -1.0f,
- ((float)level_count - (float)level_select * 2.0f ) * selection_scale * 0.6f,
- selection_scale
- );
- draw_mesh( 2, 2 );
-
- use_mesh( &world.circle );
-
- if( vg_get_button_down( "primary" ) )
- {
- console_changelevel( 1, level_pack_1 + level_select );
- }
- }
- }
- else mouse_ui_space[1] = INFINITY;
+static ui_colourset flcol_list_complete_b = {
+ .main = 0xff79b37b,
+ .hover = 0xff8dc18f,
+ .active = 0xffb2ddb3
+};
+
+static ui_colourset flcol_list_locked = {
+ .main = 0xff655959,
+ .hover = 0xff655959,
+ .active = 0xff655959
+};
- glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.4f, 0.39f, 0.45f, 1.0f );
- // Draw levels
- for( int i = 0; i < level_count; i ++ )
- {
- struct career_level *clevel = &career.levels[i];
- v3f level_ui_space = {
- -0.97f,
- ((float)level_count - (float)i * 2.0f ) * selection_scale * 0.6f + selection_scale * 0.5f,
- selection_scale * 0.5f
- };
-
- float scale = vg_clampf( 1.0f - fabsf(level_ui_space[1] - mouse_ui_space[1]) * 2.0f, 0.9f, 1.0f );
- level_ui_space[2] *= scale;
+static void draw_levels_list( struct cmp_level *levels, int count, int unlocked )
+{
+ static struct ui_scrollbar sb = {
+ .bar_height = 400
+ };
+
+ ui_px view_height = ui_global_ctx.cursor[3];
+ ui_px level_height = 50;
+
+ // Level scroll view
+ gui_new_node();
+ {
+ gui_fill_rect( ui_global_ctx.cursor, 0xff5a4e4d );
+ gui_set_clip( ui_global_ctx.cursor );
- glUniform3fv( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), 1, level_ui_space );
+ ui_global_ctx.cursor[2] = 14;
+ gui_align_right();
- if( clevel->completed )
- draw_mesh( filled_start, filled_count );
+ ui_px content_height = count*level_height;
+ if( content_height > view_height )
+ {
+ ui_scrollbar( &ui_global_ctx, &sb, 1 );
+ ui_global_ctx.cursor[1] -= ui_calculate_content_scroll( &sb, content_height );
+ }
else
- draw_mesh( empty_start, empty_count );
- }
-
- // Level scores
- glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.4f*1.25f, 0.39f*1.25f, 0.45f*1.25f, 1.0f );
-
- use_mesh( &world.numbers );
- for( int i = 0; i < level_count; i ++ )
- {
- struct career_level *clevel = &career.levels[i];
-
- v3f level_ui_space = {
- -0.94f,
- ((float)level_count - (float)i * 2.0f ) * selection_scale * 0.6f + selection_scale * 0.5f,
- 0.02f
- };
+ {
+ gui_fill_rect( ui_global_ctx.cursor, 0xff807373 );
+ }
+
+ ui_global_ctx.cursor[2] = 240;
+ ui_global_ctx.cursor[3] = level_height;
+ gui_align_left();
+
+ for( int i = 0; i < count; i ++ )
+ {
+ struct cmp_level *lvl_info = &levels[i];
- if( clevel->completed )
- draw_numbers( level_ui_space, clevel->score );
+ if( i < unlocked )
+ {
+ if( lvl_info->completed_score != 0 )
+ gui_override_colours( i&0x1? &flcol_list_complete_a: &flcol_list_complete_b );
+ else
+ gui_override_colours( i&0x1? &flcol_list_a: &flcol_list_b );
+ }
+ else
+ gui_override_colours( &flcol_list_locked );
+
+ if( i < unlocked )
+ {
+ if( gui_button( 2 + i ) == k_button_click )
+ {
+ console_changelevel( 1, &lvl_info->map_name );
+ }
+
+ ui_global_ctx.override_colour = 0xffffffff;
+ gui_text( lvl_info->title, 3, 0 );
+ ui_global_ctx.cursor[1] += 18;
+ gui_text( "incomplete", 2, 0 );
+ }
+ else
+ {
+ gui_button( 2 + i );
+
+ ui_global_ctx.override_colour = 0xff786f6f;
+ gui_text( "???", 3, 0 );
+ ui_global_ctx.cursor[1] += 18;
+ gui_text( "locked", 2, 0 );
+ }
- level_ui_space[0] = -0.975f;
- level_ui_space[1] -= 0.01f;
- draw_numbers( level_ui_space, i );
+ gui_end_down();
+ }
+
+ gui_reset_colours();
+ gui_release_clip();
}
+ gui_end_down();
}
void vg_ui(void)
ui_global_ctx.id_base = 4 << 16;
+ static int pack_selection = 0;
+ static struct pack_info
+ {
+ struct cmp_level *levels;
+ u32 level_count;
+ const char *name;
+ }
+ pack_infos[] =
+ {
+ {
+ .levels = cmp_levels_tutorials,
+ .level_count = vg_list_size(cmp_levels_tutorials),
+ .name = "Training"
+ },
+ {
+ .levels = cmp_levels_basic,
+ .level_count = vg_list_size(cmp_levels_basic),
+ .name = "Main"
+ },
+ {
+ .levels = cmp_levels_grad,
+ .level_count = vg_list_size(cmp_levels_tutorials),
+ .name = "Expert"
+ }
+ };
+
gui_new_node();
{
gui_fill_rect( ui_global_ctx.cursor, 0xff5577ff );
- gui_text( "MARBLE COMPUTING", 4, 0 );
+ gui_text( "ASSIGNMENTS", 4, 0 );
- ui_global_ctx.cursor[1] += 45;
- ui_global_ctx.cursor[3] = 709;
+ ui_global_ctx.cursor[1] += 30;
+ ui_global_ctx.cursor[3] = 25;
- // Level scroll view
gui_new_node();
{
- gui_fill_rect( ui_global_ctx.cursor, 0xffff7729 );
- gui_set_clip( ui_global_ctx.cursor );
-
- ui_global_ctx.cursor[2] = 16;
- gui_align_right();
-
- static struct ui_scrollbar sb = {
- .bar_height = 400
- };
- ui_scrollbar( &ui_global_ctx, &sb, 0 );
-
- ui_global_ctx.cursor[2] = 240;
- ui_global_ctx.cursor[3] = 50;
- gui_align_left();
-
- ui_px content_height = vg_list_size(cmp_levels_basic)*ui_global_ctx.cursor[3];
- ui_global_ctx.cursor[1] -= ui_calculate_content_scroll( &sb, content_height );
+ ui_rect_pad( ui_global_ctx.cursor, 2 );
+ ui_global_ctx.cursor[2] = 84;
- for( int i = 0; i < vg_list_size(cmp_levels_basic); i ++ )
+ for( int i = 0; i < 3; i ++ )
{
- struct cmp_level *lvl_info = &cmp_levels_basic[i];
-
- gui_new_node();
- {
- gui_fill_rect( ui_global_ctx.cursor, i&0x1?0xff23fce45:0xff8722f8 );
- gui_text( lvl_info->title, 3, 0 );
- }
- gui_end_down();
- }
-
- gui_release_clip();
+ if( i == pack_selection )
+ gui_override_colours( &flcol_list_locked );
+
+ if( gui_button( 2000 + i ) == k_button_click )
+ pack_selection = i;
+
+ ui_global_ctx.cursor[1] += 2;
+ gui_text( pack_infos[i].name, 2, 0 );
+ gui_end_right();
+
+ gui_reset_colours();
+ }
}
gui_end_down();
+
+ ui_global_ctx.cursor[3] = 500;
+
+ draw_levels_list( pack_infos[ pack_selection ].levels, pack_infos[ pack_selection ].level_count, 3 );
}
gui_end();
}
.name = "Balls Extra"
};
+ui_colourset ui_fl_colours = {
+ .main = 0xff807373,
+ .hover = 0xff918484,
+ .active = 0xffad9f9e
+};
+
+ui_colourset ui_fl_colours_inactive = {
+ .main = 0xff655958,
+ .hover = 0xff655958,
+ .active = 0xff655958
+};
+
static void resource_load_main(void)
{
// Textures
vg_tex2d_init( texture_list, vg_list_size( texture_list ) );
ui_override_font( tex_monofur.name, 7 );
+
+ ui_global_ctx.colours_main = &ui_fl_colours;
+ gui_reset_colours();
// Audio
sfx_set_init( &audio_tile_mod, NULL );
const char *title;
const char *description;
+ int completed_score;
+
+ int unlocks; // When completed, unlock this many levels
+ int linked_unlocks; // When unlocked, unlock this many levels additionally
+
int serial_id;
};
.map_name = "cmp_t01",
.description = "Utilize basic transport methods",
- .serial_id = 0
+ .serial_id = 0,
+ .unlocks = 1
},
{
.title = "PRINCIPLE 2",
.map_name = "cmp_t02",
.description = "Utilize the twisty turny(TM) piece",
- .serial_id = 1
+ .serial_id = 1,
+ .unlocks = 1
},
{
.title = "PRINCIPLE 3",
.map_name = "cmp_t03",
.description = "Merge transport into one",
- .serial_id = 2
+ .serial_id = 2,
+ .unlocks = 1,
},
{
.title = "PRINCIPLE 4",
.map_name = "cmp_t04",
.description = "Some stages require multiple runs to succeed in order to pass",
- .serial_id = 12
+ .serial_id = 12,
+ .unlocks = 3
}
};
.map_name = "cmp_b01",
.description = "Simple maths, branching required.",
- .serial_id = 3
+ .serial_id = 3,
+ .unlocks = 1
},
{
.title = "SUBDIVISION 2",
.map_name = "cmp_b02",
.description = "Simple maths. Futher.",
- .serial_id = 4
+ .serial_id = 4,
+ .unlocks = 1
},
{
.title = "RESTRUCTURE",
.map_name = "cmp_b03",
.description = "Not so simple swap",
- .serial_id = 5
+ .serial_id = 5,
+ .unlocks = 1
},
{
.title = "SERIALIZE",
.map_name = "cmp_b04",
.description = "Merge and sort",
- .serial_id = 6
+ .serial_id = 6,
+ .unlocks = 1
},
{
.title = "PATTERNS 1",
.map_name = "cmp_b05",
.description = "Replicate",
- .serial_id = 7
+ .serial_id = 7,
+ .unlocks = 1
},
{
.title = "PATTERNS 2",
.map_name = "cmp_b06",
.description = "Replicate MORE",
- .serial_id = 8
+ .serial_id = 8,
+ .unlocks = 1
},
{
.title = "MIGHTY CONSUMER",
.map_name = "cmp_b07",
.description = "Build a greedy system",
- .serial_id = 9
+ .serial_id = 9,
+ .unlocks = 1
},
{
.title = "ENCRYPTED 1",
.map_name = "cmp_b08",
.description = "Some configurations may not be valid",
- .serial_id = 10
+ .serial_id = 10,
+ .unlocks = 1
},
{
.title = "REVERSE",
.map_name = "cmp_b09",
.description = "Reverse the incoming order. Always length 4",
- .serial_id = 11
+ .serial_id = 11,
+ .unlocks = 1
},
{
.title = "PRINCIPLE 5",
"as part of your training package, you will now be\n"
"tasked to complete them",
- .serial_id = 15
+ .serial_id = 15,
+ .linked_unlocks = 1
},
{
.title = "ROUTING PROBLEM",
"Do your best to utilize principle 5 to get the job\n"
"done.",
- .serial_id = 16
+ .serial_id = 16,
+ .unlocks = 1
},
{
.title = "PRINCIPLE 6",
"time, this results in no operation being performed,\n"
"and no state changes take place in the Twisty Turny(TM)\n",
- .serial_id = 17
+ .serial_id = 17,
+ .linked_unlocks = 1
},
{
.title = "NOT GATE",
"Test your knowledge of triggers, build an 'NOT GATE'\n"
"emulated by marble logic.",
- .serial_id = 18
+ .serial_id = 18,
+ .unlocks = 1
},
{
.title = "AND GATE",
"A slightly more complicated gate, but shouldn't be\n"
"too difficult for your skillset.",
- .serial_id = 19
+ .serial_id = 19,
+ .unlocks = 1
},
{
.title = "QUALIFICATION PROJECT",
.description =
"There's no instructions here, resolve and complete this\n"
"task to qualify yourself as an official marble engineer",
- .serial_id = 20
+ .serial_id = 20,
+ .unlocks = 3
}
};
.title = "THIRDS",
.map_name = "cmp_i02",
.description =
- "Spit your inputs up into a third of its value\n"
+ "Split the inputs up into a third of their values\n"
"Is this possible? -HG",
.serial_id = 14
.serial_id = 22
}
};
+
+struct
+{
+ int total_unlocked;
+}
+career_local =
+{
+ .total_unlocked = 1
+};
typedef u32 ui_colour;
typedef ui_px ui_rect[4];
typedef struct ui_ctx ui_ctx;
+typedef struct ui_colourset ui_colourset;
+
+struct ui_colourset
+{
+ union
+ {
+ struct
+ {
+ ui_colour main;
+ ui_colour hover;
+ ui_colour active;
+ };
+ struct
+ {
+ ui_colour background;
+ ui_colour bar;
+ ui_colour bar_hover;
+ };
+ };
+};
struct ui_ctx
{
// User input
ui_px mouse[2];
int click_state; // 0: released, 1: on down, 2: pressed, 3: on release
+
+ ui_colourset *colours_main;
+ ui_colourset *colours_current;
};
// Shortnames
#define gui_hasmouse(...) ui_hasmouse( &ui_global_ctx, __VA_ARGS__)
#define gui_end() ui_end( &ui_global_ctx )
#define gui_end_down() ui_end_down( &ui_global_ctx )
-#define gui_end_right() ui_fill_right( &ui_global_ctx )
+#define gui_end_right() ui_end_right( &ui_global_ctx )
#define gui_fill_y() ui_fill_y( &ui_global_ctx)
#define gui_fill_x() ui_fill_x( &ui_global_ctx)
#define gui_align_bottom() ui_align_bottom( &ui_global_ctx )
#define gui_window(...) ui_window( &ui_global_ctx, __VA_ARGS__)
#define gui_want_mouse() ui_want_mouse( &ui_global_ctx )
+#define gui_scrollbar(...) ui_scrollbar( &ui_global_ctx, __VA_ARGS__)
+#define gui_override_colours(...) ui_override_colours( &ui_global_ctx, __VA_ARGS__)
+#define gui_reset_colours(...) ui_reset_colours( &ui_global_ctx )
+
// Globals
// ===========================================================================================================
#define UI_BUFFER_SIZE 30000
#define UI_INDEX_SIZE 20000
-ui_ctx ui_global_ctx = { .padding = 8 };
+ui_colourset ui_default_colours = {
+ .main = 0xff00ff00,
+ .hover = 0xffff00ff,
+ .active = 0xffff0000
+};
+ui_ctx ui_global_ctx = {
+ .padding = 8,
+ .colours_current = &ui_default_colours,
+ .colours_main = &ui_default_colours
+};
// Initialization
if( ui_hasmouse(ctx) )
{
- ui_fill_rect( ctx, ctx->cursor, 0xffcccccc );
+ ui_fill_rect( ctx, ctx->cursor, ctx->colours_current->hover );
if( ctx->click_state == 1 )
{
return k_button_hold;
}
else
- ui_fill_rect( ctx, ctx->cursor, 0xff999999 );
+ ui_fill_rect( ctx, ctx->cursor, ctx->colours_current->main );
}
return k_button_released;
ui_new_node( ctx );
{
- ui_fill_rect( ctx, ctx->cursor, 0xff000000 );
- ui_capture_mouse( ctx, __COUNTER__ );
+ ui_fill_rect( ctx, ctx->cursor, ctx->colours_current->background );
+ ui_capture_mouse( ctx, id );
ctx->cursor[1] += scrollbar->py;
ctx->cursor[3] = scrollbar->bar_height;
ui_new_node( ctx );
{
ui_capture_mouse( ctx, __COUNTER__ );
- struct ui_vert *drag_bar = ui_fill_rect( ctx, ctx->cursor, 0xff555555 );
+ struct ui_vert *drag_bar = ui_fill_rect( ctx, ctx->cursor, ctx->colours_current->bar );
if( ui_hasmouse( ctx ) || scrollbar->drag )
{
- drag_bar[0].colour = 0xff777777;
- drag_bar[1].colour = 0xff777777;
- drag_bar[2].colour = 0xff777777;
- drag_bar[3].colour = 0xff777777;
+ drag_bar[0].colour = ctx->colours_current->bar_hover;
+ drag_bar[1].colour = ctx->colours_current->bar_hover;
+ drag_bar[2].colour = ctx->colours_current->bar_hover;
+ drag_bar[3].colour = ctx->colours_current->bar_hover;
// start drag
if( ctx->click_state == 1 )
float range = scrollbar->view_height - scrollbar->bar_height;
return ((float)scrollbar->py / range) * overlap;
}
+
+static void ui_override_colours( ui_ctx *ctx, ui_colourset *set )
+{
+ ctx->colours_current = set;
+}
+
+static void ui_reset_colours( ui_ctx *ctx )
+{
+ ctx->colours_current = ctx->colours_main;
+ ctx->override_colour = 0xffffffff;
+}