From 2c83caa3f6a9c5e0b0df6fc39b93689cce72db87 Mon Sep 17 00:00:00 2001 From: hgn Date: Thu, 4 Jan 2024 13:13:38 +0000 Subject: [PATCH] fully ported to vg2 --- fishladder_resources_vg1.h | 14 +- fishladder_vg1.c | 487 ++++++++----------------------------- marblecomp.c | 23 +- marblecomp_settings.h | 160 ++++++++++++ steam.h | 282 +++++++++++++++++++++ 5 files changed, 560 insertions(+), 406 deletions(-) create mode 100644 marblecomp_settings.h create mode 100644 steam.h diff --git a/fishladder_resources_vg1.h b/fishladder_resources_vg1.h index 7d0ea2f..df93a50 100644 --- a/fishladder_resources_vg1.h +++ b/fishladder_resources_vg1.h @@ -128,15 +128,6 @@ audio_clip audio_music[] = { { .path="sound/mccompt2.ogg" }, }; -#if 0 -static void *load_and_play_bgm( void *_inf ) -{ - sfx_set_init( &audio_music, NULL ); - sfx_set_play( &audio_music, &audio_system_music, 0 ); - return NULL; -} -#endif - #define INIT_AUDIO( X ) audio_clip_loadn( X, vg_list_size(X), NULL ); static void _mc_resource_load_main(void){ @@ -154,10 +145,7 @@ static void _mc_resource_load_main(void){ INIT_AUDIO( audio_random ); INIT_AUDIO( audio_clicks ); INIT_AUDIO( audio_tones ); - -#if 0 - vg_thread_run( load_and_play_bgm, NULL ); -#endif + INIT_AUDIO( audio_music ); } /* diff --git a/fishladder_vg1.c b/fishladder_vg1.c index 6eb5534..d58d229 100644 --- a/fishladder_vg1.c +++ b/fishladder_vg1.c @@ -373,19 +373,6 @@ m3x3f m_projection; m3x3f m_view; m3x3f m_mdl; -static int colour_set_id = 0; -static int world_theme_id = 0; -static int enable_bloom = 1; -static int enable_vignette = 1; -static float music_volume = 1.0f; - -static void music_volume_update(void) -{ -#if 0 - sfx_vol_fset( &audio_volume_music, music_volume ); -#endif -} - static v3f colour_sets[][4] = { { { 1.0f, 0.9f, 0.3f }, @@ -431,11 +418,9 @@ world_themes[] = } }; -static void colour_code_v3( i8 cc, v3f target ) -{ - if( (cc >= 0) && (cc < vg_list_size( colour_sets[0] )) ) - { - v3_copy( colour_sets[colour_set_id][ cc ], target ); +static void colour_code_v3( i8 cc, v3f target ){ + if( (cc >= 0) && (cc < vg_list_size( colour_sets[0] )) ){ + v3_copy( colour_sets[marblecomp.colour_set][ cc ], target ); return; } @@ -1413,7 +1398,6 @@ static void career_pass_level( struct cmp_level *lvl, int score, int upload ) if( lvl->unlock ) career_unlock_level( lvl->unlock ); - #ifdef VG_STEAM if( lvl->achievement ) sw_set_achievement( lvl->achievement ); @@ -1430,7 +1414,6 @@ static void career_pass_level( struct cmp_level *lvl, int score, int upload ) } sw_set_achievement( "MASTER_ENGINEER" ); - #endif } } @@ -2133,9 +2116,7 @@ static void _mc_vg1_update(void) if( cell_entry->config == k_cell_type_con_r || cell_entry->config == k_cell_type_con_u || cell_entry->config == k_cell_type_con_l || cell_entry->config == k_cell_type_con_d ) { - #ifdef VG_STEAM sw_set_achievement( "CAN_DO_THAT" ); - #endif fish->state = k_fish_state_soon_alive; @@ -2254,9 +2235,7 @@ static void _mc_vg1_update(void) if( collide_next_frame || collide_this_frame ) { - #ifdef VG_STEAM sw_set_achievement( "BANG" ); - #endif // Shatter death (+0.5s) float death_time = world.sim_internal_time + ( collide_this_frame? 0.0f: 0.5f ); @@ -2401,10 +2380,8 @@ static void _mc_vg1_update(void) } else { - #ifdef VG_STEAM if( world.sim_run > 0 ) sw_set_achievement( "GOOD_ENOUGH" ); - #endif vg_error( "Level failed :(\n" ); } @@ -2778,7 +2755,7 @@ static void _mc_vg1_framebuffer_resize(int w, int h){ } static void _mc_vg1_render(void){ - if( enable_bloom || enable_vignette ) + if( marblecomp.bloom || marblecomp.vignette ) glBindFramebuffer( GL_FRAMEBUFFER, world.st.framebuffer ); else glBindFramebuffer( GL_FRAMEBUFFER, 0 ); @@ -2798,11 +2775,7 @@ static void _mc_vg1_render(void){ int const empty_start = circle_base+32; int const empty_count = circle_base+32*2; -#if 0 - struct world_theme *theme = &world_themes[ world_theme_id ]; -#else - struct world_theme *theme = &world_themes[ 0 ]; -#endif + struct world_theme *theme = &world_themes[ marblecomp.world_theme ]; if( !world.initialzed ) return; @@ -3091,10 +3064,11 @@ static void _mc_vg1_render(void){ } } - if( world_button_exec( &world.st.buttons[k_world_button_settings], (v2f){ 1.0f, 2.0f }, btn_orange, &stat )) + if( world_button_exec( &world.st.buttons[k_world_button_settings], + (v2f){ 1.0f, 2.0f }, btn_orange, &stat )) { - world.st.state = stat == k_world_button_on_enable? - k_game_state_settings: k_game_state_main; + world.st.buttons[k_world_button_settings].state = 0; + vg_settings_open(); } level_selection_buttons(); @@ -3499,9 +3473,8 @@ static void _mc_vg1_render(void){ draw_numbers( (v3f){ 2.0f, (float)world.h-1.875f, 0.3333f }, world.score ); */ - if( !enable_bloom ) - { - if( enable_vignette ) + if( !marblecomp.bloom ){ + if( marblecomp.vignette ) goto image_composite; return; @@ -3564,307 +3537,95 @@ image_composite: shader_post_comp_uTexBloom(1); shader_post_comp_uComp( (v2f){ - enable_bloom? 1.0f: 0.0f, - enable_vignette? 0.0f: 1.0f + marblecomp.bloom? 1.0f: 0.0f, + marblecomp.vignette? 0.0f: 1.0f }); draw_mesh( 0, 2 ); } void _mc_vg1_ui(void) { - // Drawing world name -#if 0 - if( world.pCmpLevel ) - { - gui_text( (ui_px [2]){ vg.window_x / 2, 4 }, world.pCmpLevel->title, 2, k_text_align_center ); - gui_text( (ui_px [2]){ vg.window_x / 2, 28 }, world.pCmpLevel->description, 1, k_text_align_center ); - } -#endif + ui_px const unit_scale_px = 4*vg_ui.font->spacing; + #if 0 - if( world.st.state == k_game_state_update ) - { - gui_group_id( 34 ); + if( world.pCmpLevel ){ + for( int i = 0; i < vg_list_size( world.pCmpLevel->strings ); i ++ ){ + struct world_string *wstr = &world.pCmpLevel->strings[i]; - ui_global_ctx.cursor[2] = 458; - ui_global_ctx.cursor[3] = 316; - ui_global_ctx.cursor[0] = vg.window_x / 2 - 229; - ui_global_ctx.cursor[1] = vg.window_y / 2 - 158; + if( wstr->str ){ + ui_px pos[2]; + pos[0] = -vg_ui.font->spacing/2; - gui_new_node(); - { - gui_capture_mouse( 200 ); - gui_fill_rect( ui_global_ctx.cursor, 0xE8303030 ); - - ui_px title_pos[2]; - title_pos[0] = ui_global_ctx.cursor[0] + 229; - title_pos[1] = ui_global_ctx.cursor[1] + 16; - - gui_text( title_pos, "Update 1.5", 2, k_text_align_center ); - - gui_text( (ui_px [2]){ ui_global_ctx.cursor[0] + 16, title_pos[1] + 45 }, - "Welcome to the first update to marble computing!" - "\n" - "New features have been added:\n" - "\n" - " - Settings menu\n" - " - Map skins\n" - " - More levels and a new block type\n" - " - Scores for each level\n" - " - Zooming and panning (mousewheel)\n" - "\n" - "There is much more in the works, such as a\n" - "soundtrack, and the rest of the levels for the\n" - "3 bit computer!\n" - "\n" - "Thank you everyone for enjoying my game :)\n", - 1, k_text_align_left - ); - - ui_global_ctx.cursor[2] = 100; - ui_global_ctx.cursor[3] = 30; - ui_global_ctx.cursor[0] += 229 - 50; - ui_global_ctx.cursor[1] += 316 - 30 - 16; - - if( gui_button( 1 ) ) - { - world.st.state = k_game_state_main; + if( wstr->placement == k_placement_bottom ) + pos[1] = 2*-unit_scale_px; + else + pos[1] = (world.h-1)*-unit_scale_px -6; + + ui_text( &world.st.world_text, pos, wstr->str, + 1, k_text_align_left ); } - gui_text( (ui_px [2]){ ui_global_ctx.cursor[0] + 50, - ui_global_ctx.cursor[1] + 4 }, "OK", 1, k_text_align_center ); - gui_end(); } - gui_end(); } - else #endif -#if 0 - if( world.st.state == k_game_state_settings ) - { - gui_group_id( 35 ); + u32 sum = 0; - ui_global_ctx.cursor[2] = 225; - gui_fill_y(); - gui_align_right(); - - gui_new_node(); - { - gui_capture_mouse( 200 ); - - gui_fill_rect( ui_global_ctx.cursor, 0xC0202020 ); - ui_rect_pad( ui_global_ctx.cursor, 8 ); - - ui_global_ctx.cursor[3] = 25; - - gui_new_node(); - { - gui_text( ui_global_ctx.cursor, "SETTINGS", 2, 0 ); - - ui_global_ctx.cursor[2] = 25; - gui_align_right(); - - if( gui_button(4) == k_button_click ) - { - world.st.buttons[ k_world_button_settings ].state = 0; - world.st.state = k_game_state_main; - vg_info( "exit\n" ); - } - ui_global_ctx.cursor[0] += 4; - ui_global_ctx.cursor[1] -= 4; - gui_text( ui_global_ctx.cursor, "x", 2, 0 ); - gui_end(); - } - gui_end(); - - // Colour scheme selection - ui_global_ctx.cursor[1] += 30; - - gui_text( ui_global_ctx.cursor, "Colour Scheme", 1, 0 ); - ui_global_ctx.cursor[1] += 25; - - gui_new_node(); - { - ui_global_ctx.cursor[2] = 50; - - for( int i = 0; i < 4; i ++ ) - { - gui_new_node(); - { - // Convert to RGB - u32 rgb = 0xff000000; - - for( int j = 0; j < 3; j ++ ) - rgb |= (u32)(colour_sets[ colour_set_id ][i][j]*255.0f) << j * 8; - - gui_fill_rect( ui_global_ctx.cursor, rgb ); - } - gui_end_right(); - } - } - gui_end_down(); - - gui_new_node(); - { - ui_global_ctx.cursor[2] = 25; - if( gui_button( 0 ) == k_button_click ) - { - if( colour_set_id > 0 ) - colour_set_id --; - } - gui_text( ui_global_ctx.cursor, "<", 2, 0 ); - gui_end_right(); - - ui_global_ctx.cursor[2] = 150; - gui_new_node(); - { - gui_fill_rect( ui_global_ctx.cursor, 0x33ffffff ); - gui_text( - (ui_px [2]){ ui_global_ctx.cursor[0] + 75, ui_global_ctx.cursor[1] + 6 }, - (const char *[]){ "Normal", "Extra1", "Extra2" }[ colour_set_id ], - 1, k_text_align_center - ); - } - gui_end_right(); - - ui_global_ctx.cursor[2] = 25; - if( gui_button( 1 ) == k_button_click ) - { - if( colour_set_id < vg_list_size( colour_sets )-1 ) - colour_set_id ++; - } - gui_text( ui_global_ctx.cursor, ">", 2, 0 ); - gui_end_down(); - } - gui_end_down(); - - // Theme select - ui_global_ctx.cursor[1] += 16; - -#if 0 - gui_text( ui_global_ctx.cursor, "Tile Theme", 1, 0 ); - ui_global_ctx.cursor[1] += 20; - - gui_new_node(); - { - ui_global_ctx.cursor[2] = 25; - if( gui_button( 2 ) == k_button_click ) - { - if( world_theme_id > 0 ) - world_theme_id --; - } - gui_text( ui_global_ctx.cursor, "<", 2, 0 ); - gui_end_right(); - - ui_global_ctx.cursor[2] = 150; - gui_new_node(); - { - gui_fill_rect( ui_global_ctx.cursor, 0x33ffffff ); - gui_text( - (ui_px [2]){ ui_global_ctx.cursor[0] + 75, ui_global_ctx.cursor[1] + 6 }, - world_themes[ world_theme_id ].name, 1, k_text_align_center - ); - } - gui_end_right(); - - ui_global_ctx.cursor[2] = 25; - if( gui_button( 3 ) == k_button_click ) - { - if( world_theme_id < vg_list_size( world_themes )-1 ) - world_theme_id ++; - } - gui_text( ui_global_ctx.cursor, ">", 2, 0 ); - gui_end_down(); - } - gui_end_down(); -#endif - - gui_text( ui_global_ctx.cursor, "Graphics", 1, 0 ); - ui_global_ctx.cursor[1] += 20; - - gui_new_node(); - { - ui_global_ctx.cursor[2] = 200; - if( gui_button( 5 ) == k_button_click ) - { - enable_bloom ^= 0x1; - } - ui_global_ctx.cursor[0] += 4; - ui_global_ctx.cursor[1] += 4; - gui_text( ui_global_ctx.cursor, enable_bloom? - "Bloom: ENABLED": - "Bloom: DISABLED", 1, 0 ); - gui_end_down(); - } - gui_end_down(); - - ui_global_ctx.cursor[1] += 10; - gui_new_node(); - { - ui_global_ctx.cursor[2] = 200; - if( gui_button( 6 ) == k_button_click ) - { - enable_vignette ^= 0x1; - } - ui_global_ctx.cursor[0] += 4; - ui_global_ctx.cursor[1] += 4; - gui_text( ui_global_ctx.cursor, enable_vignette? - "Vignette: ENABLED": - "Vignette: DISABLED", 1, 0 ); - gui_end_down(); - } - gui_end_down(); - - ui_global_ctx.cursor[1] += 16; - gui_text( ui_global_ctx.cursor, "Music Volume", 1, 0 ); - ui_global_ctx.cursor[1] += 20; + // re-create level scores + for( int i = 0; i < vg_list_size( career_packs ); i ++ ){ + struct career_level_pack *set = &career_packs[i]; - gui_new_node(); - { - ui_px slider_start = ui_global_ctx.cursor[0]; - - float const bar_width = 45.0f, - bar_total = 200.0f, - bar_movement = bar_total-bar_width, - bar_start = bar_width * 0.5f; - - ui_global_ctx.cursor[2] = bar_total; - ui_fill_rect( &ui_global_ctx, - ui_global_ctx.cursor, - 0xff111111 ); - - ui_global_ctx.cursor[2] = bar_width; - ui_global_ctx.cursor[0] = slider_start + music_volume * bar_movement; - - int status = gui_button( 7 ); - - static ui_px drag_start = 0.0f; + for( int j = 0; j < set->count; j ++ ){ + struct cmp_level *lvl = &set->pack[j]; - if( status == k_button_start_click ) - drag_start = ui_global_ctx.mouse[0]; - else if( ui_global_ctx.capture_lock && - (ui_global_ctx.capture_mouse_id == ui_group_id(&ui_global_ctx,7))) - { - ui_px drag_offset = ui_global_ctx.mouse[0] - drag_start; - float offset_local = (drag_start + drag_offset - slider_start - bar_start) / bar_movement; + if( lvl->completed_score && !lvl->is_tutorial ){ + char num[10]; + snprintf( num, 9, "%d", lvl->completed_score ); + sum += lvl->completed_score; + + v3f pos = { + (f32)lvl->btn.position[0]+0.5f, + (f32)lvl->btn.position[1]+0.5f, + 1.0f }; + + m3x3_mulv( vg.pv, pos, pos ); + pos[0] += 1.0f; + pos[0] *= (f32)vg.window_x * 0.5f; + pos[1] += 1.0f; + pos[1] = 2.0f - pos[1]; + pos[1] *= (f32)vg.window_y * 0.5f; + + ui_text( (ui_rect){ pos[0]-100, pos[1], 200, 24 }, num, 1, + k_ui_align_center, 0xffcccccc ); + } + } + } - music_volume = vg_minf( vg_maxf( offset_local, 0.0f ), 1.0f ); - music_volume_update(); - } - - ui_global_ctx.cursor[0] += 4; - ui_global_ctx.cursor[1] += 4; - - char volbuf[12]; - snprintf( volbuf, 12, "%.2f", music_volume ); - gui_text( ui_global_ctx.cursor, volbuf, 1, 0 ); - gui_end_down(); - } - gui_end_down(); - } - gui_end(); - } -#endif + v3f pos = { -2, 8, 1 }; + + m3x3_mulv( vg.pv, pos, pos ); + pos[0] += 1.0f; + pos[0] *= (f32)vg.window_x * 0.5f; + pos[1] += 1.0f; + pos[1] = 2.0f - pos[1]; + pos[1] *= (f32)vg.window_y * 0.5f; + + char tot[32]; + snprintf( tot, 31, "%u", sum ); + + vg_ui.font = &vg_ui_font_big; + ui_text( (ui_rect){ pos[0]-100, pos[1], 200, 24 }, tot, 1, + k_ui_align_center, 0xffcccccc ); + vg_ui.font = &vg_ui_font_small; + + if( world.pCmpLevel ){ + vg_ui.font = &vg_ui_font_big; + ui_text( (ui_rect){ 0, 0, vg.window_x, 28 }, world.pCmpLevel->title, + 1, k_ui_align_middle_center, 0 ); + vg_ui.font = &vg_ui_font_small; + ui_text( (ui_rect){ 0, 28,vg.window_x, 14 }, world.pCmpLevel->description, + 1, k_ui_align_middle_center, 0 ); + } } // CONSOLE COMMANDS @@ -3873,8 +3634,7 @@ void _mc_vg1_ui(void) { static int console_credits( int argc, char const *argv[] ) { vg_info( "Aknowledgements:\n" ); - vg_info( " GLFW zlib/libpng glfw.org\n" ); - vg_info( " miniaudio MIT0 miniaud.io\n" ); + vg_info( " SDL2 ZLIB libsdl.org\n" ); vg_info( " QOI MIT phoboslab.org\n" ); vg_info( " STB library MIT nothings.org\n" ); return 0; @@ -3995,71 +3755,20 @@ void _mc_vg1_start(void){ sw_leaderboard_downloaded = &leaderboard_downloaded; #endif -#if 0 - vg_function_push( (struct vg_cmd){ - .name = "_map_write", - .function = console_save_map - }); - - vg_function_push( (struct vg_cmd){ - .name = "_map_load", - .function = console_load_map - }); - - vg_function_push( (struct vg_cmd){ - .name = "map", - .function = console_changelevel - }); - - vg_function_push( (struct vg_cmd){ - .name = "credits", - .function = console_credits - }); - - vg_convar_push( (struct vg_convar){ - .name = "colours", - .data = &colour_set_id, - .data_type = k_convar_dtype_i32, - .opt_i32 = { .min = 0, .max = 2, .clamp = 1 }, - .persistent = 1 - }); - - vg_convar_push( (struct vg_convar){ - .name = "theme", - .data = &world_theme_id, - .data_type = k_convar_dtype_i32, - .opt_i32 = { .min = 0, .max = vg_list_size( world_themes )-1, .clamp = 1 }, - .persistent = 1, - .update = NULL - }); - - vg_convar_push( (struct vg_convar){ - .name = "enable_bloom", - .data = &enable_bloom, - .data_type = k_convar_dtype_i32, - .opt_i32 = { .min = 0, .max = 1, .clamp = 1 }, - .persistent = 1, - .update = NULL - }); - - vg_convar_push( (struct vg_convar){ - .name = "enable_vignette", - .data = &enable_vignette, - .data_type = k_convar_dtype_i32, - .opt_i32 = { .min = 0, .max = 1, .clamp = 1 }, - .persistent = 1, - .update = NULL - }); - - vg_convar_push( (struct vg_convar){ - .name = "music_volume", - .data = &music_volume, - .data_type = k_convar_dtype_f32, - .opt_f32 = { .min = 0.0f, .max = 1.0f, .clamp = 1 }, - .persistent = 1, - .update = music_volume_update - }); -#endif + vg_console_reg_cmd( "_map_write", console_save_map, NULL ); + vg_console_reg_cmd( "_map_load", console_load_map, NULL ); + vg_console_reg_cmd( "map", console_changelevel, NULL ); + vg_console_reg_cmd( "credits", console_credits, NULL ); + vg_console_reg_var( "colours", &marblecomp.colour_set, k_var_dtype_i32, + VG_VAR_PERSISTENT ); + vg_console_reg_var( "theme", &marblecomp.world_theme, k_var_dtype_i32, + VG_VAR_PERSISTENT ); + vg_console_reg_var( "enable_bloom", &marblecomp.bloom, k_var_dtype_i32, + VG_VAR_PERSISTENT ); + vg_console_reg_var( "enable_vignette", &marblecomp.vignette, k_var_dtype_i32, + VG_VAR_PERSISTENT ); + vg_console_reg_var( "music", &marblecomp.music, k_var_dtype_i32, + VG_VAR_PERSISTENT ); // Combined quad, long quad / empty circle / filled circle mesh { @@ -4226,10 +3935,6 @@ void _mc_vg1_start(void){ /* FIXME: run this at vg exit */ void _mc_vg1_free(void) { -#ifdef VG_STEAM - sw_free_opengl(); -#endif - console_save_map( 0, NULL ); career_serialize(); } diff --git a/marblecomp.c b/marblecomp.c index fe6176c..35416db 100644 --- a/marblecomp.c +++ b/marblecomp.c @@ -3,6 +3,7 @@ #define VG_2D #define VG_LOG_SOURCE_INFO #define VG_TIMESTEP_FIXED (1.0/60.0) +#define VG_GAME_SETTINGS #ifndef VG_RELEASE #define VG_DEVWINDOW @@ -14,7 +15,7 @@ #include "vg/submodules/stb/stb_ds.h" #include "vg/vg.h" - +#include "steam.h" struct { enum mc_op { @@ -24,11 +25,15 @@ struct { op; v3f mouse_ws; + i32 colour_set, world_theme, bloom, vignette, music; + audio_channel *music_channel; } -static marblecomp = { .op = k_mc_op_clientloading }; +static marblecomp = { .op = k_mc_op_clientloading, .bloom = 1, .vignette = 1 }; #include "input.h" #include "fishladder_vg1.c" +#include "marblecomp_settings.h" +#include "steam.h" int main( int argc, char *argv[] ){ vg_mem.use_libc_malloc = 0; @@ -42,6 +47,7 @@ static void vg_launch_opt(void){ } static void vg_preload(void){ + vg_audio.dsp_enabled = 0; vg_info(" Copyright . . . -----, ,----- ,---. .---. \n" ); vg_info(" 2021-2023 |\\ /| | / | | | | /| \n" ); vg_info(" | \\ / | +-- / +----- +---' | / | \n" ); @@ -49,11 +55,23 @@ vg_info(" | \\ / | | / | | \\ | / | \n" ); vg_info(" | \\/ | | / | | \\ | / | \n" ); vg_info(" ' ' '--' [] '----- '----- ' ' '---' " "SOFTWARE\n" ); + + steam_init(); + vg_loader_step( NULL, steam_end ); } static void async_call_ready( void *payload, u32 size ){ _mc_vg1_start(); marblecomp.op = k_mc_op_none; + + audio_lock(); + if( marblecomp.music ){ + marblecomp.music_channel = audio_get_first_idle_channel(); + audio_channel_init( marblecomp.music_channel, &audio_music[0], + AUDIO_FLAG_LOOP ); + audio_channel_fadein( marblecomp.music_channel, 0.25f ); + } + audio_unlock(); } static void vg_load(void){ @@ -81,6 +99,7 @@ void _mc_vg1_projection_update(void){ static void vg_pre_update(void){ + steam_update(); if( marblecomp.op == k_mc_op_clientloading ) return; skaterift_preupdate_inputs(); _mc_vg1_update(); diff --git a/marblecomp_settings.h b/marblecomp_settings.h new file mode 100644 index 0000000..3952fba --- /dev/null +++ b/marblecomp_settings.h @@ -0,0 +1,160 @@ +struct ui_enum_opt mc_settings_colourscheme_enum[] = { + { 0, "Normal" }, + { 1, "Extra1" }, + { 2, "Extra2" } +}; + +struct ui_enum_opt mc_settings_binary[] = { + { 1, "Enabled" }, + { 0, "Disabled" }, +}; + +struct ui_enum_opt mc_settings_theme_enum[] = { + { 0, "Minimal" }, + { 1, "Wood" }, + { 2, "Lab" }, +}; + +struct { + struct vg_setting_enum colourscheme, bloom, vignette, theme, music; +} +static mc_settings = { + .colourscheme = { .label = "Colour Scheme", + .actual_value = &marblecomp.colour_set, + .options = mc_settings_colourscheme_enum, + .option_count = 3 }, + .bloom = { .label = "Bloom", + .actual_value = &marblecomp.bloom, + .options = mc_settings_binary, .option_count = 2 }, + .vignette = { .label = "Vignette", + .actual_value = &marblecomp.vignette, + .options = mc_settings_binary, .option_count = 2 }, + .theme = { .label = "Tile Theme", + .actual_value = &marblecomp.world_theme, + .options = mc_settings_theme_enum, .option_count = 3 }, + .music = { .label = "Music", + .actual_value = &marblecomp.music, + .options = mc_settings_binary, .option_count = 2 } +}; + +static void vg_game_settings_init(void){ + ui_settings_enum_init( &mc_settings.colourscheme ); + ui_settings_enum_init( &mc_settings.bloom ); + ui_settings_enum_init( &mc_settings.vignette ); + ui_settings_enum_init( &mc_settings.theme ); + ui_settings_enum_init( &mc_settings.music ); +} + +static void vg_game_settings_gui( ui_rect panel ){ + ui_rect rq; + ui_standard_widget( panel, rq, 1 ); + + ui_rect opt, display; + ui_split_ratio( rq, k_ui_axis_v, 0.5f, 16, opt, display ); + vg_settings_enum( &mc_settings.colourscheme, opt ); + + ui_rect blocks[4]; + ui_split_ratio( display, k_ui_axis_v, 0.5f, 2, blocks[0], blocks[2] ); + ui_split_ratio( blocks[0], k_ui_axis_v, 0.5f, 2, blocks[0], blocks[1] ); + ui_split_ratio( blocks[2], k_ui_axis_v, 0.5f, 2, blocks[2], blocks[3] ); + + v3f *set = colour_sets[ mc_settings.colourscheme.new_value ]; + for( u32 i=0; i<4; i ++ ){ + u32 rgb = 0xff000000; + for( u32 j=0; j < 3; j ++ ) + rgb |= (u32)(set[i][j]*255.0f) << j * 8; + + ui_fill( blocks[i], rgb ); + } + + ui_standard_widget( panel, rq, 1 ); + vg_settings_enum( &mc_settings.theme, rq ); + + ui_standard_widget( panel, rq, 1 ); + vg_settings_enum( &mc_settings.bloom, rq ); + + ui_standard_widget( panel, rq, 1 ); + vg_settings_enum( &mc_settings.vignette, rq ); + + ui_standard_widget( panel, rq, 1 ); + vg_settings_enum( &mc_settings.music, rq ); + + if( vg_settings_apply_button( panel, 1 ) ){ + marblecomp.colour_set = mc_settings.colourscheme.new_value; + marblecomp.world_theme = mc_settings.theme.new_value; + marblecomp.bloom = mc_settings.bloom.new_value; + marblecomp.vignette = mc_settings.vignette.new_value; + + audio_lock(); + marblecomp.music = mc_settings.music.new_value; + + if( marblecomp.music ){ + if( !marblecomp.music_channel ){ + marblecomp.music_channel = audio_get_first_idle_channel(); + audio_channel_init( marblecomp.music_channel, &audio_music[0], + AUDIO_FLAG_LOOP ); + audio_channel_fadein( marblecomp.music_channel, 0.25f ); + } + } + else{ + if( marblecomp.music_channel ){ + marblecomp.music_channel = audio_channel_fadeout( + marblecomp.music_channel, 0.25f ); + } + } + + audio_unlock(); + } + +#if 0 + ui_global_ctx.cursor[1] += 16; + gui_text( ui_global_ctx.cursor, "Music Volume", 1, 0 ); + ui_global_ctx.cursor[1] += 20; + + gui_new_node(); + { + ui_px slider_start = ui_global_ctx.cursor[0]; + + float const bar_width = 45.0f, + bar_total = 200.0f, + bar_movement = bar_total-bar_width, + bar_start = bar_width * 0.5f; + + ui_global_ctx.cursor[2] = bar_total; + ui_fill_rect( &ui_global_ctx, + ui_global_ctx.cursor, + 0xff111111 ); + + ui_global_ctx.cursor[2] = bar_width; + ui_global_ctx.cursor[0] = slider_start + music_volume * bar_movement; + + int status = gui_button( 7 ); + + static ui_px drag_start = 0.0f; + + if( status == k_button_start_click ) + drag_start = ui_global_ctx.mouse[0]; + else if( ui_global_ctx.capture_lock && + (ui_global_ctx.capture_mouse_id == ui_group_id(&ui_global_ctx,7))) + { + ui_px drag_offset = ui_global_ctx.mouse[0] - drag_start; + float offset_local = (drag_start + drag_offset - slider_start - bar_start) / bar_movement; + + music_volume = vg_minf( vg_maxf( offset_local, 0.0f ), 1.0f ); + music_volume_update(); + } + + ui_global_ctx.cursor[0] += 4; + ui_global_ctx.cursor[1] += 4; + + char volbuf[12]; + snprintf( volbuf, 12, "%.2f", music_volume ); + gui_text( ui_global_ctx.cursor, volbuf, 1, 0 ); + gui_end_down(); + } + gui_end_down(); + } + gui_end(); + } +#endif +} diff --git a/steam.h b/steam.h new file mode 100644 index 0000000..c1a80c3 --- /dev/null +++ b/steam.h @@ -0,0 +1,282 @@ +#ifndef STEAM_H +#define STEAM_H + +#define VG_GAME +#include "vg/vg_steam.h" +#include "vg/vg_steam_utils.h" +#include "vg/vg_steam_networking.h" +#include "vg/vg_steam_auth.h" +#include "vg/vg_steam_http.h" +#include "vg/vg_steam_friends.h" +#include "vg/vg_steam_user_stats.h" +#include "submodules/anyascii/impl/c/anyascii.c" + +/* + * We only want to use steamworks if building for the networked version, + * theres not much point otherwise. We mainly want steamworks for setting + * achievements etc.. so that includes our own server too. + * + * This file also wraps the functions and interfaces that we want to use to + * make them a bit easier to read, since they are the flat API they have very + * long names. in non-networked builds they will return default errors or do + * nothing. + */ + +static char steam_username_at_startup[128] = "Unassigned"; + +static void recv_steam_warning( int severity, const char *msg ) +{ + if( severity == 0 ) + vg_low( "%s\n", msg ); + else + vg_info( "%s\n", msg ); +} + +static int steam_ready = 0, + steam_stats_ready = 0; + +static void *hSteamNetworkingSockets, + *hSteamUser; + +static ISteamUserStats *hSteamUserStats; +static HSteamPipe hSteamClientPipe; + +static const char *steam_achievement_names[] = +{ + "MASTER_ENGINEER", "CAN_DO_THAT", "BANG", "GOOD_ENOUGH", + "TUTORIALS", "MIGHTY_CONSUMER", "GRADUATE" +}; + +static void steam_store_achievements(void) +{ + if( steam_ready && steam_stats_ready ){ + SteamAPI_ISteamUserStats_StoreStats( hSteamUserStats ); + } +} + +static void steam_set_achievement( const char *name ){ + if( steam_ready && steam_stats_ready ){ + if( SteamAPI_ISteamUserStats_SetAchievement( hSteamUserStats, name ) ){ + vg_success( "Achievement set! '%s'\n", name ); + + } + else{ + vg_warn( "Failed to set achievement: %s\n", name ); + } + } + else{ + vg_warn( "Failed to set achievement (steam not ready): %s\n", name ); + } +} + +static void sw_set_achievement( const char *name ){ + steam_set_achievement( name ); + steam_store_achievements(); +} + +static void steam_clear_achievement( const char *name ) +{ + if( steam_ready && steam_stats_ready ){ + if( SteamAPI_ISteamUserStats_ClearAchievement( hSteamUserStats, name ) ){ + vg_info( "Achievement cleared: '%s'\n", name ); + } + else{ + vg_warn( "Failed to clear achievement: %s\n", name ); + } + } + else{ + vg_warn( "Failed to clear achievement (steam not ready): %s\n", name ); + } +} + + +static void steam_print_all_achievements(void){ + vg_info( "Achievements: \n" ); + + if( steam_ready && steam_stats_ready ){ + for( int i=0; im_pubParam; + + if( rec->m_eResult == k_EResultOK ){ + vg_info( "Recieved stats for: %lu (user: %lu)\n", rec->m_nGameID, + rec->m_steamIDUser ); + steam_stats_ready = 1; + } + else{ + vg_error( "Error recieveing stats for user (%u)\n", rec->m_eResult ); + } +} + +static u32 utf8_byte0_byte_count( u8 char0 ) +{ + for( u32 k=2; k<4; k++ ){ + if( !(char0 & (0x80 >> k)) ) + return k; + } + + return 0; +} + +static u32 str_utf8_collapse( const char *str, char *buf, u32 length ){ + u8 *ustr = (u8 *)str; + u32 utf32_code = 0x00000000; + u32 i=0, j=0, utf32_byte_ct=0; + + for(;j < length-1;){ + if( ustr[i] == 0x00 ) + break; + + if( ustr[i] & 0x80 ){ + if( utf32_byte_ct ){ + utf32_byte_ct --; + utf32_code |= (ustr[i] & 0x3F) << (utf32_byte_ct*6); + + if( !utf32_byte_ct ){ + const char *match; + size_t chars = anyascii( utf32_code, &match ); + + for( u32 k=0; k> utf32_byte_ct); + utf32_code <<= utf32_byte_ct*6; + } + } + else{ + utf32_byte_ct = 0x00; + buf[j ++] = str[i]; + } + + i++; + } + + buf[j] = 0x00; + return j; +} + +static int steam_init(void){ + const char *username = "offline player"; + + vg_info( "Initializing steamworks\n" ); + + if( !SteamAPI_Init() ){ + printf("\n"); + vg_error( "Steamworks failed to initialize\n" ); + return 1; + } + + steam_ready = 1; + + SteamAPI_ManualDispatch_Init(); + + /* Connect interfaces */ + hSteamClientPipe = SteamAPI_GetHSteamPipe(); + hSteamNetworkingSockets = SteamAPI_SteamNetworkingSockets_SteamAPI(); + hSteamUser = SteamAPI_SteamUser(); + + ISteamUtils *utils = SteamAPI_SteamUtils(); + SteamAPI_ISteamUtils_SetWarningMessageHook( utils, recv_steam_warning ); + + printf("\n"); + vg_success( "\nSteamworks API running\n" ); + + ISteamFriends *hSteamFriends = SteamAPI_SteamFriends(); + username = SteamAPI_ISteamFriends_GetPersonaName( hSteamFriends ); + + /* + * Request stats + * -------------------------------------------------------- + */ + hSteamUserStats = SteamAPI_SteamUserStats(); + steam_register_callback( k_iUserStatsReceived, + steam_on_recieve_current_stats ); + + if( !SteamAPI_ISteamUserStats_RequestCurrentStats( hSteamUserStats ) ) + vg_warn( "No Steam Logon: Cannot request stats\n" ); + + vg_console_reg_cmd( "ach", steam_achievement_ccmd, NULL ); + + /* TODO: On username update callback */ + str_utf8_collapse( username, steam_username_at_startup, + vg_list_size(steam_username_at_startup) ); + + return 1; +} + +static void steam_update(void) +{ + if( steam_ready ){ + steamworks_event_loop( hSteamClientPipe ); + } +} + +static void steam_end(void) +{ + if( steam_ready ){ + vg_info( "Shutting down\n..." ); + SteamAPI_Shutdown(); + } +} + +#endif /* STEAM_H */ -- 2.25.1