From: hgn Date: Sun, 5 Dec 2021 23:35:27 +0000 (+0000) Subject: level selector X-Git-Url: https://harrygodden.com/git/?p=fishladder.git;a=commitdiff_plain;h=a46972aa1ee718339c2512cae986f2943bed0e04 level selector --- diff --git a/fishladder.c b/fishladder.c index 7cda200..76e09a2 100644 --- a/fishladder.c +++ b/fishladder.c @@ -2240,98 +2240,115 @@ void vg_render(void) 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) @@ -2344,51 +2361,66 @@ 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(); } diff --git a/fishladder_resources.h b/fishladder_resources.h index da8b8ea..f3b15ca 100644 --- a/fishladder_resources.h +++ b/fishladder_resources.h @@ -90,12 +90,27 @@ sfx_system audio_system_balls_extra = .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 ); @@ -550,6 +565,11 @@ struct cmp_level 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; }; @@ -560,28 +580,32 @@ struct cmp_level cmp_levels_tutorials[] = .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 } }; @@ -592,63 +616,72 @@ struct cmp_level cmp_levels_basic[] = .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", @@ -661,7 +694,8 @@ struct cmp_level cmp_levels_basic[] = "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", @@ -671,7 +705,8 @@ struct cmp_level cmp_levels_basic[] = "Do your best to utilize principle 5 to get the job\n" "done.", - .serial_id = 16 + .serial_id = 16, + .unlocks = 1 }, { .title = "PRINCIPLE 6", @@ -695,7 +730,8 @@ struct cmp_level cmp_levels_basic[] = "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", @@ -704,7 +740,8 @@ struct cmp_level cmp_levels_basic[] = "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", @@ -713,7 +750,8 @@ struct cmp_level cmp_levels_basic[] = "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", @@ -721,7 +759,8 @@ struct cmp_level cmp_levels_basic[] = .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 } }; @@ -741,7 +780,7 @@ struct cmp_level cmp_levels_grad[] = .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 @@ -764,3 +803,12 @@ struct cmp_level cmp_levels_grad[] = .serial_id = 22 } }; + +struct +{ + int total_unlocked; +} +career_local = +{ + .total_unlocked = 1 +}; diff --git a/vg/vg.h b/vg/vg.h index cdcf431..ba392bb 100644 --- a/vg/vg.h +++ b/vg/vg.h @@ -35,8 +35,8 @@ m3x3f vg_pv; // Engine globals GLFWwindow* vg_window; -int vg_window_x = 1280; -int vg_window_y = 720; +int vg_window_x = 1366; +int vg_window_y = 768; v2f vg_mouse; v3f vg_mouse_ws; @@ -150,6 +150,7 @@ static void vg_init( int argc, char *argv[], const char *window_name ) glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 ); glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE ); glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE ); + glfwWindowHint( GLFW_RESIZABLE, GLFW_FALSE ); glfwWindowHint( GLFW_SAMPLES, 4 ); diff --git a/vg/vg_ui.h b/vg/vg_ui.h index 35a3e3b..fe46da0 100644 --- a/vg/vg_ui.h +++ b/vg/vg_ui.h @@ -55,6 +55,26 @@ typedef i16 ui_px; 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 { @@ -96,6 +116,9 @@ 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 @@ -105,7 +128,7 @@ struct ui_ctx #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 ) @@ -127,6 +150,10 @@ struct ui_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 // =========================================================================================================== @@ -141,7 +168,16 @@ GLuint ui_ebo; #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 @@ -678,7 +714,7 @@ static int ui_button( ui_ctx *ctx, u32 id ) 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 ) { @@ -691,7 +727,7 @@ static int ui_button( ui_ctx *ctx, u32 id ) 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; @@ -796,8 +832,8 @@ static void ui_scrollbar( ui_ctx *ctx, struct ui_scrollbar *scrollbar, u32 id ) 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; @@ -805,14 +841,14 @@ static void ui_scrollbar( ui_ctx *ctx, struct ui_scrollbar *scrollbar, u32 id ) 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 ) @@ -834,3 +870,14 @@ static ui_px ui_calculate_content_scroll( struct ui_scrollbar *scrollbar, ui_px 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; +}