From: hgn Date: Mon, 11 Aug 2025 20:38:38 +0000 (+0000) Subject: migration to vg4 (BROKEN) X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=523cd61216b9c5cfe9214400b5de34d6e117e6ae;p=carveJwlIkooP6JGAAIwe30JlM.git migration to vg4 (BROKEN) --- diff --git a/.gitignore b/.gitignore index 7a84ac1..a0eb0b8 100755 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ dist/ models_src/boards/workshop ccflags/png icons/png +src.generated/ # auto generated code shaders/*.h diff --git a/build.c b/build.c index bedb1e0..a5150c3 100644 --- a/build.c +++ b/build.c @@ -1,231 +1,114 @@ -#include "vg/vg_tool.h" -#include "vg/vg_platform.h" -#include "vg/vg_log.h" -#include "vg/vg_opt.h" -#include "vg/vg_build.h" -#include "vg/vg_mem_pool.h" -#include "vg/vg_build_utils_shader.h" -#include "vg/vg_msg.h" -#include "src/addon_types.h" +#define VG_BUILD_TOOLS +#define VG_MATH +#define VG_MSG_TO_KVS +#include "vg/vg.hconf" -#include "vg/vg_m.h" -#include "src/model.h" -#include "src/model.c" -#include "src/array_file.c" +#define VG_IMPLEMENTATION +#include "vg/vg.hconf" +#undef VG_IMPLEMENTATION +#define VG_THIRDPARTY +#include "vg/vg.hconf" +#undef VG_THIRDPARTY -/* - * Addon metadata utilities - * -------------------------------------------------------------------------- */ - -void write_msg( vg_msg *msg, const char *path ){ - FILE *fp = fopen( path, "wb" ); - if( !fp ){ - vg_error( "Cannot open %s for writing.\n", path ); - exit(0); - } +#define SR_MODEL +#include "src/skaterift.hconf" - fwrite( msg->buf, msg->cur.co, 1, fp ); - fclose( fp ); - vg_success( "Written %s (%ub)\n", path, msg->cur ); -} +#define SR_IMPLEMENTATION +#include "src/skaterift.hconf" +#undef SR_IMPLEMENTATION -void write_generic_addon_inf( u32 type, const char *title, - const char *content, const char *dest, u32 flags ) +void build_shaders(void) { - u8 descriptor_buf[ 512 ]; - vg_msg descriptor = {0}; - descriptor.buf = descriptor_buf; - descriptor.max = sizeof(descriptor_buf); - vg_msg_frame( &descriptor, "workshop" ); - vg_msg_wkvstr( &descriptor, "title", title ); - vg_msg_wkvstr( &descriptor, "author", "Skaterift" ); - vg_msg_wkvnum( &descriptor, "type", k_vg_msg_u32, 1, &type ); - vg_msg_end_frame( &descriptor ); - vg_msg_wkvstr( &descriptor, "content", content ); - if( flags ) - vg_msg_wkvnum( &descriptor, "flags", k_vg_msg_u32, 1, &flags ); - write_msg( &descriptor, dest ); -} - -/* - * Compilation specifications - * -------------------------------------------------------------------------- */ + vg_info( "Compiling shader headers\n" ); + vg_shader_set_include_dir( "shaders" ); -/* operates in the local files, not in the bin folders */ -void build_game_metadata(void) -{ - vg_info( "Building game metadata\n" ); - write_generic_addon_inf( k_addon_type_board, - "Longboard", "board.mdl", - "content_skaterift/boards/skaterift_long/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_board, - "Fractal", "board.mdl", - "content_skaterift/boards/skaterift_fract/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_board, - "Striped", "board.mdl", - "content_skaterift/boards/skaterift_striped/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_board, - "Licco", "board.mdl", - "content_skaterift/boards/skaterift_licco/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_board, - "Hypno", "board.mdl", - "content_skaterift/boards/skaterift_spiral/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_board, - "Shark", "board.mdl", - "content_skaterift/boards/skaterift_shark/addon.inf", 0 ); - - write_generic_addon_inf( k_addon_type_player, - "De'folde", "ch_new.mdl", - "content_skaterift/playermodels/skaterift_new/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_player, - "Jordan", "ch_jordan.mdl", - "content_skaterift/playermodels/skaterift_jordan/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_player, - "Outlaw", "ch_outlaw.mdl", - "content_skaterift/playermodels/skaterift_outlaw/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_player, - "Chip", "ch_chip.mdl", - "content_skaterift/playermodels/skaterift_chip/addon.inf", ADDON_REG_HIDDEN ); - write_generic_addon_inf( k_addon_type_player, - "Aaron", "ch_aaron.mdl", - "content_skaterift/playermodels/skaterift_aaron/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_player, - "JC", "ch_john.mdl", - "content_skaterift/playermodels/skaterift_john/addon.inf", ADDON_REG_HIDDEN ); - write_generic_addon_inf( k_addon_type_player, - "Ela", "ch_ela.mdl", - "content_skaterift/playermodels/skaterift_ela/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_player, - "Custom", "ch_sr2t.mdl", - "content_skaterift/playermodels/sr2t/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_player, - "Pro", "ch_pro.mdl", - "content_skaterift/playermodels/skaterift_pro/addon.inf", 0 ); - write_generic_addon_inf( k_addon_type_player, - "Amin", "ch_amin.mdl", - "content_skaterift/playermodels/skaterift_amin/addon.inf", 0 ); - - write_generic_addon_inf( k_addon_type_player, - "Jesus", "ch_jesus.mdl", - "content_skaterift/playermodels/skaterift_jesus/addon.inf", ADDON_REG_HIDDEN ); - write_generic_addon_inf( k_addon_type_player, - "FBI", "ch_fbi.mdl", - "content_skaterift/playermodels/skaterift_fbi/addon.inf", ADDON_REG_HIDDEN ); - write_generic_addon_inf( k_addon_type_player, - "FBI2", "ch_fbi2.mdl", - "content_skaterift/playermodels/skaterift_fbi2/addon.inf", ADDON_REG_HIDDEN ); - write_generic_addon_inf( k_addon_type_player, - "President", "ch_president.mdl", - "content_skaterift/playermodels/skaterift_president/addon.inf", ADDON_REG_HIDDEN ); - - struct + struct { c8 *name, *vs, *fs; } shaders[] = { - const char *title, *location, *file; - u32 flags; - } - maps[] = - { - { "Mt.Zero Island", "Australia", "content_skaterift/maps/mp_mtzero/addon.inf", ADDON_REG_CAMPAIGN | ADDON_REG_MTZERO | ADDON_REG_PREMIUM }, - { "Flat World", "...", "content_skaterift/maps/dev_flatworld/addon.inf", ADDON_REG_CAMPAIGN | ADDON_REG_HIDDEN }, - { "Heaven", "...", "content_skaterift/maps/dev_heaven/addon.inf", ADDON_REG_CAMPAIGN | ADDON_REG_HIDDEN }, - { "Valley", "Cambodia", "content_skaterift/maps/mp_line1/addon.inf", ADDON_REG_CAMPAIGN | ADDON_REG_VALLEY | ADDON_REG_PREMIUM }, - { "Training Island", "Australia", "content_skaterift/maps/dev_tutorial/addon.inf", ADDON_REG_CAMPAIGN | ADDON_REG_VOLC }, - { "Center Island", "Australia", "content_skaterift/maps/dev_hub/addon.inf", ADDON_REG_CAMPAIGN | ADDON_REG_HUB }, - { "Downtown", "USA, Georgia", "content_skaterift/maps/mp_spawn/addon.inf", ADDON_REG_CAMPAIGN | ADDON_REG_CITY | ADDON_REG_PREMIUM }, - { "Moon", "Venus", "content_skaterift/maps/vm/addon.inf", ADDON_REG_VENUS | ADDON_REG_PREMIUM }, + /* TODO: We need to move this into a vg header */ + { "debug_lines", "vg/shaders/debug_lines.vs", "vg/shaders/debug_lines.fs" }, + { "debug_rigidbody", "vg/shaders/rigidbody_view.vs", "vg/shaders/rigidbody_view.fs" }, + { "vgui", "vg/shaders/ui.vs", "vg/shaders/ui.fs" }, + { "vgui_image", "vg/shaders/ui_image.vs", "vg/shaders/ui_image.fs" }, + { "vgui_image_grad", "vg/shaders/ui_image.vs", "vg/shaders/ui_image_grad.fs" }, + { "vgui_image_hsv", "vg/shaders/ui_image.vs", "vg/shaders/ui_image_hsv.fs" }, + { "vgloader", "vg/shaders/blit.vs", "vg/shaders/loader.fs" }, + + /* Scene */ + { "scene_standard", "shaders/scene.vs", "shaders/scene_standard.fs" }, + { "scene_standard_alphatest", "shaders/scene.vs", "shaders/scene_standard_alphatest.fs" }, + { "scene_foliage", "shaders/scene_foliage.vs", "shaders/scene_foliage.fs" }, + { "scene_override", "shaders/scene_override.vs", "shaders/scene_override.fs" }, + { "scene_preview", "shaders/scene_override.vs", "shaders/scene_preview.fs" }, + { "scene_fxglow", "shaders/scene_fxglow.vs", "shaders/scene_fxglow.fs" }, + { "scene_vertex_blend", "shaders/scene.vs", "shaders/scene_vertex_blend.fs" }, + { "scene_terrain", "shaders/scene.vs", "shaders/scene_terrain.fs" }, + { "scene_route", "shaders/scene_override.vs", "shaders/scene_route.fs" }, + { "scene_depth", "shaders/scene.vs", "shaders/scene_depth.fs" }, + { "scene_position", "shaders/scene.vs", "shaders/scene_position.fs" }, + { "scene_cubemapped", "shaders/scene.vs", "shaders/scene_cubemapped.fs" }, + { "scene_water", "shaders/scene.vs", "shaders/scene_water.fs" }, + { "scene_water_fast", "shaders/scene.vs", "shaders/scene_water_fast.fs" }, + { "scene_scoretext", "shaders/scene_sfd.vs", "shaders/scene_standard.fs" }, + { "scene_font", "shaders/model_font.vs", "shaders/scene_font.fs" }, + + /* Models */ + { "model_sky", "shaders/model.vs", "shaders/model_sky.fs" }, + { "model_sky_space", "shaders/model.vs", "shaders/model_sky_space.fs" }, + { "model_sky_cubemap", "shaders/model_sky.vs", "shaders/model_sky_cubemap.fs" }, + { "model_menu", "shaders/model.vs", "shaders/model_menu.fs" }, + { "model_character_view", "shaders/model_skinned.vs", "shaders/model_character_view.fs" }, + { "model_board_view", "shaders/model.vs", "shaders/model_character_view.fs" }, + { "model_entity", "shaders/model.vs", "shaders/model_entity.fs" }, + { "model_gate", "shaders/model.vs", "shaders/model_gate_lq.fs" }, + { "model_superworld", "shaders/model.vs", "shaders/model_superworld.fs" }, + { "model_gate_unlinked", "shaders/model.vs", "shaders/model_gate_unlinked.fs" }, + { "model_font", "shaders/model_font.vs", "shaders/model_font.fs" }, + + { "particle", "shaders/particle.vs", "shaders/particle.fs" }, + { "trail", "shaders/trail.vs", "shaders/trail.fs" }, + + /* 2D */ + { "workshop_compositor", "shaders/workshop_compositor.vs", "shaders/workshop_compositor.fs" }, + { "blit", "vg/shaders/blit.vs", "vg/shaders/blit_tex.fs" }, + { "blitblur", "vg/shaders/blit.vs", "vg/shaders/blit_blur.fs" }, + { "blitcolour", "vg/shaders/blit.vs", "vg/shaders/blit_colour.fs" }, + { "blit_transition", "vg/shaders/blit.vs", "shaders/blit_transition.fs" }, + { "compass", "shaders/compass.vs", "shaders/compass.fs" }, + { "routeui", "shaders/routeui.vs", "shaders/routeui.fs" }, }; - for( u32 i=0; iuid.buffer ); - vg_syscall( "mkdir -p bin/%s/savedata", proj->uid.buffer ); - vg_syscall( "mkdir -p bin/%s/tools", proj->uid.buffer ); - vg_syscall( "cp bin/skaterift_blender.zip bin/%s/tools/", proj->uid.buffer ); + FILE *hdr = fopen( "src.generated/control_overlay.h", "w" ); + VG_ASSERT( hdr ); + + vg_stack_allocator stack; + vg_stack_init( &stack, NULL, VG_MB(8), "Model buffer" ); + + vg_model model; + VG_ASSERT( vg_model_load( &model, VG_MODEL_CPU_METADATA, "content_skaterift/models/rs_overlay.mdl", &stack ) ); + + for( u32 i=0; ipstr_name ), mesh->submesh_start ); + } + vg_stack_free( &stack ); + fclose( hdr ); } - -#include "src/build_control_overlay.c" void build_game_bin( struct vg_project *proj, struct vg_compiler_env *env ) { @@ -234,12 +117,10 @@ void build_game_bin( struct vg_project *proj, struct vg_compiler_env *env ) { meta = 1; build_shaders(); - build_game_metadata(); + build_control_overlay(); vg_low( "\n\n" ); } - build_control_overlay(); - struct vg_compiler_conf conf = {0}; if( env->platform == k_platform_windows ) @@ -256,14 +137,63 @@ void build_game_bin( struct vg_project *proj, struct vg_compiler_env *env ) .steam_api = 1, .use_3d = 1, .custom_game_settings = 0, - .custom_shaders = 1, .multiplayer = 1 }, - env, &conf, "src/client.c", "skaterift" ); + env, &conf, "src/unit_skaterift.c", "skaterift" ); vg_add_controller_database( proj ); + vg_add_blob( proj, "steam_appid.txt", "" ); } +void build_game_content( struct vg_project *proj ) +{ + vg_symlink( proj, "content_skaterift/textures", "textures" ); + vg_symlink( proj, "content_skaterift/models", "models" ); + vg_symlink( proj, "content_skaterift/boards", "boards" ); + vg_symlink( proj, "content_skaterift/maps", "maps" ); + vg_symlink( proj, "content_skaterift/sound", "sound" ); + vg_symlink( proj, "content_skaterift/playermodels", "playermodels" ); + vg_symlink( proj, "content_skaterift/metascenes", "metascenes" ); + vg_syscall( "mkdir -p bin/%s/cfg", proj->uid.buffer ); + vg_syscall( "mkdir -p bin/%s/savedata", proj->uid.buffer ); + vg_syscall( "mkdir -p bin/%s/tools", proj->uid.buffer ); + vg_syscall( "cp bin/skaterift_blender.zip bin/%s/tools/", proj->uid.buffer ); +} + +void vg_build_scripts(void) +{ + if( vg_long_opt( "skaterift", "Make skaterift" ) ) + { + struct vg_project proj; + vg_project_init( &proj, "bin", "skaterift", NULL, 0 ); + + build_game_bin( &proj, &_vg_common_env ); + build_game_content( &proj ); + vg_add_blob( &proj, "steam_appid.txt", "" ); + } +} + +#if 0 +#include "vg/vg_tool.h" +#include "vg/vg_platform.h" +#include "vg/vg_log.h" +#include "vg/vg_opt.h" +#include "vg/vg_build.h" +#include "vg/vg_mem_pool.h" +#include "vg/vg_build_utils_shader.h" +#include "vg/vg_msg.h" +#include "src/addon_types.h" + +#include "vg/vg_m.h" +#include "src/model.h" +#include "src/model.c" +#include "src/array_file.c" + + +/* + * Addon metadata utilities + * -------------------------------------------------------------------------- */ + void build_crash_reporter( struct vg_project *proj, struct vg_compiler_env *env ) { struct vg_compiler_conf conf = {0}; @@ -470,7 +400,6 @@ void s_utest_build(void) .log_source_info = 1, .use_3d = 0, .custom_game_settings = 0, - .custom_shaders = 0, .multiplayer = 0 }, env, &conf, "src/utest.c", "utest" ); @@ -511,10 +440,9 @@ void s_dbtest_build(void) int main( int argc, const char *argv[] ) { - vg_log_init(); + _vg_log_pre_init(); _vg_opt_init( argc, argv ); - const char *arg; if( (arg = vg_long_opt_arg( "glsl-dir", "Specify output directory for preprocessed GLSL" )) ) @@ -566,3 +494,4 @@ int main( int argc, const char *argv[] ) vg_success( "All scripts completed\n" ); } +#endif diff --git a/build.sh b/build.sh index 4ad323c..7f4e7b2 100755 --- a/build.sh +++ b/build.sh @@ -1 +1 @@ -clang -fsanitize=address -O0 -I. -I./vg build.c vg/vg_tool.c -o /tmp/tmpsr && /tmp/tmpsr $@ +zig cc -lasan -fsanitize=address -O0 -I. build.c -o /tmp/build_sr && /tmp/build_sr $@ diff --git a/content_skaterift/boards/skaterift_fract/addon.inf b/content_skaterift/boards/skaterift_fract/addon.inf deleted file mode 100644 index 3c85c64..0000000 Binary files a/content_skaterift/boards/skaterift_fract/addon.inf and /dev/null differ diff --git a/content_skaterift/boards/skaterift_fract/addon.kv b/content_skaterift/boards/skaterift_fract/addon.kv new file mode 100644 index 0000000..5c5b36a --- /dev/null +++ b/content_skaterift/boards/skaterift_fract/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title Fractal + author "Skate Rift" +} + +content board.mdl diff --git a/content_skaterift/boards/skaterift_licco/addon.inf b/content_skaterift/boards/skaterift_licco/addon.inf deleted file mode 100644 index 0cb8f45..0000000 Binary files a/content_skaterift/boards/skaterift_licco/addon.inf and /dev/null differ diff --git a/content_skaterift/boards/skaterift_licco/addon.kv b/content_skaterift/boards/skaterift_licco/addon.kv new file mode 100644 index 0000000..44c0a25 --- /dev/null +++ b/content_skaterift/boards/skaterift_licco/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title Licco + author "Skate Rift" +} + +content board.mdl diff --git a/content_skaterift/boards/skaterift_long/addon.inf b/content_skaterift/boards/skaterift_long/addon.inf deleted file mode 100644 index daf6b76..0000000 Binary files a/content_skaterift/boards/skaterift_long/addon.inf and /dev/null differ diff --git a/content_skaterift/boards/skaterift_long/addon.kv b/content_skaterift/boards/skaterift_long/addon.kv new file mode 100644 index 0000000..f2e7248 --- /dev/null +++ b/content_skaterift/boards/skaterift_long/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title Longboard + author "Skate Rift" +} + +content board.mdl diff --git a/content_skaterift/boards/skaterift_shark/addon.inf b/content_skaterift/boards/skaterift_shark/addon.inf deleted file mode 100644 index 7f8c3fc..0000000 Binary files a/content_skaterift/boards/skaterift_shark/addon.inf and /dev/null differ diff --git a/content_skaterift/boards/skaterift_shark/addon.kv b/content_skaterift/boards/skaterift_shark/addon.kv new file mode 100644 index 0000000..bb06ef8 --- /dev/null +++ b/content_skaterift/boards/skaterift_shark/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title Shark + author "Skate Rift" +} + +content board.mdl diff --git a/content_skaterift/boards/skaterift_spiral/addon.inf b/content_skaterift/boards/skaterift_spiral/addon.inf deleted file mode 100644 index 6cc3ef5..0000000 Binary files a/content_skaterift/boards/skaterift_spiral/addon.inf and /dev/null differ diff --git a/content_skaterift/boards/skaterift_spiral/addon.kv b/content_skaterift/boards/skaterift_spiral/addon.kv new file mode 100644 index 0000000..6f4da15 --- /dev/null +++ b/content_skaterift/boards/skaterift_spiral/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title Hypno + author "Skate Rift" +} + +content board.mdl diff --git a/content_skaterift/boards/skaterift_striped/addon.inf b/content_skaterift/boards/skaterift_striped/addon.inf deleted file mode 100644 index 2c2ba4e..0000000 Binary files a/content_skaterift/boards/skaterift_striped/addon.inf and /dev/null differ diff --git a/content_skaterift/boards/skaterift_striped/addon.kv b/content_skaterift/boards/skaterift_striped/addon.kv new file mode 100644 index 0000000..94a5c96 --- /dev/null +++ b/content_skaterift/boards/skaterift_striped/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title Striped + author "Skate Rift" +} + +content board.mdl diff --git a/content_skaterift/maps/dev_flatworld/addon.inf b/content_skaterift/maps/dev_flatworld/addon.inf deleted file mode 100644 index d4fef53..0000000 Binary files a/content_skaterift/maps/dev_flatworld/addon.inf and /dev/null differ diff --git a/content_skaterift/maps/dev_flatworld/addon.kv b/content_skaterift/maps/dev_flatworld/addon.kv new file mode 100644 index 0000000..16ba10e --- /dev/null +++ b/content_skaterift/maps/dev_flatworld/addon.kv @@ -0,0 +1,10 @@ +workshop +{ + title "Flat World" + author "Skate Rift" +} + +content main.mdl +flags CAMPAIGN|HIDDEN + +location Nowhere diff --git a/content_skaterift/maps/dev_heaven/addon.inf b/content_skaterift/maps/dev_heaven/addon.inf deleted file mode 100644 index 95f2519..0000000 Binary files a/content_skaterift/maps/dev_heaven/addon.inf and /dev/null differ diff --git a/content_skaterift/maps/dev_heaven/addon.kv b/content_skaterift/maps/dev_heaven/addon.kv new file mode 100644 index 0000000..c4aa0a8 --- /dev/null +++ b/content_skaterift/maps/dev_heaven/addon.kv @@ -0,0 +1,10 @@ +workshop +{ + title "Heaven" + author "Skate Rift" +} + +content main.mdl +flags CAMPAIGN|HIDDEN + +location Nowhere diff --git a/content_skaterift/maps/dev_hub/addon.inf b/content_skaterift/maps/dev_hub/addon.inf deleted file mode 100644 index 691e963..0000000 Binary files a/content_skaterift/maps/dev_hub/addon.inf and /dev/null differ diff --git a/content_skaterift/maps/dev_hub/addon.kv b/content_skaterift/maps/dev_hub/addon.kv new file mode 100644 index 0000000..de840d3 --- /dev/null +++ b/content_skaterift/maps/dev_hub/addon.kv @@ -0,0 +1,10 @@ +workshop +{ + title "Center Island" + author "Skate Rift" +} + +content main.mdl +flags CAMPAIGN|HUB + +location Australia diff --git a/content_skaterift/maps/dev_tutorial/addon.inf b/content_skaterift/maps/dev_tutorial/addon.inf deleted file mode 100644 index ae4c4b9..0000000 Binary files a/content_skaterift/maps/dev_tutorial/addon.inf and /dev/null differ diff --git a/content_skaterift/maps/dev_tutorial/addon.kv b/content_skaterift/maps/dev_tutorial/addon.kv new file mode 100644 index 0000000..410a9a5 --- /dev/null +++ b/content_skaterift/maps/dev_tutorial/addon.kv @@ -0,0 +1,10 @@ +workshop +{ + title "Training Island" + author "Skate Rift" +} + +content main.mdl +flags CAMPAIGN|VOLC + +location Australia diff --git a/content_skaterift/maps/mp_line1/addon.inf b/content_skaterift/maps/mp_line1/addon.inf deleted file mode 100644 index e7d0d6c..0000000 Binary files a/content_skaterift/maps/mp_line1/addon.inf and /dev/null differ diff --git a/content_skaterift/maps/mp_line1/addon.kv b/content_skaterift/maps/mp_line1/addon.kv new file mode 100644 index 0000000..e898856 --- /dev/null +++ b/content_skaterift/maps/mp_line1/addon.kv @@ -0,0 +1,10 @@ +workshop +{ + title "Valley" + author "Skate Rift" +} + +content main.mdl +flags CAMPAIGN|VALLEY|PREMIUM + +location Cambodia diff --git a/content_skaterift/maps/mp_mtzero/addon.inf b/content_skaterift/maps/mp_mtzero/addon.inf deleted file mode 100644 index 39fda55..0000000 Binary files a/content_skaterift/maps/mp_mtzero/addon.inf and /dev/null differ diff --git a/content_skaterift/maps/mp_mtzero/addon.kv b/content_skaterift/maps/mp_mtzero/addon.kv new file mode 100644 index 0000000..c0ab0c7 --- /dev/null +++ b/content_skaterift/maps/mp_mtzero/addon.kv @@ -0,0 +1,10 @@ +workshop +{ + title "Mt.Zero Island" + author "Skate Rift" +} + +content main.mdl +flags CAMPAIGN|MTZERO|PREMIUM + +location Australia diff --git a/content_skaterift/maps/mp_spawn/addon.inf b/content_skaterift/maps/mp_spawn/addon.inf deleted file mode 100644 index 79e6c26..0000000 Binary files a/content_skaterift/maps/mp_spawn/addon.inf and /dev/null differ diff --git a/content_skaterift/maps/mp_spawn/addon.kv b/content_skaterift/maps/mp_spawn/addon.kv new file mode 100644 index 0000000..1ff8634 --- /dev/null +++ b/content_skaterift/maps/mp_spawn/addon.kv @@ -0,0 +1,10 @@ +workshop +{ + title "Downtown" + author "Skate Rift" +} + +content main.mdl +flags CAMPAIGN|CITY|PREMIUM + +location USA diff --git a/content_skaterift/maps/vm/addon.inf b/content_skaterift/maps/vm/addon.inf deleted file mode 100644 index 0aa565c..0000000 Binary files a/content_skaterift/maps/vm/addon.inf and /dev/null differ diff --git a/content_skaterift/maps/vm/addon.kv b/content_skaterift/maps/vm/addon.kv new file mode 100644 index 0000000..000e56a --- /dev/null +++ b/content_skaterift/maps/vm/addon.kv @@ -0,0 +1,10 @@ +workshop +{ + title "Moon" + author "Skate Rift" +} + +content main.mdl +flags VENUS|PREMIUM + +location Venus diff --git a/content_skaterift/playermodels/skaterift_aaron/addon.inf b/content_skaterift/playermodels/skaterift_aaron/addon.inf deleted file mode 100644 index f357ede..0000000 Binary files a/content_skaterift/playermodels/skaterift_aaron/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_aaron/addon.kv b/content_skaterift/playermodels/skaterift_aaron/addon.kv new file mode 100644 index 0000000..a7a9feb --- /dev/null +++ b/content_skaterift/playermodels/skaterift_aaron/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title "Aaron" + author "Skate Rift" +} + +content ch_aaron.mdl diff --git a/content_skaterift/playermodels/skaterift_amin/addon.inf b/content_skaterift/playermodels/skaterift_amin/addon.inf deleted file mode 100644 index 4cb227f..0000000 Binary files a/content_skaterift/playermodels/skaterift_amin/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_amin/addon.kv b/content_skaterift/playermodels/skaterift_amin/addon.kv new file mode 100644 index 0000000..f329d81 --- /dev/null +++ b/content_skaterift/playermodels/skaterift_amin/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title "Amin" + author "Skate Rift" +} + +content ch_amin.mdl diff --git a/content_skaterift/playermodels/skaterift_chip/addon.inf b/content_skaterift/playermodels/skaterift_chip/addon.inf deleted file mode 100644 index c8f4cbe..0000000 Binary files a/content_skaterift/playermodels/skaterift_chip/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_chip/addon.kv b/content_skaterift/playermodels/skaterift_chip/addon.kv new file mode 100644 index 0000000..544607d --- /dev/null +++ b/content_skaterift/playermodels/skaterift_chip/addon.kv @@ -0,0 +1,8 @@ +workshop +{ + title "Chip" + author "Skate Rift" +} + +content ch_chip.mdl +flags HIDDEN diff --git a/content_skaterift/playermodels/skaterift_ela/addon.inf b/content_skaterift/playermodels/skaterift_ela/addon.inf deleted file mode 100644 index 54f5411..0000000 Binary files a/content_skaterift/playermodels/skaterift_ela/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_ela/addon.kv b/content_skaterift/playermodels/skaterift_ela/addon.kv new file mode 100644 index 0000000..da655f3 --- /dev/null +++ b/content_skaterift/playermodels/skaterift_ela/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title "Ela" + author "Skate Rift" +} + +content ch_ela.mdl diff --git a/content_skaterift/playermodels/skaterift_fbi/addon.inf b/content_skaterift/playermodels/skaterift_fbi/addon.inf deleted file mode 100644 index 5961ecf..0000000 Binary files a/content_skaterift/playermodels/skaterift_fbi/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_fbi/addon.kv b/content_skaterift/playermodels/skaterift_fbi/addon.kv new file mode 100644 index 0000000..6d8e89a --- /dev/null +++ b/content_skaterift/playermodels/skaterift_fbi/addon.kv @@ -0,0 +1,8 @@ +workshop +{ + title "FBI" + author "Skate Rift" +} + +content ch_fbi.mdl +flags HIDDEN diff --git a/content_skaterift/playermodels/skaterift_fbi2/addon.inf b/content_skaterift/playermodels/skaterift_fbi2/addon.inf deleted file mode 100644 index 0705e5d..0000000 Binary files a/content_skaterift/playermodels/skaterift_fbi2/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_fbi2/addon.kv b/content_skaterift/playermodels/skaterift_fbi2/addon.kv new file mode 100644 index 0000000..c3c0288 --- /dev/null +++ b/content_skaterift/playermodels/skaterift_fbi2/addon.kv @@ -0,0 +1,8 @@ +workshop +{ + title "FBI2" + author "Skate Rift" +} + +content ch_fbi2.mdl +flags HIDDEN diff --git a/content_skaterift/playermodels/skaterift_j/addon.inf b/content_skaterift/playermodels/skaterift_j/addon.inf deleted file mode 100644 index 9e372d1..0000000 Binary files a/content_skaterift/playermodels/skaterift_j/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_jesus/addon.inf b/content_skaterift/playermodels/skaterift_jesus/addon.inf deleted file mode 100644 index 18e258c..0000000 Binary files a/content_skaterift/playermodels/skaterift_jesus/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_jesus/addon.kv b/content_skaterift/playermodels/skaterift_jesus/addon.kv new file mode 100644 index 0000000..b7fba83 --- /dev/null +++ b/content_skaterift/playermodels/skaterift_jesus/addon.kv @@ -0,0 +1,8 @@ +workshop +{ + title "Jesus" + author "Skate Rift" +} + +content ch_jesus.mdl +flags HIDDEN diff --git a/content_skaterift/playermodels/skaterift_john/addon.inf b/content_skaterift/playermodels/skaterift_john/addon.inf deleted file mode 100644 index 1a03b82..0000000 Binary files a/content_skaterift/playermodels/skaterift_john/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_john/addon.kv b/content_skaterift/playermodels/skaterift_john/addon.kv new file mode 100644 index 0000000..8646391 --- /dev/null +++ b/content_skaterift/playermodels/skaterift_john/addon.kv @@ -0,0 +1,8 @@ +workshop +{ + title "JC" + author "Skate Rift" +} + +content ch_john.mdl +flags HIDDEN diff --git a/content_skaterift/playermodels/skaterift_jordan/addon.inf b/content_skaterift/playermodels/skaterift_jordan/addon.inf deleted file mode 100644 index 513da41..0000000 Binary files a/content_skaterift/playermodels/skaterift_jordan/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_jordan/addon.kv b/content_skaterift/playermodels/skaterift_jordan/addon.kv new file mode 100644 index 0000000..be14a37 --- /dev/null +++ b/content_skaterift/playermodels/skaterift_jordan/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title "Jordan" + author "Skate Rift" +} + +content ch_jordan.mdl diff --git a/content_skaterift/playermodels/skaterift_new/addon.inf b/content_skaterift/playermodels/skaterift_new/addon.inf deleted file mode 100644 index 9a932a5..0000000 Binary files a/content_skaterift/playermodels/skaterift_new/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_new/addon.kv b/content_skaterift/playermodels/skaterift_new/addon.kv new file mode 100644 index 0000000..097375a --- /dev/null +++ b/content_skaterift/playermodels/skaterift_new/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title "De'folde" + author "Skate Rift" +} + +content ch_new.mdl diff --git a/content_skaterift/playermodels/skaterift_outlaw/addon.inf b/content_skaterift/playermodels/skaterift_outlaw/addon.inf deleted file mode 100644 index 49e9bec..0000000 Binary files a/content_skaterift/playermodels/skaterift_outlaw/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_outlaw/addon.kv b/content_skaterift/playermodels/skaterift_outlaw/addon.kv new file mode 100644 index 0000000..7a47e7f --- /dev/null +++ b/content_skaterift/playermodels/skaterift_outlaw/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title "Outlaw" + author "Skate Rift" +} + +content ch_outlaw.mdl diff --git a/content_skaterift/playermodels/skaterift_president/addon.inf b/content_skaterift/playermodels/skaterift_president/addon.inf deleted file mode 100644 index da72eec..0000000 Binary files a/content_skaterift/playermodels/skaterift_president/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_president/addon.kv b/content_skaterift/playermodels/skaterift_president/addon.kv new file mode 100644 index 0000000..6ce9f36 --- /dev/null +++ b/content_skaterift/playermodels/skaterift_president/addon.kv @@ -0,0 +1,8 @@ +workshop +{ + title "President" + author "Skate Rift" +} + +content ch_president.mdl +flags HIDDEN diff --git a/content_skaterift/playermodels/skaterift_pro/addon.inf b/content_skaterift/playermodels/skaterift_pro/addon.inf deleted file mode 100644 index 22f2c6a..0000000 Binary files a/content_skaterift/playermodels/skaterift_pro/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/skaterift_pro/addon.kv b/content_skaterift/playermodels/skaterift_pro/addon.kv new file mode 100644 index 0000000..46a5a86 --- /dev/null +++ b/content_skaterift/playermodels/skaterift_pro/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title "Pro" + author "Skate Rift" +} + +content ch_pro.mdl diff --git a/content_skaterift/playermodels/sr2t/addon.inf b/content_skaterift/playermodels/sr2t/addon.inf deleted file mode 100644 index 6d79c74..0000000 Binary files a/content_skaterift/playermodels/sr2t/addon.inf and /dev/null differ diff --git a/content_skaterift/playermodels/sr2t/addon.kv b/content_skaterift/playermodels/sr2t/addon.kv new file mode 100644 index 0000000..f866bf2 --- /dev/null +++ b/content_skaterift/playermodels/sr2t/addon.kv @@ -0,0 +1,7 @@ +workshop +{ + title "Custom" + author "Skate Rift" +} + +content ch_sr2t.mdl diff --git a/control_overlay.h.c0 b/control_overlay.h.c0 deleted file mode 100644 index 115fbfc..0000000 --- a/control_overlay.h.c0 +++ /dev/null @@ -1,111 +0,0 @@ - ov_carve_l = 0, - ov_y = 1, - ov_a = 2, - ov_b = 3, - ov_x = 4, - ov_ls = 5, - ov_key = 6, - ov_key_down = 7, - ov_shift = 8, - ov_shift_down = 9, - ov_space = 10, - ov_space_down = 11, - ov_text_jump = 12, - ov_jump_ind = 13, - ov_text_carve = 14, - ov_text_crouch = 15, - ov_stored_ind = 16, - ov_text_stored = 17, - ov_text_push = 18, - ov_text_left = 19, - ov_text_right = 20, - ov_text_manual = 21, - ov_text_front_flip = 22, - ov_text_back_flip = 23, - ov_text_w = 24, - ov_text_s = 25, - ov_text_shift = 26, - ov_text_grab = 27, - ov_key_fill = 28, - ov_shift_fill = 29, - ov_space_fill = 30, - ov_lmb = 31, - ov_rmb = 32, - ov_mouse = 33, - ov_text_shuvit = 34, - ov_text_kickflip = 35, - ov_text_treflip = 36, - ov_rmb_down = 37, - ov_lmb_down = 38, - ov_mouse_grabs = 39, - ov_text_walk = 40, - ov_text_back = 41, - ov_text_skate = 42, - ov_text_forward = 43, - ov_text_e = 44, - ov_text_glide = 45, - ov_text_walk_lwr = 46, - ov_text_camera = 47, - ov_text_run = 48, - ov_text_look = 49, - ov_text_rewind = 50, - ov_text_respawn = 51, - ov_ls_circ_walk = 52, - ov_rs_circ_look = 53, - ov_rs = 54, - ov_ls_circ_skate = 55, - ov_ls_circ_manual = 56, - ov_ls_circ_frontflip = 57, - ov_ls_circ_backflip = 58, - ov_rs_circ_grab = 59, - ov_lt = 60, - ov_lb = 61, - ov_carve_r = 62, - ov_lb_down = 63, - ov_rb = 64, - ov_rb_down = 65, - ov_lt_act = 66, - ov_rt = 67, - ov_rt_act = 68, - ov_lt_run = 69, - ov_rt_grab = 70, - ov_rt_crouch = 71, - ov_dpad = 72, - ov_text_dw_rewind = 73, - ov_text_a_shuvit = 74, - ov_text_b_kickflip = 75, - ov_text_x_treflip = 76, - ov_text_y_walk = 77, - ov_text_y_glide = 78, - ov_text_y_walk_lwr = 79, - ov_text_de_camera = 80, - ov_y_down = 81, - ov_a_down = 82, - ov_b_down = 83, - ov_x_down = 84, - ov_text_a_jump = 85, - ov_text_a_jump_mid = 86, - ov_text_b_push = 87, - ov_text_y_skate = 88, - ov_dpad_w = 89, - ov_dpad_n = 90, - ov_dpad_e = 91, - ov_dpad_s = 92, - ov_text_dn_respawn = 93, - ov_text_met_menu = 94, - ov_met_r = 95, - ov_met = 96, - ov_met_r_down = 97, - ov_met_l = 98, - ov_met_l_down = 99, - ov_text_menu = 100, - ov_key_menu = 101, - ov_key_menu_down = 102, - ov_y_ps = 103, - ov_a_ps = 104, - ov_b_ps = 105, - ov_x_ps = 106, - ov_y_down_ps = 107, - ov_a_down_ps = 108, - ov_b_down_ps = 109, - ov_x_down_ps = 110, diff --git a/shaders/common_scene.glsl b/shaders/common_scene.glsl index 76658f2..3978a27 100644 --- a/shaders/common_scene.glsl +++ b/shaders/common_scene.glsl @@ -19,8 +19,7 @@ float sdLine( vec3 p, vec3 a, vec3 b ) float compute_board_shadow() { // player shadow - float dist_to_player = max( 0.0, sdLine( aWorldCo, g_board_0.xyz, - g_board_1.xyz )-0.1 ); + float dist_to_player = max( 0.0, sdLine( aWorldCo, g_board_0.xyz, g_board_1.xyz )-0.1 ); float player_shadow = max( 1.0-dist_to_player*2.7, 0.0 ); player_shadow *= player_shadow*player_shadow*player_shadow; diff --git a/src/addon.c b/src/addon.c index c418032..0ed7edc 100644 --- a/src/addon.c +++ b/src/addon.c @@ -1,13 +1,3 @@ -#include "vg/vg_engine.h" -#include "vg/vg_io.h" -#include "vg/vg_loader.h" -#include "addon.h" -#include "addon_types.h" -#include "vg/vg_msg.h" -#include "vg/vg_steam2.h" -#include "workshop.h" -#include - struct _addon _addon; /* @@ -166,12 +156,29 @@ void addon_make_uid_cpart( addon_id id, char buf[ ADDON_UID_MAX ], char cpart[ A addon_reg *reg = addon_details(id); addon_alias *alias = ®->alias; - if( alias->steam_workshop_id ) - snprintf( buf, ADDON_UID_MAX, "sr%03d-steam-"PRINTF_U64"%s%s", alias->type, alias->steam_workshop_id, - cpart? ":": "", cpart? cpart: "" ); - else - snprintf( buf, ADDON_UID_MAX, "sr%03d-local-%s%s%s", alias->type, alias->folder, - cpart? ":": "", cpart? cpart: "" ); + vg_str str_alias; + vg_strnull( &str_alias, buf, ADDON_UID_MAX ); + vg_strcat( &str_alias, "sr" ); + vg_strcati64r( &str_alias, alias->type, 10, 3, '0' ); + + if( alias->steam_workshop_id ) + { + vg_strcat( &str_alias, "-steam-" ); + vg_strcatu64( &str_alias, alias->steam_workshop_id, 10 ); + } + else + { + vg_strcat( &str_alias, "-local-" ); + vg_strcat( &str_alias, alias->folder ); + } + + if( cpart ) + { + vg_strcat( &str_alias, ":" ); + vg_strcat( &str_alias, cpart ); + } + + VG_ASSERT( vg_strgood( &str_alias ) ); } else buf[0] = '\0'; @@ -305,12 +312,10 @@ bool addon_parse_uid( const char *uid, addon_alias *alias ) return 1; } -void addon_system_init( void ) +VG_API void _addon_system_init(void) { - THREAD_1; - u32 reg_size = sizeof(addon_reg)*ADDON_MOUNTED_MAX; - _addon.registry = vg_stack_allocate( &vg.rtmem, reg_size, 8, "Addon Registry" ); + _addon.registry = vg_stack_allocate( NULL, reg_size, 8, "Addon Registry" ); for( u32 type=0; typecache_count; - cache->entries = vg_stack_allocate( &vg.rtmem, alloc_size, 8, "Cache entries" ); - memset( cache->entries, 0, alloc_size ); - vg_pool_init( &cache->pool, &cache->pool_unreferenced, inf->cache_count, &vg.rtmem ); + cache->entries = vg_stack_allocate( NULL, alloc_size, 8, "Cache entries" ); + vg_zero_mem( cache->entries, alloc_size ); + vg_pool_init( &cache->pool, &cache->pool_unreferenced, inf->cache_count, NULL ); /* create the real memory */ u32 cache_size = inf->cache_stride*inf->cache_count; - cache->items = vg_stack_allocate( &vg.rtmem, cache_size, 8, "Cache data" ); + cache->items = vg_stack_allocate( NULL, cache_size, 8, "Cache data" ); cache->stride = inf->cache_stride; - memset( cache->items, 0, cache_size ); + vg_zero_mem( cache->items, cache_size ); for( i32 j=0; jcache_count; j++ ) { @@ -337,9 +342,7 @@ void addon_system_init( void ) entry->addon_id = 0; if( inf->item_arena_size ) - entry->item_arena = vg_stack_make_substack( &vg.rtmem, inf->item_arena_size, "Addon item arena" ); - else - entry->item_arena = NULL; + vg_stack_init( &entry->item_arena, NULL, inf->item_arena_size, "Addon item arena" ); } } } @@ -347,38 +350,43 @@ void addon_system_init( void ) static bool addon_try_load_metadata( addon_reg *reg, const char *folder_path ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); VG_ASSERT( reg ); char path_buf[ 4096 ]; vg_str meta_path; vg_strnull( &meta_path, path_buf, sizeof(path_buf) ); vg_strcat( &meta_path, folder_path ); - vg_strcat( &meta_path, "/addon.inf" ); - + vg_strcat( &meta_path, "/addon.kv" ); if( !vg_strgood( &meta_path ) ) { vg_error( "The metadata path is too long\n" ); return 0; } - FILE *fp = fopen( meta_path.buffer, "rb" ); - if( !fp ) - { - vg_error( "Could not open the '%s'\n", meta_path.buffer ); - return 0; - } + vg_kv_parser parser; + vg_kv_parser_init( &parser, ®->metadata, 0 ); - reg->metadata_len = fread( reg->metadata, 1, 512, fp ); - if( !feof(fp) ) + vg_stream file; + if( vg_file_stream_open( &file, path_buf, VG_STREAM_READ ) ) { - fclose(fp); - vg_error( "Metadata too big\n" ); - return 0; + vg_kv_parse_stream( &parser, &file ); + vg_file_stream_close( &file ); + return 1; } - fclose(fp); + else + { + u32 size; + void *legacy_msg_buf = vg_file_read( NULL, path_buf, &size, 0 ); - return 1; + if( legacy_msg_buf ) + { + vg_kvs_append_from_legacy_msg2( ®->metadata, 0, legacy_msg_buf, size ); + vg_free( legacy_msg_buf ); + return 1; + } + else return 0; + } } static addon_id addon_alloc_reg( PublishedFileId_t workshop_id, enum addon_type type ) @@ -395,13 +403,15 @@ static addon_id addon_alloc_reg( PublishedFileId_t workshop_id, enum addon_type addon_reg *reg = &_addon.registry[ id-1 ]; reg->flags = 0; - reg->metadata_len = 0; reg->cache_id = 0; memset( ®->alias, 0, sizeof(addon_alias) ); reg->alias.steam_workshop_id = workshop_id; reg->alias.type = type; + vg_stack_init( ®->metadata_stack, NULL, VG_KB(8), "Addon metadata KV\n" ); + vg_kvs_init( ®->metadata, ®->metadata_stack ); + if( workshop_id ) { #if 0 @@ -437,7 +447,7 @@ static void addon_fail_allocation(void) */ addon_id _addon_mount_from_folder_path( const char *folder_path, enum addon_type type, const char *content_ext ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); u32 folder_name_length = 0; const char *folder_name = folder_path; @@ -480,11 +490,8 @@ addon_id _addon_mount_from_folder_path( const char *folder_path, enum addon_type bool loaded_metadata = addon_try_load_metadata( reg, folder_path ); if( loaded_metadata ) { - vg_msg msg; - vg_msg_init( &msg, reg->metadata, reg->metadata_len ); - u32 flags = 0x00; - vg_msg_getkvintg( &msg, "flags", k_vg_msg_u32, &flags, NULL ); + vg_kv_read_vu32( ®->metadata, 0, "flags", NULL, &flags, 1 ); reg->flags |= ADDON_REG_MOUNTED | flags; addon_complete_allocation(); return id; @@ -506,14 +513,9 @@ addon_id _addon_mount_from_folder_path( const char *folder_path, enum addon_type } /* create our own content commands */ - vg_msg msg; - vg_msg_init( &msg, reg->metadata, sizeof(reg->metadata) ); - vg_msg_frame( &msg, "workshop" ); - { - vg_msg_wkvstr( &msg, "title", reg->alias.folder ); - vg_msg_wkvstr( &msg, "author", "Custom Mod" ); - } - vg_msg_end_frame( &msg ); + u32 workshop_block = vg_kv_append( ®->metadata, 0, "workshop", NULL ); + vg_kv_append( ®->metadata, workshop_block, "title", reg->alias.folder ); + vg_kv_append( ®->metadata, workshop_block, "author", "Custom Mod" ); u32 content_count = 0; while( vg_dir_next_entry(&subdir) ) @@ -532,7 +534,8 @@ addon_id _addon_mount_from_folder_path( const char *folder_path, enum addon_type continue; if( strcmp( ext, content_ext ) ) continue; - vg_msg_wkvstr( &msg, "content", fname ); + + vg_kv_append( ®->metadata, 0, "content", fname ); content_count ++; } } @@ -544,25 +547,15 @@ addon_id _addon_mount_from_folder_path( const char *folder_path, enum addon_type return 0; } - if( msg.error == k_vg_msg_error_OK ) - { - reg->metadata_len = msg.cur.co; - reg->flags |= ADDON_REG_MOUNTED; - addon_complete_allocation(); - return id; - } - else - { - vg_error( "Error creating metadata: %d\n", msg.error ); - addon_fail_allocation(); - return 0; - } + reg->flags |= ADDON_REG_MOUNTED; + addon_complete_allocation(); + return id; } } void _addon_mount_content_folder( enum addon_type type, const char *base_folder, const char *content_ext ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); vg_info( "Mounting addons(type:%d) matching skaterift/%s/*/*%s\n", type, base_folder, content_ext ); @@ -609,19 +602,17 @@ void _addon_mount_content_folder( enum addon_type type, const char *base_folder, struct workshop_mount_info { u64 workshop_id; - char path[]; + c8 path[4096]; }; -static void workshop_mount_task( vg_async_task *task ) +static void workshop_mount_task( struct workshop_mount_info *in_args ) { - THREAD_1; - struct workshop_mount_info *info = (void *)task->data; - - addon_id id = addon_alloc_reg( info->workshop_id, k_addon_type_none ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + addon_id id = addon_alloc_reg( in_args->workshop_id, k_addon_type_none ); if( !id ) return; addon_reg *reg = &_addon.registry[ id-1 ]; - bool loaded_metadata = addon_try_load_metadata( reg, info->path ); + bool loaded_metadata = addon_try_load_metadata( reg, in_args->path ); if( !loaded_metadata ) { @@ -629,12 +620,11 @@ static void workshop_mount_task( vg_async_task *task ) return; } - enum addon_type type = k_addon_type_none; - vg_msg msg; - vg_msg_init( &msg, reg->metadata, reg->metadata_len ); + u32 type = k_addon_type_none; - if( vg_msg_seekframe( &msg, "workshop" )) - vg_msg_getkvintg( &msg, "type", k_vg_msg_u32, &type, NULL ); + u32 workshop_block = vg_kv_find( ®->metadata, 0, "workshop" ); + if( workshop_block ) + vg_kv_read_vu32( ®->metadata, workshop_block, "type", NULL, &type, 1 ); if( type == k_addon_type_none ) { @@ -648,52 +638,11 @@ static void workshop_mount_task( vg_async_task *task ) addon_complete_allocation(); } -struct workshop_scan_info -{ - enum workshop_scan_state - { - k_workshop_scan_state_filter_mounted, - k_workshop_scan_state_mount - } - state; - - u32 count; - PublishedFileId_t workshop_ids[ ADDON_MOUNTED_MAX ]; -}; -static void workshop_scan_t1( vg_async_task *co_task ) -{ - THREAD_1; - struct workshop_scan_info *co_info = (void *)co_task->data; - - if( co_info->state == k_workshop_scan_state_filter_mounted ) - { - vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct workshop_scan_info), 1 ); - struct workshop_scan_info *info = (void *)task->data; - info->state = k_workshop_scan_state_mount; - - u32 send_count = 0; - for( u32 i=0; icount; i ++ ) - { - for( u32 j=0; j<_addon.registry_count; j ++ ) - { - if( _addon.registry[j].alias.steam_workshop_id == co_info->workshop_ids[i] ) - goto s1; - } - - info->workshop_ids[ send_count ++ ] = co_info->workshop_ids[i]; -s1:; - } - - info->count = send_count; - vg_async_task_dispatch( task, _mount_workshop_addons ); - } -} - -void _mount_workshop_addons( vg_async_task *co_task ) +VG_API void _mount_workshop_addons(void) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); - if( g_client.demo_mode ) + if( _is_running_demo() ) { vg_info( "Won't load workshop items in demo mode\n" ); return; @@ -702,58 +651,48 @@ void _mount_workshop_addons( vg_async_task *co_task ) if( _steam_api.disabled ) return; - if( !co_task ) - { - vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct workshop_scan_info), 1 ); - struct workshop_scan_info *info = (void *)task->data; - info->state = k_workshop_scan_state_filter_mounted; - u32 count = SteamAPI_ISteamUGC_GetSubscribedItems( _steam_api.pSteamUGC, info->workshop_ids, ADDON_MOUNTED_MAX, 0 ); - vg_info( "Found %u subscribed items\n", count ); + PublishedFileId_t workshop_ids[ ADDON_MOUNTED_MAX ]; + u32 count = SteamAPI_ISteamUGC_GetSubscribedItems( _steam_api.pSteamUGC, workshop_ids, ADDON_MOUNTED_MAX, 0 ); + vg_info( "Found %u subscribed items\n", count ); - u32 send_count = 0; + for( u32 i=0; iworkshop_ids[i] ); - if( !(state & k_EItemStateInstalled) ) - continue; - - info->workshop_ids[ send_count ++ ] = info->workshop_ids[i]; + if( _addon.registry[j].alias.steam_workshop_id == workshop_ids[i] ) + { + mounted = 1; + break; + } } - - info->count = send_count; - vg_async_task_dispatch( task, workshop_scan_t1 ); - } - else - { - struct workshop_scan_info *co_info = (void *)co_task->data; - for( u32 i=0; icount; i ++ ) + + if( !mounted ) { - char path[ 4096 ]; - + struct workshop_mount_info *out_args = _vg_async_alloc(VG_THREAD_ASYNC_ID, sizeof(struct workshop_mount_info)); + out_args->workshop_id = workshop_ids[i]; u64 _size; u32 _ts; - if( !SteamAPI_ISteamUGC_GetItemInstallInfo( _steam_api.pSteamUGC, co_info->workshop_ids[i], - &_size, path, sizeof(path), &_ts )) + if( !SteamAPI_ISteamUGC_GetItemInstallInfo( _steam_api.pSteamUGC, workshop_ids[i], + &_size, out_args->path, sizeof(out_args->path), &_ts )) { - vg_error( "GetItemInstallInfo failed for addon %lu\n", co_info->workshop_ids[i] ); + vg_error( "GetItemInstallInfo failed for addon %lu\n", workshop_ids[i] ); continue; } - - u32 len = strlen( path ); - vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct workshop_mount_info)+len+1, 1 ); - struct workshop_mount_info *info = (void *)task->data; - strcpy( info->path, path ); - info->workshop_id = co_info->workshop_ids[i]; - vg_async_task_dispatch( task, workshop_mount_task ); + _vg_async_send( out_args, (vg_async_fn)workshop_mount_task ); } } } bool addon_get_content_folder( addon_id addon_id, vg_str *folder ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); VG_ASSERT( addon_id ); addon_reg *reg = addon_details( addon_id ); @@ -768,7 +707,7 @@ bool addon_get_content_folder( addon_id addon_id, vg_str *folder ) return 0; } - folder->i = strlen( folder->buffer ); + folder->i = vg_strlen( folder->buffer ); return 1; } else @@ -789,41 +728,36 @@ struct cache_complete_info addon_cache_id cache_id; enum addon_cache_state result_state; }; -static void cache_load_complete( vg_async_task *task ) +static void cache_load_complete( struct cache_complete_info *in_args ) { - THREAD_0; - struct cache_complete_info *info = (void *)task->data; - struct addon_cache *cache = &_addon.cache[info->type]; - cache->entries[ vg_pool_index( &cache->pool, info->cache_id ) ].state = info->result_state; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + struct addon_cache *cache = &_addon.cache[in_args->type]; + cache->entries[ vg_pool_index( &cache->pool, in_args->cache_id ) ].state = in_args->result_state; } struct cache_load_info { enum addon_type type; addon_cache_id cache_id; - - char path[]; + char path[4096]; }; -static void cache_load_task( vg_async_task *task ) +static void cache_load_task( struct cache_load_info *in_args ) { - THREAD_1; - struct cache_load_info *info = (void *)task->data; - addon_cache_entry *cache_entry = get_addon_cache_entry( info->type, info->cache_id ); - vg_info( "process cache load request (%u#%u): %s\n", info->type, info->cache_id, info->path ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + addon_cache_entry *cache_entry = get_addon_cache_entry( in_args->type, in_args->cache_id ); + vg_info( "process cache load request (%u#%u): %s\n", in_args->type, in_args->cache_id, in_args->path ); + + enum addon_cache_state result_state = k_addon_cache_state_errored; /* load content files * --------------------------------- */ char path_buf[4096]; vg_str content_path; vg_strnull( &content_path, path_buf, sizeof(path_buf) ); - vg_strcat( &content_path, info->path ); + vg_strcat( &content_path, in_args->path ); addon_reg *reg = addon_details( cache_entry->addon_id ); - vg_msg msg; - vg_msg_init( &msg, reg->metadata, reg->metadata_len ); - enum addon_cache_state result_state = k_addon_cache_state_errored; - - const char *kv_content = vg_msg_getkvstr( &msg, "content" ); + const c8 *kv_content = vg_kv_value( ®->metadata, vg_kv_find( ®->metadata, 0, "content" ), NULL ); if( kv_content ) { vg_strcat( &content_path, "/" ); @@ -840,30 +774,29 @@ static void cache_load_task( vg_async_task *task ) vg_error( " Metadata path too long\n" ); goto e0; } - - vg_stack_allocator *arena = cache_entry->item_arena; - if( info->type == k_addon_type_board ) + + vg_stack_allocator *arena = &cache_entry->item_arena; + if( in_args->type == k_addon_type_board ) { - struct player_board *board = addon_cache_item_data( info->type, info->cache_id, 0 ); + struct player_board *board = addon_cache_item_data( in_args->type, in_args->cache_id, 0 ); vg_stack_clear( arena ); player_board_load( board, content_path.buffer, arena ); result_state = k_addon_cache_state_loaded; } - else if( info->type == k_addon_type_player ) + else if( in_args->type == k_addon_type_player ) { - struct player_model *model = addon_cache_item_data( info->type, info->cache_id, 0 ); + struct player_model *model = addon_cache_item_data( in_args->type, in_args->cache_id, 0 ); vg_stack_clear( arena ); player_model_load( model, content_path.buffer, arena ); result_state = k_addon_cache_state_loaded; } e0:; - vg_async_task *res_task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct cache_complete_info), 1 ); - struct cache_complete_info *complete_info = (void *)res_task->data; - complete_info->type = info->type; - complete_info->cache_id = info->cache_id; - complete_info->result_state = result_state; - vg_async_task_dispatch( res_task, cache_load_complete ); + struct cache_complete_info *out_args = _vg_async_alloc( VG_THREAD_MAIN_ID, sizeof(struct cache_complete_info) ); + out_args->type = in_args->type; + out_args->cache_id = in_args->cache_id; + out_args->result_state = result_state; + _vg_async_send( out_args, (vg_async_fn)cache_load_complete ); } /* @@ -882,25 +815,22 @@ void _addon_system_pre_update(void) addon_cache_entry *entry = &cache->entries[ vg_pool_index( &cache->pool, id ) ]; if( entry->state == k_addon_cache_state_load_request ) { - char path_buf[4096]; + struct cache_load_info *out_args = _vg_async_alloc( VG_THREAD_ASYNC_ID, sizeof(struct cache_load_info) ); vg_str folder; - vg_strnull( &folder, path_buf, 4096 ); + vg_strnull( &folder, out_args->path, sizeof(out_args->path) ); + if( !addon_get_content_folder( entry->addon_id, &folder ) ) { + _vg_async_send( out_args, NULL ); entry->state = k_addon_cache_state_errored; continue; } - u32 len = strlen( path_buf ) + 1; - vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct cache_load_info) + len, 1 ); - struct cache_load_info *info = (void *)task->data; - - info->type = type; - info->cache_id = id; - strcpy( info->path, path_buf ); - + out_args->type = type; + out_args->cache_id = id; entry->state = k_addon_cache_state_loading; - vg_async_task_dispatch( task, cache_load_task ); + _vg_async_send( out_args, (vg_async_fn)cache_load_task ); + } id = vg_pool_next( &cache->pool, id, 0 ); } @@ -927,7 +857,7 @@ void *addon_cache_item_data( enum addon_type type, addon_cache_id cache_id, bool addon_cache_id addon_cache_create_viewer( enum addon_type type, addon_id addon_id ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); if( !addon_id ) return 0; @@ -993,7 +923,7 @@ addon_id addon_get_from_uid( enum addon_type type, const char uid[ADDON_UID_MAX] addon_cache_id addon_cache_create_viewer_from_uid( enum addon_type type, const char uid[ADDON_UID_MAX] ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); addon_id id = addon_get_from_uid( type, uid ); if( id ) @@ -1007,7 +937,7 @@ addon_cache_id addon_cache_create_viewer_from_uid( enum addon_type type, const c void addon_cache_watch( enum addon_type type, addon_cache_id cache_id ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); if( !cache_id ) return; @@ -1019,7 +949,7 @@ void addon_cache_watch( enum addon_type type, addon_cache_id cache_id ) void addon_cache_unwatch( enum addon_type type, addon_cache_id cache_id ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); if( !cache_id ) return; diff --git a/src/addon.h b/src/addon.h index 901e667..f3da438 100644 --- a/src/addon.h +++ b/src/addon.h @@ -1,9 +1,6 @@ -#pragma once -#include "vg/vg_steam2.h" -#include "vg/vg_mem_pool.h" -#include "vg/vg_string.h" -#include "addon_types.h" -#include "vg/vg_mutex.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/addon.c" +#else typedef struct addon_reg addon_reg; typedef struct addon_cache_entry addon_cache_entry; @@ -25,8 +22,9 @@ struct _addon addon_alias alias; u32 alias_hash; - u8 metadata[512]; /* vg_msg buffer */ - u32 metadata_len; + vg_stack_allocator metadata_stack; + vg_kvs metadata; + u32 flags; addon_cache_id cache_id; } @@ -50,7 +48,7 @@ struct _addon state; char local_cpart[ ADDON_CPART_MAX ]; - vg_stack_allocator *item_arena; + vg_stack_allocator item_arena; } *entries; vg_pool pool; @@ -63,7 +61,7 @@ struct _addon } extern _addon; -void addon_system_init( void ); +VG_API void _addon_system_init(void); addon_reg *addon_details( addon_id id ); u32 _addon_filtered_count( enum addon_type type, u32 whitelist, u32 blacklist ); @@ -84,7 +82,7 @@ bool addon_get_content_folder( addon_id addon_id, vg_str *folder ); addon_id _addon_mount_from_folder_path( const char *folder, enum addon_type type, const char *content_ext ); void _addon_mount_content_folder( enum addon_type type, const char *base_folder, const char *content_ext ); -void _mount_workshop_addons( vg_async_task *co_task ); +VG_API void _mount_workshop_addons(void); void _addon_system_pre_update(void); addon_id addon_get_from_uid( enum addon_type type, const char uid[ADDON_UID_MAX] ); @@ -94,3 +92,5 @@ void addon_cache_watch( enum addon_type type, addon_cache_id cache_id ); void addon_cache_unwatch( enum addon_type type, addon_cache_id cache_id ); void *addon_cache_item_data( enum addon_type type, addon_cache_id cache_id, bool only_if_loaded ); addon_cache_entry *get_addon_cache_entry( enum addon_type type, u16 cache_id ); + +#endif diff --git a/src/addon_types.c b/src/addon_types.c index 32186ad..b392de5 100644 --- a/src/addon_types.c +++ b/src/addon_types.c @@ -1,7 +1,3 @@ -#include "player.h" -#include "player_render.h" -#include "player_api.h" - struct addon_type_info addon_type_infos[] = { [k_addon_type_board] = { diff --git a/src/addon_types.h b/src/addon_types.h index e54fc74..df05d09 100644 --- a/src/addon_types.h +++ b/src/addon_types.h @@ -1,4 +1,6 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/addon_types.c" +#else enum addon_type{ k_addon_type_none = 0, @@ -44,3 +46,4 @@ struct addon_type_info extern addon_type_infos[]; #endif +#endif diff --git a/src/array_file.c b/src/array_file.c index f97988e..7b0a63a 100644 --- a/src/array_file.c +++ b/src/array_file.c @@ -1,90 +1,55 @@ -#include "array_file.h" -#include - -u32 af_str_hash( array_file_context *af, u32 pstr ) +VG_TIER_0 u32 af_str_hash( const void *packed_strings, u32 pstr ) { if( pstr & 0x3 ) vg_fatal_error( "ALIGNMENT ERROR (%u)\n", pstr ); - - return *((u32 *)(af->strings + pstr)); + return *((u32 *)(packed_strings + pstr)); } -const char *af_str( array_file_context *af, u32 pstr ) +VG_TIER_0 const c8 *af_str( const void *packed_strings, u32 pstr ) { - return af->strings + pstr + 4; + return packed_strings + pstr + 4; } -bool af_str_eq( array_file_context *af, u32 pstr, const char *str, u32 str_hash ) +VG_TIER_0 bool af_str_eq( const void *packed_strings, u32 pstr, const c8 *str, u32 str_hash ) { - if( af_str_hash( af, pstr ) == str_hash ) - if( !strcmp( str, af_str( af, pstr ))) + if( af_str_hash( packed_strings, pstr ) == str_hash ) + if( !strcmp( str, af_str( packed_strings, pstr ))) return 1; return 0; } -static void af_load_array_file_buffer( array_file_context *ctx, array_file_meta *arr, void *buffer, u32 stride ) +VG_TIER_0 void af_load_array_file_buffer( array_file_context *ctx, array_file_meta *arr, void *buffer, u32 stride ) { if( arr->item_count ) { - fseek( ctx->fp, arr->file_offset, SEEK_SET ); - - if( stride == arr->item_size ) - { - u64 l = fread( buffer, arr->item_size*arr->item_count, 1, ctx->fp ); - if( l != 1 ) - { - vg_file_error_info( ctx->fp ); - fclose( ctx->fp ); - vg_fatal_error( "AF file buffer error\n" ); - } - } - else + vg_zero_mem( buffer, stride*arr->item_count ); + u32 read_size = VG_MIN( stride, arr->item_size ); + for( u32 i=0; iitem_count; i++ ) { - vg_warn( "Applying alignment fixup to array '%s' [%u -> %u] x %u\n", - arr->name, arr->item_size, stride, arr->item_count ); - - if( stride > arr->item_size ) - memset( buffer, 0, stride*arr->item_count ); - - u32 read_size = VG_MIN( stride, arr->item_size ); - - for( u32 i=0; iitem_count; i++ ) - { - u64 l = fread( buffer+i*stride, read_size, 1, ctx->fp ); - if( stride < arr->item_size ) - fseek( ctx->fp, arr->item_size - stride, SEEK_CUR ); - - if( l != 1 ) - { - vg_file_error_info( ctx->fp ); - fclose( ctx->fp ); - vg_fatal_error( "AF read arror\n" ); - } - } + vg_stream_seek( ctx->stream, arr->file_offset + i*arr->item_size ); + vg_stream_read( ctx->stream, buffer+i*stride, read_size ); } } } -void af_load_array_file( array_file_context *ctx, array_file_ptr *out_ptr, - array_file_meta *arr, vg_stack_allocator *stack, u32 stride ) +VG_TIER_1 void af_load_array_file( array_file_context *ctx, array_file_ptr *out_ptr, + array_file_meta *arr, vg_stack_allocator *stack, u32 stride ) { if( arr->item_count ) { u32 size = stride*arr->item_count; - out_ptr->data = stack? vg_stack_allocate( stack, size, 8, NULL ): malloc( size ); + out_ptr->data = vg_stack_allocate( stack, size, 8, NULL ); af_load_array_file_buffer( ctx, arr, out_ptr->data, stride ); } else - { out_ptr->data = NULL; - } out_ptr->stride = stride; out_ptr->count = arr->item_count; } -void *af_arritm( array_file_ptr *arr, u32 index ) +VG_TIER_0 void *af_arritm( array_file_ptr *arr, u32 index ) { if( index >= arr->count ) vg_fatal_error( "Index out of range (%u >= %u)\n", index, arr->count ); @@ -92,12 +57,12 @@ void *af_arritm( array_file_ptr *arr, u32 index ) return ((u8 *)arr->data) + index*arr->stride; } -u32 af_arrcount( array_file_ptr *arr ) +VG_TIER_0 u32 af_arrcount( array_file_ptr *arr ) { return arr->count; } -array_file_meta *af_find_array( array_file_context *ctx, const char *name ) +VG_TIER_0 array_file_meta *af_find_array( array_file_context *ctx, const c8 *name ) { for( u32 i=0; iindex); i++ ) { @@ -110,7 +75,8 @@ array_file_meta *af_find_array( array_file_context *ctx, const char *name ) return NULL; } -int af_load_array( array_file_context *ctx, array_file_ptr *ptr, const char *name, vg_stack_allocator *stack, u32 stride ) +VG_TIER_1 bool af_load_array( array_file_context *ctx, array_file_ptr *ptr, const c8 *name, + vg_stack_allocator *stack, u32 stride ) { array_file_meta *arr = af_find_array( ctx, name ); @@ -128,45 +94,30 @@ int af_load_array( array_file_context *ctx, array_file_ptr *ptr, const char *nam } } -void af_open( array_file_context *ctx, const char *path, u32 min_version, u32 max_version, vg_stack_allocator *stack ) +VG_TIER_1 bool af_open_stream( array_file_context *afc, vg_stream *stream, u32 min_version, u32 max_version, + vg_stack_allocator *stack ) { - ctx->fp = fopen( path, "rb" ); - if( !ctx->fp ) - vg_fatal_error( "open('%s'): %s\n", path, strerror(errno) ); - - u64 l = fread( &ctx->header, sizeof(array_file_header), 1, ctx->fp ); - if( l != 1 ) + afc->stream = stream; + if( vg_stream_read( stream, &afc->header, sizeof(array_file_header)) != sizeof(array_file_header) ) { - fclose( ctx->fp ); - vg_fatal_error( "Array file corrupt\n" ); + vg_error( "Array file not large enough to contain header.\n" ); + return 0; } - if( ctx->header.version < min_version || ctx->header.version > max_version ) + if( (afc->header.version < min_version) || (afc->header.version > max_version) ) { - vg_info( "Legacy model version incompatable" ); - vg_info( "For model: %s\n", path ); - vg_info( " version: %u (min: %u, max: %u)\n", - ctx->header.version, min_version, max_version ); - fclose( ctx->fp ); - vg_fatal_error( "Legacy\n" ); + vg_error( "Array file version out of range\n" ); + vg_error( " version: %u (min: %u, max: %u)\n", afc->header.version, min_version, max_version ); + return 0; } - af_load_array_file( ctx, &ctx->index, &ctx->header.index, stack, sizeof(array_file_meta) ); - - array_file_ptr strings; - af_load_array( ctx, &strings, "strings", stack, 1 ); - ctx->strings = strings.data; -} - -void af_close( array_file_context *ctx ) -{ - fclose( ctx->fp ); - ctx->fp = NULL; + af_load_array_file( afc, &afc->index, &afc->header.index, stack, sizeof(array_file_meta) ); + return 1; } /* compiler * ---------------------------------------------------------------------- */ - +#if defined( VG_ENGINE ) struct af_compiler_iter { u32 i, j; @@ -210,7 +161,7 @@ static bool af_next( struct af_compiler_iter *iter ) af_compiler_item *af_compiler_allocate_items( af_compiler *compiler, af_compiler_index *index, u32 count ) { - af_compiler_item *entry = VG_STACK_ALLOCATE_STRUCT( compiler->stack, af_compiler_item ); + af_compiler_item *entry = vg_stack_allocate( compiler->stack, sizeof(af_compiler_item), 1, "Compiler item" ); entry->next = NULL; u32 data_size = count * index->element_size; @@ -276,7 +227,7 @@ static void af_write_bin( af_compiler *compiler, void *data, u32 data_len, u32 p { if( data ) { - fwrite( data, data_len, 1, compiler->fp ); + vg_stream_write( &compiler->stream, data, data_len ); compiler->file_offset += data_len; } @@ -285,7 +236,7 @@ static void af_write_bin( af_compiler *compiler, void *data, u32 data_len, u32 p while( compiler->file_offset % padding ) { const u8 pad_byte = 0xac; - fwrite( &pad_byte, 1, 1, compiler->fp ); + vg_stream_write( &compiler->stream, &pad_byte, 1 ); compiler->file_offset ++; } } @@ -324,9 +275,8 @@ bool af_write( af_compiler *compiler, const char *path, u32 version ) u32 header_size = vg_align8( sizeof( array_file_header ) ); u32 index_size = vg_align8( sizeof( array_file_meta ) * indices_to_write ); - - compiler->fp = fopen( path, "wb" ); - if( !compiler->fp ) + + if( !vg_file_stream_open( &compiler->stream, path, VG_STREAM_WRITE ) ) return 0; compiler->file_offset = 0; @@ -377,6 +327,7 @@ bool af_write( af_compiler *compiler, const char *path, u32 version ) } } - fclose( compiler->fp ); + vg_file_stream_close( &compiler->stream ); return 1; } +#endif diff --git a/src/array_file.h b/src/array_file.h index f67337f..7c6d1d2 100644 --- a/src/array_file.h +++ b/src/array_file.h @@ -1,5 +1,6 @@ -#pragma once -#include "vg_mem.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/array_file.c" +#else typedef struct array_file_ptr array_file_ptr; typedef struct array_file_meta array_file_meta; @@ -28,20 +29,19 @@ struct array_file_header struct array_file_context { - FILE *fp; + vg_stream *stream; array_file_header header; array_file_ptr index; - const void *strings; }; -void af_open( array_file_context *ctx, const char *path, u32 min_version, u32 max_version, vg_stack_allocator *stack ); -void af_close( array_file_context *ctx ); - /* array loading */ -array_file_meta *af_find_array( array_file_context *ctx, const char *name ); -void af_load_array_file( array_file_context *ctx, array_file_ptr *out_ptr, - array_file_meta *arr, vg_stack_allocator *stack, u32 stride ); -int af_load_array( array_file_context *ctx, array_file_ptr *ptr, const char *name, vg_stack_allocator *stack, u32 stride ); +VG_TIER_0 array_file_meta *af_find_array( array_file_context *ctx, const c8 *name ); + + +VG_TIER_1 void af_load_array_file( array_file_context *ctx, array_file_ptr *out_ptr, + array_file_meta *arr, vg_stack_allocator *stack, u32 stride ); +VG_TIER_1 bool af_load_array( array_file_context *ctx, array_file_ptr *ptr, const char *name, vg_stack_allocator *stack, u32 stride ); +VG_TIER_0 void af_load_array_file_buffer( array_file_context *ctx, array_file_meta *arr, void *buffer, u32 stride ); #define AF_LOAD_ARRAY_STRUCT( CTX, PTR, STRUCT, STACK ) \ af_load_array( CTX, PTR, #STRUCT, STACK, sizeof(STRUCT) ) @@ -51,9 +51,9 @@ void *af_arritm( array_file_ptr *arr, u32 index ); u32 af_arrcount( array_file_ptr *arr ); /* packed string buffer access (with djb2 hash prefix) */ -const char *af_str( array_file_context *af, u32 pstr ); -u32 af_str_hash( array_file_context *af, u32 pstr ); -bool af_str_eq( array_file_context *af, u32 pstr, const char *str, u32 str_hash ); +VG_TIER_0 const c8 *af_str( const void *packed_strings, u32 pstr ); +VG_TIER_0 u32 af_str_hash( const void *packed_strings, u32 pstr ); +VG_TIER_0 bool af_str_eq( const void *packed_strings, u32 pstr, const char *str, u32 str_hash ); #define AF_STR_EQ( CTX, PSTR, CONSTR ) \ af_str_eq( CTX, PSTR, CONSTR, vg_strdjb2( CONSTR ) ) @@ -61,7 +61,7 @@ bool af_str_eq( array_file_context *af, u32 pstr, const char *str, u32 str_hash /* COmpiler * ------------------------------------ */ - +#if defined( VG_ENGINE ) typedef struct af_compiler af_compiler; typedef struct af_compiler_item af_compiler_item; typedef struct af_compiler_index af_compiler_index; @@ -90,7 +90,7 @@ struct af_compiler af_compiler_item *most_recent_item; - FILE *fp; + vg_stream stream; u32 file_offset; }; @@ -100,3 +100,5 @@ af_compiler_index *af_compiler_create_index( af_compiler *compiler, const char * bool af_write( af_compiler *compiler, const char *path, u32 version ); af_compiler_index *af_get_or_make_index( af_compiler *compiler, const char *alias, u32 element_size ); u32 af_compile_string( af_compiler *compiler, const char *string ); +#endif +#endif diff --git a/src/audio.c b/src/audio.c index 8186c46..400df40 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1,7 +1,3 @@ -#include "world.h" -#include "audio.h" -#include "vg/vg_audio_dsp.h" - audio_clip audio_board[] = { { .path="sound/skate_hpf.ogg" }, @@ -186,29 +182,36 @@ static audio_clip air_synth = .any_data = &air_audio_data }; -void audio_init(void) +static void _audio_load_content_async( void *_, vg_async_info *async ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + + vg_audio_clip_loadn( audio_board, VG_ARRAY_LEN(audio_board), NULL ); + vg_audio_clip_loadn( audio_taps, VG_ARRAY_LEN(audio_taps), NULL ); + vg_audio_clip_loadn( audio_flips, VG_ARRAY_LEN(audio_flips), NULL ); + vg_audio_clip_loadn( audio_hits, VG_ARRAY_LEN(audio_hits), NULL ); + vg_audio_clip_loadn( &audio_splash, 1, NULL ); + vg_audio_clip_loadn( &audio_gate_pass, 1, NULL ); + vg_audio_clip_loadn( &audio_gate_lap, 1, NULL ); + vg_audio_clip_loadn( &audio_gate_ambient, 1, NULL ); + vg_audio_clip_loadn( &audio_wood_break, 1, NULL ); + vg_audio_clip_loadn( audio_jumps, VG_ARRAY_LEN(audio_jumps), NULL ); + vg_audio_clip_loadn( audio_lands, VG_ARRAY_LEN(audio_lands), NULL ); + vg_audio_clip_loadn( audio_water, VG_ARRAY_LEN(audio_water), NULL ); + vg_audio_clip_loadn( audio_grass, VG_ARRAY_LEN(audio_grass), NULL ); + vg_audio_clip_loadn( audio_footsteps, VG_ARRAY_LEN(audio_footsteps), NULL ); + vg_audio_clip_loadn( audio_footsteps_grass, VG_ARRAY_LEN(audio_footsteps_grass), NULL ); + vg_audio_clip_loadn( audio_footsteps_wood, VG_ARRAY_LEN(audio_footsteps_wood), NULL ); + vg_audio_clip_loadn( audio_rewind, VG_ARRAY_LEN(audio_rewind), NULL ); + vg_audio_clip_loadn( audio_ui, VG_ARRAY_LEN(audio_ui), NULL ); + vg_audio_clip_loadn( audio_challenge, VG_ARRAY_LEN(audio_challenge), NULL ); + vg_audio_clip_loadn( audio_gino, VG_ARRAY_LEN(audio_gino), NULL ); +} + +VG_API void _audio_init(void) { - audio_clip_loadn( audio_board, VG_ARRAY_LEN(audio_board), NULL ); - audio_clip_loadn( audio_taps, VG_ARRAY_LEN(audio_taps), NULL ); - audio_clip_loadn( audio_flips, VG_ARRAY_LEN(audio_flips), NULL ); - audio_clip_loadn( audio_hits, VG_ARRAY_LEN(audio_hits), NULL ); - audio_clip_loadn( &audio_splash, 1, NULL ); - audio_clip_loadn( &audio_gate_pass, 1, NULL ); - audio_clip_loadn( &audio_gate_lap, 1, NULL ); - audio_clip_loadn( &audio_gate_ambient, 1, NULL ); - audio_clip_loadn( &audio_wood_break, 1, NULL ); - - audio_clip_loadn( audio_jumps, VG_ARRAY_LEN(audio_jumps), NULL ); - audio_clip_loadn( audio_lands, VG_ARRAY_LEN(audio_lands), NULL ); - audio_clip_loadn( audio_water, VG_ARRAY_LEN(audio_water), NULL ); - audio_clip_loadn( audio_grass, VG_ARRAY_LEN(audio_grass), NULL ); - audio_clip_loadn( audio_footsteps, VG_ARRAY_LEN(audio_footsteps), NULL ); - audio_clip_loadn( audio_footsteps_grass, VG_ARRAY_LEN(audio_footsteps_grass), NULL ); - audio_clip_loadn( audio_footsteps_wood, VG_ARRAY_LEN(audio_footsteps_wood), NULL ); - audio_clip_loadn( audio_rewind, VG_ARRAY_LEN(audio_rewind), NULL ); - audio_clip_loadn( audio_ui, VG_ARRAY_LEN(audio_ui), NULL ); - audio_clip_loadn( audio_challenge, VG_ARRAY_LEN(audio_challenge), NULL ); - audio_clip_loadn( audio_gino, VG_ARRAY_LEN(audio_gino), NULL ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_audio_load_content_async ); vg_audio_lock(); air_audio_data.channel_id = vg_audio_get_first_idle_channel(); @@ -228,31 +231,3 @@ void audio_ambient_sprite_play( v3f co, audio_clip *clip ) } vg_audio_unlock(); } - -enum audio_sprite_type world_audio_sample_sprite_random(v3f origin, v3f output); -void audio_ambient_sprites_update( world_instance *world, v3f co ) -{ - static float accum = 0.0f; - accum += vg.time_delta; - - if( accum > 0.1f ) - accum -= 0.1f; - else return; - - v3f sprite_pos; - enum audio_sprite_type sprite_type = - world_audio_sample_sprite_random( co, sprite_pos ); - - if( sprite_type != k_audio_sprite_type_none ){ - if( sprite_type == k_audio_sprite_type_grass ){ - audio_ambient_sprite_play( sprite_pos, - &audio_grass[vg_randu32(&vg.rand)%4] ); - } - else if( sprite_type == k_audio_sprite_type_water ){ - if( world->water.enabled ){ - audio_ambient_sprite_play( sprite_pos, - &audio_water[vg_randu32(&vg.rand)%6] ); - } - } - } -} diff --git a/src/audio.h b/src/audio.h index 11eb136..7489ee5 100644 --- a/src/audio.h +++ b/src/audio.h @@ -1,13 +1,6 @@ -/* - * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#pragma once - -#include "vg/vg_engine.h" -#include "vg/vg_audio.h" -#include "vg/vg_audio_dsp.h" -#include "world.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/audio.c" +#else struct air_synth_data { f32 speed; @@ -22,12 +15,12 @@ struct air_synth_data { } extern air_audio_data; -void audio_init(void); +VG_API void _audio_init(void); void audio_ambient_sprite_play( v3f co, audio_clip *clip ); -void audio_ambient_sprites_update( world_instance *world, v3f co ); /* TODO(ASSETS): * Have these as asignable ID's and not a bunch of different arrays. + * TODO: Just marking here again because this still isn't fucking fixed */ extern audio_clip audio_board[]; extern audio_clip audio_taps[]; @@ -55,3 +48,5 @@ enum audio_sprite_type k_audio_sprite_type_grass, k_audio_sprite_type_water }; + +#endif diff --git a/src/board_maker.c b/src/board_maker.c index d5a894e..af92dd8 100644 --- a/src/board_maker.c +++ b/src/board_maker.c @@ -1,28 +1,5 @@ -#include "board_maker.h" -#include "shaders/workshop_compositor.h" -#include "vg/vg_ui/filebrowser.h" - struct _board_maker _board_maker = { - .compositor_fb = - { - .display_name = "Workshop Compositor texture", - .resolution_div = 0, - .fixed_w = 512, .fixed_h = 512, - .attachments = (vg_framebuffer_attachment[]) - { - { - .display_name = "RGBA", - .purpose = k_framebuffer_attachment_type_texture, - .quality = k_framebuffer_quality_all, - .internalformat = GL_RGBA, - .format = GL_RGBA, - .type = GL_UNSIGNED_BYTE, - .attachment = GL_COLOR_ATTACHMENT0 - } - }, - .attachment_count = 1 - } }; /* image loader thread @@ -34,9 +11,9 @@ struct board_maker_image_info i32 w, h; }; -static void _async_board_maker_image_finish( vg_async_task *task ) +static void _async_board_maker_image_finish( struct board_maker_image_info *in_args, vg_async_info *async ) { - struct board_maker_image_info *inf = (void *)task->data; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_OWNS_OPENGL ) ); struct board_maker_decal *decal = &_board_maker.decals[ _board_maker.ui_target_part ]; if( decal->loaded ) @@ -46,14 +23,13 @@ static void _async_board_maker_image_finish( vg_async_task *task ) glGenTextures( 1, &decal->texture ); glBindTexture( GL_TEXTURE_2D, decal->texture ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, inf->w, inf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, inf->data ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, in_args->w, in_args->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, in_args->data ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); glGenerateMipmap( GL_TEXTURE_2D ); - - stbi_image_free( inf->data ); + stbi_image_free( in_args->data ); _board_maker.state = k_board_maker_state_none; _board_maker.compositor_state = k_board_maker_compositor_dirty; @@ -61,19 +37,18 @@ static void _async_board_maker_image_finish( vg_async_task *task ) static void _board_maker_image_t1( void *userdata ) { - THREAD_1; - vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct board_maker_image_info), 1 ); - struct board_maker_image_info *info = (void *)task->data; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + struct board_maker_image_info *out_args = _vg_async_alloc( VG_THREAD_MAIN_ID, sizeof(struct board_maker_image_info)); i32 nc; stbi_set_flip_vertically_on_load(1); - info->data = stbi_load( _board_maker.browser->current_path, &info->w, &info->h, &nc, 4 ); - vg_async_task_dispatch( task, _async_board_maker_image_finish ); + out_args->data = stbi_load( _board_maker.browser->current_path, &out_args->w, &out_args->h, &nc, 4 ); + _vg_async_send( out_args, (vg_async_fn)_async_board_maker_image_finish ); } /* model loader thread * ----------------------------------------- */ -static void _async_board_maker_load_finish( void *userdata ) +static void _async_board_maker_load_finish( void *nothing, vg_async_info *async ) { _board_maker.state = k_board_maker_state_none; _board_maker.template_loaded = _board_maker.template_selection; @@ -81,7 +56,7 @@ static void _async_board_maker_load_finish( void *userdata ) _board_maker.base_shader = NULL; - mdl_context *mdl = &_board_maker.template_mdl; + vg_model *mdl = &_board_maker.template_mdl; if( mdl->version <= 105 ) return; @@ -92,7 +67,7 @@ static void _async_board_maker_load_finish( void *userdata ) if( mat0->shader != k_shader_workshop ) return; - _board_maker.base_shader = mat0->props.compiled; + _board_maker.base_shader = &mdl->shader_props[0]; } struct ui_enum_opt _board_maker_template_opts[] = @@ -109,38 +84,51 @@ const char *_board_maker_template_paths[] = [2] = "models/workshop/longboard.mdl" }; -static void _board_maker_load_template( void *_ ) +static void _board_maker_load_template( void *_, vg_async_info *async ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); vg_stack_clear( &_board_maker.template_stack ); - mdl_context *mdl = &_board_maker.template_mdl; - mdl_open( mdl, _board_maker_template_paths[_board_maker.template_selection], &_board_maker.template_stack ); - mdl_load_metadata_block( mdl, &_board_maker.template_stack ); + vg_model_stream_context ctx; + VG_ASSERT( vg_model_stream_open( &ctx, &_board_maker.template_mdl, + _board_maker_template_paths[_board_maker.template_selection] ) ); + vg_model_stream_metadata( &ctx, &_board_maker.template_stack ); /* we need this for compiling it back down */ - mdl_load_mesh_block( mdl, &_board_maker.template_stack ); - AF_LOAD_ARRAY_STRUCT( &mdl->af, &_board_maker.template_mdl_markers, ent_marker, &_board_maker.template_stack ); + vg_model_stream_meshes_cpu( &ctx, &_board_maker.template_stack ); + vg_model_stream_meshes_gpu( &ctx, NULL ); + vg_model_stream_textures_gpu( &ctx ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &_board_maker.template_mdl_markers, ent_marker, &_board_maker.template_stack ); + vg_model_stream_close( &ctx ); - mdl_async_full_load_std( mdl, NULL ); - mdl_close( mdl ); - vg_async_call( &vg.main_tasks, _async_board_maker_load_finish, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)_async_board_maker_load_finish ); } /* system init thread * ----------------------------------------------------- */ -static void _async_board_maker_init_finish( void *userdata ) +static void _board_maker_init_late(void) { - THREAD_0; - _board_maker.state = k_board_maker_state_none; -} + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + + _board_maker.compositor_fb = _vg_framebuffer_alloc( VG_STACK_USE_HEAP, 1, 0 ); + _board_maker.compositor_fb->display_name = "Workshop Compositor texture"; + _board_maker.compositor_fb->resolution_div = 0; + _board_maker.compositor_fb->fixed_w = 512; + _board_maker.compositor_fb->fixed_h = 512; + _board_maker.compositor_fb->attachments[0] = (vg_framebuffer_attachment) + { + .display_name = "RGBA", + .purpose = k_framebuffer_attachment_type_texture, + .quality = k_framebuffer_quality_all, + .internalformat = GL_RGBA, + .format = GL_RGBA, + .type = GL_UNSIGNED_BYTE, + .attachment = GL_COLOR_ATTACHMENT0 + }; + vg_framebuffer_init( _board_maker.compositor_fb ); -static void _board_maker_init_t1( void *userdata ) -{ - THREAD_1; - vg_framebuffer_create( &_board_maker.compositor_fb ); - vg_async_call( &vg.main_tasks, _async_board_maker_init_finish, NULL ); + _board_maker.state = k_board_maker_state_none; } static void _board_maker_export(void) @@ -170,38 +158,43 @@ static void _board_maker_export(void) .channels = 3, .colorspace = QOI_SRGB }; - - void *raw_data = malloc( 512*512*3 ), - *qoi_data = malloc( vg_query_qoi_storage_size( &desc ) ); - - vg_framebuffer_bind( &_board_maker.compositor_fb, 1.0f ); - glReadBuffer( GL_COLOR_ATTACHMENT0 ); - glReadPixels( 0,0, 512,512, GL_RGB, GL_UNSIGNED_BYTE, raw_data ); - - i32 qoi_len; - if( !vg_encode_qoi2( raw_data, &desc, qoi_data, &qoi_len ) ) + + u32 onetex; + u32 temp_frame = _vg_start_temp_frame(); { - free( raw_data ); - free( qoi_data ); - - _board_maker.export_success = 0; - _board_maker.export_message = "Texture failed to compress"; - _board_maker.ui_state = k_board_maker_ui_state_export_signal_done; - return; - } + void *raw_data = vg_stack_allocate( _vg_temp_stack(), 512*512*3, 8, "Raw data" ), + *qoi_data = vg_stack_allocate( _vg_temp_stack(), vg_query_qoi_max_compressed_size( &desc ), 8, "QOI" ); - u32 onetex = mdl_compiler_compile_texture_qoi( &compiler, "Maker Tex", qoi_data, qoi_len ); + vg_framebuffer_bind( _board_maker.compositor_fb, 1.0f ); + glReadBuffer( GL_COLOR_ATTACHMENT0 ); + glReadPixels( 0,0, 512,512, GL_RGB, GL_UNSIGNED_BYTE, raw_data ); - free( raw_data ); - free( qoi_data ); + vg_stream qoi_stream; + vg_buffer_stream_open( &qoi_stream, qoi_data, vg_query_qoi_max_compressed_size( &desc ), VG_STREAM_WRITE ); - u8 shader_buf[ 512 ]; - vg_msg shader_kvs; - vg_msg_init( &shader_kvs, shader_buf, sizeof(shader_buf) ); - vg_msg_wkvnum( &shader_kvs, "tex_diffuse", k_vg_msg_u32, 1, &onetex ); + i32 qoi_len = vg_qoi_stream_encode( &desc, raw_data, &qoi_stream, 0 ); + if( qoi_len == 0 ) + { + _board_maker.export_success = 0; + _board_maker.export_message = "Texture failed to compress"; + _board_maker.ui_state = k_board_maker_ui_state_export_signal_done; + _vg_end_temp_frame( temp_frame ); + return; + } + onetex = mdl_compiler_compile_texture_qoi( &compiler, "Maker Tex", qoi_data, qoi_len ); + } + _vg_end_temp_frame( temp_frame ); - u32 onemat = mdl_compiler_start_material( &compiler, "Maker Mat" ); - mdl_compiler_push_shaderdata( &compiler, k_shader_standard, &shader_kvs ); + u32 onemat; + temp_frame = _vg_start_temp_frame(); + { + vg_kvs shader_kvs; + vg_kvs_init( &shader_kvs, _vg_temp_stack() ); + vg_kv_append_vu32( &shader_kvs, 0, "tex_diffuse", &onetex, 1 ); + onemat = mdl_compiler_start_material( &compiler, "Maker Mat" ); + mdl_compiler_push_shaderdata( &compiler, k_shader_standard, &shader_kvs ); + } + _vg_end_temp_frame( temp_frame ); for( u32 i=0; i<_board_maker.template_mdl.mesh_count; i ++ ) { @@ -213,7 +206,7 @@ static void _board_maker_export(void) u32 ref_marker_index = mdl_entity_id_id( ref_mesh->entity_id ); ent_marker *ref_marker = af_arritm( &_board_maker.template_mdl_markers, ref_marker_index ); - const char *ref_marker_alias = af_str( &_board_maker.template_mdl.af, ref_marker->pstr_alias ); + const c8 *ref_marker_alias = af_str( _board_maker.template_mdl.packed_strings, ref_marker->pstr_alias ); ent_marker copy_marker = *ref_marker; copy_marker.pstr_alias = af_compile_string( &compiler.af, ref_marker_alias ); @@ -228,7 +221,7 @@ static void _board_maker_export(void) ref_submesh->indice_count ); } - af_write( &compiler.af, _board_maker.export_path, MDL_VERSION_NR ); + af_write( &compiler.af, _board_maker.export_path, VG_MODEL_VERSION_NR ); mdl_compiler_free( &compiler ); _board_maker.export_success = 1; @@ -248,7 +241,7 @@ void _board_maker_pre_update(void) { if( _board_maker.compositor_state == k_board_maker_compositor_dirty ) { - vg_framebuffer_bind( &_board_maker.compositor_fb, 1.0f ); + vg_framebuffer_bind( _board_maker.compositor_fb, 1.0f ); glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); glClear( GL_COLOR_BUFFER_BIT ); @@ -265,14 +258,13 @@ void _board_maker_pre_update(void) { for( u32 i=0; itex_all[i]; + u32 tex_id = _board_maker.base_shader->workshop.tex_all[i]; if( tex_id ) { - mdl_texture *tex = &_board_maker.template_mdl.textures[ tex_id-1 ]; + mdl_texture *mdl_tex = &_board_maker.template_mdl.textures[ tex_id-1 ]; - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, tex->glname ); + vg_tex_bind( GL_TEXTURE_2D, &mdl_tex->tex, 0 ); shader_workshop_compositor_uColour( _board_maker.colours[i] ); struct board_maker_decal *decal = &_board_maker.decals[ i ]; @@ -308,12 +300,12 @@ void _board_maker_pre_update(void) { if( _board_maker.template_loaded != -1 ) { - mdl_sync_std_unload( &_board_maker.template_mdl ); + vg_model_unload_gpu( &_board_maker.template_mdl ); _board_maker.template_loaded = -1; } _board_maker.state = k_board_maker_state_loading_template; - vg_async_call( &vg.loader_tasks, _board_maker_load_template, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_board_maker_load_template ); } } else @@ -321,12 +313,12 @@ void _board_maker_pre_update(void) if( _board_maker.state == k_board_maker_state_not_ready ) { _board_maker.state = k_board_maker_state_initializing; - vg_async_call( &vg.loader_tasks, _board_maker_init_t1, NULL ); + _board_maker_init_late(); } else if( _board_maker.state == k_board_maker_state_load_image ) { _board_maker.state = k_board_maker_state_loading_image; - vg_async_call( &vg.loader_tasks, _board_maker_image_t1, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_board_maker_image_t1 ); } else if( _board_maker.state == k_board_maker_state_export ) { @@ -372,22 +364,20 @@ void _board_maker_render( world_instance *world, vg_camera *cam ) if( _board_maker.template_loaded >= 0 ) { - vg_framebuffer_bind_texture( &_board_maker.compositor_fb, 0, 0 ); - + vg_framebuffer_bind_texture( _board_maker.compositor_fb, 0, 0 ); shader_model_entity_use(); shader_model_entity_uTexMain( 0 ); shader_model_entity_uCamera( cam->transform[3] ); shader_model_entity_uPv( cam->mtx.pv ); - - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_entity ); + WORLD_LINK_LIGHTING( world, model_entity ); m4x3f root_mmdl; m4x3_identity( root_mmdl ); q_m3x3( _board_maker.q, root_mmdl ); v3_copy( _board_maker.origin, root_mmdl[3] ); - mdl_context *mdl = &_board_maker.template_mdl; - mesh_bind( &mdl->mesh ); + vg_model *mdl = &_board_maker.template_mdl; + vg_model_bind_mesh( mdl ); for( u32 i=0; imesh_count; i ++ ) { @@ -406,7 +396,7 @@ void _board_maker_render( world_instance *world, vg_camera *cam ) for( u32 j=0; jsubmesh_count; j ++ ) { mdl_submesh *sm = &mdl->submeshes[ mesh->submesh_start + j ]; - mdl_draw_submesh( sm ); + vg_model_draw_submesh( sm ); } } } @@ -580,7 +570,7 @@ void _board_maker_ui( ui_context *ctx ) if( _board_maker.ui_state == k_board_maker_ui_state_export ) { ui_rect export_rect = { 0,0, 400, 300 }; - ui_rect_center( (ui_rect){0,0,vg.window_x,vg.window_y}, export_rect ); + ui_rect_center( (ui_rect){0,0,_vg_window.w,_vg_window.h}, export_rect ); ui_panel( ctx, export_rect, export_rect ); /* title */ @@ -881,8 +871,8 @@ void _board_maker_ui( ui_context *ctx ) } } - ui_rect box = { vg.window_x-(400+8),8, 400,400 }; - ui_image( ctx, box, &_board_maker.compositor_fb.attachments[0].id, 0 ); + ui_rect box = { _vg_window.w-(400+8),8, 400,400 }; + ui_image( ctx, box, &_board_maker.compositor_fb->attachments[0].tex, 0 ); ui_outline( ctx, box, 1, ui_colour( ctx, k_ui_fg ), 0 ); if( quit_me ) @@ -931,8 +921,8 @@ void _board_maker_open(void) _board_maker.template_loaded = -1; _board_maker.template_selection = 0; - vg_stack_init( &_board_maker.static_stack, NULL, VG_MB(8), "Board Maker: Static Stack" ); - vg_stack_init( &_board_maker.template_stack, NULL, VG_MB(16), "Board Maker: Template Stack" ); + vg_stack_init( &_board_maker.static_stack, VG_STACK_USE_HEAP, VG_MB(8), "Board Maker: Static Stack" ); + vg_stack_init( &_board_maker.template_stack, VG_STACK_USE_HEAP, VG_MB(16), "Board Maker: Template Stack" ); for( u32 i=0; ipstr_name ), mesh->submesh_start ); - } - - vg_stack_free( &stack ); - fclose( hdr ); -} diff --git a/src/client.c b/src/client.c index b8cbacc..55486ca 100644 --- a/src/client.c +++ b/src/client.c @@ -1,19 +1,511 @@ -#include "vg/vg_opt.h" -#include "vg/vg_loader.h" -#include "vg/vg_io.h" -#include "vg/vg_audio.h" - -#include "client.h" -#include "render.h" -#include "network.h" -#include "player_remote.h" -#include "menu.h" - const char* __asan_default_options() { return "detect_leaks=0"; } -struct game_client g_client = +struct game_client _client = { - .demo_mode = 1, }; -#include "skaterift.c" +struct skaterift_globals skaterift = +{ + .time_rate = 1.0f, +}; + +static void _skaterift_mount_addons_async( void *_, vg_async_info *async ) +{ + _world.default_hub_addon = _addon_mount_from_folder_path( "maps/dev_hub", k_addon_type_world, ".mdl" ); + VG_ASSERT( _world.default_hub_addon ); + _addon_mount_content_folder( k_addon_type_player, "playermodels", ".mdl" ); + _addon_mount_content_folder( k_addon_type_board, "boards", ".mdl" ); + _addon_mount_content_folder( k_addon_type_world, "maps", ".mdl" ); +} + +int skaterift_quit_command( int argc, const char *argv[] ) +{ + if( argc >= 1 ) + if( !strcmp( argv[0], "1" ) ) + skaterift.no_save_location = 1; + + _vg_terminate(); + return 1; +} + +/* + * UPDATE LOOP + * ---------------------------------------------------------------------------*/ + +static void draw_origin_axis(void) +{ + vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 ); + vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 ); + vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff ); +} + +void client_event_handler( vg_event_info *info ) +{ + if( info->type == k_vg_event_opts ) + { + const char *arg; + if( vg_long_opt( "noauth", "Disable server authentication" ) ) + network_client.auth_mode = eServerModeNoAuthentication; + + if( (arg = vg_long_opt_arg( "server", "Specify server address" )) ) + network_set_host( arg, NULL ); + + if( (arg = vg_long_opt_arg( "world", "Specify path to world to load" )) ) + skaterift.override_load_world = arg; + + _demo_check_opts(); + } + else if( info->type == k_vg_event_register ) + { + vg_console_reg_cmd( "quit", skaterift_quit_command, NULL ); + vg_console_reg_cmd( "load_world", skaterift_load_world_command, NULL ); + vg_console_reg_var( "immobile", &localplayer.immobile, k_var_dtype_i32, 0 ); + vg_console_reg_var( "allow_resume", &skaterift.allow_replay_resume, k_var_dtype_i32, VG_VAR_CHEAT ); + vg_console_reg_var( "boost_scale", &skaterift.boost_scale, k_var_dtype_f32, VG_VAR_CHEAT ); + + _render_register(); + _remote_players_register(); + _network_register(); + _menu_register(); + _control_overlay_register(); + _world_render_register(); + _gui_register(); + _compass_register(); + _player_register(); + _player_ragdoll_register(); + _cutscene_register(); + _workshop_register(); + _ent_tornado_register(); + _replay2_register(); + _ent_atom_register(); + _ent_challenge_register(); + + _steam_api.cb_connection_changed = cb_skaterift_connection_changed; + _steam_api.cb_persona_changed = cb_skaterift_persona_changed; + + network_set_host( "skaterift.com", NULL ); + } + else if( info->type == k_vg_event_init ) + { + _vg_loader_set_user_information( "Initializing subsystems" ); + + _vg_async_context_push_groups( SKATERIFT_LOAD_GROUP ); + _demo_check_init(); + _render_init(); + _remote_players_init(); + _network_init(); + _menu_init(); + _user_profile_init(); + _particles_init(); + _addon_system_init(); + + _player_init(); + _player_render_init(); + + _control_overlay_init(); + _world_init(); + _gui_init(); + _compass_init(); + _skateshop_init(); + _world_map_init(); + _replay2_init(); + _ent_npc_init(); + _audio_init(); + _ent_atom_init(); + + _mount_workshop_addons(); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_skaterift_mount_addons_async ); + + if( network_client.auto_connect ) + network_client.user_intent = k_server_intent_online; + menu_at_begin(); + _vg_async_context_pop_groups(); + } + else if( info->type == k_vg_event_pre_update ) + { + +#if 0 + if( co_step( co, 1 ) ) + { + /* initializing / loading world. */ + vg_loader_set_user_information( "Loading savedata" ); + skaterift_load_mainsave(); + + if( skaterift.override_load_world ) + _world.load_addon = _addon_mount_from_folder_path( skaterift.override_load_world, k_addon_type_world, ".mdl" ); + + _world.loader_instance = &_world.main; + _world.loader_preview_mode = 0; + _world.loader_stack = _world.stack; + + if( !_world.load_addon ) + { + vg_warn( "Falling back to default hub world...\n" ); + _world.load_addon = _world.default_hub_addon; + } + + _world_loader_set_addon( _world.load_addon ); + } +#endif + + + skaterift_preupdate_inputs(); + world_switcher_update(); + + if( !skaterift.ready_to_show_game ) + return; + + //draw_origin_axis(); + //_skaterift_script_update(); + _addon_system_pre_update(); + _network_update(); + + /* time rate */ + f32 target = 1; + if( skaterift.activity & k_skaterift_replay ) + target = 0; + + if( skaterift.activity == k_skaterift_spectate ) + { + if( button_down( k_srbind_mback ) ) + { + vg_audio_lock(); + vg_audio_oneshot( &audio_ui[3], 1.0f, 0.0f, 0, 0 ); + vg_audio_unlock(); + menu_close(); /* sets tate to default*/ + menu_open( k_menu_page_quick ); + _gui_helper_reset( k_gui_helper_mode_clear ); + localplayer.immobile = 0; + } + } + + world_update( &_world.main, localplayer.rb.co ); + _board_maker_pre_update(); + + cutscene_update( vg.time_rate * vg.time_frame_delta ); + + if( !((skaterift.activity == k_skaterift_menu) && (menu.page != k_menu_page_quick)) ) + player__pre_update(); + + _replay2_pre_update(); + remote_sfx_pre_update(); + + v3f listen_co; + v3_copy( localplayer.rb.co, listen_co ); + if( skaterift.activity & k_skaterift_menu ) + { + if( menu.page != k_menu_page_quick ) + { + if( menu.bg_cam ) + v3_copy( menu.bg_cam->co, listen_co ); + else target = 0; + } + } + + vg_slewf( &skaterift.time_rate, target, vg.time_frame_delta * (1.0f/0.3f) ); + vg.time_rate = vg_smoothstepf( skaterift.time_rate ); + } + else if( info->type == k_vg_event_fixed_update ) + { + if( !skaterift.ready_to_show_game ) + return; + + world_routes_fixedupdate( &_world.main ); + player__update(); + } + else if( info->type == k_vg_event_post_update ) + { + if( !skaterift.ready_to_show_game ) + return; + + player__post_update(); + + float dist; + int sample_index; + world_audio_sample_distances( localplayer.rb.co, &sample_index, &dist ); + + vg_audio_lock(); + vg_dsp.echo_distances[sample_index] = dist; + + v3f ears = { 1.0f,0.0f,0.0f }; + m3x3_mulv( g_render.cam.transform, ears, ears ); + v3_copy( ears, _vg_audio.controls.listener_right_ear_direction ); + v3_copy( g_render.cam.transform[3], _vg_audio.controls.listener_position ); + + if( localplayer.gate_waiting ) + { + m4x3_mulv( localplayer.gate_waiting->transport, _vg_audio.controls.listener_position, + _vg_audio.controls.listener_position ); + } + + v3_copy( localplayer.rb.v, _vg_audio.controls.listener_velocity ); + vg_audio_unlock(); + + _skaterift_autosave_post_update(); + localplayer.immunity = 0; + } + else if( info->type == k_vg_event_render ) + { + if( !skaterift.ready_to_show_game ) + return; + + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + + glViewport( 0,0, _vg_window.w, _vg_window.h ); + glDisable( GL_DEPTH_TEST ); + glDisable( GL_BLEND ); + + glClearColor( 1.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); + + /* RENDER main game + * ------------------------------------------------------------------------------------------------------------ */ + { + if( (_cutscene.state >= k_cutscene_state_ready) && _cutscene.player_binding ) + { + struct cs_instance *inst = _cutscene.player_binding; + ms_skeleton *sk = &localplayer.skeleton; + for( u32 i=0; ibone_count; i ++ ) + m4x3_copy( inst->skinning_data[i], localplayer.final_mtx[i] ); + } + else if( skaterift.activity == k_skaterift_replay ){} + else + { + player__animate(); + _replay2_record_local_frame(); + } + + animate_remote_players(); + player__pre_render(); + + + /* world entity driven camera + * ------------------------------------------------------------------------------ */ + if( _world.entity_set_camera ) + { + _world.entity_set_camera = 0; + _world.entity_camera_modulate = vg_minf( 1.0f, _world.entity_camera_modulate+vg.time_frame_delta ); + } + else + { + _world.entity_camera_modulate = vg_maxf( 0.0f, _world.entity_camera_modulate-vg.time_frame_delta ); + } + + vg_camera_lerp( &localplayer.cam, &_world.entity_driven_camera, + vg_smoothstepf(_world.entity_camera_modulate), &g_render.cam ); + + /* replay camera + * ------------------------------------------------------------------ */ + if( skaterift.activity == k_skaterift_replay ) + { + _replay2_get_camera( &g_render.cam ); + } + + if( skaterift.activity == k_skaterift_spectate ) + { + _network_get_spectate_cam( &g_render.cam ); + } + + g_render.cam.nearz = 0.1f; + g_render.cam.farz = 2100.0f; + + /* menu override camera + * -------------------------------------------------------------------- */ + if( (skaterift.activity == k_skaterift_menu) && menu.bg_cam ) + { + ent_camera_unpack( menu.bg_cam, &g_render.cam ); + } + + /* cutscene camera TODO: Fix the action camera + * ---------------------------------------------------------------- */ + ent_camera *cs_cam = _cutscene_active_camera(); + if( cs_cam ) + ent_camera_unpack( cs_cam, &g_render.cam ); + + world_map_get_transition_cam( &g_render.cam ); + + vg_camera_update_transform( &g_render.cam ); + + vg_camera_update_view( &g_render.cam ); + vg_camera_update_projection( &g_render.cam, _vg_window.w, _vg_window.h ); + vg_camera_finalize( &g_render.cam ); + + + + + + + + bool render_actual_game = !menu_viewing_map(); + bool render_stenciled = 0; + + if( render_actual_game ) + { + world_instance *world = &_world.main; + render_world_cubemaps( world ); + } + + /* variable res target */ + vg_framebuffer_bind( _vg_render.fb_main, _vg_render.scale ); + glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); + + if( !render_actual_game ) + { + render_world_map(); + + if( world_map_get_transition_cam(NULL) ) + { + glEnable( GL_STENCIL_TEST ); + glDisable( GL_DEPTH_TEST ); + glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); + glStencilFunc( GL_ALWAYS, 1, 0xFF ); + glStencilMask( 0xFF ); + + shader_blit_transition_use(); + shader_blit_transition_uInverseRatio( (v2f){1.0f,1.0f} ); + shader_blit_transition_uT( -(sqrtf(2)+0.5f) * world_map.spawn_timer ); + render_fsquad(); + render_stenciled = 1; + render_actual_game = 1; + } + } + + if( render_actual_game ) + { + /* Draw world */ + glEnable( GL_DEPTH_TEST ); + world_prerender( &_world.main ); + + render_world( &_world.main, &g_render.cam, render_stenciled, 0, 1, 1, _vg_render.fb_main ); + + particle_system_update( &particles_grind, vg.time_delta ); + //particle_system_debug( &particles_grind ); + particle_system_prerender( &particles_grind ); + particle_system_render( &particles_grind, &g_render.cam ); + + ent_tornado_pre_update(); + particle_system_update( &particles_env, vg.time_delta ); + particle_system_prerender( &particles_env ); + particle_system_render( &particles_env, &g_render.cam ); + + player_glide_render_effects( &g_render.cam ); + } + + glEnable( GL_DEPTH_TEST ); + + /* full res target */ + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glViewport( 0,0, _vg_window.w, _vg_window.h ); + + if( render_actual_game && !render_stenciled ) + { + bool render_player_transparent = 1; + + if( (skaterift.activity == k_skaterift_menu) && + (menu.page == k_menu_page_main) && + (menu.main_index == k_menu_main_guide) ) + { + render_player_transparent = 0; + } + + if( skaterift.activity == k_skaterift_replay ) + render_player_transparent = 0; + + if( render_player_transparent ) + { + static vg_camera small_cam; /* DOES NOT NEED TO BE STATIC BUT MINGW + SAIS OTHERWISE */ + + m4x3_copy( g_render.cam.transform, small_cam.transform ); + + small_cam.fov = g_render.cam.fov; + small_cam.nearz = 0.05f; + small_cam.farz = 60.0f; + + vg_camera_update_view( &small_cam ); + vg_camera_update_projection( &small_cam, _vg_window.w, _vg_window.h ); + vg_camera_finalize( &small_cam ); + + /* Draw player to window buffer and blend background ontop */ + player__render( &small_cam ); + } + + /* continue with variable rate */ + vg_framebuffer_bind( _vg_render.fb_main, _vg_render.scale ); + render_world_gates( &_world.main, &g_render.cam, _vg_render.fb_main ); + } + + /* composite */ + if( (skaterift.activity == k_skaterift_menu) && menu.bg_blur ) + v2_muls( (v2f){ 0.04f, 0.001f }, 1.0f-skaterift.time_rate, g_render.blur_override ); + else + v2_zero( g_render.blur_override ); + + vg_postprocess_to_screen( _vg_render.fb_main ); + _cutscene_render_fadeout(); + + if( !_gui_helpers_active() ) + control_overlay_render(); + } + + + m4x4_copy( g_render.cam.mtx.pv, vg.pv ); + + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glViewport( 0,0, _vg_window.w, _vg_window.h ); + + _gui_render_icons(); + compass_render_texture(); + } + else if( info->type == k_vg_event_gui ) + { + if( !skaterift.ready_to_show_game ) + return; + + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glViewport( 0,0, _vg_window.w, _vg_window.h ); + + _gui_draw( info->gui.ctx ); + _compass_render_imgui( info->gui.ctx ); + + if( k_light_editor ) + imgui_world_light_edit( info->gui.ctx, &_world.main ); + + vg_ui.tex_bg = &_vg_render.fb_main->attachments[0].tex; + vg_framebuffer_inverse_ratio( _vg_render.fb_main, vg_ui.bg_inverse_ratio ); + + _cutscene_gui( info->gui.ctx ); + _board_maker_ui( info->gui.ctx ); + menu_gui( info->gui.ctx ); + player__im_gui( info->gui.ctx ); + world_instance *world = &_world.main; + + if( skaterift.activity != k_skaterift_replay ) + { + world_routes_imgui( info->gui.ctx, world ); + _ent_route_imgui( info->gui.ctx ); + } + _replay2_imgui( info->gui.ctx ); + workshop_form_gui( info->gui.ctx ); + world_gui( info->gui.ctx, world ); + + if( menu_viewing_map() ) + { + remote_players_imgui_world( info->gui.ctx, &_world.main, vg.pv, 2000.0f, 0 ); + //remote_players_imgui_lobby( ctx ); + } + else + { + remote_players_chat_imgui( info->gui.ctx ); /* TODO: conditional */ + remote_players_imgui_world( info->gui.ctx, &_world.main, vg.pv, 100.0f, 1 ); + } + } +} + +int main( int argc, const char *argv[] ) +{ + vg_run( argc, argv, client_event_handler ); + return 0; +} diff --git a/src/client.h b/src/client.h index d11add9..36d1865 100644 --- a/src/client.h +++ b/src/client.h @@ -1,17 +1,52 @@ -#pragma once -#include "vg/vg_platform.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/client.c" +#else -/* - * client - entry point. window, common things like render init.. etc - * vg - backend code - * game - top layer: game content, state - */ +#define SKATERIFT_APPID 2103940 +#define SKATERIFT_WORLD_READY 0x10000 +#define SKATERIFT_LOAD_GROUP VG_ASYNC_GROUP_CLIENT3 struct game_client { - bool demo_mode; + u32 async_init_count; } -extern g_client; +extern _client; /* game defined */ void game_launch_opt( void ); + +enum skaterift_rt +{ + k_skaterift_rt_workshop_preview, + k_skaterift_rt_server_status, + k_skaterift_rt_max +}; + +struct skaterift_globals +{ + f32 time_rate; + + enum skaterift_activity { + k_skaterift_default = 0x00, /* regular playing */ + k_skaterift_replay = 0x01, + k_skaterift_spectate = 0x02, + k_skaterift_menu = 0x04, + k_skaterift_activity_max = 0x8 + } + activity; + + vg_tex *rt_textures[k_skaterift_rt_max]; + + u32 achievements; + i32 allow_replay_resume; + + const char *override_load_world; + + f32 boost_scale; + bool no_save_location; + + bool ready_to_show_game; +} +extern skaterift; + +#endif diff --git a/src/common.h b/src/common.h deleted file mode 100644 index 6f0c2f9..0000000 --- a/src/common.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#ifndef COMMON_H -#define COMMON_H - -#endif /* COMMON_H */ diff --git a/src/compass.c b/src/compass.c index 019241b..197d424 100644 --- a/src/compass.c +++ b/src/compass.c @@ -1,35 +1,33 @@ -#include "compass.h" -#include "shaders/compass.h" -#include "world.h" - struct _compass _compass = { .alpha = 1 }; -void compass_register(void) +VG_API void _compass_register(void) { vg_console_reg_var( "compass_alpha", &_compass.alpha, k_var_dtype_f32, VG_VAR_PERSISTENT ); } -void compass_init(void) +static void _compass_load_content_async( void *_, vg_async_info *async ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + vg_model_load( &_compass.model, VG_MODEL_ENGINE_STANDARD, "models/rs_compass.mdl", NULL ); + _compass.sm_comp = vg_model_get_submesh_index( &_compass.model, "comp" ); + _compass.sm_comp_bar = vg_model_get_submesh_index( &_compass.model, "comp_bar" ); + _compass.sm_comp_dot = vg_model_get_submesh_index( &_compass.model, "comp_dot" ); + _compass.sm_comp_e = vg_model_get_submesh_index( &_compass.model, "comp_e" ); + _compass.sm_comp_fade = vg_model_get_submesh_index( &_compass.model, "comp_fade" ); + _compass.sm_comp_friend = vg_model_get_submesh_index( &_compass.model, "comp_friend" ); + _compass.sm_comp_gate = vg_model_get_submesh_index( &_compass.model, "comp_gate" ); + _compass.sm_comp_n = vg_model_get_submesh_index( &_compass.model, "comp_n" ); + _compass.sm_comp_notify = vg_model_get_submesh_index( &_compass.model, "comp_notify" ); + _compass.sm_comp_person = vg_model_get_submesh_index( &_compass.model, "comp_person" ); + _compass.sm_comp_s = vg_model_get_submesh_index( &_compass.model, "comp_s" ); + _compass.sm_comp_w = vg_model_get_submesh_index( &_compass.model, "comp_w" ); + _compass.sm_comp_objective = vg_model_get_submesh_index( &_compass.model, "comp_objective" ); +} + +VG_API void _compass_init(void) { - mdl_context *mdl = &_compass.mdl; - - mdl_open( mdl, "models/rs_compass.mdl", &vg.rtmem ); - mdl_load_metadata_block( mdl, &vg.rtmem ); - mdl_async_full_load_std( mdl, NULL ); - _compass.sm_comp = mdl_get_submesh_index( mdl, "comp" ); - _compass.sm_comp_bar = mdl_get_submesh_index( mdl, "comp_bar" ); - _compass.sm_comp_dot = mdl_get_submesh_index( mdl, "comp_dot" ); - _compass.sm_comp_e = mdl_get_submesh_index( mdl, "comp_e" ); - _compass.sm_comp_fade = mdl_get_submesh_index( mdl, "comp_fade" ); - _compass.sm_comp_friend = mdl_get_submesh_index( mdl, "comp_friend" ); - _compass.sm_comp_gate = mdl_get_submesh_index( mdl, "comp_gate" ); - _compass.sm_comp_n = mdl_get_submesh_index( mdl, "comp_n" ); - _compass.sm_comp_notify = mdl_get_submesh_index( mdl, "comp_notify" ); - _compass.sm_comp_person = mdl_get_submesh_index( mdl, "comp_person" ); - _compass.sm_comp_s = mdl_get_submesh_index( mdl, "comp_s" ); - _compass.sm_comp_w = mdl_get_submesh_index( mdl, "comp_w" ); - _compass.sm_comp_objective = mdl_get_submesh_index( mdl, "comp_objective" ); - mdl_close( mdl ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_compass_load_content_async ); } static void compass_project( m3x3f base_projection, f32 x, f32 height ) @@ -76,37 +74,36 @@ void compass_render_texture(void) projection[0][0] = 512.0f/400.0f; projection[1][1] = 512.0f/50.0f; - mdl_context *mdl = &_compass.mdl; - mesh_bind( &mdl->mesh ); + vg_model *mdl = &_compass.model; + vg_model_bind_mesh( mdl ); shader_compass_use(); shader_compass_uTexMain( 0 ); - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, mdl->textures[0].glname ); + vg_tex_bind( GL_TEXTURE_2D, &mdl->textures[0].tex, 0 ); /* base */ shader_compass_uColour( (v4f){ 1,1,1,0.4 } ); compass_project( projection, 0,0 ); - mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_bar ] ); + vg_model_draw_submesh( &mdl->submeshes[ _compass.sm_comp_bar ] ); if( compass_a( projection, 0.0f, 0 ) ) - mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_n ] ); + vg_model_draw_submesh( &mdl->submeshes[ _compass.sm_comp_n ] ); if( compass_a( projection, VG_PIf/2.0f, 0 ) ) - mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_e ] ); + vg_model_draw_submesh( &mdl->submeshes[ _compass.sm_comp_e ] ); if( compass_a( projection, VG_PIf, 0 ) ) - mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_s ] ); + vg_model_draw_submesh( &mdl->submeshes[ _compass.sm_comp_s ] ); if( compass_a( projection, -VG_PIf/2.0f, 0 ) ) - mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_w ] ); + vg_model_draw_submesh( &mdl->submeshes[ _compass.sm_comp_w ] ); for( u32 i=0; i<4; i ++ ) { f32 a = VG_PIf/4.0f + (f32)i * (VG_PIf/2.0f); if( compass_a( projection, a, 0 ) ) { - mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_dot ] ); + vg_model_draw_submesh( &mdl->submeshes[ _compass.sm_comp_dot ] ); } } @@ -120,11 +117,11 @@ void compass_render_texture(void) struct network_player *player = &netplayers.list[i]; if( player->active && player->same_world ) { - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; m4x3f *final_mtx = &netplayers.final_mtx[ sk->bone_count*i ]; if( compass_co( projection, final_mtx[0][3], 0.0f ) ) - mdl_draw_submesh( &mdl->submeshes[ player->isfriend? _compass.sm_comp_friend: _compass.sm_comp_person ] ); + vg_model_draw_submesh( &mdl->submeshes[ player->isfriend? _compass.sm_comp_friend: _compass.sm_comp_person ] ); } } } @@ -141,7 +138,7 @@ void compass_render_texture(void) if( marker->flags & k_ent_marker_flag_gui_icon ) { if( compass_co( projection, marker->transform.co, 0.0f ) ) - mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_notify ] ); + vg_model_draw_submesh( &mdl->submeshes[ _compass.sm_comp_notify ] ); } } for( u32 i=0; ient_challenge); i++ ) @@ -152,7 +149,7 @@ void compass_render_texture(void) if( !challenge->status ) { if( compass_co( projection, challenge->transform.co, 0.0f ) ) - mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_objective ] ); + vg_model_draw_submesh( &mdl->submeshes[ _compass.sm_comp_objective ] ); } } @@ -181,7 +178,7 @@ void compass_render_texture(void) ent_gate *gate = af_arritm( &world->ent_gate, cp->gate_index ); if( compass_co( projection, gate->co[0], 0.0f ) ) - mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_gate ] ); + vg_model_draw_submesh( &mdl->submeshes[ _compass.sm_comp_gate ] ); } } } @@ -194,21 +191,21 @@ void compass_render_texture(void) if( !(route->flags & (k_ent_route_flag_achieve_gold|k_ent_route_flag_achieve_silver)) ) { if( compass_co( projection, route->board_transform[3], 0.0f ) ) - mdl_draw_submesh( &mdl->submeshes[ _compass.sm_comp_objective ] ); + vg_model_draw_submesh( &mdl->submeshes[ _compass.sm_comp_objective ] ); } } } } -void compass_render_imgui( ui_context *ctx ) +VG_API void _compass_render_imgui( ui_context *ctx ) { if( skaterift.activity == k_skaterift_replay ) return; ui_rect rect = { 0,0, 800, 100 }; - ui_rect_center( (ui_rect){0,0,vg.window_x,100}, rect ); + ui_rect_center( (ui_rect){0,0,_vg_window.w,100}, rect ); ui_flush( ctx, k_ui_shader_colour, NULL ); vg_ui.colour[3] = _compass.alpha; - ui_image( ctx, rect, &g_render.fb_compass->attachments[0].id, 0 ); + ui_image( ctx, rect, &g_render.fb_compass->attachments[0].tex, 0 ); vg_ui.colour[3] = 1.0f; } diff --git a/src/compass.h b/src/compass.h index 8337610..ec48551 100644 --- a/src/compass.h +++ b/src/compass.h @@ -1,9 +1,10 @@ -#pragma once -#include "vg/vg_framebuffer.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/compass.c" +#else struct _compass { - mdl_context mdl; + vg_model model; i32 sm_comp, sm_comp_bar, @@ -23,7 +24,9 @@ struct _compass } extern _compass; -void compass_init(void); -void compass_register(void); +VG_API void _compass_register(void); +VG_API void _compass_init(void); void compass_render_texture(void); -void compass_render_imgui( ui_context *ctx ); +VG_API void _compass_render_imgui( ui_context *ctx ); + +#endif diff --git a/src/control_overlay.c b/src/control_overlay.c index 9c42938..a55f5e0 100644 --- a/src/control_overlay.c +++ b/src/control_overlay.c @@ -1,50 +1,26 @@ -#include "control_overlay.h" -#include "model.h" -#include "input.h" -#include "player.h" -#include "player_skate.h" -#include "player_walk.h" -#include "shaders/model_menu.h" -#include "vg/vg_engine.h" -#include "vg/vg_mem.h" -#include "vg/vg_m.h" - -struct control_overlay control_overlay = { .enabled = 1 }; +struct control_overlay _control_overlay = { .enabled = 1 }; static void render_overlay_mesh( enum control_overlay_mesh index ) { - mdl_draw_submesh( &control_overlay.mdl.submeshes[ index ] ); + vg_model_draw_submesh( &_control_overlay.model.submeshes[ index ] ); } -static void control_overlay_init_finish( void *userdata ) +VG_API void _control_overlay_register(void) { - mdl_context *mdl = &control_overlay.mdl; - if( mdl->texture_count ) - { - mdl_texture *tex = &mdl->textures[ 0 ]; - control_overlay.tex = tex->glname; - } - else - { - control_overlay.tex = vg.tex_missing; - vg_error( "No texture in control overlay\n" ); - } + vg_console_reg_var( "control_overlay", &_control_overlay.enabled, k_var_dtype_i32, VG_VAR_PERSISTENT ); } -void control_overlay_register(void) +static void _control_overlay_load_content_async( void *_, vg_async_info *async ) { - vg_console_reg_var( "control_overlay", &control_overlay.enabled, k_var_dtype_i32, VG_VAR_PERSISTENT ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + vg_model_load( &_control_overlay.model, VG_MODEL_ENGINE_STANDARD, "models/rs_overlay.mdl", NULL ); + VG_ASSERT( _control_overlay.model.texture_count ); } -void control_overlay_init(void) +VG_API void _control_overlay_init(void) { - mdl_context *mdl = &control_overlay.mdl; - - mdl_open( mdl, "models/rs_overlay.mdl", &vg.rtmem ); - mdl_load_metadata_block( mdl, &vg.rtmem ); - mdl_async_full_load_std( mdl, NULL ); - mdl_close( mdl ); - vg_async_call( &vg.main_tasks, control_overlay_init_finish, NULL ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_control_overlay_load_content_async ); } static void draw_key( bool press, bool wide ) @@ -72,7 +48,7 @@ static void colorize( bool press, bool condition ) void control_overlay_render(void) { - if( !control_overlay.enabled ) return; + if( !_control_overlay.enabled ) return; if( skaterift.activity != k_skaterift_default ) return; if( _cutscene.state != k_cutscene_state_none ) return; if( localplayer.subsystem == k_player_subsystem_dead ) return; @@ -93,7 +69,7 @@ void control_overlay_render(void) glBlendEquation(GL_FUNC_ADD); m4x4f ortho; - f32 r = (f32)vg.window_x / (f32)vg.window_y, + f32 r = (f32)_vg_window.w / (f32)_vg_window.h, fl = -r, fr = r, fb = 1.0f, @@ -117,10 +93,8 @@ void control_overlay_render(void) shader_model_menu_uPv( ortho ); shader_model_menu_uColour( cnorm ); - mdl_context *mdl = &control_overlay.mdl; - mesh_bind( &mdl->mesh ); - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, control_overlay.tex ); + vg_model_bind_mesh( &_control_overlay.model ); + vg_tex_bind( GL_TEXTURE_2D, &_control_overlay.model.textures[0].tex, 1 ); enum player_subsystem subsytem = localplayer.subsystem; diff --git a/src/control_overlay.h b/src/control_overlay.h index a8f734a..bda9485 100644 --- a/src/control_overlay.h +++ b/src/control_overlay.h @@ -1,18 +1,22 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/control_overlay.c" +#else enum control_overlay_mesh { - #include "control_overlay.h.generated" + #include "src.generated/control_overlay.h" }; struct control_overlay { - mdl_context mdl; - GLuint tex; + vg_model model; i32 enabled; } -extern control_overlay; +extern _control_overlay; + +VG_API void _control_overlay_register(void); +VG_API void _control_overlay_init(void); void control_overlay_render(void); -void control_overlay_init(void); -void control_overlay_register(void); + +#endif diff --git a/src/cutscene.c b/src/cutscene.c new file mode 100644 index 0000000..b5c65d6 --- /dev/null +++ b/src/cutscene.c @@ -0,0 +1,978 @@ +struct _cutscene _cutscene; + +struct cs_instance *_cutscene_get_first_model_instance( const c8 *mdl_name ) +{ + for( u32 i=0; i<_cutscene.instance_count; i ++ ) + { + struct cs_instance *inst = &_cutscene.instances[i]; + struct model_ref *mref = &_cutscene.refs[ inst->ref_id ]; + + if( vg_str_eq( mdl_name, mref->name ) ) + return inst; + } + + return NULL; +} + +void _cutscene_unload(void) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + vg_info( "Unloading cutscene\n" ); + vg_audio_lock(); + vg_audio_set_flagged_pause( AUDIO_FLAG_CUTSCENE, 0 ); + vg_audio_fadeout_flagged_audio( AUDIO_FLAG_CUTSCENE, 1.0f ); + vg_audio_unlock(); + + for( u32 i=0; i<_cutscene.unique_refs; i ++ ) + vg_model_unload_gpu( &_cutscene.refs[i].model ); + + _cutscene.unique_refs = 0; + _cutscene.active_camera = NULL; + _cutscene.strip = 0; + _cutscene.time = 0.0f; + _cutscene.active_samplers = 0; + _cutscene.state = k_cutscene_state_unloading; + _cutscene.player_binding = NULL; + _cutscene.subtitle = NULL; + _cutscene.raiser_entity = 0; + _cutscene.fadeout = 0; + _cutscene.skipped = 0; + _cutscene.fadeout_start = 0.0f; +} + +/* + * Find associated entity data. We should also probably do this on the world + * thingy + */ +struct cs_asoc +{ + vg_model *orig_data; + u16 entity_type, + entity_index; + ms_override *override; +}; + +static void _cutscene_override_asoc( u32 instance_id, u32 override_index, struct cs_asoc *out_asoc ) +{ + struct cs_instance *instance = &_cutscene.instances[ instance_id ]; + vg_model *model = &_cutscene.refs[ instance->ref_id ].model; + + ms_instance *oins = af_arritm( &_cutscene.meta.instances, instance_id ); + ms_override *override = af_arritm( &_cutscene.meta.overrides, oins->override_start + override_index ); + + out_asoc->orig_data = model; + out_asoc->entity_type = override->entity_type; + out_asoc->override = override; + const char *name = af_str( _cutscene.meta.packed_strings, override->pstr_name ); + u32 name_hash = af_str_hash( _cutscene.meta.packed_strings, override->pstr_name ); + + if( out_asoc->entity_type != 28 ) + goto NOT_IMPLEMENTED; + + for( u32 j=0; jarmature_count; j ++ ) + { + mdl_armature *armature = &model->armatures[ j ]; + if( af_str_eq( model->packed_strings, armature->pstr_name, name, name_hash ) ) + { + out_asoc->entity_index = j; + return; + } + } + +NOT_IMPLEMENTED: + + vg_fatal_error( "The data association was not found.\n" + " Entity Type: %u\n" + " Entity name: %s\n", override->entity_type, name ); +} + +static void _cutscene_get_strip_asoc( ms_strip *strip, struct cs_asoc *out_asoc ) +{ + VG_ASSERT( strip->mode & k_ms_strip_mode_animation ); + if( strip->strip.instance_id == 0xffffffff ) + { + out_asoc->orig_data = NULL;// &_cutscene.meta; + out_asoc->entity_type = mdl_entity_id_type( strip->strip.object_id ); + out_asoc->entity_index = mdl_entity_id_id( strip->strip.object_id ); + out_asoc->override = NULL; + } + else + _cutscene_override_asoc( strip->strip.instance_id, strip->strip.object_id, out_asoc ); +} + +static void sync_cutscene_loaded( void *nothing, vg_async_info *async ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + vg_info( "Cutscene loaded\n" ); + _cutscene.state = k_cutscene_state_ready; +} + +struct cutscene_load_info +{ + u32 nothing; + char path[]; +}; +static void cutscene_load_thread( struct cutscene_load_info *in_args, vg_async_info *info ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + + vg_info( "Loading cutscene: %s\n", in_args->path ); + vg_stack_init( &_cutscene.stack, NULL, VG_MB(20), "Cutscene Stack" ); + metascene_load( &_cutscene.meta, in_args->path, &_cutscene.stack ); + _cutscene.instance_count = af_arrcount( &_cutscene.meta.instances ); + _cutscene.instances = vg_stack_allocate( &_cutscene.stack, sizeof(struct cs_instance) * _cutscene.instance_count, + 8, "Instances" ); + + _cutscene.refs = vg_stack_allocate( &_cutscene.stack, 0, 8, "References" ); + _cutscene.unique_refs = 0; + for( u32 i=0; i < _cutscene.instance_count; i ++ ) + { + ms_instance *instance = af_arritm( &_cutscene.meta.instances, i ); + const char *name = af_str( _cutscene.meta.packed_strings, instance->pstr_name ); + u32 name_hash = af_str_hash( _cutscene.meta.packed_strings, instance->pstr_name ); + + struct model_ref *ref = NULL; + u32 ref_id = 0; + + for( u32 j=0; j<_cutscene.unique_refs; j ++ ) + { + struct model_ref *ref_j = &_cutscene.refs[ j ]; + + if( af_str_eq( _cutscene.meta.packed_strings, instance->pstr_name, ref_j->name, ref_j->name_hash ) ) + { + ref = ref_j; + ref_id = j; + break; + } + } + + if( !ref ) + { + vg_stack_extend_last( &_cutscene.stack, sizeof(struct model_ref) ); + ref_id = _cutscene.unique_refs; + ref = &_cutscene.refs[ ref_id ]; + ref->name = name; + ref->name_hash = name_hash; + ref->reference_count = 0; + vg_info( "Indexed reference '%s'\n", name ); + _cutscene.unique_refs ++; + } + + ref->reference_count ++; + _cutscene.instances[ i ].ref_id = ref_id; + _cutscene.instances[ i ].skinning_data = NULL; + _cutscene.instances[ i ].disable_render = 0; + } + + /* load model data */ + for( u32 i=0; i<_cutscene.unique_refs; i ++ ) + { + struct model_ref *ref = &_cutscene.refs[ i ]; + char mdl_path_buf[ 512 ]; + vg_str mdl_path; + vg_strnull( &mdl_path, mdl_path_buf, sizeof(mdl_path_buf) ); + vg_strcat( &mdl_path, ref->name ); + vg_strcat( &mdl_path, ".mdl" ); + + vg_info( "Loading instance model: %s\n", mdl_path.buffer ); + vg_model_load( &ref->model, VG_MODEL_ENGINE_STANDARD, mdl_path.buffer, &_cutscene.stack ); + + u32 skeleton_count = ref->model.armature_count; + if( skeleton_count ) + { + ref->skeletons = vg_stack_allocate( &_cutscene.stack, sizeof(struct cs_skeleton) * skeleton_count, 8, "Skeletons" ); + ref->total_skinning_bones = 0; + for( u32 j=0; jskeletons[ j ]; + skeleton_setup( &skele->sk, &ref->model, j, &_cutscene.stack ); + skele->skinning_offset = ref->total_skinning_bones; + ref->total_skinning_bones += skele->sk.bone_count; + } + } + else + { + ref->skeletons = NULL; + ref->total_skinning_bones = 0; + } + } + + /* allocate skinning memory per-instance */ + for( u32 i=0; i<_cutscene.instance_count; i ++ ) + { + struct cs_instance *ins = &_cutscene.instances[ i ]; + struct model_ref *ref = &_cutscene.refs[ ins->ref_id ]; + + ins->skinning_data = vg_stack_allocate( &_cutscene.stack, sizeof(m4x3f) * ref->total_skinning_bones, + 8, "Skinning Data" ); + for( u32 j=0; jtotal_skinning_bones; j ++ ) + m4x3_identity( ins->skinning_data[ j ] ); + + /* load overrides */ + ms_instance *oins = af_arritm( &_cutscene.meta.instances, i ); + for( u32 j=0; joverride_count; j ++ ) + { + ms_override *override = af_arritm( &_cutscene.meta.overrides, oins->override_start + j ); + + struct cs_asoc asoc; + _cutscene_override_asoc( i, j, &asoc ); + + VG_ASSERT( asoc.entity_type == 28 ); + + struct cs_skeleton *skele = &ref->skeletons[ asoc.entity_index ]; + m4x3f mmdl; + mdl_transform_m4x3( &override->transform, mmdl ); + + for( u32 l=0; lsk.bone_count; l ++ ) + m4x3_copy( mmdl, ins->skinning_data[skele->skinning_offset+l] ); + } + } + + /* audio packs */ + for( u32 j=0; jclip_count; k++ ) + { + ent_audio_clip *clip = af_arritm( &_cutscene.meta.audio_clips, audio->clip_start+k ); + if( clip->_.file.pack_size ) + vg_error( "Currently not support packed audio in metascene..." ); + else + { + clip->_.clip.path = af_str( _cutscene.meta.packed_strings, clip->_.file.pstr_path ); + clip->_.clip.flags = audio->flags; + clip->_.clip.any_data = NULL; + clip->_.clip.size = 0; + } + vg_audio_clip_load( &clip->_.clip, &_cutscene.stack ); + } + } + + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)sync_cutscene_loaded ); +} + +bool _cutscene_load_and_play( const char *path, bool freeze_player, u32 raiser_entity ) +{ + if( _cutscene.state != k_cutscene_state_none ) + { + vg_error( "Tried to play cutscene '%s' while already playing one.\n", path ); + return 0; + } + + _cutscene.raiser_entity = raiser_entity; + + for( u32 i=0; ipath, path ); + _vg_async_send( out_args, (vg_async_fn)cutscene_load_thread ); + return 1; +} + +/* + * Currently draws everything as skinned meshes. + */ +static void cutscene_render_instance( struct cs_instance *ins, vg_camera *cam ) +{ + if( ins->disable_render ) + return; + + struct model_ref *ref = &_cutscene.refs[ ins->ref_id ]; + vg_model *mdl = &ref->model; + vg_model_bind_mesh( mdl ); + + shader_model_character_view_use(); + shader_model_character_view_uCamera( cam->transform[3] ); + shader_model_character_view_uPv( cam->mtx.pv ); + shader_model_character_view_uDepthMode( 0 ); + shader_model_character_view_uShadeless( 0 ); + shader_model_character_view_uUvOffset( (v2f){0,0} ); + + WORLD_LINK_LIGHTING( &_world.main, model_character_view ); + shader_model_character_view_uTexMain( 0 ); + + u32 armature_id = 0x00; + u32 material_id = 0x00; + bool using_additive = 0; + + for( u32 i=0; imesh_count; i ++ ) + { + mdl_mesh *mesh = &mdl->meshes[ i ]; + VG_ASSERT( mesh->armature_id ); + + if( mesh->armature_id != armature_id ) + { + armature_id = mesh->armature_id; + u32 sk_index = mdl_entity_id_id( armature_id ); + + struct cs_skeleton *skele = &ref->skeletons[ sk_index ]; + m4x3f *skinning_data = ins->skinning_data + skele->skinning_offset; + shader_model_character_view_uTransforms( skinning_data, skele->sk.bone_count ); + } + + for( u32 j=0; jsubmesh_count; j ++ ) + { + mdl_submesh *sm = &mdl->submeshes[ mesh->submesh_start+j ]; + VG_ASSERT( sm->material_id ); + + if( sm->material_id != material_id ) + { + mdl_material *m = &mdl->materials[ sm->material_id-1 ]; + VG_ASSERT( m->shader == k_shader_standard ); + + union shader_props *props = &mdl->shader_props[ sm->material_id-1 ]; + VG_ASSERT( props->standard.tex_diffuse ); + vg_tex_bind( GL_TEXTURE_2D, &mdl->textures[ props->standard.tex_diffuse-1 ].tex, 0 ); + + if( props->standard.render_flags & k_material_render_additive ) + { + using_additive = 1; + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + glBlendEquation(GL_FUNC_ADD); + glDisable( GL_CULL_FACE ); + shader_model_character_view_uShadeless( 1 ); + } + else + { + if( using_additive ) + { + using_additive = 0; + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + glEnable( GL_CULL_FACE ); + shader_model_character_view_uShadeless( 0 ); + } + } + } + + vg_model_draw_submesh( sm ); + } + } + + if( using_additive ) + { + shader_model_character_view_uShadeless( 0 ); + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + } +} + +#define CS_LOCATION 0 +#define CS_ANGLES 4 +#define CS_FOV 8 + +struct cs_link_info +{ + f32 *target; + u32 semantic_type; +}; + +static bool link_internal_datapath( struct cs_asoc *asoc, const char *datapath, struct cs_link_info *out_link ) +{ + if( asoc->entity_type != k_ent_camera ) + { + vg_warn( "Failed link %d#%d:'%s'\n", asoc->entity_type, asoc->entity_index, datapath ); + VG_ASSERT( 0 ); + } + ent_camera *cam = af_arritm( &_cutscene.meta.cameras, asoc->entity_index ); + + struct + { + const char *prefix; + f32 *arr; + u32 semantic; + } + reference[] = + { + { "location:", cam->co, CS_LOCATION }, + { "rotation_euler:", cam->r, CS_ANGLES }, + { "lens:", &cam->fov, CS_FOV } + }; + + for( u32 i=0; itarget = reference[i].arr + offset; + out_link->semantic_type = reference[i].semantic + offset; + + vg_info( "Linked %d#%d:'%s'\n", asoc->entity_type, asoc->entity_index, datapath ); + return 1; + } + } + + vg_warn( "Failed link %d#%d:'%s'\n", asoc->entity_type, asoc->entity_index, datapath ); + return 0; +} + +ent_camera *_cutscene_active_camera(void) +{ + return _cutscene.active_camera; +} + +void cutscene_update( f32 delta ) +{ + if( _cutscene.state == k_cutscene_state_unloading ) + { + // NOTE: This somestimes still fails! + if( !vg_audio_flagged_stopped( AUDIO_FLAG_CUTSCENE ) ) + { + static u32 ticker = 0; + ticker ++; + if( ticker > 50 ) + { + vg_low( "waiting for audio to stop...\n" ); + ticker = 0; + } + return; + } + + vg_stack_free( &_cutscene.stack ); + _cutscene.state = k_cutscene_state_none; + _cutscene.marker_this_frame = NULL; + _cutscene.subtitle = NULL; + _cutscene.raiser_entity = 0; + vg_info( "Finished unloading cutscene\n" ); + return; + } + + if( _cutscene.state == k_cutscene_state_ready ) + { + _cutscene.player_binding = _cutscene_get_first_model_instance( "models/ch_none" ); + if( _cutscene.player_binding ) + _cutscene.player_binding->disable_render = 1; + + /* start playing */ + if( _cutscene.freeze_player ) + localplayer.immobile = 1; + + vg_audio_lock(); + for( u32 j=0; jclip_start ); + + if( audio->flags & AUDIO_FLAG_AUTO_START ) + { + const u16 group = 0xfff1; + const u32 flags = AUDIO_FLAG_CUTSCENE; + + if( audio->flags & AUDIO_FLAG_SPACIAL_3D ) + vg_audio_oneshot_3d( &clip->_.clip, audio->transform.co, audio->transform.s[0], audio->volume, group,flags); + else + vg_audio_oneshot( &clip->_.clip, 1.0f, 0.0f, group, flags ); + } + } + vg_audio_unlock(); + + _cutscene.state = k_cutscene_state_playing; + _world_raise_event( _cutscene.raiser_entity, "start" ); + } + + if( _cutscene.state != k_cutscene_state_playing ) + return; + + _cutscene.marker_this_frame = NULL; + _cutscene.time += delta; + i32 frame = _cutscene.time * _cutscene.meta.info.framerate; + + /* clear out finished samplers */ + bool move = 0; + u32 j = 0; + for( u32 i=0; i<_cutscene.active_samplers; i ++ ) + { + struct cs_sampler *si = &_cutscene.samplers[i]; + + if( frame > (si->strip->offset + (i32)si->strip->strip.length) ) + move = 1; + else + { + if( move ) + { + struct cs_sampler *sj = &_cutscene.samplers[j]; + *sj = *si; + } + + j ++; + } + } + _cutscene.active_samplers = j; + + /* add new samplers as we get to them */ + for( u32 i=_cutscene.strip; ioffset ) + break; + + if( strip->mode & k_ms_strip_mode_animation ) + { + if( frame > strip->offset + (i32)strip->strip.length ) + { + vg_warn( "Skipping?\n" ); + _cutscene.strip ++; + continue; + } + + if( _cutscene.skipped == 2 ) + { + _cutscene.strip ++; + continue; + } + + if( strip->strip.instance_id == 0xffffffff ) + { + const char *strip_name = af_str( _cutscene.meta.packed_strings, strip->strip.pstr_name ); + vg_info( "+ Strip: '%s' entity: %u\n", strip_name, strip->strip.object_id ); + + /* internal link */ + struct cs_asoc asoc; + _cutscene_get_strip_asoc( strip, &asoc ); + + if( strip->mode == k_ms_strip_mode_curves ) + { + for( u32 j=0; jstrip.count; j ++ ) + { + ms_track *track = af_arritm( &_cutscene.meta.tracks, strip->strip.start + j ); + const char *datapath = af_str( _cutscene.meta.packed_strings, track->pstr_datapath ); + + struct cs_link_info link; + if( !link_internal_datapath( &asoc, datapath, &link ) ) + continue; + + VG_ASSERT( _cutscene.active_samplers < VG_ARRAY_LEN(_cutscene.samplers) ); + struct cs_sampler *samp = &_cutscene.samplers[ _cutscene.active_samplers ++ ]; + samp->strip = strip; + samp->curves.track = track; + + samp->curves.target = link.target; + samp->curves.semantic = link.semantic_type; + samp->curves.keyframe = 0; + samp->override = asoc.override; + VG_ASSERT( samp->curves.target ); + } + } + else VG_ASSERT(0); + } + else + { + /* external link */ + struct cs_instance *ins = &_cutscene.instances[ strip->strip.instance_id ]; + struct cs_asoc asoc; + _cutscene_get_strip_asoc( strip, &asoc ); + VG_ASSERT( asoc.entity_type == 28 ); + + if( strip->mode == k_ms_strip_mode_keyframes ) + { + VG_ASSERT( _cutscene.active_samplers < VG_ARRAY_LEN(_cutscene.samplers) ); + + struct cs_sampler *samp = &_cutscene.samplers[ _cutscene.active_samplers ++ ]; + struct model_ref *ref = &_cutscene.refs[ ins->ref_id ]; + struct cs_skeleton *skele = &ref->skeletons[ asoc.entity_index ]; + + samp->strip = strip; + samp->skeleton.skinning_data = &ins->skinning_data[ skele->skinning_offset ]; + samp->skeleton.ref_sk = &skele->sk; + samp->override = asoc.override; + } + else + { + VG_ASSERT(0); + } + } + } + else + { + if( strip->mode == k_ms_strip_mode_camera ) + { + u32 type = mdl_entity_id_type( strip->camera.entity_id ), + index = mdl_entity_id_id( strip->camera.entity_id ); + VG_ASSERT( type == k_ent_camera ); + ent_camera *cam = af_arritm( &_cutscene.meta.cameras, index ); + _cutscene.active_camera = cam; + } + + if( strip->mode == k_ms_strip_mode_fadeout ) + { + _cutscene.fadeout = 1; + _cutscene.fadeout_start = _cutscene.time; + } + + if( strip->mode == k_ms_strip_mode_subtitle ) + { + // FIXME: COLOURS + _cutscene.subtitle = af_str( _cutscene.meta.packed_strings, strip->subtitle.pstr_en ); + } + + if( strip->mode == k_ms_strip_mode_event ) + { + const char *str = af_str( _cutscene.meta.packed_strings, strip->event.pstr_string ); + vg_info( "cutscene event: %s\n", str ); + _world_raise_event( _cutscene.raiser_entity, str ); + } + } + + _cutscene.strip ++; + } + + /* sample da samplers */ + for( u32 i=0; i<_cutscene.active_samplers && (_cutscene.skipped != 2); i ++ ) + { + struct cs_sampler *samp = &_cutscene.samplers[ i ]; + + if( samp->strip->mode == k_ms_strip_mode_keyframes ) + { + ms_skeletal_animation temp_anim = + { + .strip = samp->strip, + .framerate = _cutscene.meta.info.framerate, + .keyframes_base = af_arritm( &_cutscene.meta.keyframes, samp->strip->strip.start ) + }; + + f32 t = _cutscene.time; + t -= (f32)samp->strip->offset / _cutscene.meta.info.framerate; + + ms_skeleton *ref_sk = samp->skeleton.ref_sk; + m4x3f *final_mtx = samp->skeleton.skinning_data; + + ms_keyframe pose[32]; + skeleton_sample_anim_clamped( ref_sk, &temp_anim, t, pose ); + + skeleton_apply_pose( ref_sk, pose, k_anim_apply_defer_ik, final_mtx ); + skeleton_apply_ik_pass( ref_sk, final_mtx ); + skeleton_apply_pose( ref_sk, pose, k_anim_apply_deffered_only, final_mtx ); + skeleton_apply_inverses( ref_sk, final_mtx ); + + if( samp->override ) + { + m4x3f mmdl; + mdl_transform_m4x3( &samp->override->transform, mmdl ); + skeleton_apply_transform( ref_sk, mmdl, final_mtx ); + } + + skeleton_debug( ref_sk, final_mtx ); + } + else + { + f32 scene_t = _cutscene.time * _cutscene.meta.info.framerate, + t = (f32)(scene_t - samp->strip->offset) + samp->strip->strip.timing_offset; + + ms_curve_keyframe *kl = af_arritm( &_cutscene.meta.curves, + samp->curves.track->keyframe_start + samp->curves.keyframe ), + *kr = NULL; + + if( t > kl->co[0] ) + { + if( samp->curves.track->keyframe_count > 1 ) + { + for( u32 j=samp->curves.keyframe+1; jcurves.track->keyframe_count; j ++ ) + { + kr = af_arritm( &_cutscene.meta.curves, samp->curves.track->keyframe_start + j ); + if( kr->co[0] <= t ) + { + kl = kr; + kr = NULL; + samp->curves.keyframe = j; + } + else break; + } + } + } + + if( kl && kr ) + *samp->curves.target = explicit_bezier( kl->co, kl->r, kr->l, kr->co, t ); + else + *samp->curves.target = kl->co[1]; + + if( samp->curves.semantic == CS_FOV ) + { + f32 mm = *samp->curves.target, + fov = 2.0f * 57.2957795f * atanf( (36.0f*0.5f) / mm ); + *samp->curves.target = fov; + } + } + } + + for( u32 i=0; ico, VG__RED, 0.2f ); + } + + f32 scene_t = _cutscene.time * _cutscene.meta.info.framerate, + end_t = _cutscene.meta.info.end_frame; + + if( scene_t >= end_t ) + { + if( _cutscene.strip != af_arrcount(&_cutscene.meta.strips) ) + { + _cutscene.time = 9999999.9f; + _cutscene.skipped = 2; /* signal we can ignore animation strips, just want events for correctness */ + return; + } + _world_raise_event( _cutscene.raiser_entity, "end" ); + + if( _cutscene.freeze_player ) + localplayer.immobile = 0; + + _cutscene_unload(); + } +} + +void _cutscene_render_fadeout(void) +{ + bool render = 0; + f32 render_alpha = 0.0f; + + if( _cutscene.state >= k_cutscene_state_ready ) + { + if( _cutscene.fadeout ) + { + f32 l = ((f32)_cutscene.meta.info.end_frame/(f32)_cutscene.meta.info.framerate) - _cutscene.fadeout_start, + t = (_cutscene.time - _cutscene.fadeout_start) / l; + render = 1; + render_alpha = t; + _cutscene.fadeout_cooldown = 1.0f; + } + } + else + { + if( _cutscene.fadeout_cooldown > 0.0f ) + { + render = 1; + render_alpha = _cutscene.fadeout_cooldown; + _cutscene.fadeout_cooldown -= vg.time_delta; + } + } + + if( render ) + { + glEnable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + + shader_blitcolour_use(); + shader_blitcolour_uColour( (v4f){ 0.04f, 0.02f, 0.03f, vg_clampf( render_alpha, 0.0f, 1.0f ) } ); + render_fsquad(); + } +} + +void _cutscene_render( vg_camera *cam ) +{ + if( _cutscene.state >= k_cutscene_state_ready ) + { + for( u32 i=0; i<_cutscene.instance_count; i ++ ) + cutscene_render_instance( &_cutscene.instances[i], cam ); + } +} + +void _cutscene_gui( ui_context *ctx ) +{ + if( _cutscene.subtitle ) + { + ctx->font = &vgf_default_small; + ctx->kern[1] = 16; + ui_px scale = 2; + ui_rect box = { 0,0, 1000, 80*2 }; + ui_rect_center( (ui_rect){0,0,_vg_window.w,_vg_window.h}, box ); + box[1] = _vg_window.h - (box[3] + 8); + + i32 lines = 1; + + const char *_c = _cutscene.subtitle; + u8 c; + + i32 length = 0; + ui_px y = box[1]; + + while(1) + { + c = *(_c ++); + + /* TODO: This is pasted straight from vg_ui, maybe create a vg_ui_text_iter() ...? */ + if( c == '\x1B' ) + { + while( (c = *(_c ++)) ) + { + if( c == 'm' ) + break; + } + + if( c == 0 ) + break; + else + continue; + } + + if( c >= 32 ) + length ++; + else if( c == '\n' || c == '\0' ) + { + ui_px w = length * ctx->font->sx*scale + 16; + ui_rect background_rect = { _vg_window.w/2 - w/2, y-8, w, ctx->font->sy*scale+16 }; + + ui_fill( ctx, background_rect, ui_opacity( GUI_COL_DARK, 0.75f ) ); + y += (ctx->font->sy)*scale + 16; + length = 0; + lines ++; + } + + if( c == '\0' ) + break; + } + + ui_text( ctx, box, _cutscene.subtitle, scale, k_ui_align_center, 0 ); + ctx->font = &vgf_default_small; + ctx->kern[1] = 0; + } +} + +/* cutscene magi + * ---------------------------------------------------------------------------- + */ + +static void cb_cutscene_view( ui_context *ctx, ui_rect rect, struct vg_magi_panel *magi ) +{ + if( _cutscene.state == k_cutscene_state_none ) + { + ui_text( ctx, rect, "No cutscene loaded.", 1, k_ui_align_middle_center, 0 ); + return; + } + + if( _cutscene.state == k_cutscene_state_loading ) + { + ui_text( ctx, rect, "Cutscene loading..", 1, k_ui_align_middle_center, 0 ); + return; + } + + if( _cutscene.state == k_cutscene_state_unloading ) + { + ui_text( ctx, rect, "Cutscene UN-loading..", 1, k_ui_align_middle_center, 0 ); + return; + } + + ms_strip *usage[8]; + for( u32 i=0; iname, mref->reference_count ); + ui_text( ctx, box, inf, 1, k_ui_align_middle_left, 0 ); + box[1] += 16; + } + } + + if( ui_clip( rect, panel_r, panel_r ) ) + { + ui_px root[2] = { panel_r[0]+8, panel_r[1]+8 }; + + for( u32 i=0; imode & k_ms_strip_mode_animation) ) + { + ui_rect box = { root[0]+strip->offset, root[1], 1, panel_r[3]-16 }; + ui_fill( ctx, box, 0xff00ff00 ); + + box[1] += box[3] -16; + box[2] = 200; + box[3] = 16; + + if( ui_clip( panel_r, box, box ) ) + { + if( strip->mode == k_ms_strip_mode_camera ) + ui_text( ctx, box, "Camera", 1, k_ui_align_middle_left, 0 ); + if( strip->mode == k_ms_strip_mode_subtitle ) + ui_text( ctx, box, "\"", 1, k_ui_align_middle_left, 0 ); + if( strip->mode == k_ms_strip_mode_fadeout ) + ui_text( ctx, box, "\\", 1, k_ui_align_middle_left, 0 ); + } + continue; + } + + u32 layer = 0; + for( u32 k=0; koffset + (i32)usage[k]->strip.length < strip->offset ) + usage[k] = NULL; + + if( !usage[k] ) + { + usage[k] = strip; + layer = k; + break; + } + } + + ui_rect box = { strip->offset, layer*32, (i32)strip->strip.length, 30 }; + box[0] += root[0]; + box[1] += root[1]; + + if( ui_clip( panel_r, box, box ) ) + { + u32 colour = af_str_hash( _cutscene.meta.packed_strings, strip->strip.pstr_name ); + ui_fill( ctx, box, colour | 0xff000000 ); + ui_text( ctx, box, af_str( _cutscene.meta.packed_strings, strip->strip.pstr_name ), + 1, k_ui_align_middle_center, 0 ); + } + } + + ui_rect cursor = { (f32)_cutscene.time*_cutscene.meta.info.framerate, 0, 1, VG_ARRAY_LEN(usage)*32 }; + cursor[0] += root[0]; + cursor[1] += root[1]; + if( ui_clip( panel_r, cursor, cursor ) ) + ui_fill( ctx, cursor, 0xffffffff ); + } +} + +static int cmd_cutscene_play( int argc, const char *argv[] ) +{ + if( argc == 1 ) + _cutscene_load_and_play( argv[0], 0, 0 ); + return 1; +} + +static int cmd_cutscene_inspector( int argc, const char *argv[] ) +{ + ui_px w = 800, h = 400; + struct vg_magi_panel *magi = _vg_magi_open( w, h, VG_MAGI_ALL ); + magi->title = "Cutscene Inpsector"; + magi->data = NULL; + magi->ui_cb = cb_cutscene_view; + magi->close_cb = NULL; + return 1; +} + +VG_API void _cutscene_register(void) +{ + vg_console_reg_cmd( "cutscene_play", cmd_cutscene_play, NULL ); + vg_console_reg_cmd( "cutscene_inspector", cmd_cutscene_inspector, NULL ); +} diff --git a/src/cutscene.h b/src/cutscene.h new file mode 100644 index 0000000..534e6ab --- /dev/null +++ b/src/cutscene.h @@ -0,0 +1,111 @@ +#if defined( SR_IMPLEMENTATION ) +# include "src/cutscene.c" +#else + +struct cs_instance +{ + bool disable_render; + u32 ref_id; + m4x3f *skinning_data; +}; + +struct cs_subtitle +{ + const char *key, *value; +}; + +struct _cutscene +{ + metascene meta; + vg_stack_allocator stack; + + enum cutscene_state + { + k_cutscene_state_none, + k_cutscene_state_loading, + k_cutscene_state_unloading, + k_cutscene_state_ready, + k_cutscene_state_playing, + k_cutscene_state_done, + } + state; + + struct model_ref + { + const char *name; + u32 name_hash; + u32 reference_count; + + vg_model model; + struct cs_skeleton + { + ms_skeleton sk; + u32 skinning_offset; + } + *skeletons; + u32 total_skinning_bones; + } + * refs; + u32 unique_refs; + + struct cs_instance *instances; + u32 instance_count; + + struct cs_sampler + { + ms_strip *strip; + ms_override *override; + union + { + struct + { + ms_track *track; + f32 *target; + u32 keyframe; + u32 semantic; + } + curves; + + struct + { + ms_skeleton *ref_sk; + m4x3f *skinning_data; + } + skeleton; + }; + } + samplers[32]; + u32 active_samplers; + + ent_camera *active_camera; + struct cs_instance *player_binding; + + u32 strip; + f32 time; + + bool fadeout; + u8 skipped; + f32 fadeout_start, fadeout_cooldown; + + const char *marker_this_frame; + const char *subtitle; + bool subtitle_length_warning; + + bool freeze_player; + + u32 raiser_entity; +} +extern _cutscene; + +VG_API void _cutscene_register(void); +void _cutscene_render( vg_camera *cam ); +void _cutscene_render_fadeout(void); +bool _cutscene_load_and_play( const char *path, bool freeze_player, u32 raiser_entity ); +void _cutscene_unload(void); +void cutscene_update( f32 delta ); +ent_camera *_cutscene_active_camera(void); +void _cutscene_gui( ui_context *ctx ); + +struct cs_instance *_cutscene_get_first_model_instance( const c8 *mdl_name ); + +#endif diff --git a/src/demo_check.c b/src/demo_check.c new file mode 100644 index 0000000..926f8b5 --- /dev/null +++ b/src/demo_check.c @@ -0,0 +1,47 @@ +struct _demo_check _demo_check; + +static void demo_check_not_demo( void *_, vg_async_info *async ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _demo_check.mode = 0; + _steam_api.demo_mode = 0; +} + +static void demo_check_task( void *_, vg_async_info *async ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + + c8 drm[ 32 ]; + vg_stream drm_file; + if( vg_file_stream_open( &drm_file, "DRM", VG_STREAM_READ ) ) + { + vg_stream_read( &drm_file, drm, sizeof(drm) ); + vg_file_stream_close( &drm_file ); + if( !strncmp( drm, "blibby!", sizeof(drm) ) ) + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)demo_check_not_demo ); + } +} + +VG_API void _demo_check_init(void) +{ + if( _demo_check.mode == 0 ) + { + _demo_check.mode = 1; + _steam_api.demo_mode = 1; + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)demo_check_task ); + } +} + +VG_API void _demo_check_opts(void) +{ + if( vg_long_opt( "demo", "Turn demo mode on" ) ) + { + _demo_check.mode = 2; + _steam_api.demo_mode = 1; + } +} + +VG_API bool _is_running_demo(void) +{ + return _demo_check.mode > 0; +} diff --git a/src/demo_check.h b/src/demo_check.h new file mode 100644 index 0000000..fbb0bbf --- /dev/null +++ b/src/demo_check.h @@ -0,0 +1,15 @@ +#if defined( SR_IMPLEMENTATION ) +# include "src/demo_check.c" +#else + +struct _demo_check +{ + i32 mode; +} +extern _demo_check; + +VG_API void _demo_check_opts(void); +VG_API void _demo_check_init(void); +VG_API bool _is_running_demo(void); + +#endif diff --git a/src/depth_compare.h b/src/depth_compare.h index 41f0fac..c6e5300 100644 --- a/src/depth_compare.h +++ b/src/depth_compare.h @@ -1,9 +1,6 @@ -#pragma once -#include "vg/vg_m.h" -#include "vg/vg_framebuffer.h" -#include "vg/vg_render.h" -#include "skaterift.h" -#include "render.h" +#if defined( SR_IMPLEMENTATION ) +//# include "src/depth_compare.c" +#else static inline void depth_compare_bind( void (*uTexSceneDepth)(int), @@ -22,3 +19,5 @@ static inline void depth_compare_bind( inverse[2] = cam->farz-cam->nearz; uInverseRatioMain( inverse ); } + +#endif diff --git a/src/ent_atom.c b/src/ent_atom.c index 73b49fd..b2d96e3 100644 --- a/src/ent_atom.c +++ b/src/ent_atom.c @@ -1,5 +1,3 @@ -#include "ent_atom.h" - struct _atom { struct atom_list @@ -19,7 +17,7 @@ const char *_ent_atom_name( u32 atom_entity_id ) if( atom->flags & k_ent_atom_scrap ) return ""; else - return af_str( &world->meta.af, atom->pstr_alias ); + return af_str( world->meta.packed_strings, atom->pstr_alias ); } i32 _ent_atom_get( u32 atom_entity_id ) @@ -32,7 +30,7 @@ i32 _ent_atom_get( u32 atom_entity_id ) return atom->scrap_value; else { - const char *alias = af_str( &world->meta.af, atom->pstr_alias ); + const char *alias = af_str( world->meta.packed_strings, atom->pstr_alias ); return _atom_get( (atom->flags & k_ent_atom_global)? k_atom_list_global: k_atom_list_world, alias ); } } @@ -53,7 +51,7 @@ void _ent_atom_set( u32 atom_entity_id, i32 value ) else { enum e_atom_list list = (atom->flags & k_ent_atom_global)? k_atom_list_global: k_atom_list_world; - const char *alias = af_str( &world->meta.af, atom->pstr_alias ); + const char *alias = af_str( world->meta.packed_strings, atom->pstr_alias ); _atom_set( list, alias, value ); _atom_notify( list, alias ); } @@ -64,7 +62,7 @@ entity_event_result _ent_atom_event( ent_event *event ) world_instance *world = &_world.main; bool pass = 0, fail = 0; - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "pass_equal" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "pass_equal" ) ) { if( event->flags & k_ent_event_data_const_i32 ) { @@ -73,7 +71,7 @@ entity_event_result _ent_atom_event( ent_event *event ) } else return k_entity_event_result_invalid; } - else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "pass_greater" ) ) + else if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "pass_greater" ) ) { if( event->flags & k_ent_event_data_const_i32 ) { @@ -82,7 +80,7 @@ entity_event_result _ent_atom_event( ent_event *event ) } else return k_entity_event_result_invalid; } - else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "set" ) ) + else if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "set" ) ) { if( event->flags & k_ent_event_data_const_i32 ) { @@ -91,7 +89,7 @@ entity_event_result _ent_atom_event( ent_event *event ) } else return k_entity_event_result_invalid; } - else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "set_or" ) ) + else if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "set_or" ) ) { if( event->flags & k_ent_event_data_const_i32 ) { @@ -101,7 +99,7 @@ entity_event_result _ent_atom_event( ent_event *event ) } else return k_entity_event_result_invalid; } - else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "set_and" ) ) + else if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "set_and" ) ) { if( event->flags & k_ent_event_data_const_i32 ) { @@ -118,13 +116,16 @@ entity_event_result _ent_atom_event( ent_event *event ) return k_entity_event_result_OK; } -void serialize_atoms( enum e_atom_list list, vg_msg *msg ) +void serialize_atoms( enum e_atom_list list, vg_kvs *savedata, u32 root ) { + // FIXME +#if 0 for( u32 i=0; i<_atom.lists[list].count; i ++ ) { atom *a = &_atom.lists[list].atoms[i]; - vg_msg_wkvnum( msg, a->alias, k_vg_msg_i32, 1, &a->status ); + vg_kv_append_vu32( savedata, root, a->alias, &a->status, 1 ); } +#endif } static atom *_atom_internal( enum e_atom_list list, const char *alias ) @@ -157,7 +158,7 @@ void _atom_notify( enum e_atom_list list, const char *alias ) if( atom->flags & k_ent_atom_scrap ) continue; - if( af_str_eq( &world->meta.af, atom->pstr_alias, alias, vg_strdjb2(alias)) ) + if( af_str_eq( world->meta.packed_strings, atom->pstr_alias, alias, vg_strdjb2(alias)) ) { _world_raise_event( mdl_entity_id( k_ent_atom, i ), "changed" ); _world_raise_event( mdl_entity_id( k_ent_atom, i ), value? "true": "false" ); @@ -258,7 +259,7 @@ void _ent_atom_register(void) void _ent_atom_init(void) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); if( _steam_api.disabled ) return; diff --git a/src/ent_atom.h b/src/ent_atom.h index f8be7ed..1a950ee 100644 --- a/src/ent_atom.h +++ b/src/ent_atom.h @@ -1,4 +1,6 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_atom.c" +#else enum e_atom_list { @@ -14,7 +16,7 @@ struct atom i32 status; }; -void serialize_atoms( enum e_atom_list list, vg_msg *msg ); +void serialize_atoms( enum e_atom_list list, vg_kvs *savedata, u32 root ); void _atom_list_clear( enum e_atom_list list ); i32 _atom_get( enum e_atom_list list, const char *alias ); @@ -25,3 +27,5 @@ void _atom_notify_list( enum e_atom_list list ); entity_event_result _ent_atom_event( ent_event *event ); void _ent_atom_register(void); void _ent_atom_init(void); + +#endif diff --git a/src/ent_camera.c b/src/ent_camera.c index d68341f..7ad83ff 100644 --- a/src/ent_camera.c +++ b/src/ent_camera.c @@ -1,5 +1,3 @@ -#include "entity.h" - void ent_camera_unpack( ent_camera *ent, vg_camera *cam ) { v3_copy( ent->co, cam->pos ); /* wow */ diff --git a/src/ent_camera.h b/src/ent_camera.h index bf4ce14..5353ed5 100644 --- a/src/ent_camera.h +++ b/src/ent_camera.h @@ -1,3 +1,7 @@ -#include "entity.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_camera.c" +#else void ent_camera_unpack( ent_camera *ent, vg_camera *cam ); + +#endif diff --git a/src/ent_challenge.c b/src/ent_challenge.c index e8eec54..391a81c 100644 --- a/src/ent_challenge.c +++ b/src/ent_challenge.c @@ -1,10 +1,3 @@ -#include "vg/vg_engine.h" -#include "entity.h" -#include "input.h" -#include "gui.h" -#include "audio.h" -#include "ent_region.h" - void _ent_challenge_clear( ent_challenge *challenge ) { world_instance *world = &_world.main; @@ -28,7 +21,7 @@ void _ent_challenge_win(void) if( !challenge->status ) { - gui_notify( "\xb3 Challenge complete!", 5.0f, k_ui_fg ); + _gui_notify( "\xb3 Challenge complete!", 5.0f, k_ui_fg ); } _ent_challenge_clear( challenge ); @@ -56,16 +49,16 @@ entity_event_result ent_challenge_event( ent_event *event ) { world_instance *world = &_world.main; ent_challenge *challenge = af_arritm( &world->ent_challenge, mdl_entity_id_id( event->recieve_entity_id ) ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "view" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "view" ) ) { if( world_set_event( k_world_event_challenge ) ) { srinput.state = k_input_state_resume; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); vg_str text; - if( gui_new_helper( input_button_list[k_srbind_maccept], &text )) + if( _gui_new_helper( input_button_list[k_srbind_maccept], &text )) vg_strcat( &text, "Start" ); - if( gui_new_helper( input_button_list[k_srbind_mback], &text )) + if( _gui_new_helper( input_button_list[k_srbind_mback], &text )) vg_strcat( &text, "Exit" ); localplayer.immobile = 1; @@ -140,7 +133,7 @@ void _restart_active_challenge(void) _world_raise_event( _world.active_challenge_id, "activate" ); } -void ent_challenge_update(void) +void _ent_challenge_update(void) { world_instance *world = &_world.main; @@ -162,7 +155,7 @@ void ent_challenge_update(void) if( button_down( k_srbind_maccept ) ) { menu_close(); - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); _world.challenge_state = k_challenge_state_running; localplayer.immobile = 0; /* TODO: Unify this probably after eating some potats */ menu.disable_open = 0; @@ -176,7 +169,7 @@ void ent_challenge_update(void) _world.active_challenge_id = 0; _world.challenge_target = NULL; _world.challenge_timer = 0.0f; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); _world.challenge_state = k_challenge_state_none; localplayer.immobile = 0; /* TODO: Unify this probably after eating some potats */ menu.disable_open = 0; @@ -220,7 +213,7 @@ void ent_challenge_update(void) vg_audio_oneshot_3d( &audio_challenge[6], localplayer.rb.co, 30.0f, 1.0f, 0, 0 ); vg_audio_unlock(); vg_info( "Challenge expired due to player being out of range.\n" ); - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); } } } @@ -239,7 +232,7 @@ void ent_challenge_update(void) srinput.state = k_input_state_resume; _restart_active_challenge(); _world.challenge_reset_timer = 0.0f; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); } } else @@ -260,7 +253,7 @@ void _ent_challenge_ui( ui_context *ctx ) ent_challenge *challenge = af_arritm( &world->ent_challenge, challenge_index ); ui_px w = 340; - ui_rect description_box = { vg.window_x - (w + 8), 8, w, 32 }; + ui_rect description_box = { _vg_window.w - (w + 8), 8, w, 32 }; ctx->font = &vgf_default_large; if( !(_world.challenge_state >= k_challenge_state_running) ) @@ -285,7 +278,7 @@ void _ent_challenge_ui( ui_context *ctx ) ui_fill( ctx, description_box, ui_opacity( GUI_COL_DARK, 0.36f ) ); ui_outline( ctx, description_box, 1, colour, 0 ); - const char *description = af_str( &world->meta.af, objective->pstr_description_ui ); + const char *description = af_str( world->meta.packed_strings, objective->pstr_description_ui ); ui_text( ctx, description_box, description, 1, k_ui_align_middle_center, colour ); description_box[1] += description_box[3] + 4; @@ -296,7 +289,7 @@ void _ent_challenge_ui( ui_context *ctx ) if( _world.challenge_reset_timer > 0.0f ) { - ui_rect box = { vg.window_x/2 - 200, vg.window_y - 200, 400, 100 }; + ui_rect box = { _vg_window.w/2 - 200, _vg_window.h - 200, 400, 100 }; ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, 0.35f ) ); ui_outline( ctx, box, 1, GUI_COL_NORM, 0 ); @@ -332,7 +325,7 @@ static int _skaterift_challenge_ccmd( int argc, const char *argv[] ) for( u32 i=0; ient_challenge ); i ++ ) { ent_challenge *challenge = af_arritm( &world->ent_challenge, i ); - const char *alias = af_str( &world->meta.af, challenge->pstr_alias ); + const char *alias = af_str( world->meta.packed_strings, challenge->pstr_alias ); if( all || (atoi( argv[0] ) == index) ) { @@ -359,7 +352,7 @@ static int _skaterift_challenge_ccmd( int argc, const char *argv[] ) for( u32 i=0; ient_route ); i ++ ) { ent_route *route = af_arritm( &world->ent_route, i ); - const char *alias = af_str( &world->meta.af, route->pstr_name ); + const c8 *alias = af_str( world->meta.packed_strings, route->pstr_name ); if( all || (atoi( argv[0] ) == index) ) { diff --git a/src/ent_challenge.h b/src/ent_challenge.h index 0e3a860..44845e6 100644 --- a/src/ent_challenge.h +++ b/src/ent_challenge.h @@ -1,9 +1,14 @@ -#pragma once -#include "entity.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_challenge.c" +#else entity_event_result ent_challenge_event( ent_event *event ); void _ent_challenge_ui( ui_context *ctx ); void _restart_active_challenge(void); void _ent_challenge_complete( ent_challenge *challenge ); void _ent_challenge_win(void); +void _ent_challenge_clear( ent_challenge *challenge ); void _ent_challenge_register(void); +void _ent_challenge_update(void); + +#endif diff --git a/src/ent_cutscene.c b/src/ent_cutscene.c index eb95116..693135e 100644 --- a/src/ent_cutscene.c +++ b/src/ent_cutscene.c @@ -1,13 +1,11 @@ -#include "ent_cutscene.h" - entity_event_result _ent_cutscene_event( ent_event *event ) { world_instance *world = &_world.main; ent_cutscene *cs = af_arritm( &world->ent_cutscene, mdl_entity_id_id( event->recieve_entity_id ) ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "play" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "play" ) ) { - const char *path = af_str( &world->meta.af, cs->pstr_path ); + const char *path = af_str( world->meta.packed_strings, cs->pstr_path ); _cutscene_load_and_play( path, (cs->flags & k_ent_cutscene_freeze_player), event->recieve_entity_id ); return k_entity_event_result_OK; diff --git a/src/ent_cutscene.h b/src/ent_cutscene.h index 13e6ce9..59adfab 100644 --- a/src/ent_cutscene.h +++ b/src/ent_cutscene.h @@ -1,3 +1,7 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_cutscene.c" +#else entity_event_result _ent_cutscene_event( ent_event *event ); + +#endif diff --git a/src/ent_glider.c b/src/ent_glider.c index 0a4a6e4..b8d3c9d 100644 --- a/src/ent_glider.c +++ b/src/ent_glider.c @@ -1,12 +1,8 @@ -#pragma once -#include "entity.h" -#include "player_glide.h" - entity_event_result ent_glider_event( ent_event *event ) { world_instance *world = &_world.main; ent_glider *glider = af_arritm( &world->ent_glider, mdl_entity_id_id( event->recieve_entity_id ) ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "lock" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "lock" ) ) { // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you) if( event->flags == k_ent_event_data_const_i32 ) @@ -18,7 +14,7 @@ entity_event_result ent_glider_event( ent_event *event ) else return k_entity_event_result_invalid; } - else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "equip" ) ) + else if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "equip" ) ) { if( !(glider->flags & k_ent_glider_flag_locked) ) player_glide_equip_glider(); diff --git a/src/ent_glider.h b/src/ent_glider.h index d92b4d2..ff2683c 100644 --- a/src/ent_glider.h +++ b/src/ent_glider.h @@ -1,4 +1,8 @@ -#pragma once -#include "entity.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_glider.c" +#else entity_event_result ent_glider_call( ent_event *event ); +entity_event_result ent_glider_event( ent_event *event ); + +#endif diff --git a/src/ent_list.c b/src/ent_list.c index 8301bf7..4eb437a 100644 --- a/src/ent_list.c +++ b/src/ent_list.c @@ -1,5 +1,3 @@ -#include "ent_list.h" - ent_list *_ent_list_get_aliased( const char *alias ) { world_instance *world = &_world.main; @@ -8,7 +6,7 @@ ent_list *_ent_list_get_aliased( const char *alias ) { ent_list *list = af_arritm( &world->ent_list, i ); if( list->alias_type == k_list_alias_string ) - if( af_str_eq( &world->meta.af, list->pstr_alias, alias, hash ) ) + if( af_str_eq( world->meta.packed_strings, list->pstr_alias, alias, hash ) ) return list; } return NULL; @@ -129,7 +127,7 @@ entity_event_result _ent_list_world_event( ent_event *event ) world_instance *world = &_world.main; ent_list *list = af_arritm( &world->ent_list, mdl_entity_id_id( event->recieve_entity_id ) ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "visible" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "visible" ) ) { // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you) if( event->flags == k_ent_event_data_const_i32 ) diff --git a/src/ent_list.h b/src/ent_list.h index 808d08d..af4b359 100644 --- a/src/ent_list.h +++ b/src/ent_list.h @@ -1,4 +1,6 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_list.c" +#else struct ent_list_iter { @@ -15,3 +17,5 @@ void _ent_list_set_visible( ent_list *list, bool visible ); entity_event_result _ent_list_world_event( ent_event *event ); bool _ent_list_check_completed( ent_list *list ); void _ent_list_set_as_targets( ent_list *list, bool yes ); + +#endif diff --git a/src/ent_npc.c b/src/ent_npc.c index 5f26403..982ebb0 100644 --- a/src/ent_npc.c +++ b/src/ent_npc.c @@ -1,5 +1,3 @@ -#include "ent_npc.h" - struct { struct @@ -12,7 +10,7 @@ struct } state; - mdl_context mdl; + vg_model mdl; i32 sm_main, sm_hat, sm_glow; v3f co, p0, p1; f64 command_t; @@ -41,7 +39,7 @@ struct } humans[4]; - struct skeleton_anim anim_idle, anim_stand, anim_sit; + ms_skeletal_animation anim_idle, anim_stand, anim_sit; enum npc_sub_state { @@ -207,8 +205,30 @@ static *_sub_contexts[] = }, }; -void _ent_npc_init(void) +static void _ent_npc_load_content( void *_, vg_async_info *async ) +{ + vg_model_load( &_npc.gino.mdl, VG_MODEL_ENGINE_STANDARD, "models/gino.mdl", VG_STACK_USE_HEAP ); + _npc.gino.sm_main = vg_model_get_submesh_index( &_npc.gino.mdl, "gino" ); + _npc.gino.sm_hat = vg_model_get_submesh_index( &_npc.gino.mdl, "gino.hat" ); + _npc.gino.sm_glow = vg_model_get_submesh_index( &_npc.gino.mdl, "gino.spt" ); + + ms_skeleton *sk = &localplayer.skeleton; + u32 mtx_size = sizeof(m4x3f)*sk->bone_count; + for( u32 i=0; i<4; i ++ ) + { + struct human_npc *human = &_npc.humans[i]; + human->final_mtx = vg_stack_allocate( VG_STACK_USE_HEAP, mtx_size, 8, "Final MTX" ); + } + player_get_anim( &_npc.anim_idle, "idle_lean+y" ); + player_get_anim( &_npc.anim_stand, "idle_cycle+y" ); + player_get_anim( &_npc.anim_sit, "sit" ); +} + +VG_API void _ent_npc_init(void) { + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_ent_npc_load_content ); + for( u32 i=0; ialias == NULL ) break; - context->alias_hash = vg_strdjb2( context->alias ); } } - - mdl_context *mdl = &_npc.gino.mdl; - mdl_open( mdl, "models/gino.mdl", &vg.rtmem ); - mdl_load_metadata_block( mdl, &vg.rtmem ); - mdl_async_full_load_std( mdl, NULL ); - _npc.gino.sm_main = mdl_get_submesh_index( mdl, "gino" ); - _npc.gino.sm_hat = mdl_get_submesh_index( mdl, "gino.hat" ); - _npc.gino.sm_glow = mdl_get_submesh_index( mdl, "gino.spt" ); - mdl_close( mdl ); - - struct skeleton *sk = &localplayer.skeleton; - u32 mtx_size = sizeof(m4x3f)*sk->bone_count; - for( u32 i=0; i<4; i ++ ) - { - struct human_npc *human = &_npc.humans[i]; - human->final_mtx = vg_stack_allocate( &vg.rtmem, mtx_size, 8, "Final MTX" ); - } - player_get_anim( &_npc.anim_idle, "idle_lean+y" ); - player_get_anim( &_npc.anim_stand, "idle_cycle+y" ); - player_get_anim( &_npc.anim_sit, "sit" ); } void _ent_npc_reset(void) @@ -312,9 +311,9 @@ void _ent_npc_speech( enum npc npc_id, const char *speech_alias ) _npc.sub_state = k_npc_sub_reading; _cutscene.subtitle = sub->value; - gui_helper_reset( k_gui_helper_mode_black_bars ); + _gui_helper_reset( k_gui_helper_mode_black_bars ); vg_str text; - if( gui_new_helper( input_button_list[k_srbind_maccept], &text )) + if( _gui_new_helper( input_button_list[k_srbind_maccept], &text )) vg_strcat( &text, "Next" ); v3_copy( localplayer.rb.co, _npc.sub_position ); } @@ -324,7 +323,7 @@ void _ent_npc_speech( enum npc npc_id, const char *speech_alias ) _npc.sub_state = k_npc_sub_off; _npc.subtitles = NULL; _cutscene.subtitle = NULL; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); } } @@ -337,7 +336,7 @@ void _ent_npc_preupdate(void) { _npc.sub_state = k_npc_sub_off; _cutscene.subtitle = NULL; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); } } @@ -423,7 +422,7 @@ void _ent_npc_preupdate(void) if( human->alive && (v3_dist2( localplayer.rb.co, human->co ) < 40.0f*40.0f) ) { ms_keyframe apose[32], bpose[32]; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; player_pose *pose = &human->pose; pose->type = k_player_pose_type_ik; pose->board.lean = 0.0f; @@ -458,7 +457,7 @@ void _ent_npc_render( vg_camera *cam ) if( !((_cutscene.state == k_cutscene_state_playing) && human->in_cutscene) ) { m4x3f *final_mtx = human->final_mtx; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; render_playermodel( cam, world, 0, &human->playermodel, sk, final_mtx ); } } @@ -471,28 +470,27 @@ void _ent_npc_render( vg_camera *cam ) shader_model_entity_uTexMain( 0 ); shader_model_entity_uCamera( cam->transform[3] ); shader_model_entity_uPv( cam->mtx.pv ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_entity ); + WORLD_LINK_LIGHTING( world, model_entity ); - mesh_bind( &_npc.gino.mdl.mesh ); - glActiveTexture( GL_TEXTURE0 ); + vg_model_bind_mesh( &_npc.gino.mdl ); glDepthMask(GL_FALSE); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); - glBindTexture( GL_TEXTURE_2D, _npc.gino.mdl.textures[1].glname ); + vg_tex_bind( GL_TEXTURE_2D, &_npc.gino.mdl.textures[1].tex, 0 ); m4x3f mmdl; m3x3_copy( cam->transform, mmdl ); v3_copy( _npc.gino.co, mmdl[3] ); shader_model_entity_uMdl( mmdl ); glDrawBuffers( 1, (GLenum[]){ GL_COLOR_ATTACHMENT0 } ); - mdl_draw_submesh( &_npc.gino.mdl.submeshes[ _npc.gino.sm_glow ] ); + vg_model_draw_submesh( &_npc.gino.mdl.submeshes[ _npc.gino.sm_glow ] ); glDrawBuffers( 2, (GLenum[]){ GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 } ); glDepthMask(GL_TRUE); glDisable(GL_BLEND); - glBindTexture( GL_TEXTURE_2D, _npc.gino.mdl.textures[0].glname ); + vg_tex_bind( GL_TEXTURE_2D, &_npc.gino.mdl.textures[0].tex, 0 ); v3f v0 = { localplayer.rb.co[0] - _npc.gino.co[0], 0.0f, localplayer.rb.co[2] - _npc.gino.co[2] }; v3_normalize( v0 ); @@ -506,7 +504,7 @@ void _ent_npc_render( vg_camera *cam ) m4x4_mul( cam->mtx_prev.pv, m4mmdl, m4mmdl ); shader_model_entity_uMdl( mmdl ); shader_model_entity_uPvmPrev( m4mmdl ); - mdl_draw_submesh( &_npc.gino.mdl.submeshes[ _npc.gino.sm_main ] ); + vg_model_draw_submesh( &_npc.gino.mdl.submeshes[ _npc.gino.sm_main ] ); m3x3f mspin; v4f qspin; @@ -517,7 +515,7 @@ void _ent_npc_render( vg_camera *cam ) m4x4_mul( cam->mtx_prev.pv, m4mmdl, m4mmdl ); shader_model_entity_uMdl( mmdl ); shader_model_entity_uPvmPrev( m4mmdl ); - mdl_draw_submesh( &_npc.gino.mdl.submeshes[ _npc.gino.sm_hat ] ); + vg_model_draw_submesh( &_npc.gino.mdl.submeshes[ _npc.gino.sm_hat ] ); } entity_event_result ent_npc_event( ent_event *event ) @@ -540,7 +538,7 @@ entity_event_result ent_npc_event( ent_event *event ) { if( npc_aliases[i] ) { - if( AF_STR_EQ( &world->meta.af, npc->pstr_id, npc_aliases[i] ) ) + if( AF_STR_EQ( world->meta.packed_strings, npc->pstr_id, npc_aliases[i] ) ) { npc_id = i; break; @@ -550,21 +548,21 @@ entity_event_result ent_npc_event( ent_event *event ) if( npc_id == k_npc_none ) { - vg_warn( "No npc with alias: %s\n", af_str( &world->meta.af, npc->pstr_id ) ); + vg_warn( "No npc with alias: %s\n", af_str( world->meta.packed_strings, npc->pstr_id ) ); return k_entity_event_result_invalid; } if( npc_id == k_npc_gino ) { - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "interact" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "interact" ) ) { vg_audio_lock(); vg_audio_oneshot( &audio_ui[1], 1.0f, 0.0f, 0, 0 ); vg_audio_unlock(); - _ent_npc_speech( npc_id, af_str( &world->meta.af, npc->pstr_context_id ) ); + _ent_npc_speech( npc_id, af_str( world->meta.packed_strings, npc->pstr_context_id ) ); return k_entity_event_result_OK; } - else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "proximity" ) ) + else if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "proximity" ) ) { if( _npc.gino.current_entity_id != event->source_entity_id ) { @@ -587,20 +585,20 @@ entity_event_result ent_npc_event( ent_event *event ) struct human_npc *human = human_npc( npc_id ); VG_ASSERT( human ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "interact" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "interact" ) ) { vg_audio_lock(); vg_audio_oneshot( &audio_ui[1], 1.0f, 0.0f, 0, 0 ); vg_audio_unlock(); - _ent_npc_speech( npc_id, af_str( &world->meta.af, npc->pstr_context_id ) ); + _ent_npc_speech( npc_id, af_str( world->meta.packed_strings, npc->pstr_context_id ) ); return k_entity_event_result_OK; } - else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "proximity" ) ) + else if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "proximity" ) ) { human->anim = 0; - if( AF_STR_EQ( &world->meta.af, npc->pstr_anim, "sit" ) ) + if( AF_STR_EQ( world->meta.packed_strings, npc->pstr_anim, "sit" ) ) human->anim = k_npc_sit; - else if( AF_STR_EQ( &world->meta.af, npc->pstr_anim, "stand" ) ) + else if( AF_STR_EQ( world->meta.packed_strings, npc->pstr_anim, "stand" ) ) human->anim = k_npc_stand; if( human->alive == 0 ) diff --git a/src/ent_npc.h b/src/ent_npc.h index 4b607b6..85342eb 100644 --- a/src/ent_npc.h +++ b/src/ent_npc.h @@ -1,4 +1,6 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_npc.c" +#else #define KCOL_JOHN KNRM #define KCOL_MIKE KBLU @@ -17,7 +19,8 @@ enum npc k_npc_max }; -void _ent_npc_init(void); +VG_API void _ent_npc_init(void); + void _ent_npc_render( vg_camera *cam ); void _ent_npc_goto( v3f pos, i32 uid ); void _ent_npc_preupdate(void); @@ -25,3 +28,5 @@ void _ent_npc_speech( enum npc npc_id, const char *speech_alias ); void _ent_npc_reset(void); void _ent_npc_set_in_cutscene( enum npc npc_id, bool yes ); entity_event_result ent_npc_event( ent_event *event ); + +#endif diff --git a/src/ent_objective.c b/src/ent_objective.c index 54e947c..b8ce2eb 100644 --- a/src/ent_objective.c +++ b/src/ent_objective.c @@ -1,12 +1,3 @@ -#include "world.h" -#include "world_load.h" -#include "entity.h" -#include "audio.h" -#include "vg/vg_steam2.h" -#include "ent_region.h" -#include "player.h" -#include "player_skate.h" - static void ent_objective_pass( world_instance *world, ent_objective *objective ) { objective->flags |= k_ent_objective_passed; @@ -120,7 +111,7 @@ entity_event_result ent_objective_event( ent_event *event ) world_instance *world = &_world.main; ent_objective *objective = af_arritm( &world->ent_objective, mdl_entity_id_id( event->recieve_entity_id ) ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "trigger" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "trigger" ) ) { if( (_world.event == k_world_event_challenge) && (_world.challenge_state == k_challenge_state_running) ) { @@ -152,10 +143,10 @@ entity_event_result ent_objective_event( ent_event *event ) objective->flags |= k_ent_objective_failed; _world.challenge_state = k_challenge_state_fail; - gui_helper_reset( k_gui_helper_mode_black_bars ); + _gui_helper_reset( k_gui_helper_mode_black_bars ); vg_str str; struct gui_helper *helper; - if( (helper = gui_new_helper(input_button_list[k_srbind_reset], &str)) ) + if( (helper = _gui_new_helper(input_button_list[k_srbind_reset], &str)) ) vg_strcat( &str, "Retry" ); } } @@ -164,7 +155,7 @@ entity_event_result ent_objective_event( ent_event *event ) return k_entity_event_result_OK; } - else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "hide" ) ) + else if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "hide" ) ) { // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you) if( event->flags == k_ent_event_data_const_i32 ) diff --git a/src/ent_objective.h b/src/ent_objective.h index e5e84ac..bca917b 100644 --- a/src/ent_objective.h +++ b/src/ent_objective.h @@ -1,4 +1,7 @@ -#pragma once -#include "entity.h" -#include "world.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_objective.c" +#else + entity_event_result ent_objective_event( ent_event *event ); + +#endif diff --git a/src/ent_prop.c b/src/ent_prop.c index 3b95445..bb51957 100644 --- a/src/ent_prop.c +++ b/src/ent_prop.c @@ -1,5 +1,3 @@ -#include "ent_prop.h" - void ent_prop_update( world_instance *world ) { for( u32 i=0; ient_prop ); i ++ ) diff --git a/src/ent_prop.h b/src/ent_prop.h index 8e294eb..1f655c4 100644 --- a/src/ent_prop.h +++ b/src/ent_prop.h @@ -1,3 +1,7 @@ -#pragma once -#include "world.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_prop.c" +#else + void ent_prop_update( world_instance *world ); + +#endif diff --git a/src/ent_region.c b/src/ent_region.c index 2024ed6..a7fc82e 100644 --- a/src/ent_region.c +++ b/src/ent_region.c @@ -1,8 +1,3 @@ -#include "ent_region.h" -#include "gui.h" -#include "network_common.h" -#include "network.h" - struct global_ent_region global_ent_region; u32 region_spark_colour( u32 flags ) @@ -24,10 +19,10 @@ entity_event_result ent_region_event( ent_event *event ) if( region->v109.id_list != 0 ) challenge_list = af_arritm( &world->ent_list, mdl_entity_id_id( region->v109.id_list ) ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "set_active" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "set_active" ) ) { - gui_location_print_ccmd( 1, (const char *[]){af_str( &world->meta.af, region->pstr_title)} ); - vg_strncpy( af_str( &world->meta.af, region->pstr_title ), + gui_location_print_ccmd( 1, (const char *[]){af_str( world->meta.packed_strings, region->pstr_title)} ); + vg_strncpy( af_str( world->meta.packed_strings, region->pstr_title ), global_ent_region.location, NETWORK_REGION_MAX, k_strncpy_always_add_null ); global_ent_region.flags = region->flags; @@ -118,7 +113,7 @@ void ent_region_re_eval( world_instance *world, bool init ) if( !(original_flags & (k_ent_route_flag_achieve_silver|k_ent_route_flag_achieve_gold)) && region->flags & (k_ent_route_flag_achieve_silver|k_ent_route_flag_achieve_gold) ) { - gui_notify( "\xb3 Region completed!", 6.0f, k_ui_fg ); + _gui_notify( "\xb3 Region completed!", 6.0f, k_ui_fg ); } } } diff --git a/src/ent_region.h b/src/ent_region.h index 4565d64..24b9c89 100644 --- a/src/ent_region.h +++ b/src/ent_region.h @@ -1,6 +1,6 @@ -#pragma once -#include "world_entity.h" -#include "network_common.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_region.c" +#else struct global_ent_region { @@ -18,3 +18,5 @@ struct ent_region_unlock_data u32 region_spark_colour( u32 flags ); void ent_region_re_eval( world_instance *world, bool init ); entity_event_result ent_region_event( ent_event *event ); + +#endif diff --git a/src/ent_relay.c b/src/ent_relay.c index 711e71c..e69de29 100644 --- a/src/ent_relay.c +++ b/src/ent_relay.c @@ -1 +0,0 @@ -#include "ent_relay.h" diff --git a/src/ent_relay.h b/src/ent_relay.h index 9030863..263df8d 100644 --- a/src/ent_relay.h +++ b/src/ent_relay.h @@ -1,2 +1,4 @@ -#pragma once -#include "entity.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_relay.c" +#else +#endif diff --git a/src/ent_route.c b/src/ent_route.c index c82593d..1d8273d 100644 --- a/src/ent_route.c +++ b/src/ent_route.c @@ -1,9 +1,3 @@ -#include "ent_route.h" -#include "input.h" -#include "gui.h" -#include "network_requests.h" -#include "user_profile.h" - struct _ent_route _ent_route; entity_event_result ent_route_event( ent_event *event ) @@ -11,15 +5,15 @@ entity_event_result ent_route_event( ent_event *event ) world_instance *world = &_world.main; ent_route *route = af_arritm( &world->ent_route, mdl_entity_id_id( event->recieve_entity_id ) ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "view" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "view" ) ) { if( world_set_event( k_world_event_route_leaderboard ) ) { menu_close(); - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); vg_str text; - if( gui_new_helper( input_button_list[k_srbind_mback], &text ) ) + if( _gui_new_helper( input_button_list[k_srbind_mback], &text ) ) vg_strcat( &text, "Exit" ); _ent_route.viewing_route_id = event->recieve_entity_id; localplayer.immobile = 1; @@ -53,7 +47,7 @@ void ent_route_preupdate(void) { srinput.state = k_input_state_resume; localplayer.immobile = 0; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); return; } } @@ -66,9 +60,9 @@ void _ent_route_imgui( ui_context *ctx ) u32 index = mdl_entity_id_id( _ent_route.viewing_route_id ); - ui_fill( ctx, (ui_rect){0,0,vg.window_x,vg.window_y}, 0x01ffffff ); + ui_fill( ctx, (ui_rect){0,0,_vg_window.w,_vg_window.h}, 0x01ffffff ); ui_px w = 500; - ent_route_leaderboard_ui( ctx, (ui_rect){ vg.window_x/2 - w/2, 64, w, 0 }, index ); + ent_route_leaderboard_ui( ctx, (ui_rect){ _vg_window.w/2 - w/2, 64, w, 0 }, index ); } void ent_route_leaderboard_ui( ui_context *ctx, ui_rect ref_box, u32 route_index ) @@ -135,7 +129,7 @@ void ent_route_leaderboard_ui( ui_context *ctx, ui_rect ref_box, u32 route_index char mod_uid[ ADDON_UID_MAX ]; addon_make_uid( _world.main.addon_id, mod_uid ); - network_request_scoreboard( mod_uid, af_str( &world->meta.af, route->pstr_name ), + network_request_scoreboard( mod_uid, af_str( world->meta.packed_strings, route->pstr_name ), NETWORK_LEADERBOARD_ALLTIME_AND_CURRENT_WEEK, route_index ); } @@ -146,6 +140,11 @@ void ent_route_leaderboard_ui( ui_context *ctx, ui_rect ref_box, u32 route_index return; } + ui_fill( ctx, leaderboard_box, ui_opacity( GUI_COL_DARK, 0.36f ) ); + ui_text( ctx, leaderboard_box, "FIXME FIXME!!!!!", 1, k_ui_align_middle_center, 0 ); + + //FIXME////FIXME +#if 0 vg_msg body; vg_msg_init( &body, board->data, board->data_len ); @@ -275,8 +274,8 @@ void ent_route_leaderboard_ui( ui_context *ctx, ui_rect ref_box, u32 route_index u64 steamid; vg_msg_getkvintg( &body, "steamid", k_vg_msg_u64, &steamid, NULL ); ui_px y = bl[1]; - if( (y + 200+8) > vg.window_y ) - y = vg.window_y - (200+8); + if( (y + 200+8) > _vg_window.h ) + y = _vg_window.h - (200+8); _user_profile_ui( ctx, (ui_rect){ bl[0]-(360+8),y, 360,200 }, steamid ); } @@ -286,30 +285,17 @@ void ent_route_leaderboard_ui( ui_context *ctx, ui_rect ref_box, u32 route_index { skaterift.activity = k_skaterift_default; - u32 last_minute = (u32)( lastsec / 60 ); - - // TODO: put this in a header - u32 minutes_span = (centiseconds+(200*60)) / (100*60); - vg_queue_clear( &_remote_replay.buffer ); - _remote_replay.min_frame_t = 0.0; - _remote_replay.total_chunks = minutes_span; - _remote_replay.chunks_downloaded = 0; + // FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME//// +#if 0 u64 steamid; vg_msg_getkvintg( &body, "steamid", k_vg_msg_u64, &steamid, NULL ); - _remote_replay.steamid = steamid; - _remote_replay.state = k_remote_replay_state_init; - _remote_replay.last_second = lastsec; - - for( u32 i=0; iminute = last_minute - minutes_span + 1 + i; - chunk->state = k_chunk_state_none; - } +#endif + u64 steamid = 0; + _remote_replay_reset( centiseconds, lastsec, steamid ); world_clear_event( k_world_event_route_leaderboard ); srinput.state = k_input_state_resume; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); _replay2_open_player( k_replay_type_network, 0 ); } } @@ -320,6 +306,7 @@ void ent_route_leaderboard_ui( ui_context *ctx, ui_rect ref_box, u32 route_index _ent_route.entries_max = count; vg_ui.frosting = 0.015f; ui_flush( ctx, k_ui_shader_colour, NULL ); +#endif vg_ui.frosting = 0.0f; ctx->font = &vgf_default_small; } diff --git a/src/ent_route.h b/src/ent_route.h index 2c8f080..830e882 100644 --- a/src/ent_route.h +++ b/src/ent_route.h @@ -1,5 +1,6 @@ -#pragma once -#include "entity.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_route.c" +#else struct _ent_route { @@ -17,3 +18,5 @@ entity_event_result ent_route_event( ent_event *event ); void ent_route_preupdate(void); void ent_route_leaderboard_ui( ui_context *ctx, ui_rect ref_box, u32 route_index ); void _ent_route_imgui( ui_context *ctx ); + +#endif diff --git a/src/ent_script.c b/src/ent_script.c index a35b8fc..650ed31 100644 --- a/src/ent_script.c +++ b/src/ent_script.c @@ -1,5 +1,3 @@ -#include "ent_script.h" - struct { void **userdata_array; @@ -46,7 +44,7 @@ void ent_script_alloc( world_instance *world, vg_stack_allocator *stack ) for( u32 i=0; ient_script ); i ++ ) { ent_script *script = af_arritm( &world->ent_script, i ); - const char *script_name = af_str( &world->meta.af, script->pstr_script_name ); + const char *script_name = af_str( world->meta.packed_strings, script->pstr_script_name ); for( u32 j=0; 1; j ++ ) { diff --git a/src/ent_script.h b/src/ent_script.h index a29b2fe..d6bb64b 100644 --- a/src/ent_script.h +++ b/src/ent_script.h @@ -1,4 +1,6 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_script.c" +#else struct script_event_allocate { @@ -57,3 +59,5 @@ void ent_script_start( world_instance *world ); void ent_script_update( world_instance *world ); void ent_script_alloc( world_instance *world, vg_stack_allocator *stack ); entity_event_result _ent_script_world_event( ent_event *event ); + +#endif diff --git a/src/ent_skateshop.c b/src/ent_skateshop.c index 004d716..efe5a29 100644 --- a/src/ent_skateshop.c +++ b/src/ent_skateshop.c @@ -1,17 +1,3 @@ -#include "vg/vg_steam2.h" -#include "vg/vg_msg.h" -#include "vg/vg_tex.h" -#include "vg/vg_image.h" -#include "vg/vg_loader.h" -#include "ent_skateshop.h" -#include "world.h" -#include "player.h" -#include "gui.h" -#include "menu.h" -#include "addon.h" -#include "save.h" -#include "network.h" - struct global_skateshop _skateshop; static void skateshop_update_viewpage(void) @@ -34,22 +20,12 @@ static void skateshop_update_viewpage(void) } } -static void skateshop_init_async( void *userdata ) -{ - THREAD_0; - - skaterift.rt_textures[ k_skaterift_rt_workshop_preview ] = vg.tex_missing; - skaterift.rt_textures[ k_skaterift_rt_server_status ] = vg.tex_missing; - render_server_status_gui(); -} - /* * VG event init */ -void skateshop_init(void) +VG_API void _skateshop_init(void) { - THREAD_1; - vg_async_call( &vg.main_tasks, skateshop_init_async, NULL ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); } static addon_cache_id skateshop_selected_board_cache_id(void) @@ -68,7 +44,7 @@ static void skateshop_server_helper_update(void) vg_str text; vg_strnull( &text, _skateshop.helper_toggle->text, sizeof(_skateshop.helper_toggle->text) ); - if( g_client.demo_mode ) + if( _is_running_demo() ) { vg_strcat( &text, "Not availible in demo" ); } @@ -85,39 +61,37 @@ struct skateshop_scan_info { enum addon_type type; }; -static void skateshop_addon_scan_task( vg_async_task *task ) +static void skateshop_addon_scan_task( struct skateshop_scan_info *in_args, vg_async_info *async ) { - THREAD_1; - struct skateshop_scan_info *info = (void *)task->data; - if( info->type == k_addon_type_board ) + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + if( in_args->type == k_addon_type_board ) _addon_mount_content_folder( k_addon_type_board, "boards", ".mdl" ); - else if( info->type == k_addon_type_player ) + else if( in_args->type == k_addon_type_player ) _addon_mount_content_folder( k_addon_type_world, "playermodels", ".mdl" ); - else if( info->type == k_addon_type_world ) + else if( in_args->type == k_addon_type_world ) _addon_mount_content_folder( k_addon_type_world, "maps", ".mdl" ); } static void skateshop_scan( enum addon_type specific_type ) { - THREAD_0; - _mount_workshop_addons( NULL ); - vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct skateshop_scan_info), 1 ); - struct skateshop_scan_info *info = (void *)task->data; - info->type = specific_type; - vg_async_task_dispatch( task, skateshop_addon_scan_task ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _mount_workshop_addons(); + struct skateshop_scan_info *out_args = _vg_async_alloc( VG_THREAD_ASYNC_ID, sizeof(struct skateshop_scan_info) ); + out_args->type = specific_type; + _vg_async_send( out_args, (vg_async_fn)skateshop_addon_scan_task ); } static void ent_skateshop_helpers_pickable( const char *acceptance ) { vg_str text; - if( gui_new_helper( input_button_list[k_srbind_mback], &text )) + if( _gui_new_helper( input_button_list[k_srbind_mback], &text )) vg_strcat( &text, "Exit" ); - if( (_skateshop.helper_pick = gui_new_helper( input_button_list[k_srbind_maccept], &text))) + if( (_skateshop.helper_pick = _gui_new_helper( input_button_list[k_srbind_maccept], &text))) vg_strcat( &text, acceptance ); - if( (_skateshop.helper_browse = gui_new_helper( input_axis_list[k_sraxis_mbrowse_h], &text ))) + if( (_skateshop.helper_browse = _gui_new_helper( input_axis_list[k_sraxis_mbrowse_h], &text ))) vg_strcat( &text, "Browse" ); } @@ -137,7 +111,7 @@ static void skateshop_accept_board( addon_cache_id cache_id ) addon_cache_watch( k_addon_type_board, cache_id ); localplayer.board_view_slot = cache_id; network_send_item( k_netmsg_playeritem_board ); - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); skateshop_playermod( 0 ); _skateshop.open = 0; } @@ -146,7 +120,7 @@ static void skateshop_accept_board( addon_cache_id cache_id ) void charshop_quitsave(void) { _skateshop.open = 0; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); skateshop_playermod( 0 ); srinput.state = k_input_state_resume; @@ -163,14 +137,18 @@ void charshop_quitsave(void) if( model->flags & PLAYER_MODEL_FLAG_CUSTOMIZABLE ) { + // FIXME////FIXME/FIXME write cpart +#if 0 addon_cache_entry *cache_entry = get_addon_cache_entry( k_addon_type_player, slot ); memcpy( cache_entry->local_cpart, localplayer.playermodel.cpart, ADDON_CPART_MAX ); savedata_file file; init_savefile( &file, "" ); - addon_make_savedata_path( cache_entry->addon_id, file.path ); - vg_msg_wkvstr( &file.msg, "cpart", localplayer.playermodel.cpart ); - write_savefile( &file, 1 ); + //addon_make_savedata_path( cache_entry->addon_id, file.path ); + + //vg_msg_wkvstr( &file.msg, "cpart", localplayer.playermodel.cpart ); + //write_savefile( &file, 1 ); +#endif } network_send_item( k_netmsg_playeritem_player ); @@ -199,7 +177,7 @@ void ent_skateshop_update(void) else { _skateshop.open = 0; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); skateshop_playermod( 0 ); srinput.state = k_input_state_resume; } @@ -274,7 +252,7 @@ void ent_skateshop_update(void) { f64 delta = vg.time_real - network_client.last_intent_change; - if( (delta > 5.0) && (!g_client.demo_mode) ) + if( (delta > 5.0) && !_is_running_demo() ) { _skateshop.helper_pick->greyed = 0; if( button_down( k_srbind_maccept ) ) @@ -353,7 +331,7 @@ fade_out:; float scale = 0.2f, thickness = 0.03f; - font3d_bind( &gui.font, k_font_shader_default, 0, world, cam ); + font3d_bind( &gui.font, k_font_shader_default, 0, cam ); shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} ); /* Selection counter @@ -372,9 +350,9 @@ fade_out:; char buf[16]; vg_str str; vg_strnull( &str, buf, sizeof(buf) ); - vg_strcati32( &str, _skateshop.selected_board_index+1 ); + vg_strcati64( &str, _skateshop.selected_board_index+1, 10 ); vg_strcatch( &str, '/' ); - vg_strcati32( &str, valid_count ); + vg_strcati64( &str, valid_count, 10 ); font3d_simple_draw( 0, buf, cam, mmdl ); } else @@ -397,17 +375,17 @@ fade_out:; { _skateshop.render.item_title = ""; _skateshop.render.item_desc = ""; - vg_msg msg; - vg_msg_init( &msg, reg->metadata, reg->metadata_len ); - if( vg_msg_seekframe( &msg, "workshop" ) ) + u32 workshop_block = vg_kv_find( ®->metadata, 0, "workshop" ); + if( workshop_block ) { - const char *title = vg_msg_getkvstr( &msg, "title" ); - if( title ) _skateshop.render.item_title = title; + const c8 *title = vg_kv_value( ®->metadata, vg_kv_find( ®->metadata, workshop_block, "title" ), NULL ); + if( title ) + _skateshop.render.item_title = title; - const char *dsc = vg_msg_getkvstr( &msg, "author" ); - if( dsc ) _skateshop.render.item_desc = dsc; - vg_msg_skip_frame( &msg ); + const c8 *dsc = vg_kv_value( ®->metadata, vg_kv_find( ®->metadata, workshop_block, "author" ), NULL ); + if( dsc ) + _skateshop.render.item_desc = dsc; } _skateshop.render.addon_id = entry->addon_id; @@ -509,7 +487,7 @@ entity_event_result ent_skateshop_event( ent_event *event ) world_instance *world = &_world.main; ent_skateshop *shop = af_arritm( &world->ent_skateshop, mdl_entity_id_id( event->recieve_entity_id ) ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "open" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "open" ) ) { if( world_set_event( k_world_event_shop ) ) { @@ -521,7 +499,7 @@ entity_event_result ent_skateshop_event( ent_event *event ) skateshop_scan( k_addon_type_board ); } - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); if( shop->type == k_skateshop_type_charshop ) { @@ -573,7 +551,7 @@ void charshop_gui( ui_context *ctx ) i32 R = menu_nav( &_skateshop.charshop_row, mv, _skateshop.charshop_row_max ); - ui_rect panel = { 8, 8, 350, vg.window_y }; + ui_rect panel = { 8, 8, 350, _vg_window.h }; ui_fill( ctx, panel, ui_opacity( GUI_COL_DARK, 0.35f ) ); ui_outline( ctx, panel, 1, GUI_COL_NORM, 0 ); ui_rect_pad( panel, (ui_px[]){8,8} ); @@ -625,14 +603,12 @@ void charshop_gui( ui_context *ctx ) player__use_model( id ); addon_reg *reg = addon_details( id ); - vg_msg msg; - vg_msg_init( &msg, reg->metadata, reg->metadata_len ); - - if( vg_msg_seekframe( &msg, "workshop" ) ) + u32 workshop_block = vg_kv_find( ®->metadata, 0, "workshop" ); + if( workshop_block ) { - const char *title = vg_msg_getkvstr( &msg, "title" ); - if( title ) _skateshop.render.item_title = title; - vg_msg_skip_frame( &msg ); + const c8 *title = vg_kv_value( ®->metadata, vg_kv_find( ®->metadata, workshop_block, "title" ), NULL ); + if( title ) + _skateshop.render.item_title = title; } } @@ -664,7 +640,7 @@ void charshop_gui( ui_context *ctx ) for( u32 i=0; iediter_property, i ); - const char *alias = af_str( &model->mdl.af, prop->pstr_alias ); + const char *alias = af_str( &model->model.packed_strings, prop->pstr_alias ); if( prop->ui_type == k_editer_type_toggle ) { @@ -701,7 +677,7 @@ void charshop_gui( ui_context *ctx ) } else if( prop->ui_type == k_editer_type_selecter ) { - const char *options = af_str( &model->mdl.af, prop->max.pstr_options ); + const char *options = af_str( model->model.packed_strings, prop->max.pstr_options ); if( menu_options( ctx, panel, R == i+1, &_skateshop.charshop_col, alias, options, &view->property_values[i]._u32, mh, enter ) ) edited = 1; @@ -739,7 +715,7 @@ void charshop_gui( ui_context *ctx ) ctx->font = &vgf_default_small; } -void ent_skateshop_gui( ui_context *ctx ) +void _ent_skateshop_gui( ui_context *ctx ) { if( _world.event == k_world_event_shop ) { @@ -775,7 +751,7 @@ void ent_skateshop_gui( ui_context *ctx ) v2_divs( handles[i], handles[i][3], handles[i] ); v2_muladds( (v2f){0.5f,0.5f}, handles[i], 0.5f, handles[i] ); handles[i][1] = 1.0f - handles[i][1]; - v2_mul( (v2f){ vg.window_x, vg.window_y }, handles[i], handles[i] ); + v2_mul( (v2f){ _vg_window.w, _vg_window.h }, handles[i], handles[i] ); } ui_px r = 24; diff --git a/src/ent_skateshop.h b/src/ent_skateshop.h index fc5e304..49d0caa 100644 --- a/src/ent_skateshop.h +++ b/src/ent_skateshop.h @@ -1,10 +1,6 @@ -#pragma once -#include "world.h" -#include "world_load.h" -#include "player.h" -#include "vg/vg_steam2.h" -#include "workshop.h" -#include "addon.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_skateshop.c" +#else #define SKATESHOP_VIEW_SLOT_MAX 5 @@ -45,7 +41,7 @@ struct global_skateshop } extern _skateshop; -void skateshop_init(void); +VG_API void _skateshop_init(void); void ent_skateshop_update(void); void ent_skateshop_render( vg_camera *cam ); @@ -53,3 +49,6 @@ void skateshop_autostart_loading(void); void skateshop_world_preupdate(void); entity_event_result ent_skateshop_event( ent_event *event ); void skateshop_world_preview_preupdate(void); +void _ent_skateshop_gui( ui_context *ctx ); + +#endif diff --git a/src/ent_tornado.c b/src/ent_tornado.c index 52b33d4..e707241 100644 --- a/src/ent_tornado.c +++ b/src/ent_tornado.c @@ -1,11 +1,8 @@ -#include "world.h" -#include "particle.h" - static f32 k_tornado_strength = 0.0f, k_tornado_ratio = 0.5f, k_tornado_range = 10.f; -void ent_tornado_register(void) +VG_API void _ent_tornado_register(void) { vg_console_reg_var( "k_tonado_strength", &k_tornado_strength, k_var_dtype_f32, VG_VAR_PERSISTENT|VG_VAR_CHEAT ); @@ -21,8 +18,7 @@ void ent_tornado_debug(void) for( u32 i=0; ient_marker); i ++ ) { ent_marker *marker = af_arritm( &world->ent_marker, i ); - - if( AF_STR_EQ( &world->meta.af, marker->pstr_alias, "tornado" ) ) + if( AF_STR_EQ( world->meta.packed_strings, marker->pstr_alias, "tornado" ) ) { v3f p1; v3_add( marker->transform.co, (v3f){0,20,0}, p1 ); @@ -44,8 +40,7 @@ void ent_tornado_forces( v3f co, v3f cv, v3f out_a ) for( u32 i=0; ient_marker); i ++ ) { ent_marker *marker = af_arritm( &world->ent_marker, i ); - - if( AF_STR_EQ( &world->meta.af, marker->pstr_alias, "tornado" ) ) + if( AF_STR_EQ( world->meta.packed_strings, marker->pstr_alias, "tornado" ) ) { v3f d, dir; v3_sub( co, marker->transform.co, d ); @@ -74,8 +69,7 @@ void ent_tornado_pre_update(void) for( u32 i=0; ient_marker); i ++ ) { ent_marker *marker = af_arritm( &world->ent_marker, i ); - - if( AF_STR_EQ( &world->meta.af, marker->pstr_alias, "tornado" ) ) + if( AF_STR_EQ( world->meta.packed_strings, marker->pstr_alias, "tornado" ) ) { v3f co; vg_rand_sphere( &vg.rand, co ); diff --git a/src/ent_tornado.h b/src/ent_tornado.h index c2dfb8b..424f9d0 100644 --- a/src/ent_tornado.h +++ b/src/ent_tornado.h @@ -1,6 +1,10 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_tornado.c" +#else -void ent_tornado_register(void); +VG_API void _ent_tornado_register(void); void ent_tornado_debug(void); void ent_tornado_forces( v3f co, v3f cv, v3f out_a ); void ent_tornado_pre_update(void); + +#endif diff --git a/src/ent_traffic.c b/src/ent_traffic.c index a14f62f..693fcfb 100644 --- a/src/ent_traffic.c +++ b/src/ent_traffic.c @@ -1,5 +1,3 @@ -#include "world.h" - void ent_traffic_update( world_instance *world, v3f pos ) { for( u32 i=0; ient_traffic ); i++ ){ diff --git a/src/ent_traffic.h b/src/ent_traffic.h index 18d8d1e..6d60f5e 100644 --- a/src/ent_traffic.h +++ b/src/ent_traffic.h @@ -1,3 +1,5 @@ -#pragma once -#include "world.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/ent_traffic.c" +#else void ent_traffic_update( world_instance *world, v3f pos ); +#endif diff --git a/src/entity.c b/src/entity.c index 2004502..e69de29 100644 --- a/src/entity.c +++ b/src/entity.c @@ -1,16 +0,0 @@ -#include "world.h" -#include "entity.h" -#include "world_entity.h" - -#include "ent_objective.h" -#include "ent_skateshop.h" -#include "ent_relay.h" -#include "ent_challenge.h" -#include "ent_route.h" -#include "ent_region.h" -#include "ent_glider.h" -#include "ent_prop.h" -#include "world_water.h" - -#include - diff --git a/src/entity.h b/src/entity.h index 10ca6b4..0d6b4dd 100644 --- a/src/entity.h +++ b/src/entity.h @@ -1,8 +1,6 @@ -#pragma once - -#include "vg/vg_audio.h" -#include "vg/vg_ui/imgui.h" -#include "model.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/entity.c" +#else typedef struct ent_spawn ent_spawn; typedef struct ent_light ent_light; @@ -781,3 +779,5 @@ struct ent_event } data; }; + +#endif diff --git a/src/font.c b/src/font.c new file mode 100644 index 0000000..514de1c --- /dev/null +++ b/src/font.c @@ -0,0 +1,252 @@ +VG_TIER_2 void font3d_load( font3d *font, const c8 *mdl_path, vg_stack_allocator *stack ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + vg_model_stream_context ctx; + VG_ASSERT( vg_model_stream_open( &ctx, &font->model, mdl_path ) ); + vg_model_stream_metadata( &ctx, stack ); + vg_model_stream_meshes_gpu( &ctx, NULL ); + vg_model_stream_textures_gpu( &ctx ); + + u32 temp_frame = _vg_start_temp_frame(); + { + array_file_ptr fonts; + AF_LOAD_ARRAY_STRUCT( &ctx.af, &fonts, ent_font, _vg_temp_stack() ); + VG_ASSERT( af_arrcount(&fonts) ); + font->info = *((ent_font *)af_arritm(&fonts,0)); + } + _vg_end_temp_frame( temp_frame ); + + AF_LOAD_ARRAY_STRUCT( &ctx.af, &font->font_variants, ent_font_variant, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &font->glyphs, ent_glyph, stack ); + vg_model_stream_close( &ctx ); +} + +VG_TIER_0 u32 font3d_find_variant( font3d *font, const c8 *name ) +{ + for( u32 i=0; ifont_variants ); i ++ ) + { + ent_font_variant *variant = af_arritm( &font->font_variants, i ); + if( !strcmp( af_str( font->model.packed_strings, variant->name ), name ) ) + return i; + } + + return 0; +} + +struct _font3d_render +{ + v4f offset; + font3d *font; + u32 variant_id; + + enum font_shader shader; +} +static gui_font3d; + +/* + * world can be null if not using world shader + */ +VG_TIER_0 void font3d_bind( font3d *font, enum font_shader shader, i32 depth_compare, vg_camera *cam ) +{ + gui_font3d.shader = shader; + gui_font3d.font = font; + vg_tex_bind( GL_TEXTURE_2D, &font->model.textures[0].tex, 1 ); + + if( shader == k_font_shader_default ) + { + shader_model_font_use(); + shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} ); + shader_model_font_uTexMain( 1 ); + shader_model_font_uDepthMode( depth_compare ); + if( depth_compare ) + { + depth_compare_bind( shader_model_font_uTexSceneDepth, + shader_model_font_uInverseRatioDepth, + shader_model_font_uInverseRatioMain, cam ); + } + shader_model_font_uPv( cam->mtx.pv ); + } + else if( shader == k_font_shader_world ) + { + shader_scene_font_use(); + shader_scene_font_uTexGarbage(0); + shader_scene_font_uTexMain(1); + + shader_scene_font_uPv( g_render.cam.mtx.pv ); + shader_scene_font_uTime( vg.time ); + + WORLD_LINK_TERRAIN_NOISE( &_world.main, scene_font ); + WORLD_LINK_LIGHTING( &_world.main, scene_font ); + shader_scene_font_uCamera( g_render.cam.transform[3] ); + } + + vg_model_bind_mesh( &font->model ); +} + +VG_TIER_0 ent_glyph *font3d_glyph( font3d *font, u32 variant_id, u32 utf32 ) +{ + if( utf32 < font->info.glyph_utf32_base ) return NULL; + if( utf32 >= font->info.glyph_utf32_base+font->info.glyph_count) return NULL; + + u32 index = utf32 - font->info.glyph_utf32_base; + index += font->info.glyph_start; + index += font->info.glyph_count * variant_id; + return af_arritm( &font->glyphs, index ); +} + +VG_API void font3d_set_transform( const c8 *text, vg_camera *cam, m4x3f transform ) +{ + v4_copy( (v4f){0.0f,0.0f,0.0f,1.0f}, gui_font3d.offset ); + + m4x4f prev_mtx; + m4x3_expand( transform, prev_mtx ); + m4x4_mul( cam->mtx_prev.pv, prev_mtx, prev_mtx ); + + if( gui_font3d.shader == k_font_shader_default ) + { + shader_model_font_uPvmPrev( prev_mtx ); + shader_model_font_uMdl( transform ); + } + else if( gui_font3d.shader == k_font_shader_world ) + { + shader_scene_font_uPvmPrev( prev_mtx ); + shader_scene_font_uMdl( transform ); + } +} + +VG_API void font3d_setoffset( v4f offset ) +{ + if( gui_font3d.shader == k_font_shader_default ) + shader_model_font_uOffset( offset ); + else if( gui_font3d.shader == k_font_shader_world ) + shader_scene_font_uOffset( offset ); +} + +VG_API void font3d_setcolour( v4f colour ) +{ + if( gui_font3d.shader == k_font_shader_default ) + shader_model_font_uColour( colour ); +#if 0 + else if( gui_font3d.shader == k_font_shader_world ) + shader_scene_font_uColour( colour ); +#endif +} + +VG_API void font3d_draw( const c8 *text ) +{ + u8 *u8pch = (u8*)text; + + u32 max_chars = 512; + while( u8pch && max_chars ) + { + max_chars --; + + u32 c0 = *u8pch, c1; + u8pch ++; + + if( !c0 ) + break; + ent_glyph *glyph0 = font3d_glyph( gui_font3d.font, gui_font3d.variant_id, c0 ), + *glyph1 = NULL; + /* multibyte characters */ + if( c0 >= 1 && c0 < k_SRglyph_ascii_min ) + { + c1 = *u8pch; + if( !c1 ) break; + glyph1 = font3d_glyph( gui_font3d.font, gui_font3d.variant_id, c1 ); + } + + if( c0 == k_SRglyph_ctrl_variant ) + { + gui_font3d.variant_id = c1; + u8pch ++; + continue; + } + else if( c0 == k_SRglyph_ctrl_size ) + { + gui_font3d.offset[3] = (float)c1 * (1.0f/255.0f); + u8pch ++; + continue; + } + else if( c0 == k_SRglyph_ctrl_baseline ) + { + gui_font3d.offset[1] = 0.0f; + continue; + } + else if( c0 == k_SRglyph_ctrl_center ) + { + if( glyph1 ) + { + float diff = glyph1->size[1] - glyph1->size[1]*gui_font3d.offset[3]; + gui_font3d.offset[1] = diff * 0.5f; + } + continue; + } + else if( c0 == k_SRglyph_ctrl_top ) + { + if( glyph1 ) + { + float diff = glyph1->size[1] - glyph1->size[1]*gui_font3d.offset[3]; + gui_font3d.offset[1] = diff; + } + continue; + } + + if( !glyph0 ) + continue; + + if( glyph1 && (c0 == k_SRglyph_mod_square || c0 == k_SRglyph_mod_circle)) + { + v4f v0; + v2_sub( glyph0->size, glyph1->size, v0 ); + v2_muladds( gui_font3d.offset, v0, -0.5f, v0 ); + v0[2] = gui_font3d.offset[2]; + v0[3] = gui_font3d.offset[3]; + + font3d_setoffset( v0 ); + vg_model_draw_elements( glyph0->indice_start, glyph0->indice_count ); + continue; + } + else + { + font3d_setoffset( gui_font3d.offset ); + vg_model_draw_elements( glyph0->indice_start, glyph0->indice_count ); + } + + gui_font3d.offset[0] += glyph0->size[0]*gui_font3d.offset[3]; + } +} + +VG_API f32 font3d_simple_draw( u32 variant_id, const c8 *text, vg_camera *cam, m4x3f transform ) +{ + if( !text ) + return 0.0f; + + gui_font3d.variant_id = variant_id; + font3d_set_transform( text, cam, transform ); + font3d_draw( text ); + return gui_font3d.offset[0]; +} + +VG_TIER_0 f32 font3d_string_width( u32 variant_id, const c8 *text ) +{ + if( !text ) + return 0.0f; + f32 width = 0.0f; + + const u8 *buf = (const u8 *)text; + for( u32 i=0;; i++ ) + { + u32 c = buf[i]; + if( !c ) + break; + + ent_glyph *glyph = font3d_glyph( gui_font3d.font, variant_id, c ); + if( !glyph ) + continue; + + width += glyph->size[0]; + } + + return width; +} diff --git a/src/font.h b/src/font.h index c1da41c..a69c497 100644 --- a/src/font.h +++ b/src/font.h @@ -1,13 +1,6 @@ -#pragma once -#include "model.h" -#include "entity.h" -#include "vg/vg_camera.h" -#include "shaders/model_font.h" -#include "shaders/scene_font.h" -#include "world_render.h" -#include "depth_compare.h" -#include "vg/vg_tex.h" -#include +#if defined( SR_IMPLEMENTATION ) +# include "src/font.c" +#else enum efont_SRglyph{ k_SRglyph_end = 0x00, /* control characters */ @@ -71,257 +64,28 @@ enum efont_SRglyph{ }; typedef struct font3d font3d; -struct font3d{ - mdl_context mdl; - GLuint texture; - glmesh mesh; - +struct font3d +{ + vg_model model; ent_font info; - array_file_ptr font_variants, - glyphs; + array_file_ptr font_variants, glyphs; }; -static void font3d_load( font3d *font, const char *mdl_path, void *alloc ) -{ - THREAD_1; - mdl_context *mdl = &font->mdl; - mdl_open( mdl, mdl_path, alloc ); - mdl_load_metadata_block( mdl, alloc ); - - vg_stack_clear( &vg.scratch ); - array_file_ptr fonts; - AF_LOAD_ARRAY_STRUCT( &mdl->af, &fonts, ent_font, &vg.scratch ); - font->info = *((ent_font *)af_arritm(&fonts,0)); - - AF_LOAD_ARRAY_STRUCT( &mdl->af, &font->font_variants, ent_font_variant, alloc ); - AF_LOAD_ARRAY_STRUCT( &mdl->af, &font->glyphs, ent_glyph, alloc ); - vg_stack_clear( &vg.scratch ); - - if( !font->mdl.texture_count ) - vg_fatal_error( "No texture in font file" ); - - mdl_texture *tex0 = &mdl->textures[ 0 ]; - void *data = vg_stack_allocate( &vg.scratch, tex0->file.pack_size, 8, "Pack data" ); - mdl_fread_pack_file( mdl, &tex0->file, data ); - - mdl_async_load_glmesh( mdl, &font->mesh, NULL ); - vg_tex2d_load_qoi_async( data, tex0->file.pack_size, VG_TEX2D_LINEAR|VG_TEX2D_CLAMP, &font->texture ); - - mdl_close( mdl ); -} - -static u32 font3d_find_variant( font3d *font, const char *name ) -{ - for( u32 i=0; ifont_variants ); i ++ ) - { - ent_font_variant *variant = af_arritm( &font->font_variants, i ); - - if( !strcmp( af_str( &font->mdl.af, variant->name ), name ) ) - return i; - } - - return 0; -} - -struct _font3d_render{ - v4f offset; - font3d *font; - u32 variant_id; - - enum font_shader { - k_font_shader_default, - k_font_shader_world - } - shader; -} -static gui_font3d; - -/* - * world can be null if not using world shader - */ -static void font3d_bind( font3d *font, enum font_shader shader, int depth_compare, world_instance *world,vg_camera *cam ) +enum font_shader { - gui_font3d.shader = shader; - gui_font3d.font = font; - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, font->texture ); - - if( shader == k_font_shader_default ) - { - shader_model_font_use(); - shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} ); - shader_model_font_uTexMain( 1 ); - shader_model_font_uDepthMode( depth_compare ); - - if( depth_compare ) - { - depth_compare_bind( - shader_model_font_uTexSceneDepth, - shader_model_font_uInverseRatioDepth, - shader_model_font_uInverseRatioMain, cam ); - } - - shader_model_font_uPv( cam->mtx.pv ); - } - else if( shader == k_font_shader_world ) - { - shader_scene_font_use(); - shader_scene_font_uTexGarbage(0); - shader_scene_font_uTexMain(1); - - shader_scene_font_uPv( g_render.cam.mtx.pv ); - shader_scene_font_uTime( vg.time ); - - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_font ); - - bind_terrain_noise(); - shader_scene_font_uCamera( g_render.cam.transform[3] ); - } - mesh_bind( &font->mesh ); -} - -static ent_glyph *font3d_glyph( font3d *font, u32 variant_id, u32 utf32 ){ - if( utf32 < font->info.glyph_utf32_base ) return NULL; - if( utf32 >= font->info.glyph_utf32_base+font->info.glyph_count) return NULL; - - u32 index = utf32 - font->info.glyph_utf32_base; - index += font->info.glyph_start; - index += font->info.glyph_count * variant_id; - return af_arritm( &font->glyphs, index ); -} - -static void font3d_set_transform( const char *text, - vg_camera *cam, m4x3f transform ){ - v4_copy( (v4f){0.0f,0.0f,0.0f,1.0f}, gui_font3d.offset ); - - m4x4f prev_mtx; - m4x3_expand( transform, prev_mtx ); - m4x4_mul( cam->mtx_prev.pv, prev_mtx, prev_mtx ); - - if( gui_font3d.shader == k_font_shader_default ){ - shader_model_font_uPvmPrev( prev_mtx ); - shader_model_font_uMdl( transform ); - } - else if( gui_font3d.shader == k_font_shader_world ){ - shader_scene_font_uPvmPrev( prev_mtx ); - shader_scene_font_uMdl( transform ); - } -} + k_font_shader_default, + k_font_shader_world +}; -static void font3d_setoffset( v4f offset ){ - if( gui_font3d.shader == k_font_shader_default ) - shader_model_font_uOffset( offset ); - else if( gui_font3d.shader == k_font_shader_world ) - shader_scene_font_uOffset( offset ); -} +VG_TIER_2 void font3d_load( font3d *font, const c8 *mdl_path, vg_stack_allocator *stack ); +VG_TIER_0 u32 font3d_find_variant( font3d *font, const c8 *name ); +VG_TIER_0 void font3d_bind( font3d *font, enum font_shader shader, i32 depth_compare, vg_camera *cam ); +VG_TIER_0 ent_glyph *font3d_glyph( font3d *font, u32 variant_id, u32 utf32 ); +VG_API void font3d_set_transform( const c8 *text, vg_camera *cam, m4x3f transform ); +VG_API void font3d_setoffset( v4f offset ); +VG_API void font3d_setcolour( v4f colour ); +VG_API void font3d_draw( const c8 *text ); +VG_API f32 font3d_simple_draw( u32 variant_id, const c8 *text, vg_camera *cam, m4x3f transform ); +VG_TIER_0 f32 font3d_string_width( u32 variant_id, const c8 *text ); -static void font3d_setcolour( v4f colour ){ - if( gui_font3d.shader == k_font_shader_default ) - shader_model_font_uColour( colour ); -#if 0 - else if( gui_font3d.shader == k_font_shader_world ) - shader_scene_font_uColour( colour ); #endif -} - -static void font3d_draw( const char *text ){ - u8 *u8pch = (u8*)text; - - u32 max_chars = 512; - while( u8pch && max_chars ){ - max_chars --; - - u32 c0 = *u8pch, c1; - u8pch ++; - - if( !c0 ) break; - - ent_glyph *glyph0 = font3d_glyph( gui_font3d.font, - gui_font3d.variant_id, c0 ), - *glyph1 = NULL; - - /* multibyte characters */ - if( c0 >= 1 && c0 < k_SRglyph_ascii_min ){ - c1 = *u8pch; - if( !c1 ) break; - glyph1 = font3d_glyph( gui_font3d.font, gui_font3d.variant_id, c1 ); - } - - if( c0 == k_SRglyph_ctrl_variant ){ - gui_font3d.variant_id = c1; - u8pch ++; - continue; - } - else if( c0 == k_SRglyph_ctrl_size ){ - gui_font3d.offset[3] = (float)c1 * (1.0f/255.0f); - u8pch ++; - continue; - } - else if( c0 == k_SRglyph_ctrl_baseline ){ - gui_font3d.offset[1] = 0.0f; - continue; - } - else if( c0 == k_SRglyph_ctrl_center ){ - if( glyph1 ){ - float diff = glyph1->size[1] - glyph1->size[1]*gui_font3d.offset[3]; - gui_font3d.offset[1] = diff * 0.5f; - } - continue; - } - else if( c0 == k_SRglyph_ctrl_top ){ - if( glyph1 ){ - float diff = glyph1->size[1] - glyph1->size[1]*gui_font3d.offset[3]; - gui_font3d.offset[1] = diff; - } - continue; - } - - if( !glyph0 ) continue; - - if( glyph1 && (c0 == k_SRglyph_mod_square || c0 == k_SRglyph_mod_circle)){ - v4f v0; - v2_sub( glyph0->size, glyph1->size, v0 ); - v2_muladds( gui_font3d.offset, v0, -0.5f, v0 ); - v0[2] = gui_font3d.offset[2]; - v0[3] = gui_font3d.offset[3]; - - font3d_setoffset( v0 ); - mesh_drawn( glyph0->indice_start, glyph0->indice_count ); - continue; - } - else{ - font3d_setoffset( gui_font3d.offset ); - mesh_drawn( glyph0->indice_start, glyph0->indice_count ); - } - - gui_font3d.offset[0] += glyph0->size[0]*gui_font3d.offset[3]; - } -} - -static f32 font3d_simple_draw( u32 variant_id, const char *text, - vg_camera *cam, m4x3f transform ){ - if( !text ) return 0.0f; - - gui_font3d.variant_id = variant_id; - font3d_set_transform( text, cam, transform ); - font3d_draw( text ); - return gui_font3d.offset[0]; -} - -static f32 font3d_string_width( u32 variant_id, const char *text ){ - if( !text ) return 0.0f; - float width = 0.0f; - - const u8 *buf = (const u8 *)text; - for( int i=0;; i++ ){ - u32 c = buf[i]; - if(!c) break; - - ent_glyph *glyph = font3d_glyph( gui_font3d.font, variant_id, c ); - if( !glyph ) continue; - - width += glyph->size[0]; - } - - return width; -} diff --git a/src/freecam.c b/src/freecam.c deleted file mode 100644 index c0a0f57..0000000 --- a/src/freecam.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "skaterift.h" -#include "player.h" -#include "player_render.h" -#include "replay2.h" -#include "input.h" - -void freecam_preupdate(void) -{ - vg_camera *cam = &_replay2.replay_freecam; - v3f angles; - v3_copy( cam->angles, angles ); - player_look( angles, 1.0f ); - - f32 decay = vg_maxf(0.0f,1.0f-vg.time_frame_delta*10.0f); - - v3f d; - v3_sub( angles, cam->angles, d ); - v3_muladds( _replay2.freecam_w, d, 20.0f, _replay2.freecam_w ); - v3_muls( _replay2.freecam_w, decay, _replay2.freecam_w ); - v3_muladds( cam->angles, _replay2.freecam_w, vg.time_frame_delta, cam->angles ); - cam->angles[1] = vg_clampf( cam->angles[1], -VG_PIf*0.5f,VG_PIf*0.5f); - - vg_camera_update_transform( cam ); - - v3f lookdir = { 0.0f, 0.0f, -1.0f }, - sidedir = { 1.0f, 0.0f, 0.0f }; - - m3x3_mulv( cam->transform, lookdir, lookdir ); - m3x3_mulv( cam->transform, sidedir, sidedir ); - - v2f input; - joystick_state( k_srjoystick_steer, input ); - v2_muls( input, vg.time_frame_delta*6.0f*20.0f, input ); - - v3_muladds( _replay2.freecam_v, lookdir, -input[1], _replay2.freecam_v ); - v3_muladds( _replay2.freecam_v, sidedir, input[0], _replay2.freecam_v ); - - v3_muls( _replay2.freecam_v, decay, _replay2.freecam_v ); - v3_muladds( cam->pos,_replay2.freecam_v, vg.time_frame_delta, cam->pos ); -} diff --git a/src/freecam.h b/src/freecam.h deleted file mode 100644 index 1f9f5e2..0000000 --- a/src/freecam.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once -void freecam_preupdate(void); -int freecam_cmd( int argc, const char *argv[] ); diff --git a/src/gameserver.c b/src/gameserver.c index fab3e35..00554c7 100644 --- a/src/gameserver.c +++ b/src/gameserver.c @@ -775,7 +775,7 @@ struct task_writeusertime static void setlap_task( vg_async_task *task ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); struct task_writeusertime *info = (void *)task->data; db_writeusertime( info->uid, info->steamid, info->centiseconds, info->last_second, info->only_if_faster ); } diff --git a/src/gameserver.h b/src/gameserver.h index 4730a52..6386d96 100644 --- a/src/gameserver.h +++ b/src/gameserver.h @@ -1,12 +1,13 @@ -#pragma once - -#include "vg/vg_platform.h" -#include "vg/vg_steam2.h" -#include "vg/vg_async2.h" -#include "network_msg.h" -#include "network_common.h" +#include "vg/vg.h" #include +#include "gameserver_database.h" +#include "gameserver_db.h" +#include "gameserver_monitor.h" +#include "gameserver_replay.h" +#include "gameserver_requests.h" + + #define CLIENT_KNOWLEDGE_SAME_WORLD0 0x1 #define CLIENT_KNOWLEDGE_SAME_WORLD1 0x2 #define CLIENT_KNOWLEDGE_FRIENDS 0x4 /* unused */ diff --git a/src/gameserver_database.c b/src/gameserver_database.c index cff7600..c66ab66 100644 --- a/src/gameserver_database.c +++ b/src/gameserver_database.c @@ -163,7 +163,7 @@ static i32 leaderboard_time_compare( vg_skipper_context *ctx, void *comparand, u bool db_writeusertime( char uid[DB_TABLE_UID_MAX], u64 steamid, u32 centiseconds, u64 last_second, bool only_if_faster ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); u64 leaderboard_addr = db_leaderboard_address( uid ), table = leaderboard_addr + offsetof(struct skaterift_leaderboard,entries); @@ -213,7 +213,7 @@ bool db_writeusertime( char uid[DB_TABLE_UID_MAX], u64 steamid, u32 centiseconds bool db_get_username( u64 steamid, char *out_username, u32 username_max ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); u64 user_address = vg_db_translate( &_gs_db.db, _gs_db.users_tree, steamid ); if( user_address ) @@ -230,7 +230,7 @@ bool db_get_username( u64 steamid, char *out_username, u32 username_max ) void _db_edit_profile( struct profile_edits *info ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); if( info->steamid == k_steamid_max ) return; @@ -268,13 +268,13 @@ void _db_edit_profile( struct profile_edits *info ) static void task_edit_profile( vg_async_task *task ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); _db_edit_profile( (void *)task->data ); } void db_action_edit_profile( struct profile_edits *edits ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); vg_async_task *task = vg_allocate_async_task( &_gs_db.tasks, sizeof(struct profile_edits), 1 ); memcpy( (void *)task->data, edits, sizeof(struct profile_edits) ); vg_async_task_dispatch( task, task_edit_profile ); @@ -282,7 +282,7 @@ void db_action_edit_profile( struct profile_edits *edits ) enum request_status gameserver_read_highscore_table( vg_msg *msg, char uid[ DB_TABLE_UID_MAX ] ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); u64 leaderboard_address = db_leaderboard_address( uid ); u64 table_address = leaderboard_address + offsetof(struct skaterift_leaderboard,entries); @@ -332,7 +332,7 @@ enum request_status gameserver_read_highscore_table( vg_msg *msg, char uid[ DB_T enum request_status _gs_db_get_profile( vg_msg *msg, u64 steamid ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); u16 top3_count = 0, top10_count = 0; @@ -404,7 +404,7 @@ struct task_db_dump void _gs_db_dump_task( vg_async_task *task ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); struct task_db_dump *info = (void *)task->data; FILE *fp = fopen( info->output_path, "w" ); @@ -518,7 +518,7 @@ void _gs_db_dump_task( vg_async_task *task ) void db_action_dump( const char *path, bool kv_mode ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); vg_async_task *task = vg_allocate_async_task( &_gs_db.tasks, sizeof(struct task_db_dump) + strlen(path)+1, 1 ); struct task_db_dump *info = (void *)task->data; info->mode = kv_mode? k_dump_mode_kv: k_dump_mode_commands; diff --git a/src/gameserver_monitor.c b/src/gameserver_monitor.c index 3a70d3b..f3f64ee 100644 --- a/src/gameserver_monitor.c +++ b/src/gameserver_monitor.c @@ -17,7 +17,7 @@ struct task_monitor_write void _monitor_write_task( vg_async_task *task ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); struct task_monitor_write *info = (void *)task->data; FILE *fp = fopen( _gs_monitor.html_path, "w" ); @@ -212,7 +212,7 @@ struct task_journal void _monitor_journal_task( vg_async_task *task ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); struct task_journal *info = (void *)task->data; fputs( info->buf, _gs_monitor.journal_fp ); } @@ -243,11 +243,11 @@ void _gs_monitor_journal( bool thread1, const char *message, ... ) if( thread1 ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); } else { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); } va_list args; diff --git a/src/gameserver_replay.c b/src/gameserver_replay.c index 42d85bf..325d54e 100644 --- a/src/gameserver_replay.c +++ b/src/gameserver_replay.c @@ -15,7 +15,7 @@ struct serialized_replay static void task_write_replay( vg_async_task *task ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); struct serialized_replay *info = (void *)task->data; vg_make_directory( "replaydata" ); @@ -177,7 +177,7 @@ void _gs_replay_request_save( u32 client_id, u64 steamid, i64 last_second, u32 c { if( async ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); vg_async_task *task = vg_allocate_async_task( &_gameserver.tasks, sizeof(struct request_save_info), 1 ); struct request_save_info *info = (void *)task->data; info->client_id = client_id; @@ -188,7 +188,7 @@ void _gs_replay_request_save( u32 client_id, u64 steamid, i64 last_second, u32 c return; } - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); struct gameserver_client *client = &_gameserver.clients[ client_id ]; if( client->steamid != steamid ) diff --git a/src/gameserver_requests.c b/src/gameserver_requests.c index 72d0f6a..d8d2ea9 100644 --- a/src/gameserver_requests.c +++ b/src/gameserver_requests.c @@ -15,7 +15,7 @@ static gs_request *_get_request( u16 request_id ) static void log_request_status( u16 request_id ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); gs_request *req = _get_request( request_id ); const char *associated_username = "none"; @@ -59,7 +59,7 @@ void _gs_requests_init(void) static void _gs_release_request( u16 client_id, u16 request_id ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); VG_ASSERT( request_id ); gs_request *req = _get_request( request_id ); @@ -75,7 +75,7 @@ static void _gs_release_request( u16 client_id, u16 request_id ) void _gs_requests_client_disconnect( u32 client_id ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); gs_request_client *rc = &_gs_requests.clients[ client_id ]; u16 request_id = rc->active_chain.tail; while( request_id ) @@ -93,7 +93,7 @@ static void task_request_run( vg_async_task *task ); void _gs_requests_tick(void) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); for( u32 i=0; idata; gs_request *req = _get_request( info->pool_id ); @@ -234,7 +234,7 @@ static void task_request_processing_complete( vg_async_task *task ) static void task_request_run( vg_async_task *task ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); struct task_request_run_info *info = (void *)task->data; gs_request *req = _get_request( info->pool_id ); @@ -412,7 +412,7 @@ E0:; void _gs_handle_request_message( u32 client_id, SteamNetworkingMessage_t *msg ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); if( !packet_minsize( msg, sizeof(netmsg_request)+1 )) { diff --git a/src/gui.c b/src/gui.c new file mode 100644 index 0000000..4d1f103 --- /dev/null +++ b/src/gui.c @@ -0,0 +1,340 @@ +struct +{ + struct gui_helper + { + vg_input_op *binding; + c8 text[32]; + int greyed; + } + helpers[4]; + u32 helper_count; + + enum gui_helper_mode helper_mode; + + struct gui_notifier + { + const char *string; + f32 duration, time_left; /* seconds */ + u32 colour; + } + notifiers[ 4 ]; + + struct icon_call + { + enum gui_icon icon; + v4f location; + v4f colour; + int colour_changed; + } + icon_draw_buffer[64]; + u32 icon_draw_count; + v4f cur_icon_colour; + int colour_changed; + + char location[64]; + f64 location_time; + + f32 factive; + font3d font; + + v3f trick_co; + vg_model model_icons; + + i32 icon_submeshes[ k_gui_icon_count ]; +} +static gui = {.cur_icon_colour = {1.0f,1.0f,1.0f,1.0f},.colour_changed=1}; + +VG_API void _gui_notify( const char *string, f32 duration, u32 colour ) +{ + struct gui_notifier *notifier = NULL; + for( u32 i=0; itime_left > 0.0f ) + { + notifier = NULL; + continue; + } + else break; + } + + if( !notifier ) + return; + + notifier->string = string; + notifier->duration = duration; + notifier->time_left = duration; + notifier->colour = colour; +} + +VG_API void _gui_helper_reset( enum gui_helper_mode mode ) +{ + gui.helper_count = 0; + gui.helper_mode = mode; +} + +VG_API struct gui_helper *_gui_new_helper( vg_input_op *bind, vg_str *out_text ) +{ + if( gui.helper_count >= VG_ARRAY_LEN(gui.helpers) ) + { + vg_error( "Too many helpers\n" ); + return NULL; + } + + struct gui_helper *helper = &gui.helpers[ gui.helper_count ++ ]; + helper->greyed = 0; + helper->binding = bind; + vg_strnull( out_text, helper->text, sizeof(helper->text) ); + return helper; +} + +VG_API void _gui_render_icons(void) +{ + vg_camera ortho; + + float fl = 0.0f, + fr = _vg_window.w, + fb = 0.0f, + ft = _vg_window.h, + rl = 1.0f / (fr-fl), + tb = 1.0f / (ft-fb); + + m4x4_zero( ortho.mtx.p ); + ortho.mtx.p[0][0] = 2.0f * rl; + ortho.mtx.p[1][1] = 2.0f * tb; + ortho.mtx.p[3][0] = (fr + fl) * -rl; + ortho.mtx.p[3][1] = (ft + fb) * -tb; + ortho.mtx.p[3][3] = 1.0f; + m4x3_identity( ortho.transform ); + vg_camera_update_view( &ortho ); + m4x4_mul( ortho.mtx.p, ortho.mtx.v, ortho.mtx.pv ); /* HACK */ + vg_camera_finalize( &ortho ); + + /* icons */ + font3d_bind( &gui.font, k_font_shader_default, 0, &ortho ); + vg_model_bind_mesh( &gui.model_icons ); + + m4x3f mmdl; + m4x3_identity( mmdl ); + shader_model_font_uMdl( mmdl ); + + vg_tex_bind( GL_TEXTURE_2D, &gui.model_icons.textures[0].tex, 0 ); + shader_model_font_uTexMain( 0 ); + + for( u32 i=0; icolour_changed ) + shader_model_font_uColour( call->colour ); + shader_model_font_uOffset( call->location ); + + i32 index = gui.icon_submeshes[ call->icon ]; + mdl_submesh *sm = &gui.model_icons.submeshes[ index ]; + if( sm ) + vg_model_draw_submesh( sm ); + } + + gui.icon_draw_count = 0; +} + +VG_API void _gui_draw( ui_context *ctx ) +{ + /* helpers + * ----------------------------------------------------------------- */ + + gui.factive = vg_lerpf( gui.factive, gui.helper_count?1.0f:0.0f, vg.time_frame_delta*2.0f ); + + { + ui_px y = 80; + ui_px w = 360, h = 60; + ctx->font = &vgf_default_large; + for( u32 i=0; itime_left -= vg.time_frame_delta; + if( notifier->time_left > 0.0f ) + { + const float k_trans = 0.2; + float t0 = notifier->time_left, + t1 = notifier->duration - t0, + t = vg_smoothstepf( vg_minf( vg_minf( k_trans, t0 ), t1 ) / k_trans ), + x = (f32)(w+8) * t; + ui_rect box = { _vg_window.w - (ui_px)x, y, w, h }; + ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, t*0.6f ) ); + ui_outline( ctx, box, 1, ui_opacity( GUI_COL_NORM, t*0.6f ), 0 ); + ui_text( ctx, box, notifier->string, 1, k_ui_align_middle_center, ui_colour( ctx, notifier->colour ) ); + } + y += h + 8; + } + } + + if( _cutscene.state >= k_cutscene_state_ready ) + { + ctx->font = &vgf_default_small; + return; + } + + ctx->font = &vgf_default_title; + ui_px height = ctx->font->ch + 16; + ui_rect lwr = { 0, _vg_window.h - height, _vg_window.w, height }; + + ui_px x = 0; + for( u32 i=0; ibinding, 1 ); + + ui_rect box = { x, lwr[1], 1000, lwr[3] }; + + u32 fg = 0; + f32 opacity = 0.4f; + if( helper->greyed ) + { + fg = ui_colour(ctx, k_ui_fg+2); + opacity = 0.1f; + } + + struct ui_vert *bg = ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, opacity ) ); + u32 w; + box[0] += 16; + w = ui_text( ctx, box, buf, 1, k_ui_align_middle_left, fg ); + w *= ctx->font->sx; + bg[1].co[0] = x + w + 32; + bg[2].co[0] = x + w + 32; + x += w + 32; + + box[0] = x; + bg = ui_fill( ctx, box, ui_opacity( GUI_COL_NORM, opacity*0.7f ) ); + box[0] += 8; + w = ui_text( ctx, box, helper->text, 1, k_ui_align_middle_left, fg ); + w *= ctx->font->sx; + bg[1].co[0] = box[0] + w + 16; + bg[2].co[0] = box[0] + w + 16; + x += w + 32; + } + + if( (gui.helper_mode == k_gui_helper_mode_black_bars) && gui.helper_count ) + { + ui_rect box = { x, lwr[1], _vg_window.w - x, height }; + ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, 0.4f ) ); + + box[0] = 0; + box[1] = 0; + box[2] = _vg_window.w; + ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, 0.4f ) ); + } + + vg_ui.frosting = gui.factive*0.015f; + ui_flush( ctx, k_ui_shader_colour, NULL ); + vg_ui.frosting = 0.0f; + + f64 loc_t = (vg.time_real - gui.location_time) / 5.0; + if( (loc_t < 1.0) && (gui.location_time != 0.0) ) + { + f32 t = 1.0f-vg_minf(1.0f,vg_minf(loc_t*20.0f,2.0f-loc_t*2.0f)), + o = 1.0f-t*t*(2.0f-t); + + ui_rect box = { 0, (_vg_window.h*2)/3 - height/2, _vg_window.w, height }; + ui_fill( ctx, box, ui_opacity( GUI_COL_NORM, 0.5f ) ); + ui_text( ctx, box, gui.location, 1, k_ui_align_middle_center, 0 ); + + vg_ui.colour[3] = o; + ui_flush( ctx, k_ui_shader_colour, NULL ); + } + + vg_ui.colour[3] = 1.0f; + ctx->font = &vgf_default_small; +} + +static int gui_location_print_ccmd( int argc, const char *argv[] ) +{ + if( argc > 0 ) + { + char new_loc[64]; + vg_str str; + vg_strnull( &str, new_loc, 64 ); + for( int i=0; iicon = icon; + call->location[0] = co[0] * (f32)_vg_window.w; + call->location[1] = co[1] * (f32)_vg_window.h; + call->location[2] = 0.0f; + call->location[3] = size * (f32)_vg_window.w; + + v4_copy( gui.cur_icon_colour, call->colour ); + call->colour_changed = gui.colour_changed; + gui.colour_changed = 0; +} + +static void gui_icon_setcolour( v4f colour ){ + gui.colour_changed = 1; + v4_copy( colour, gui.cur_icon_colour ); +} + +VG_API void _gui_register(void) +{ + vg_console_reg_cmd( "gui_location", gui_location_print_ccmd, NULL ); +} + +static void _gui_load_content_async( void *_, vg_async_info *async ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + font3d_load( &gui.font, "models/rs_font.mdl", VG_STACK_USE_HEAP ); + + vg_model *mdl = &gui.model_icons; + vg_model_load( mdl, VG_MODEL_ENGINE_STANDARD, "models/rs_icons.mdl", VG_STACK_USE_HEAP ); + VG_ASSERT( mdl->texture_count ); + gui.icon_submeshes[ k_gui_icon_tick1 ] = vg_model_get_submesh_index( mdl, "icon_tick1" ); + gui.icon_submeshes[ k_gui_icon_tick2 ] = vg_model_get_submesh_index( mdl, "icon_tick2" ); + gui.icon_submeshes[ k_gui_icon_run ] = vg_model_get_submesh_index( mdl, "icon_run" ); + gui.icon_submeshes[ k_gui_icon_challenge ] = vg_model_get_submesh_index( mdl, "icon_challenge" ); + gui.icon_submeshes[ k_gui_icon_exclaim ] = vg_model_get_submesh_index( mdl, "icon_exclaim" ); + gui.icon_submeshes[ k_gui_icon_board ] = vg_model_get_submesh_index( mdl, "icon_board" ); + gui.icon_submeshes[ k_gui_icon_world ] = vg_model_get_submesh_index( mdl, "icon_world" ); + gui.icon_submeshes[ k_gui_icon_rift ] = vg_model_get_submesh_index( mdl, "icon_rift" ); + gui.icon_submeshes[ k_gui_icon_rift_run ] = vg_model_get_submesh_index( mdl, "icon_rift_run" ); + gui.icon_submeshes[ k_gui_icon_rift_run_2d ] = vg_model_get_submesh_index( mdl, "icon_rift_run2d" ); + gui.icon_submeshes[ k_gui_icon_friend ] = vg_model_get_submesh_index( mdl, "icon_friend" ); + gui.icon_submeshes[ k_gui_icon_player ] = vg_model_get_submesh_index( mdl, "icon_player" ); + gui.icon_submeshes[ k_gui_icon_player2d ] = vg_model_get_submesh_index( mdl, "icon_player2d" ); + gui.icon_submeshes[ k_gui_icon_glider ] = vg_model_get_submesh_index( mdl, "icon_glider" ); + gui.icon_submeshes[ k_gui_icon_spawn ] = vg_model_get_submesh_index( mdl, "icon_spawn" ); + gui.icon_submeshes[ k_gui_icon_spawn_select ] = vg_model_get_submesh_index( mdl, "icon_spawn_select" ); + gui.icon_submeshes[ k_gui_icon_rift_run_gold ] = vg_model_get_submesh_index( mdl,"icon_rift_run_medal_gold"); + gui.icon_submeshes[ k_gui_icon_rift_run_silver]= vg_model_get_submesh_index( mdl,"icon_rift_run_medal_silver"); + gui.icon_submeshes[ k_gui_icon_story2d ]= vg_model_get_submesh_index( mdl,"icon_story2d"); + gui.icon_submeshes[ k_gui_icon_story_done2d ]= vg_model_get_submesh_index( mdl,"icon_story_done2d"); +} + +VG_API void _gui_init(void) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_gui_load_content_async ); +} + +VG_API bool _gui_helpers_active(void) +{ + return gui.helper_count > 0; +} diff --git a/src/gui.h b/src/gui.h index 51ef911..ec3e52d 100644 --- a/src/gui.h +++ b/src/gui.h @@ -1,17 +1,21 @@ -#pragma once -#include "font.h" -#include "input.h" -#include "player.h" -#include "vg/vg_engine.h" -#include "vg/vg_ui/imgui.h" - +#if defined( SR_IMPLEMENTATION ) +# include "src/gui.c" +#else #define GUI_COL_DARK ui_opacity( 0x00000000, 0.7f ) #define GUI_COL_NORM ui_opacity( 0x00101010, 0.7f ) #define GUI_COL_ACTIVE ui_opacity( 0x00444444, 0.7f ) #define GUI_COL_CLICK ui_opacity( 0x00858585, 0.7f ) #define GUI_COL_HI ui_opacity( 0x00ffffff, 0.8f ) -enum gui_icon { +enum gui_helper_mode +{ + k_gui_helper_mode_default, + k_gui_helper_mode_black_bars, + k_gui_helper_mode_clear +}; + +enum gui_icon +{ k_gui_icon_tick1 = 0, k_gui_icon_tick2, k_gui_icon_run, @@ -32,364 +36,18 @@ enum gui_icon { k_gui_icon_spawn_select, k_gui_icon_story2d, k_gui_icon_story_done2d, - k_gui_icon_count, }; -#define GUI_HELPER_TEXT_LENGTH 32 - -struct -{ - struct gui_helper - { - vg_input_op *binding; - char text[GUI_HELPER_TEXT_LENGTH]; - int greyed; - } - helpers[4]; - u32 helper_count; - - enum gui_helper_mode - { - k_gui_helper_mode_default, - k_gui_helper_mode_black_bars, - k_gui_helper_mode_clear - } - helper_mode; - - struct gui_notifier - { - const char *string; - f32 duration, time_left; /* seconds */ - u32 colour; - } - notifiers[ 4 ]; - - struct icon_call - { - enum gui_icon icon; - v4f location; - v4f colour; - int colour_changed; - } - icon_draw_buffer[64]; - u32 icon_draw_count; - v4f cur_icon_colour; - int colour_changed; - - char location[64]; - f64 location_time; - - f32 factive; - font3d font; - - v3f trick_co; - - mdl_context model_icons; - GLuint icons_texture; - glmesh icons_mesh; - - i32 icon_submeshes[ k_gui_icon_count ]; -} -static gui = {.cur_icon_colour = {1.0f,1.0f,1.0f,1.0f},.colour_changed=1}; - -void gui_notify( const char *string, f32 duration, u32 colour ) -{ - // JINGLE SOME KEYS HERE - // JINGLE SOME KEYS HERE - // JINGLE SOME KEYS HERE - // JINGLE SOME KEYS HERE - // JINGLE SOME KEYS HERE - struct gui_notifier *notifier = NULL; - for( u32 i=0; itime_left > 0.0f ) - { - notifier = NULL; - continue; - } - else break; - } - - if( !notifier ) - return; - - notifier->string = string; - notifier->duration = duration; - notifier->time_left = duration; - notifier->colour = colour; -} - -static void gui_helper_reset( enum gui_helper_mode mode ) -{ - gui.helper_count = 0; - gui.helper_mode = mode; -} - -static struct gui_helper *gui_new_helper( vg_input_op *bind, vg_str *out_text ) -{ - if( gui.helper_count >= VG_ARRAY_LEN(gui.helpers) ){ - vg_error( "Too many helpers\n" ); - return NULL; - } - - struct gui_helper *helper = &gui.helpers[ gui.helper_count ++ ]; - helper->greyed = 0; - helper->binding = bind; - vg_strnull( out_text, helper->text, sizeof(helper->text) ); - return helper; -} - -static void gui_render_icons(void) -{ - vg_camera ortho; - - float fl = 0.0f, - fr = vg.window_x, - fb = 0.0f, - ft = vg.window_y, - rl = 1.0f / (fr-fl), - tb = 1.0f / (ft-fb); - - m4x4_zero( ortho.mtx.p ); - ortho.mtx.p[0][0] = 2.0f * rl; - ortho.mtx.p[1][1] = 2.0f * tb; - ortho.mtx.p[3][0] = (fr + fl) * -rl; - ortho.mtx.p[3][1] = (ft + fb) * -tb; - ortho.mtx.p[3][3] = 1.0f; - m4x3_identity( ortho.transform ); - vg_camera_update_view( &ortho ); - m4x4_mul( ortho.mtx.p, ortho.mtx.v, ortho.mtx.pv ); /* HACK */ - vg_camera_finalize( &ortho ); - - /* icons */ - font3d_bind( &gui.font, k_font_shader_default, 0, NULL, &ortho ); - mesh_bind( &gui.icons_mesh ); - - m4x3f mmdl; - m4x3_identity( mmdl ); - shader_model_font_uMdl( mmdl ); - - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, gui.icons_texture ); - shader_model_font_uTexMain( 0 ); - - for( u32 i=0; icolour_changed ) - shader_model_font_uColour( call->colour ); - shader_model_font_uOffset( call->location ); - - i32 index = gui.icon_submeshes[ call->icon ]; - mdl_submesh *sm = &gui.model_icons.submeshes[ index ]; - if( sm ) - mdl_draw_submesh( sm ); - } - - gui.icon_draw_count = 0; -} - -static void gui_draw( ui_context *ctx ) -{ - /* helpers - * ----------------------------------------------------------------- */ - - gui.factive = vg_lerpf( gui.factive, gui.helper_count?1.0f:0.0f, vg.time_frame_delta*2.0f ); - - { - ui_px y = 80; - ui_px w = 360, h = 60; - ctx->font = &vgf_default_large; - for( u32 i=0; itime_left -= vg.time_frame_delta; - if( notifier->time_left > 0.0f ) - { - const float k_trans = 0.2; - float t0 = notifier->time_left, - t1 = notifier->duration - t0, - t = vg_smoothstepf( vg_minf( vg_minf( k_trans, t0 ), t1 ) / k_trans ), - x = (f32)(w+8) * t; - ui_rect box = { vg.window_x - (ui_px)x, y, w, h }; - ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, t*0.6f ) ); - ui_outline( ctx, box, 1, ui_opacity( GUI_COL_NORM, t*0.6f ), 0 ); - ui_text( ctx, box, notifier->string, 1, k_ui_align_middle_center, ui_colour( ctx, notifier->colour ) ); - } - y += h + 8; - } - } - - if( _cutscene.state >= k_cutscene_state_ready ) - { - ctx->font = &vgf_default_small; - return; - } - - ctx->font = &vgf_default_title; - ui_px height = ctx->font->ch + 16; - ui_rect lwr = { 0, vg.window_y - height, vg.window_x, height }; - - ui_px x = 0; - for( u32 i=0; ibinding, 1 ); - - ui_rect box = { x, lwr[1], 1000, lwr[3] }; - - u32 fg = 0; - f32 opacity = 0.4f; - if( helper->greyed ) - { - fg = ui_colour(ctx, k_ui_fg+2); - opacity = 0.1f; - } - - struct ui_vert *bg = ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, opacity ) ); - u32 w; - box[0] += 16; - w = ui_text( ctx, box, buf, 1, k_ui_align_middle_left, fg ); - w *= ctx->font->sx; - bg[1].co[0] = x + w + 32; - bg[2].co[0] = x + w + 32; - x += w + 32; - - box[0] = x; - bg = ui_fill( ctx, box, ui_opacity( GUI_COL_NORM, opacity*0.7f ) ); - box[0] += 8; - w = ui_text( ctx, box, helper->text, 1, k_ui_align_middle_left, fg ); - w *= ctx->font->sx; - bg[1].co[0] = box[0] + w + 16; - bg[2].co[0] = box[0] + w + 16; - x += w + 32; - } - - if( (gui.helper_mode == k_gui_helper_mode_black_bars) && gui.helper_count ) - { - ui_rect box = { x, lwr[1], vg.window_x - x, height }; - ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, 0.4f ) ); - - box[0] = 0; - box[1] = 0; - box[2] = vg.window_x; - ui_fill( ctx, box, ui_opacity( GUI_COL_DARK, 0.4f ) ); - } - - vg_ui.frosting = gui.factive*0.015f; - ui_flush( ctx, k_ui_shader_colour, NULL ); - vg_ui.frosting = 0.0f; - - f64 loc_t = (vg.time_real - gui.location_time) / 5.0; - if( (loc_t < 1.0) && (gui.location_time != 0.0) ) - { - f32 t = 1.0f-vg_minf(1.0f,vg_minf(loc_t*20.0f,2.0f-loc_t*2.0f)), - o = 1.0f-t*t*(2.0f-t); - - ui_rect box = { 0, (vg.window_y*2)/3 - height/2, vg.window_x, height }; - ui_fill( ctx, box, ui_opacity( GUI_COL_NORM, 0.5f ) ); - ui_text( ctx, box, gui.location, 1, k_ui_align_middle_center, 0 ); - - vg_ui.colour[3] = o; - ui_flush( ctx, k_ui_shader_colour, NULL ); - } - - vg_ui.colour[3] = 1.0f; - ctx->font = &vgf_default_small; -} - -static int gui_location_print_ccmd( int argc, const char *argv[] ) -{ - if( argc > 0 ) - { - char new_loc[64]; - vg_str str; - vg_strnull( &str, new_loc, 64 ); - for( int i=0; iicon = icon; - call->location[0] = co[0] * (f32)vg.window_x; - call->location[1] = co[1] * (f32)vg.window_y; - call->location[2] = 0.0f; - call->location[3] = size * (f32)vg.window_x; - - v4_copy( gui.cur_icon_colour, call->colour ); - call->colour_changed = gui.colour_changed; - gui.colour_changed = 0; -} - -static void gui_icon_setcolour( v4f colour ){ - gui.colour_changed = 1; - v4_copy( colour, gui.cur_icon_colour ); -} - -void gui_register(void) -{ - vg_console_reg_cmd( "gui_location", gui_location_print_ccmd, NULL ); -} - -static void gui_init(void) -{ - THREAD_1; - font3d_load( &gui.font, "models/rs_font.mdl", &vg.rtmem ); +VG_API void _gui_register(void); +VG_API void _gui_init(void); - /* load icons */ - mdl_context *mdl = &gui.model_icons; - mdl_open( mdl, "models/rs_icons.mdl", &vg.rtmem ); - mdl_load_metadata_block( mdl, &vg.rtmem ); +VG_API struct gui_helper *_gui_new_helper( vg_input_op *bind, vg_str *out_text ); +VG_API void _gui_helper_reset( enum gui_helper_mode mode ); +VG_API void _gui_notify( const char *string, f32 duration, u32 colour ); - gui.icon_submeshes[ k_gui_icon_tick1 ] = mdl_get_submesh_index( mdl, "icon_tick1" ); - gui.icon_submeshes[ k_gui_icon_tick2 ] = mdl_get_submesh_index( mdl, "icon_tick2" ); - gui.icon_submeshes[ k_gui_icon_run ] = mdl_get_submesh_index( mdl, "icon_run" ); - gui.icon_submeshes[ k_gui_icon_challenge ] = mdl_get_submesh_index( mdl, "icon_challenge" ); - gui.icon_submeshes[ k_gui_icon_exclaim ] = mdl_get_submesh_index( mdl, "icon_exclaim" ); - gui.icon_submeshes[ k_gui_icon_board ] = mdl_get_submesh_index( mdl, "icon_board" ); - gui.icon_submeshes[ k_gui_icon_world ] = mdl_get_submesh_index( mdl, "icon_world" ); - gui.icon_submeshes[ k_gui_icon_rift ] = mdl_get_submesh_index( mdl, "icon_rift" ); - gui.icon_submeshes[ k_gui_icon_rift_run ] = mdl_get_submesh_index( mdl, "icon_rift_run" ); - gui.icon_submeshes[ k_gui_icon_rift_run_2d ] = mdl_get_submesh_index( mdl, "icon_rift_run2d" ); - gui.icon_submeshes[ k_gui_icon_friend ] = mdl_get_submesh_index( mdl, "icon_friend" ); - gui.icon_submeshes[ k_gui_icon_player ] = mdl_get_submesh_index( mdl, "icon_player" ); - gui.icon_submeshes[ k_gui_icon_player2d ] = mdl_get_submesh_index( mdl, "icon_player2d" ); - gui.icon_submeshes[ k_gui_icon_glider ] = mdl_get_submesh_index( mdl, "icon_glider" ); - gui.icon_submeshes[ k_gui_icon_spawn ] = mdl_get_submesh_index( mdl, "icon_spawn" ); - gui.icon_submeshes[ k_gui_icon_spawn_select ] = mdl_get_submesh_index( mdl, "icon_spawn_select" ); - gui.icon_submeshes[ k_gui_icon_rift_run_gold ] = mdl_get_submesh_index( mdl,"icon_rift_run_medal_gold"); - gui.icon_submeshes[ k_gui_icon_rift_run_silver]= mdl_get_submesh_index( mdl,"icon_rift_run_medal_silver"); - gui.icon_submeshes[ k_gui_icon_story2d ]= mdl_get_submesh_index( mdl,"icon_story2d"); - gui.icon_submeshes[ k_gui_icon_story_done2d ]= mdl_get_submesh_index( mdl,"icon_story_done2d"); +VG_API void _gui_draw( ui_context *ctx ); +VG_API void _gui_render_icons(void); +VG_API bool _gui_helpers_active(void); - vg_stack_clear( &vg.scratch ); - if( !gui.model_icons.texture_count ) - vg_fatal_error( "No texture in menu file" ); - mdl_texture *tex0 = &gui.model_icons.textures[ 0 ]; - void *data = vg_stack_allocate( &vg.scratch, tex0->file.pack_size, 8, "Pack data" ); - mdl_fread_pack_file( &gui.model_icons, &tex0->file, data ); - vg_tex2d_load_qoi_async( data, tex0->file.pack_size, VG_TEX2D_LINEAR|VG_TEX2D_CLAMP, &gui.icons_texture ); - mdl_async_load_glmesh( &gui.model_icons, &gui.icons_mesh, NULL ); - mdl_close( &gui.model_icons ); -} +#endif diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..a4a61f7 --- /dev/null +++ b/src/input.c @@ -0,0 +1,290 @@ +#define INPUT_BASIC( KB, JS ) \ + (vg_input_op[]){vg_keyboard, KB, vg_joy_button, JS, vg_end} + +// TODO: This can probably be converted into a KV file and then compiled down into the vg_input ops.. ? +static vg_input_op *input_button_list[] = { +[k_srbind_jump] = INPUT_BASIC( SDLK_SPACE, SDL_CONTROLLER_BUTTON_A ), +[k_srbind_push] = INPUT_BASIC( SDLK_w, SDL_CONTROLLER_BUTTON_B ), +[k_srbind_trick0] = (vg_input_op[]){ + vg_mouse, SDL_BUTTON_LEFT, + vg_joy_button, SDL_CONTROLLER_BUTTON_A, vg_end +}, +[k_srbind_trick1] = (vg_input_op[]){ + vg_mouse, SDL_BUTTON_RIGHT, + vg_joy_button, SDL_CONTROLLER_BUTTON_B, vg_end +}, +[k_srbind_trick2] = (vg_input_op[]){ + vg_mouse, SDL_BUTTON_LEFT, vg_mode_mul, vg_mouse, SDL_BUTTON_RIGHT, + vg_mode_absmax, vg_joy_button, SDL_CONTROLLER_BUTTON_X, vg_end +}, +[k_srbind_skate] = INPUT_BASIC( SDLK_e, SDL_CONTROLLER_BUTTON_Y ), +[k_srbind_use] = INPUT_BASIC( SDLK_e, SDL_CONTROLLER_BUTTON_X ), +[k_srbind_reset] = INPUT_BASIC( SDLK_r, SDL_CONTROLLER_BUTTON_DPAD_UP ), +[k_srbind_camera]= INPUT_BASIC( SDLK_c, SDL_CONTROLLER_BUTTON_DPAD_RIGHT ), +[k_srbind_mleft] = INPUT_BASIC( SDLK_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT ), +[k_srbind_mright]= INPUT_BASIC( SDLK_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT ), +[k_srbind_world_left] = INPUT_BASIC( SDLK_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT ), +[k_srbind_world_right]= INPUT_BASIC( SDLK_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT ), +[k_srbind_mup] = INPUT_BASIC( SDLK_UP, SDL_CONTROLLER_BUTTON_DPAD_UP ), +[k_srbind_mdown] = INPUT_BASIC( SDLK_DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN ), +[k_srbind_mback] = INPUT_BASIC( SDLK_ESCAPE, SDL_CONTROLLER_BUTTON_B ), +[k_srbind_mopen] = INPUT_BASIC( SDLK_ESCAPE, SDL_CONTROLLER_BUTTON_START ), +[k_srbind_mquick] = INPUT_BASIC( SDLK_q, SDL_CONTROLLER_BUTTON_DPAD_LEFT ), +[k_srbind_mclose]= (vg_input_op[]){ vg_joy_button, SDL_CONTROLLER_BUTTON_START, vg_end }, +[k_srbind_mhub] = INPUT_BASIC( SDLK_h, SDL_CONTROLLER_BUTTON_Y ), +[k_srbind_maccept] = (vg_input_op[]){ + vg_keyboard, SDLK_e, vg_gui_visible, 0, + vg_keyboard, SDLK_RETURN, vg_keyboard, SDLK_RETURN2, + vg_gui_visible, 1, + vg_joy_button, SDL_CONTROLLER_BUTTON_A, vg_end +}, +[k_srbind_replay_play] = INPUT_BASIC( SDLK_SPACE, SDL_CONTROLLER_BUTTON_A ), +[k_srbind_replay_resume] = (vg_input_op[]){vg_end},//INPUT_BASIC( SDLK_SPACE, SDL_CONTROLLER_BUTTON_ ), +[k_srbind_replay_freecam] = INPUT_BASIC( SDLK_f, SDL_CONTROLLER_BUTTON_Y ), +[k_srbind_replay_hide_ui] = INPUT_BASIC( SDLK_h, SDL_CONTROLLER_BUTTON_X ), +[k_srbind_sit] = INPUT_BASIC( SDLK_z, SDL_CONTROLLER_BUTTON_B ), +[k_srbind_lobby] = INPUT_BASIC( SDLK_TAB, SDL_CONTROLLER_BUTTON_DPAD_LEFT ), +[k_srbind_chat ] = (vg_input_op[]){ vg_keyboard, SDLK_y, vg_end }, +[k_srbind_run ] = (vg_input_op[]){ vg_keyboard, SDLK_LSHIFT, + vg_joy_axis, SDL_CONTROLLER_AXIS_TRIGGERLEFT, vg_end }, + +[k_srbind_miniworld_resume] = (vg_input_op[]){ + vg_keyboard, SDLK_RETURN, vg_gui_visible, 0, + vg_keyboard, SDLK_RETURN2, + vg_gui_visible, 1, + vg_joy_button, SDL_CONTROLLER_BUTTON_X, vg_end +}, +[k_srbind_miniworld_teleport]= INPUT_BASIC( SDLK_q, + SDL_CONTROLLER_BUTTON_LEFTSHOULDER ), +[k_srbind_skid] = (vg_input_op[]){ vg_keyboard, SDLK_LCTRL, vg_end }, +[k_srbind_devbutton] = (vg_input_op[]){ vg_keyboard, SDLK_3, vg_end }, +[k_srbind_max]=NULL +}; + +static vg_input_op *input_axis_list[] = { +[k_sraxis_grab] = (vg_input_op[]){ + vg_keyboard, SDLK_LSHIFT, + vg_joy_axis, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, vg_end +}, +[k_sraxis_mbrowse_h] = (vg_input_op[]){ + vg_mode_sub, vg_keyboard, SDLK_LEFT, + vg_mode_add, vg_keyboard, SDLK_RIGHT, + vg_mode_add, vg_joy_axis, SDL_CONTROLLER_AXIS_LEFTX, + vg_end +}, +[k_sraxis_mbrowse_v] = (vg_input_op[]){ + vg_mode_sub, vg_keyboard, SDLK_DOWN, + vg_mode_add, vg_keyboard, SDLK_UP, + vg_mode_sub, vg_joy_axis, SDL_CONTROLLER_AXIS_LEFTY, + vg_end +}, +[k_sraxis_replay_h] = (vg_input_op[]){ + vg_mode_sub, vg_keyboard, SDLK_q, + vg_mode_add, vg_keyboard, SDLK_e, + vg_mode_sub, vg_joy_axis, SDL_CONTROLLER_AXIS_TRIGGERLEFT, + vg_mode_add, vg_joy_axis, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, + vg_end +}, +[k_sraxis_skid] = (vg_input_op[]){ + vg_mode_sub, vg_joy_button, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, + vg_mode_add, vg_joy_button, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, + vg_end +}, +[k_sraxis_max]=NULL +}; + +static vg_input_op *input_joy_list[] = { +[k_srjoystick_steer] = (vg_input_op[]){ + vg_index, 0, vg_mode_sub, vg_keyboard, SDLK_a, + vg_mode_add, vg_keyboard, SDLK_d, + vg_index, 1, vg_mode_sub, vg_keyboard, SDLK_w, + vg_mode_add, vg_keyboard, SDLK_s, + vg_mode_absmax, vg_joy_ls, + vg_end +}, +[k_srjoystick_grab] = (vg_input_op[]){ + vg_joy_rs, vg_end +}, +[k_srjoystick_look] = (vg_input_op[]){ + vg_joy_rs, vg_end +}, +[k_srjoystick_max]=NULL +}; + +struct +{ + float axis_states[ k_sraxis_max ][2]; + v2f joystick_states[ k_srjoystick_max ][2]; + u8 button_states[ k_srbind_max ][2]; + + enum input_state + { + k_input_state_enabled, + k_input_state_resume, + k_input_state_resuming, + k_input_state_pause + } + state; +} +static srinput; + +static bool input_filter_generic(void) +{ + if( (srinput.state != k_input_state_enabled) || vg_console.enabled || (workshop_form.page != k_workshop_form_hidden) ) + return 1; + else + return 0; +} + +static bool buttons_filter_fixed(void) +{ + if( input_filter_generic() ) + return 1; + if( vg.gameloop_stage == k_gameloop_update_fixed ) + if( vg.fixed_iterations > 0 ) + return 1; + + return 0; +} + +/* Rising edge of button */ +bool button_down( enum sr_bind button ) +{ + if( buttons_filter_fixed() ) + return 0; + + if( (skaterift.activity == k_skaterift_menu) && + (button < k_srbind_mopen) && + (vg_input.display_input_method != k_input_method_kbm) ) + return 0; + + if( srinput.button_states[ button ][0] && !srinput.button_states[ button ][1] ) + return 1; + + return 0; +} + +/* Falling edge of button */ +bool button_up( enum sr_bind button ) +{ + if( buttons_filter_fixed() ) + return 0; + + if( (skaterift.activity == k_skaterift_menu) && + (button < k_srbind_mopen) && + (vg_input.display_input_method != k_input_method_kbm) ) + return 0; + + if( !srinput.button_states[ button ][0] && srinput.button_states[ button ][1] ) + return 1; + + return 0; +} + +/* State of button */ +bool button_press( enum sr_bind button ) +{ + if( input_filter_generic() ) + return 0; + + if( (skaterift.activity == k_skaterift_menu) && + (button < k_srbind_mopen) && + (vg_input.display_input_method != k_input_method_kbm)) + return 0; + + return srinput.button_states[ button ][0]; +} + +void joystick_state( enum sr_joystick joystick, v2f state ) +{ + /* TODO: This fucking sucks */ + if( (skaterift.activity == k_skaterift_menu) && (vg_input.display_input_method != k_input_method_kbm) && + (menu.main_index != k_menu_main_map) && + !((menu.main_index == k_menu_main_online) && menu.choosing_country ) ) + { + v2_zero( state ); + return; + } + + if( input_filter_generic() ) + v2_zero( state ); + else + v2_copy( srinput.joystick_states[ joystick ][0], state ); +} + +f32 axis_state( enum sr_axis axis ) +{ + if( (skaterift.activity == k_skaterift_menu) && + (axis < k_sraxis_mbrowse_h ) && + (vg_input.display_input_method != k_input_method_kbm)) + return 0; + + if( input_filter_generic() ) + return 0.0f; + + return srinput.axis_states[axis][0]; +} + +void skaterift_preupdate_inputs(void) +{ + if( srinput.state == k_input_state_resuming ) + srinput.state = k_input_state_enabled; + + if( srinput.state == k_input_state_resume ) + srinput.state = k_input_state_resuming; + + for( u32 i=0; i sensitivity ) + { + if( x > 0.0f ) srinput.button_states[k_srbind_mright][0] = 1; + else srinput.button_states[k_srbind_mleft][0] = 1; + } + + if( fabsf(y) > sensitivity ) + { + if( y > 0.0f ) srinput.button_states[k_srbind_mup][0] = 1; + else srinput.button_states[k_srbind_mdown][0] = 1; + } +} diff --git a/src/input.h b/src/input.h index 4b33fac..14006d2 100644 --- a/src/input.h +++ b/src/input.h @@ -1,9 +1,6 @@ -#pragma once -#include "vg/vg_platform.h" -#include "vg/vg_console.h" -#include "vg/vg_input.h" -#include "vg/vg_m.h" -#include "font.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/input.c" +#else enum sr_bind { @@ -66,289 +63,11 @@ enum sr_axis{ k_sraxis_max }; +bool button_down( enum sr_bind button ); +bool button_up( enum sr_bind button ); +bool button_press( enum sr_bind button ); +void joystick_state( enum sr_joystick joystick, v2f state ); +f32 axis_state( enum sr_axis axis ); +void skaterift_preupdate_inputs(void); -#define INPUT_BASIC( KB, JS ) \ - (vg_input_op[]){vg_keyboard, KB, vg_joy_button, JS, vg_end} - -static vg_input_op *input_button_list[] = { -[k_srbind_jump] = INPUT_BASIC( SDLK_SPACE, SDL_CONTROLLER_BUTTON_A ), -[k_srbind_push] = INPUT_BASIC( SDLK_w, SDL_CONTROLLER_BUTTON_B ), -[k_srbind_trick0] = (vg_input_op[]){ - vg_mouse, SDL_BUTTON_LEFT, - vg_joy_button, SDL_CONTROLLER_BUTTON_A, vg_end -}, -[k_srbind_trick1] = (vg_input_op[]){ - vg_mouse, SDL_BUTTON_RIGHT, - vg_joy_button, SDL_CONTROLLER_BUTTON_B, vg_end -}, -[k_srbind_trick2] = (vg_input_op[]){ - vg_mouse, SDL_BUTTON_LEFT, vg_mode_mul, vg_mouse, SDL_BUTTON_RIGHT, - vg_mode_absmax, vg_joy_button, SDL_CONTROLLER_BUTTON_X, vg_end -}, -[k_srbind_skate] = INPUT_BASIC( SDLK_e, SDL_CONTROLLER_BUTTON_Y ), -[k_srbind_use] = INPUT_BASIC( SDLK_e, SDL_CONTROLLER_BUTTON_X ), -[k_srbind_reset] = INPUT_BASIC( SDLK_r, SDL_CONTROLLER_BUTTON_DPAD_UP ), -[k_srbind_camera]= INPUT_BASIC( SDLK_c, SDL_CONTROLLER_BUTTON_DPAD_RIGHT ), -[k_srbind_mleft] = INPUT_BASIC( SDLK_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT ), -[k_srbind_mright]= INPUT_BASIC( SDLK_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT ), -[k_srbind_world_left] = INPUT_BASIC( SDLK_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT ), -[k_srbind_world_right]= INPUT_BASIC( SDLK_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT ), -[k_srbind_mup] = INPUT_BASIC( SDLK_UP, SDL_CONTROLLER_BUTTON_DPAD_UP ), -[k_srbind_mdown] = INPUT_BASIC( SDLK_DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN ), -[k_srbind_mback] = INPUT_BASIC( SDLK_ESCAPE, SDL_CONTROLLER_BUTTON_B ), -[k_srbind_mopen] = INPUT_BASIC( SDLK_ESCAPE, SDL_CONTROLLER_BUTTON_START ), -[k_srbind_mquick] = INPUT_BASIC( SDLK_q, SDL_CONTROLLER_BUTTON_DPAD_LEFT ), -[k_srbind_mclose]= (vg_input_op[]){ vg_joy_button, SDL_CONTROLLER_BUTTON_START, vg_end }, -[k_srbind_mhub] = INPUT_BASIC( SDLK_h, SDL_CONTROLLER_BUTTON_Y ), -[k_srbind_maccept] = (vg_input_op[]){ - vg_keyboard, SDLK_e, vg_gui_visible, 0, - vg_keyboard, SDLK_RETURN, vg_keyboard, SDLK_RETURN2, - vg_gui_visible, 1, - vg_joy_button, SDL_CONTROLLER_BUTTON_A, vg_end -}, -[k_srbind_replay_play] = INPUT_BASIC( SDLK_SPACE, SDL_CONTROLLER_BUTTON_A ), -[k_srbind_replay_resume] = (vg_input_op[]){vg_end},//INPUT_BASIC( SDLK_SPACE, SDL_CONTROLLER_BUTTON_ ), -[k_srbind_replay_freecam] = INPUT_BASIC( SDLK_f, SDL_CONTROLLER_BUTTON_Y ), -[k_srbind_replay_hide_ui] = INPUT_BASIC( SDLK_h, SDL_CONTROLLER_BUTTON_X ), -[k_srbind_sit] = INPUT_BASIC( SDLK_z, SDL_CONTROLLER_BUTTON_B ), -[k_srbind_lobby] = INPUT_BASIC( SDLK_TAB, SDL_CONTROLLER_BUTTON_DPAD_LEFT ), -[k_srbind_chat ] = (vg_input_op[]){ vg_keyboard, SDLK_y, vg_end }, -[k_srbind_run ] = (vg_input_op[]){ vg_keyboard, SDLK_LSHIFT, - vg_joy_axis, SDL_CONTROLLER_AXIS_TRIGGERLEFT, vg_end }, - -[k_srbind_miniworld_resume] = (vg_input_op[]){ - vg_keyboard, SDLK_RETURN, vg_gui_visible, 0, - vg_keyboard, SDLK_RETURN2, - vg_gui_visible, 1, - vg_joy_button, SDL_CONTROLLER_BUTTON_X, vg_end -}, -[k_srbind_miniworld_teleport]= INPUT_BASIC( SDLK_q, - SDL_CONTROLLER_BUTTON_LEFTSHOULDER ), -[k_srbind_skid] = (vg_input_op[]){ vg_keyboard, SDLK_LCTRL, vg_end }, -[k_srbind_devbutton] = (vg_input_op[]){ vg_keyboard, SDLK_3, vg_end }, -[k_srbind_max]=NULL -}; - -static vg_input_op *input_axis_list[] = { -[k_sraxis_grab] = (vg_input_op[]){ - vg_keyboard, SDLK_LSHIFT, - vg_joy_axis, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, vg_end -}, -[k_sraxis_mbrowse_h] = (vg_input_op[]){ - vg_mode_sub, vg_keyboard, SDLK_LEFT, - vg_mode_add, vg_keyboard, SDLK_RIGHT, - vg_mode_add, vg_joy_axis, SDL_CONTROLLER_AXIS_LEFTX, - vg_end -}, -[k_sraxis_mbrowse_v] = (vg_input_op[]){ - vg_mode_sub, vg_keyboard, SDLK_DOWN, - vg_mode_add, vg_keyboard, SDLK_UP, - vg_mode_sub, vg_joy_axis, SDL_CONTROLLER_AXIS_LEFTY, - vg_end -}, -[k_sraxis_replay_h] = (vg_input_op[]){ - vg_mode_sub, vg_keyboard, SDLK_q, - vg_mode_add, vg_keyboard, SDLK_e, - vg_mode_sub, vg_joy_axis, SDL_CONTROLLER_AXIS_TRIGGERLEFT, - vg_mode_add, vg_joy_axis, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, - vg_end -}, -[k_sraxis_skid] = (vg_input_op[]){ - vg_mode_sub, vg_joy_button, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, - vg_mode_add, vg_joy_button, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, - vg_end -}, -[k_sraxis_max]=NULL -}; - -static vg_input_op *input_joy_list[] = { -[k_srjoystick_steer] = (vg_input_op[]){ - vg_index, 0, vg_mode_sub, vg_keyboard, SDLK_a, - vg_mode_add, vg_keyboard, SDLK_d, - vg_index, 1, vg_mode_sub, vg_keyboard, SDLK_w, - vg_mode_add, vg_keyboard, SDLK_s, - vg_mode_absmax, vg_joy_ls, - vg_end -}, -[k_srjoystick_grab] = (vg_input_op[]){ - vg_joy_rs, vg_end -}, -[k_srjoystick_look] = (vg_input_op[]){ - vg_joy_rs, vg_end -}, -[k_srjoystick_max]=NULL -}; - -struct -{ - float axis_states[ k_sraxis_max ][2]; - v2f joystick_states[ k_srjoystick_max ][2]; - u8 button_states[ k_srbind_max ][2]; - - enum input_state - { - k_input_state_enabled, - k_input_state_resume, - k_input_state_resuming, - k_input_state_pause - } - state; -} -static srinput; - -static int input_filter_generic(void) -{ - if( (srinput.state != k_input_state_enabled) - || vg_console.enabled - || (workshop_form.page != k_workshop_form_hidden) ) - return 1; - else - return 0; -} - -static int buttons_filter_fixed(void) -{ - if( input_filter_generic() ) - return 1; - if( vg.engine_stage == k_engine_stage_update_fixed ) - if( vg.fixed_iterations > 0 ) - return 1; - - return 0; -} - -/* Rising edge of button */ -static int button_down( enum sr_bind button ) -{ - if( buttons_filter_fixed() ) - return 0; - - if( (skaterift.activity == k_skaterift_menu) && (button < k_srbind_mopen) && (vg_input.display_input_method != k_input_method_kbm) ) - return 0; - - if( srinput.button_states[ button ][0] && !srinput.button_states[ button ][1] ) - return 1; - - return 0; -} - -/* Falling edge of button */ -static int button_up( enum sr_bind button ) -{ - if( buttons_filter_fixed() ) - return 0; - - if( (skaterift.activity == k_skaterift_menu) && (button < k_srbind_mopen) && (vg_input.display_input_method != k_input_method_kbm) ) - return 0; - - if( !srinput.button_states[ button ][0] && srinput.button_states[ button ][1] ) - return 1; - - return 0; -} - -/* State of button */ -static int button_press( enum sr_bind button ) -{ - if( input_filter_generic() ) - return 0; - - if( (skaterift.activity == k_skaterift_menu) && (button < k_srbind_mopen) && (vg_input.display_input_method != k_input_method_kbm)) - return 0; - - return srinput.button_states[ button ][0]; -} - -static void joystick_state( enum sr_joystick joystick, v2f state ) -{ - /* TODO: This fucking sucks */ - if( (skaterift.activity == k_skaterift_menu) && (vg_input.display_input_method != k_input_method_kbm) && - (menu.main_index != k_menu_main_map) && - !((menu.main_index == k_menu_main_online) && menu.choosing_country ) ) - { - v2_zero( state ); - return; - } - - if( input_filter_generic() ) - v2_zero( state ); - else - v2_copy( srinput.joystick_states[ joystick ][0], state ); -} - -static float axis_state( enum sr_axis axis ) -{ - if( (skaterift.activity == k_skaterift_menu) && - (axis < k_sraxis_mbrowse_h ) && - (vg_input.display_input_method != k_input_method_kbm)) - return 0; - - if( input_filter_generic() ) - return 0.0f; - - return srinput.axis_states[axis][0]; -} - -static void skaterift_preupdate_inputs(void) -{ - if( srinput.state == k_input_state_resuming ) - srinput.state = k_input_state_enabled; - - if( srinput.state == k_input_state_resume ) - srinput.state = k_input_state_resuming; - - for( u32 i=0; i sensitivity ) - { - if( x > 0.0f ) srinput.button_states[k_srbind_mright][0] = 1; - else srinput.button_states[k_srbind_mleft][0] = 1; - } - - if( fabsf(y) > sensitivity ) - { - if( y > 0.0f ) srinput.button_states[k_srbind_mup][0] = 1; - else srinput.button_states[k_srbind_mdown][0] = 1; - } -} +#endif diff --git a/src/menu.c b/src/menu.c index f368a2e..6d65fd2 100644 --- a/src/menu.c +++ b/src/menu.c @@ -1,18 +1,3 @@ -#pragma once -#include "skaterift.h" -#include "menu.h" -#include "model.h" -#include "entity.h" -#include "input.h" -#include "world_map.h" -#include "audio.h" -#include "workshop.h" -#include "gui.h" -#include "control_overlay.h" -#include "network.h" -#include "shaders/model_menu.h" -#include "ent_atom.h" - struct global_menu menu = { .skip_starter = 0, .prof_row = -1 }; void menu_at_begin(void) @@ -33,18 +18,23 @@ static int cmd_menu_impromptu( int argc, const char *argv[] ) return 1; } -void menu_register(void) +VG_API void _menu_register(void) { vg_console_reg_var( "skip_starter_menu", &menu.skip_starter, k_var_dtype_i32, VG_VAR_PERSISTENT ); vg_console_reg_cmd( "menu_impromptu", cmd_menu_impromptu, NULL ); } -void menu_init(void) +static void _menu_load_content_async( void *_, vg_async_info *async ) +{ + u32 flags = VG_TEX_CLAMP|VG_TEX_NOMIP|VG_TEX_NEAREST; + _vg_tex_load( &menu.prem_tex, "textures/prem.qoi", flags ); + _vg_tex_load( &menu.guide_pump_tex, "textures/guide_pump.qoi", flags ); + _vg_tex_load( &menu.guide_fliptrick_tex, "textures/guide_fliptrick.qoi", flags ); +} + +VG_API void _menu_init(void) { - u32 flags = VG_TEX2D_CLAMP|VG_TEX2D_NOMIP|VG_TEX2D_NEAREST; - vg_tex2d_load_qoi_async_file( "textures/prem.qoi", flags, &menu.prem_tex ); - vg_tex2d_load_qoi_async_file( "textures/guide_pump.qoi", flags, &menu.guide_pump_tex ); - vg_tex2d_load_qoi_async_file( "textures/guide_fliptrick.qoi", flags, &menu.guide_fliptrick_tex ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_menu_load_content_async ); } static void menu_update_world_filter(void) @@ -85,11 +75,10 @@ void menu_on_world_change( addon_id addon ) menu.world_list_selected_index[ super_id ] = index; menu.clicked_world_id = addon; - vg_msg msg; - vg_msg_init( &msg, reg->metadata, reg->metadata_len ); const char *name = NULL; - if( vg_msg_seekframe( &msg, "workshop" ) ) - name = vg_msg_getkvstr( &msg, "title" ); + u32 workshop_block = vg_kv_find( ®->metadata, 0, "workshop" ); + if( workshop_block ) + name = vg_kv_value( ®->metadata, vg_kv_find( ®->metadata, workshop_block, "title" ), NULL ); if( !name ) name = reg->alias.folder; menu.clicked_world_name = name; @@ -98,7 +87,7 @@ void menu_on_world_change( addon_id addon ) void menu_open( enum menu_page page ) { - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); skaterift.activity = k_skaterift_menu; if( _cutscene.state != k_cutscene_state_none ) @@ -461,7 +450,7 @@ void menu_heading( ui_context *ctx, ui_rect inout_panel, const char *label, u32 ui_text( ctx, rect, label, 1, k_ui_align_middle_center, colour? colour: ui_colour(ctx, k_ui_blue+k_ui_brighter) ); } -static u32 medal_colour( ui_context *ctx, u32 flags ) +u32 medal_colour( ui_context *ctx, u32 flags ) { if( flags & k_ent_route_flag_achieve_gold ) return ui_colour( ctx, k_ui_yellow ); @@ -604,11 +593,9 @@ void menu_update_world_list(void) flags |= MENU_WORLD_FLAG_HUB; const char *name = NULL; - vg_msg msg; - vg_msg_init( &msg, reg->metadata, reg->metadata_len ); - - if( vg_msg_seekframe( &msg, "workshop" ) ) - name = vg_msg_getkvstr( &msg, "title" ); + u32 workshop_block = vg_kv_find( ®->metadata, 0, "workshop" ); + if( workshop_block ) + name = vg_kv_value( ®->metadata, vg_kv_find( ®->metadata, workshop_block, "title" ), NULL ); if( !name ) name = reg->alias.folder; @@ -705,7 +692,7 @@ void menu_gui( ui_context *ctx ) //menu_try_find_cam( 3 ); ui_rect panel = { 0,0, 800, 200 }, - screen = { 0,0, vg.window_x,vg.window_y }; + screen = { 0,0, _vg_window.w,_vg_window.h }; ui_rect_center( screen, panel ); ui_fill( ctx, panel, GUI_COL_DARK ); ui_outline( ctx, panel, 1, GUI_COL_NORM, 0 ); @@ -765,14 +752,14 @@ void menu_gui( ui_context *ctx ) } - if( vg.settings_open ) + if( _vg_settings_is_open() ) { if( button_down( k_srbind_mback ) ) { vg_audio_lock(); vg_audio_oneshot( &audio_ui[3], 1.0f, 0.0f, 0, 0 ); vg_audio_unlock(); - vg_settings_close(); + _vg_settings_close(); srinput.state = k_input_state_resume; } @@ -783,7 +770,7 @@ void menu_gui( ui_context *ctx ) if( menu.page == k_menu_page_credits ) { ui_rect panel = { 0,0, 600, 400 }, - screen = { 0,0, vg.window_x,vg.window_y }; + screen = { 0,0, _vg_window.w,_vg_window.h }; ui_rect_center( screen, panel ); ui_fill( ctx, panel, GUI_COL_DARK ); ui_outline( ctx, panel, 1, GUI_COL_NORM, 0 ); @@ -831,7 +818,7 @@ void menu_gui( ui_context *ctx ) { i32 R = menu_nav( &menu.intro_row, mv, 3 ); ui_rect panel = { 0,0, 600, 400 }, - screen = { 0,0, vg.window_x,vg.window_y }; + screen = { 0,0, _vg_window.w,_vg_window.h }; ui_rect_center( screen, panel ); ui_fill( ctx, panel, ui_opacity( GUI_COL_DARK, 0.35f ) ); ui_outline( ctx, panel, 1, GUI_COL_NORM, 0 ); @@ -845,7 +832,7 @@ void menu_gui( ui_context *ctx ) ui_split( panel, k_ui_axis_h, 28, 0, title, panel ); ctx->font = &vgf_default_large; - menu_checkbox( ctx, panel, R == 0, "Show controls overlay (good for new players)", &control_overlay.enabled ); + menu_checkbox( ctx, panel, R == 0, "Show controls overlay (good for new players)", &_control_overlay.enabled ); menu_checkbox( ctx, panel, R == 1, "Auto connect to global server", &network_client.auto_connect ); ui_rect end = { panel[0], panel[1] + panel[3] - 100, panel[2], 100 }; @@ -867,7 +854,7 @@ void menu_gui( ui_context *ctx ) { i32 R = menu_nav( &menu.prem_row, mh, 1 ); ui_rect panel = { 0,0, 600, 400+240 }, - screen = { 0,0, vg.window_x,vg.window_y }; + screen = { 0,0, _vg_window.w,_vg_window.h }; ui_rect_center( screen, panel ); ui_fill( ctx, panel, ui_opacity( GUI_COL_DARK, 0.35f ) ); ui_outline( ctx, panel, 1, GUI_COL_NORM, 0 ); @@ -908,7 +895,7 @@ void menu_gui( ui_context *ctx ) /* PAGE impromptu */ else if( menu.page == k_menu_page_impromptu_guide ) { - ui_rect screen = { 0,0, vg.window_x,vg.window_y }; + ui_rect screen = { 0,0, _vg_window.w,_vg_window.h }; ui_rect image = { 0,0, 780, 840 }; ui_rect panel; @@ -945,7 +932,7 @@ void menu_gui( ui_context *ctx ) else if( menu.page == k_menu_page_quick ) { ui_px pad = 64; - ui_rect panel = { 24, pad, 300, vg.window_y-(pad*2) }; + ui_rect panel = { 24, pad, 300, _vg_window.h-(pad*2) }; ui_fill( ctx, panel, ui_opacity( GUI_COL_DARK, 0.35f ) ); ui_outline( ctx, panel, 1, GUI_COL_NORM, 0 ); ui_rect_pad( panel, (ui_px[]){8,8} ); @@ -987,7 +974,7 @@ void menu_gui( ui_context *ctx ) if( world_clear_event( k_world_event_challenge ) ) { _ent_challenge_clear( af_arritm( &_world.main.ent_challenge, mdl_entity_id_id( _world.active_challenge_id ) ) ); - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); _world.challenge_state = k_challenge_state_none; _world.active_challenge_id = 0; _world.challenge_target = NULL; @@ -1050,7 +1037,7 @@ void menu_gui( ui_context *ctx ) else if( menu.page == k_menu_page_spectate ) { ui_px pad = 64; - ui_rect panel = { 24, pad, 300, vg.window_y-(pad*2) }; + ui_rect panel = { 24, pad, 300, _vg_window.h-(pad*2) }; ui_fill( ctx, panel, ui_opacity( GUI_COL_DARK, 0.35f ) ); ui_outline( ctx, panel, 1, GUI_COL_NORM, 0 ); ui_rect_pad( panel, (ui_px[]){8,8} ); @@ -1088,9 +1075,9 @@ void menu_gui( ui_context *ctx ) localplayer.immobile = 1; vg_camera_copy( &localplayer.cam, &netplayers.spectate_camera ); - gui_helper_reset( k_gui_helper_mode_black_bars ); + _gui_helper_reset( k_gui_helper_mode_black_bars ); vg_str text; - if( gui_new_helper( input_button_list[k_srbind_mback], &text )) + if( _gui_new_helper( input_button_list[k_srbind_mback], &text )) vg_strcat( &text, "Stop spectating" ); } @@ -1115,7 +1102,7 @@ n1: { i32 R = menu_nav( &menu.cs_row, mh, 1 ); ui_rect panel = { 0,0, 600, 160 }, - screen = { 0,0, vg.window_x,vg.window_y }; + screen = { 0,0, _vg_window.w,_vg_window.h }; ui_rect_center( screen, panel ); ui_fill( ctx, panel, ui_opacity( GUI_COL_DARK, 0.35f ) ); ui_outline( ctx, panel, 1, GUI_COL_NORM, 0 ); @@ -1160,7 +1147,7 @@ n1: ctx->font = &vgf_default_title; ui_px height = ctx->font->ch + 16; - ui_rect topbar = { 0, 0, vg.window_x, height }; + ui_rect topbar = { 0, 0, _vg_window.w, height }; const char *opts[] = { [k_menu_main_main] = "Menu", @@ -1248,10 +1235,10 @@ n1: } if( draw ) - ui_fill( ctx, (ui_rect){ x+8,0, vg.window_x-(x+8),height }, GUI_COL_NORM ); + ui_fill( ctx, (ui_rect){ x+8,0, _vg_window.w-(x+8),height }, GUI_COL_NORM ); else { - x = vg.window_x/2 - x/2; + x = _vg_window.w/2 - x/2; ui_fill( ctx, (ui_rect){ 0, 0, x-8, height }, GUI_COL_NORM ); } } @@ -1267,14 +1254,14 @@ n1: menu_backable_to_exit = 1; menu.bg_blur = 0; - world_map_gui( ctx, (ui_rect){ 0, height, vg.window_x, vg.window_y - height }, mh, mv, &menu_backable_to_exit ); + world_map_gui( ctx, (ui_rect){ 0, height, _vg_window.w, _vg_window.h - height }, mh, mv, &menu_backable_to_exit ); if( world_map.spawn_timer > 0.0f ) menu_backable_to_exit = 0; } else /* menu.main_index != k_menu_main_map) */ { - ui_rect list0 = { vg.window_x/2 - 512/2, height+32, 512, vg.window_y-height-64 }, list; + ui_rect list0 = { _vg_window.w/2 - 512/2, height+32, 512, _vg_window.h-height-64 }, list; rect_copy( list0, list ); ui_rect_pad( list, (ui_px[2]){8,8} ); @@ -1325,9 +1312,7 @@ n1: ui_rect end = { list[0], list[1]+list[3]-64, list[2], 72 }; if( menu_button( ctx, end, R == 3, 1, "Quit Game" ) ) - { - vg.window_should_close = 1; - } + _vg_terminate(); } /* PAGE main */ else if( menu.main_index == k_menu_main_online ) @@ -1336,7 +1321,7 @@ n1: { menu_backable_to_exit = 0; bool close = _user_profile_country_picker( ctx, (ui_rect){ 8, height+32, - vg.window_x-16, vg.window_y-(height+32+16) } ); + _vg_window.w-16, _vg_window.h-(height+32+16) } ); if( close ) menu.choosing_country = 0; } @@ -1470,7 +1455,7 @@ n1: ctx->font = &vgf_default_large; list[1] -= 8; menu_heading( ctx, list, "Game", 0 ); - menu_checkbox( ctx, list, R == 0, "Show controls overlay", &control_overlay.enabled ); + menu_checkbox( ctx, list, R == 0, "Show controls overlay", &_control_overlay.enabled ); menu_checkbox( ctx, list, R == 1, "Auto connect to global server", &network_client.auto_connect ); menu_heading( ctx, list, "Audio/Video", 0 ); @@ -1490,7 +1475,7 @@ n1: menu_heading( ctx, end, "Advanced", 0 ); if( menu_button( ctx, end, R == 8, 1, "Open Engine Settings" ) ) { - vg_settings_open(); + _vg_settings_open(); } } /* PAGE guide */ @@ -1501,7 +1486,7 @@ n1: ui_px w = 700, marg = list0[0]+list0[2], - pw = vg.window_x - marg, + pw = _vg_window.w - marg, infx = pw/2 - w/2 + marg; ui_rect inf = { infx, height +32, w, 800 }; diff --git a/src/menu.h b/src/menu.h index 242cb74..e8dfbb2 100644 --- a/src/menu.h +++ b/src/menu.h @@ -1,4 +1,6 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/menu.c" +#else #define MENU_STACK_SIZE 8 #define MENU_WORLD_MAX_COUNT 10 @@ -7,10 +9,6 @@ #define MENU_WORLD_FLAG_DONE 0x2 #define MENU_WORLD_FLAG_LOCKED 0x4 -#include "vg/vg_engine.h" -#include "entity.h" -#include "world_map.h" - enum menu_page { k_menu_page_any, @@ -61,7 +59,7 @@ struct global_menu const char *web_link; /* if set; modal */ i32 web_choice; - GLuint prem_tex, guide_pump_tex, guide_fliptrick_tex; + vg_tex prem_tex, guide_pump_tex, guide_fliptrick_tex; addon_id world_list_entries[ MENU_WORLD_MAX_COUNT ]; const char *world_list_names[ MENU_WORLD_MAX_COUNT ]; @@ -81,8 +79,9 @@ struct global_menu } extern menu; -void menu_register(void); -void menu_init(void); +VG_API void _menu_register(void); +VG_API void _menu_init(void); + void menu_at_begin(void); void menu_gui( ui_context *ctx ); void menu_open( enum menu_page page ); @@ -107,3 +106,6 @@ bool menu_checkbox( ui_context *ctx, ui_rect inout_panel, bool select, const cha bool menu_options( ui_context *ctx, ui_rect inout_panel, bool select, i32 *subselect_x, const char *str_label, const char *options, u32 *data, i32 mh, i32 menter ); void menu_decor_select( ui_context *ctx, ui_rect rect ); +u32 medal_colour( ui_context *ctx, u32 flags ); + +#endif diff --git a/src/metascene.c b/src/metascene.c index dc46ed6..9fa0482 100644 --- a/src/metascene.c +++ b/src/metascene.c @@ -1,1016 +1,495 @@ -#include "metascene.h" -#include "vg/vg_magi.h" - -struct _cutscene _cutscene; - -void metascene_load( ms_context *ms, const char *path, void *alloc ) +void metascene_load( metascene *ms, const c8 *path, vg_stack_allocator *stack ) { - af_open( &ms->af, path, MS_VERSION_MIN, MS_VERSION_NR, alloc ); - AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->infos, ms_scene_info, alloc ); - AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->instances, ms_instance, alloc ); - AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->overrides, ms_override, alloc ); - AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->strips, ms_strip, alloc ); - AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->tracks, ms_track, alloc ); - AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->keyframes, ms_keyframe, alloc ); - AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->cameras, ent_camera, alloc ); - AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->audios, ent_audio, alloc ); - AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->audio_clips, ent_audio_clip, alloc ); - af_load_array( &ms->af, &ms->curves, "ms_curves", alloc, sizeof(ms_curve_keyframe) ); - af_close( &ms->af ); - - if( af_arrcount( &ms->infos ) ) - { - ms_scene_info *src_inf = af_arritm( &ms->infos, 0 ); - ms->info = *src_inf; - } - else - vg_fatal_error( "No scene info in metascene.\n" ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + vg_zero_mem( ms, sizeof(metascene) ); + + vg_stream stream; + VG_ASSERT( vg_file_stream_open( &stream, path, VG_STREAM_READ ) ); + + u32 temp_frame = _vg_start_temp_frame(); + + array_file_context af; + VG_ASSERT( af_open_stream( &af, &stream, MS_VERSION_MIN, MS_VERSION_NR, _vg_temp_stack() ) ); + + array_file_ptr strings; + af_load_array( &af, &strings, "strings", stack, 1 ); + ms->packed_strings = strings.data; + + AF_LOAD_ARRAY_STRUCT( &af, &ms->infos, ms_scene_info, stack ); + AF_LOAD_ARRAY_STRUCT( &af, &ms->instances, ms_instance, stack ); + AF_LOAD_ARRAY_STRUCT( &af, &ms->overrides, ms_override, stack ); + AF_LOAD_ARRAY_STRUCT( &af, &ms->strips, ms_strip, stack ); + AF_LOAD_ARRAY_STRUCT( &af, &ms->tracks, ms_track, stack ); + AF_LOAD_ARRAY_STRUCT( &af, &ms->keyframes, ms_keyframe, stack ); + AF_LOAD_ARRAY_STRUCT( &af, &ms->cameras, ent_camera, stack ); + AF_LOAD_ARRAY_STRUCT( &af, &ms->audios, ent_audio, stack ); + AF_LOAD_ARRAY_STRUCT( &af, &ms->audio_clips, ent_audio_clip, stack ); + af_load_array( &af, &ms->curves, "ms_curves", stack, sizeof(ms_curve_keyframe) ); + + VG_ASSERT( af_arrcount( &ms->infos ) ); + ms_scene_info *src_inf = af_arritm( &ms->infos, 0 ); + ms->info = *src_inf; + + vg_file_stream_close( &stream ); + _vg_end_temp_frame( temp_frame ); } -struct cs_instance *_cutscene_get_first_model_instance( const char *mdl_name ) +u32 skeleton_bone_id( ms_skeleton *skele, const char *name ) { - for( u32 i=0; i<_cutscene.instance_count; i ++ ) - { - struct cs_instance *inst = &_cutscene.instances[i]; - struct model_ref *mref = &_cutscene.refs[ inst->ref_id ]; - - if( vg_str_eq( mdl_name, mref->name ) ) - return inst; - } + for( u32 i=1; ibone_count; i++ ) + if( !strcmp( skele->bones[i].name, name )) + return i; - return NULL; -} + vg_error( "skeleton_bone_id( *, \"%s\" );\n", name ); + vg_fatal_error( "Bone does not exist\n" ); -void _cutscene_unload(void) -{ - vg_info( "Unloading cutscene\n" ); - vg_audio_lock(); - vg_audio_set_flagged_pause( AUDIO_FLAG_CUTSCENE, 0 ); - vg_audio_fadeout_flagged_audio( AUDIO_FLAG_CUTSCENE, 1.0f ); - vg_audio_unlock(); - - for( u32 i=0; i<_cutscene.unique_refs; i ++ ) - mdl_sync_std_unload( &_cutscene.refs[i].mdl ); - - _cutscene.unique_refs = 0; - _cutscene.active_camera = NULL; - _cutscene.strip = 0; - _cutscene.time = 0.0f; - _cutscene.active_samplers = 0; - _cutscene.state = k_cutscene_state_unloading; - _cutscene.player_binding = NULL; - _cutscene.subtitle = NULL; - _cutscene.raiser_entity = 0; - _cutscene.fadeout = 0; - _cutscene.skipped = 0; - _cutscene.fadeout_start = 0.0f; + return 0; } -/* - * Find associated entity data. We should also probably do this on the world - * thingy - */ -struct cs_asoc +void keyframe_copy_pose( ms_keyframe *kfa, ms_keyframe *kfb, int num ) { - mdl_context *orig_data; - u16 entity_type, - entity_index; - ms_override *override; -}; - -static void _cutscene_override_asoc( u32 instance_id, u32 override_index, struct cs_asoc *out_asoc ) -{ - struct cs_instance *instance = &_cutscene.instances[ instance_id ]; - mdl_context *mdl = &_cutscene.refs[ instance->ref_id ].mdl; - - ms_instance *oins = af_arritm( &_cutscene.meta.instances, instance_id ); - ms_override *override = af_arritm( &_cutscene.meta.overrides, oins->override_start + override_index ); - - out_asoc->orig_data = mdl; - out_asoc->entity_type = override->entity_type; - out_asoc->override = override; - const char *name = af_str( &_cutscene.meta.af, override->pstr_name ); - u32 name_hash = af_str_hash( &_cutscene.meta.af, override->pstr_name ); - - if( out_asoc->entity_type != 28 ) - goto NOT_IMPLEMENTED; - - for( u32 j=0; jarmature_count; j ++ ) - { - mdl_armature *armature = &mdl->armatures[ j ]; - if( af_str_eq( &mdl->af, armature->pstr_name, name, name_hash ) ) - { - out_asoc->entity_index = j; - return; - } - } - -NOT_IMPLEMENTED: - - vg_fatal_error( "The data association was not found.\n" - " Entity Type: %u\n" - " Entity name: %s\n", override->entity_type, name ); + for( int i=0; imode & k_ms_strip_mode_animation ); - if( strip->strip.instance_id == 0xffffffff ) - { - out_asoc->orig_data = NULL;// &_cutscene.meta; - out_asoc->entity_type = mdl_entity_id_type( strip->strip.object_id ); - out_asoc->entity_index = mdl_entity_id_id( strip->strip.object_id ); - out_asoc->override = NULL; - } - else - _cutscene_override_asoc( strip->strip.instance_id, strip->strip.object_id, out_asoc ); + v3f v0, co; + v3_add( kf->co, offset, co ); + v3_sub( co, origin, v0 ); + q_mulv( q, v0, v0 ); + v3_add( v0, origin, co ); + v3_sub( co, offset, kf->co ); + + q_mul( q, kf->q, kf->q ); + q_normalize( kf->q ); } -static void sync_cutscene_loaded( void *userdata ) +void keyframe_lerp( ms_keyframe *kfa, ms_keyframe *kfb, f32 t, ms_keyframe *kfd ) { - THREAD_0; - - vg_info( "Cutscene loaded\n" ); - _cutscene.state = k_cutscene_state_ready; + v3_lerp( kfa->co, kfb->co, t, kfd->co ); + q_nlerp( kfa->q, kfb->q, t, kfd->q ); + v3_lerp( kfa->s, kfb->s, t, kfd->s ); } -struct cutscene_load_info -{ - u32 nothing; - char path[]; -}; -static void cutscene_load_thread( vg_async_task *task ) +/* + * Lerp between two sets of keyframes and store in dest. Rotations use Nlerp. + */ +void keyframe_lerp_pose( ms_keyframe *kfa, ms_keyframe *kfb, float t, ms_keyframe *kfd, int count ) { - struct cutscene_load_info *info = (void *)task->data; - vg_info( "Loading cutscene: %s\n", info->path ); - - vg_stack_init( &_cutscene.stack, NULL, VG_MB(20), "Cutscene Stack" ); - metascene_load( &_cutscene.meta, info->path, &_cutscene.stack ); - - _cutscene.instance_count = af_arrcount( &_cutscene.meta.instances ); - _cutscene.instances = vg_stack_allocate( &_cutscene.stack, sizeof(struct cs_instance) * _cutscene.instance_count, - 8, "Instances" ); - - _cutscene.refs = vg_stack_allocate( &_cutscene.stack, 0, 8, "References" ); - _cutscene.unique_refs = 0; - for( u32 i=0; i < _cutscene.instance_count; i ++ ) + if( t <= 0.0001f ) { - ms_instance *instance = af_arritm( &_cutscene.meta.instances, i ); - const char *name = af_str( &_cutscene.meta.af, instance->pstr_name ); - u32 name_hash = af_str_hash( &_cutscene.meta.af, instance->pstr_name ); - - struct model_ref *ref = NULL; - u32 ref_id = 0; - - for( u32 j=0; j<_cutscene.unique_refs; j ++ ) - { - struct model_ref *ref_j = &_cutscene.refs[ j ]; - - if( af_str_eq( &_cutscene.meta.af, instance->pstr_name, ref_j->name, ref_j->name_hash ) ) - { - ref = ref_j; - ref_id = j; - break; - } - } - - if( !ref ) - { - _cutscene.refs = vg_stack_extend_last( &_cutscene.stack, sizeof(struct model_ref) ); - ref_id = _cutscene.unique_refs; - ref = &_cutscene.refs[ ref_id ]; - ref->name = name; - ref->name_hash = name_hash; - ref->reference_count = 0; - vg_info( "Indexed reference '%s'\n", name ); - _cutscene.unique_refs ++; - } - - ref->reference_count ++; - _cutscene.instances[ i ].ref_id = ref_id; - _cutscene.instances[ i ].skinning_data = NULL; - _cutscene.instances[ i ].disable_render = 0; - } - - /* load model data */ - for( u32 i=0; i<_cutscene.unique_refs; i ++ ) - { - struct model_ref *ref = &_cutscene.refs[ i ]; - char mdl_path_buf[ 512 ]; - vg_str mdl_path; - vg_strnull( &mdl_path, mdl_path_buf, sizeof(mdl_path_buf) ); - vg_strcat( &mdl_path, ref->name ); - vg_strcat( &mdl_path, ".mdl" ); - - vg_info( "Loading instance model: %s\n", mdl_path.buffer ); - mdl_open( &ref->mdl, mdl_path.buffer, &_cutscene.stack ); - mdl_load_metadata_block( &ref->mdl, &_cutscene.stack ); - mdl_async_full_load_std( &ref->mdl, NULL ); - mdl_close( &ref->mdl ); - - u32 skeleton_count = ref->mdl.armature_count; - if( skeleton_count ) - { - ref->skeletons = vg_stack_allocate( &_cutscene.stack, sizeof(struct cs_skeleton) * skeleton_count, 8, "Skeletons" ); - ref->total_skinning_bones = 0; - for( u32 j=0; jskeletons[ j ]; - skeleton_setup( &skele->sk, &ref->mdl, j, &_cutscene.stack ); - skele->skinning_offset = ref->total_skinning_bones; - ref->total_skinning_bones += skele->sk.bone_count; - } - } - else - { - ref->skeletons = NULL; - ref->total_skinning_bones = 0; - } - } - - /* allocate skinning memory per-instance */ - for( u32 i=0; i<_cutscene.instance_count; i ++ ) - { - struct cs_instance *ins = &_cutscene.instances[ i ]; - struct model_ref *ref = &_cutscene.refs[ ins->ref_id ]; - - ins->skinning_data = vg_stack_allocate( &_cutscene.stack, sizeof(m4x3f) * ref->total_skinning_bones, - 8, "Skinning Data" ); - for( u32 j=0; jtotal_skinning_bones; j ++ ) - m4x3_identity( ins->skinning_data[ j ] ); - - /* load overrides */ - ms_instance *oins = af_arritm( &_cutscene.meta.instances, i ); - for( u32 j=0; joverride_count; j ++ ) - { - ms_override *override = af_arritm( &_cutscene.meta.overrides, oins->override_start + j ); - - struct cs_asoc asoc; - _cutscene_override_asoc( i, j, &asoc ); - - VG_ASSERT( asoc.entity_type == 28 ); - - struct cs_skeleton *skele = &ref->skeletons[ asoc.entity_index ]; - m4x3f mmdl; - mdl_transform_m4x3( &override->transform, mmdl ); - - for( u32 l=0; lsk.bone_count; l ++ ) - m4x3_copy( mmdl, ins->skinning_data[skele->skinning_offset+l] ); - } + keyframe_copy_pose( kfa, kfd, count ); + return; } - - /* audio packs */ - for( u32 j=0; j= 0.9999f ) { - ent_audio *audio = af_arritm( &_cutscene.meta.audios, j ); - - for( u32 k=0; kclip_count; k++ ) - { - ent_audio_clip *clip = af_arritm( &_cutscene.meta.audio_clips, audio->clip_start+k ); - - if( clip->_.file.pack_size ) - vg_error( "Currently not support packed audio in metascene..." ); - else - { - clip->_.clip.path = af_str( &_cutscene.meta.af, clip->_.file.pstr_path ); - clip->_.clip.flags = audio->flags; - clip->_.clip.any_data = NULL; - clip->_.clip.size = 0; - } - - audio_clip_load( &clip->_.clip, &_cutscene.stack ); - } + keyframe_copy_pose( kfb, kfd, count ); + return; } - vg_async_call( &vg.main_tasks, sync_cutscene_loaded, NULL ); + for( int i=0; ibone_count-1 ); +} - u32 len = strlen( path ) +1; - vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct cutscene_load_info) + len, 1 ); - struct cutscene_load_info *info = (void *)task->data; - strcpy( info->path, path ); - vg_async_task_dispatch( task, cutscene_load_thread ); - return 1; +void skeleton_copy_pose( ms_skeleton *skele, ms_keyframe *kfa, ms_keyframe *kfd ) +{ + keyframe_copy_pose( kfa, kfd, skele->bone_count-1 ); } /* - * Currently draws everything as skinned meshes. + * Sample animation between 2 closest frames using time value. Output is a + * keyframe buffer that is allocated with an appropriate size + * + * Time is in SECONDS */ -void cutscene_render_instance( struct cs_instance *ins, world_instance *world, vg_camera *cam ) +void skeleton_sample_anim( ms_skeleton *skele, ms_skeletal_animation *anim, f32 time, ms_keyframe *output ) { - if( ins->disable_render ) - return; + ms_strip *strip = anim->strip; + f32 animtime = fmodf( time*anim->framerate, (f32)strip->strip.length ), + animframe = floorf( animtime ), + t = animtime - animframe; - struct model_ref *ref = &_cutscene.refs[ ins->ref_id ]; - mdl_context *mdl = &ref->mdl; - mesh_bind( &mdl->mesh ); + u32 frame = (u32)animframe % strip->strip.length, + next = (frame+1) % strip->strip.length; - shader_model_character_view_use(); - shader_model_character_view_uCamera( cam->transform[3] ); - shader_model_character_view_uPv( cam->mtx.pv ); - shader_model_character_view_uDepthMode( 0 ); - shader_model_character_view_uShadeless( 0 ); - shader_model_character_view_uUvOffset( (v2f){0,0} ); + ms_keyframe *base = anim->keyframes_base + strip->strip.count*frame, + *nbase = anim->keyframes_base + strip->strip.count*next; - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_character_view ); + skeleton_lerp_pose( skele, base, nbase, t, output ); +} - glActiveTexture( GL_TEXTURE0 ); - shader_model_character_view_uTexMain( 0 ); +/* time is in SECONDS */ +int skeleton_sample_anim_clamped( ms_skeleton *skele, ms_skeletal_animation *anim, f32 time, ms_keyframe *output ) +{ + ms_strip *strip = anim->strip; + f32 end = (strip->strip.length-1)/anim->framerate; + skeleton_sample_anim( skele, anim, vg_minf( end, time ), output ); - u32 armature_id = 0x00; - u32 material_id = 0x00; - bool using_additive = 0; + if( time > end ) return 0; + else return 1; +} - for( u32 i=0; imesh_count; i ++ ) - { - mdl_mesh *mesh = &mdl->meshes[ i ]; - VG_ASSERT( mesh->armature_id ); +static int should_apply_bone( ms_skeleton *skele, u32 id, anim_apply type ) +{ + ms_skeleton_bone *sb = &skele->bones[ id ], + *sp = &skele->bones[ sb->parent ]; - if( mesh->armature_id != armature_id ) + if( type == k_anim_apply_defer_ik ) + { + if( ((sp->flags & k_bone_flag_ik) && !(sb->flags & k_bone_flag_ik)) || sp->defer ) { - armature_id = mesh->armature_id; - u32 sk_index = mdl_entity_id_id( armature_id ); - - struct cs_skeleton *skele = &ref->skeletons[ sk_index ]; - m4x3f *skinning_data = ins->skinning_data + skele->skinning_offset; - glUniformMatrix4x3fv( _uniform_model_character_view_uTransforms, skele->sk.bone_count, 0, - (const GLfloat *)skinning_data ); + sb->defer = 1; + return 0; } - - for( u32 j=0; jsubmesh_count; j ++ ) + else { - mdl_submesh *sm = &mdl->submeshes[ mesh->submesh_start+j ]; - VG_ASSERT( sm->material_id ); - - if( sm->material_id != material_id ) - { - mdl_material *m = &mdl->materials[ sm->material_id-1 ]; - VG_ASSERT( m->shader == k_shader_standard ); - - struct shader_props_standard *props = m->props.compiled; - VG_ASSERT( props->tex_diffuse ); - - mdl_texture *tex = &mdl->textures[ props->tex_diffuse-1 ]; - glBindTexture( GL_TEXTURE_2D, tex->glname ); - - if( props->render_flags & k_material_render_additive ) - { - using_additive = 1; - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - glBlendEquation(GL_FUNC_ADD); - glDisable( GL_CULL_FACE ); - shader_model_character_view_uShadeless( 1 ); - } - else - { - if( using_additive ) - { - using_additive = 0; - glDepthMask(GL_TRUE); - glDisable(GL_BLEND); - glEnable( GL_CULL_FACE ); - shader_model_character_view_uShadeless( 0 ); - } - } - } - - mdl_draw_submesh( sm ); + sb->defer = 0; + return 1; } } - - if( using_additive ) - { - shader_model_character_view_uShadeless( 0 ); - glDepthMask(GL_TRUE); - glDisable(GL_BLEND); - } -} - -#define CS_LOCATION 0 -#define CS_ANGLES 4 -#define CS_FOV 8 - -struct cs_link_info -{ - f32 *target; - u32 semantic_type; -}; - -static bool link_internal_datapath( struct cs_asoc *asoc, const char *datapath, struct cs_link_info *out_link ) -{ - if( asoc->entity_type != k_ent_camera ) + else if( type == k_anim_apply_deffered_only ) { - vg_warn( "Failed link %d#%d:'%s'\n", asoc->entity_type, asoc->entity_index, datapath ); - VG_ASSERT( 0 ); - } - ent_camera *cam = af_arritm( &_cutscene.meta.cameras, asoc->entity_index ); - - struct - { - const char *prefix; - f32 *arr; - u32 semantic; - } - reference[] = - { - { "location:", cam->co, CS_LOCATION }, - { "rotation_euler:", cam->r, CS_ANGLES }, - { "lens:", &cam->fov, CS_FOV } - }; - - for( u32 i=0; itarget = reference[i].arr + offset; - out_link->semantic_type = reference[i].semantic + offset; - - vg_info( "Linked %d#%d:'%s'\n", asoc->entity_type, asoc->entity_index, datapath ); + if( sb->defer ) return 1; - } + else + return 0; } - vg_warn( "Failed link %d#%d:'%s'\n", asoc->entity_type, asoc->entity_index, datapath ); - return 0; -} - -ent_camera *_cutscene_active_camera(void) -{ - return _cutscene.active_camera; + return 1; } -void cutscene_update( f32 delta ) +/* + * Apply block of keyframes to skeletons final pose + */ +void skeleton_apply_pose( ms_skeleton *skele, ms_keyframe *pose, anim_apply passtype, m4x3f *final_mtx ) { - if( _cutscene.state == k_cutscene_state_unloading ) + if( passtype == k_anim_apply_absolute ) { - // NOTE: This somestimes still fails! - if( !vg_audio_flagged_stopped( AUDIO_FLAG_CUTSCENE ) ) + for( u32 i=1; ibone_count; i++ ) { - static u32 ticker = 0; - ticker ++; - if( ticker > 50 ) - { - vg_low( "waiting for audio to stop...\n" ); - ticker = 0; - } - return; - } - - vg_stack_free( &_cutscene.stack ); - _cutscene.state = k_cutscene_state_none; - _cutscene.marker_this_frame = NULL; - _cutscene.subtitle = NULL; - _cutscene.raiser_entity = 0; - vg_info( "Finished unloading cutscene\n" ); - return; - } - - if( _cutscene.state == k_cutscene_state_ready ) - { - _cutscene.player_binding = _cutscene_get_first_model_instance( "models/ch_none" ); - if( _cutscene.player_binding ) - _cutscene.player_binding->disable_render = 1; + ms_keyframe *kf = &pose[i-1]; - /* start playing */ - if( _cutscene.freeze_player ) - localplayer.immobile = 1; + v3f *posemtx = final_mtx[i]; - vg_audio_lock(); - for( u32 j=0; jclip_start ); - - if( audio->flags & AUDIO_FLAG_AUTO_START ) - { - const u16 group = 0xfff1; - const u32 flags = AUDIO_FLAG_CUTSCENE; - - if( audio->flags & AUDIO_FLAG_SPACIAL_3D ) - vg_audio_oneshot_3d( &clip->_.clip, audio->transform.co, audio->transform.s[0], audio->volume, group,flags); - else - vg_audio_oneshot( &clip->_.clip, 1.0f, 0.0f, group, flags ); - } + q_m3x3( kf->q, posemtx ); + m3x3_scale( posemtx, kf->s ); + v3_copy( kf->co, posemtx[3] ); } - vg_audio_unlock(); - - _cutscene.state = k_cutscene_state_playing; - _world_raise_event( _cutscene.raiser_entity, "start" ); + return; } - if( _cutscene.state != k_cutscene_state_playing ) - return; + m4x3_identity( final_mtx[0] ); + skele->bones[0].defer = 0; + skele->bones[0].flags &= ~k_bone_flag_ik; - _cutscene.marker_this_frame = NULL; - _cutscene.time += delta; - i32 frame = _cutscene.time * _cutscene.meta.info.framerate; - - /* clear out finished samplers */ - bool move = 0; - u32 j = 0; - for( u32 i=0; i<_cutscene.active_samplers; i ++ ) + for( u32 i=1; ibone_count; i++ ) { - struct cs_sampler *si = &_cutscene.samplers[i]; - - if( frame > (si->strip->offset + (i32)si->strip->strip.length) ) - move = 1; - else - { - if( move ) - { - struct cs_sampler *sj = &_cutscene.samplers[j]; - *sj = *si; - } - - j ++; - } - } - _cutscene.active_samplers = j; + ms_skeleton_bone *sb = &skele->bones[i], + *sp = &skele->bones[sb->parent]; + if( !should_apply_bone( skele, i, passtype ) ) + continue; - /* add new samplers as we get to them */ - for( u32 i=_cutscene.strip; ioffset ) - break; - - if( strip->mode & k_ms_strip_mode_animation ) - { - if( frame > strip->offset + (i32)strip->strip.length ) - { - vg_warn( "Skipping?\n" ); - _cutscene.strip ++; - continue; - } - - if( _cutscene.skipped == 2 ) - { - _cutscene.strip ++; - continue; - } - - if( strip->strip.instance_id == 0xffffffff ) - { - const char *strip_name = af_str( &_cutscene.meta.af, strip->strip.pstr_name ); - vg_info( "+ Strip: '%s' entity: %u\n", strip_name, strip->strip.object_id ); - - /* internal link */ - struct cs_asoc asoc; - _cutscene_get_strip_asoc( strip, &asoc ); - - if( strip->mode == k_ms_strip_mode_curves ) - { - for( u32 j=0; jstrip.count; j ++ ) - { - ms_track *track = af_arritm( &_cutscene.meta.tracks, strip->strip.start + j ); - const char *datapath = af_str( &_cutscene.meta.af, track->pstr_datapath ); - - struct cs_link_info link; - if( !link_internal_datapath( &asoc, datapath, &link ) ) - continue; - - VG_ASSERT( _cutscene.active_samplers < VG_ARRAY_LEN(_cutscene.samplers) ); - struct cs_sampler *samp = &_cutscene.samplers[ _cutscene.active_samplers ++ ]; - samp->strip = strip; - samp->curves.track = track; - - samp->curves.target = link.target; - samp->curves.semantic = link.semantic_type; - samp->curves.keyframe = 0; - samp->override = asoc.override; - VG_ASSERT( samp->curves.target ); - } - } - else VG_ASSERT(0); - } - else - { - /* external link */ - struct cs_instance *ins = &_cutscene.instances[ strip->strip.instance_id ]; - struct cs_asoc asoc; - _cutscene_get_strip_asoc( strip, &asoc ); - VG_ASSERT( asoc.entity_type == 28 ); - - if( strip->mode == k_ms_strip_mode_keyframes ) - { - VG_ASSERT( _cutscene.active_samplers < VG_ARRAY_LEN(_cutscene.samplers) ); - - struct cs_sampler *samp = &_cutscene.samplers[ _cutscene.active_samplers ++ ]; - struct model_ref *ref = &_cutscene.refs[ ins->ref_id ]; - struct cs_skeleton *skele = &ref->skeletons[ asoc.entity_index ]; - - samp->strip = strip; - samp->skeleton.skinning_data = &ins->skinning_data[ skele->skinning_offset ]; - samp->skeleton.ref_sk = &skele->sk; - samp->override = asoc.override; - } - else - { - VG_ASSERT(0); - } - } - } - else - { - if( strip->mode == k_ms_strip_mode_camera ) - { - u32 type = mdl_entity_id_type( strip->camera.entity_id ), - index = mdl_entity_id_id( strip->camera.entity_id ); - VG_ASSERT( type == k_ent_camera ); - ent_camera *cam = af_arritm( &_cutscene.meta.cameras, index ); - _cutscene.active_camera = cam; - } - - if( strip->mode == k_ms_strip_mode_fadeout ) - { - _cutscene.fadeout = 1; - _cutscene.fadeout_start = _cutscene.time; - } - - if( strip->mode == k_ms_strip_mode_subtitle ) - { - // FIXME: COLOURS - _cutscene.subtitle = af_str( &_cutscene.meta.af, strip->subtitle.pstr_en ); - } - - if( strip->mode == k_ms_strip_mode_event ) - { - const char *str = af_str( &_cutscene.meta.af, strip->event.pstr_string ); - vg_info( "cutscene event: %s\n", str ); - _world_raise_event( _cutscene.raiser_entity, str ); - } - } + sb->defer = 0; - _cutscene.strip ++; - } + /* process pose */ + m4x3f posemtx; - /* sample da samplers */ - for( u32 i=0; i<_cutscene.active_samplers && (_cutscene.skipped != 2); i ++ ) - { - struct cs_sampler *samp = &_cutscene.samplers[ i ]; + v3f temp_delta; + v3_sub( skele->bones[i].co, skele->bones[sb->parent].co, temp_delta ); - if( samp->strip->mode == k_ms_strip_mode_keyframes ) - { - struct skeleton_anim temp_anim = - { - .strip = samp->strip, - .framerate = _cutscene.meta.info.framerate, - .keyframes_base = af_arritm( &_cutscene.meta.keyframes, samp->strip->strip.start ) - }; - - f32 t = _cutscene.time; - t -= (f32)samp->strip->offset / _cutscene.meta.info.framerate; - - struct skeleton *ref_sk = samp->skeleton.ref_sk; - m4x3f *final_mtx = samp->skeleton.skinning_data; - - ms_keyframe pose[32]; - skeleton_sample_anim_clamped( ref_sk, &temp_anim, t, pose ); - - skeleton_apply_pose( ref_sk, pose, k_anim_apply_defer_ik, final_mtx ); - skeleton_apply_ik_pass( ref_sk, final_mtx ); - skeleton_apply_pose( ref_sk, pose, k_anim_apply_deffered_only, final_mtx ); - skeleton_apply_inverses( ref_sk, final_mtx ); - - if( samp->override ) - { - m4x3f mmdl; - mdl_transform_m4x3( &samp->override->transform, mmdl ); - skeleton_apply_transform( ref_sk, mmdl, final_mtx ); - } - - skeleton_debug( ref_sk, final_mtx ); - } - else - { - f32 scene_t = _cutscene.time * _cutscene.meta.info.framerate, - t = (f32)(scene_t - samp->strip->offset) + samp->strip->strip.timing_offset; - - ms_curve_keyframe *kl = af_arritm( &_cutscene.meta.curves, - samp->curves.track->keyframe_start + samp->curves.keyframe ), - *kr = NULL; - - if( t > kl->co[0] ) - { - if( samp->curves.track->keyframe_count > 1 ) - { - for( u32 j=samp->curves.keyframe+1; jcurves.track->keyframe_count; j ++ ) - { - kr = af_arritm( &_cutscene.meta.curves, samp->curves.track->keyframe_start + j ); - if( kr->co[0] <= t ) - { - kl = kr; - kr = NULL; - samp->curves.keyframe = j; - } - else break; - } - } - } - - if( kl && kr ) - *samp->curves.target = explicit_bezier( kl->co, kl->r, kr->l, kr->co, t ); - else - *samp->curves.target = kl->co[1]; - - if( samp->curves.semantic == CS_FOV ) - { - f32 mm = *samp->curves.target, - fov = 2.0f * 57.2957795f * atanf( (36.0f*0.5f) / mm ); - *samp->curves.target = fov; - } - } - } + /* pose matrix */ + ms_keyframe *kf = &pose[i-1]; + q_m3x3( kf->q, posemtx ); + m3x3_scale( posemtx, kf->s ); + v3_copy( kf->co, posemtx[3] ); + v3_add( temp_delta, posemtx[3], posemtx[3] ); - for( u32 i=0; ico, VG__RED, 0.2f ); + /* final matrix */ + m4x3_mul( final_mtx[ sb->parent ], posemtx, final_mtx[i] ); } +} - f32 scene_t = _cutscene.time * _cutscene.meta.info.framerate, - end_t = _cutscene.meta.info.end_frame; - - if( scene_t >= end_t ) +/* + * Take the final matrices and decompose it into an absolute positioned anim + */ +void skeleton_decompose_mtx_absolute( ms_skeleton *skele, ms_keyframe *anim, m4x3f *final_mtx ) +{ + for( u32 i=1; ibone_count; i++ ) { - if( _cutscene.strip != af_arrcount(&_cutscene.meta.strips) ) - { - _cutscene.time = 9999999.9f; - _cutscene.skipped = 2; /* signal we can ignore animation strips, just want events for correctness */ - return; - } - _world_raise_event( _cutscene.raiser_entity, "end" ); - - if( _cutscene.freeze_player ) - localplayer.immobile = 0; - - _cutscene_unload(); + ms_skeleton_bone *sb = &skele->bones[i]; + ms_keyframe *kf = &anim[i-1]; + m4x3_decompose( final_mtx[i], kf->co, kf->q, kf->s ); } } -void cutscene_render_fadeout(void) +/* + * creates the reference inverse matrix for an IK bone, as it has an initial + * intrisic rotation based on the direction that the IK is setup.. + */ +void skeleton_inverse_for_ik( ms_skeleton *skele, v3f ivaxis, u32 id, m3x3f inverse ) { - bool render = 0; - f32 render_alpha = 0.0f; + v3_copy( ivaxis, inverse[0] ); + v3_copy( skele->bones[id].end, inverse[1] ); + v3_normalize( inverse[1] ); + v3_cross( inverse[0], inverse[1], inverse[2] ); + m3x3_transpose( inverse, inverse ); +} - if( _cutscene.state >= k_cutscene_state_ready ) - { - if( _cutscene.fadeout ) - { - f32 l = ((f32)_cutscene.meta.info.end_frame/(f32)_cutscene.meta.info.framerate) - _cutscene.fadeout_start, - t = (_cutscene.time - _cutscene.fadeout_start) / l; - render = 1; - render_alpha = t; - _cutscene.fadeout_cooldown = 1.0f; - } - } - else - { - if( _cutscene.fadeout_cooldown > 0.0f ) - { - render = 1; - render_alpha = _cutscene.fadeout_cooldown; - _cutscene.fadeout_cooldown -= vg.time_delta; - } +/* + * Creates inverse rotation matrices which the IK system uses. + */ +void skeleton_create_inverses( ms_skeleton *skele ) +{ + /* IK: inverse 'plane-bone space' axis '(^axis,^bone,...)[base] */ + for( u32 i=0; iik_count; i++ ) + { + ms_skeleton_ik *ik = &skele->ik[i]; + m4x3f inverse; + v3f iv0, iv1, ivaxis; + v3_sub( skele->bones[ik->target].co, skele->bones[ik->lower].co, iv0 ); + v3_sub( skele->bones[ik->pole].co, skele->bones[ik->lower].co, iv1 ); + v3_cross( iv0, iv1, ivaxis ); + v3_normalize( ivaxis ); + + skeleton_inverse_for_ik( skele, ivaxis, ik->lower, ik->ia ); + skeleton_inverse_for_ik( skele, ivaxis, ik->upper, ik->ib ); } +} - if( render ) +/* + * Apply a model matrix to all bones, should be done last + */ +void skeleton_apply_transform( ms_skeleton *skele, m4x3f transform, m4x3f *final_mtx ) +{ + for( u32 i=0; ibone_count; i++ ) { - glEnable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - - shader_blitcolour_use(); - shader_blitcolour_uColour( (v4f){ 0.04f, 0.02f, 0.03f, vg_clampf( render_alpha, 0.0f, 1.0f ) } ); - render_fsquad(); + ms_skeleton_bone *sb = &skele->bones[i]; + m4x3_mul( transform, final_mtx[i], final_mtx[i] ); } } -void cutscene_render( world_instance *world, vg_camera *cam ) +/* + * Apply an inverse matrix to all bones which maps vertices from bind space into + * bone relative positions + */ +void skeleton_apply_inverses( ms_skeleton *skele, m4x3f *final_mtx ) { - if( _cutscene.state >= k_cutscene_state_ready ) + for( u32 i=0; ibone_count; i++ ) { - for( u32 i=0; i<_cutscene.instance_count; i ++ ) - cutscene_render_instance( &_cutscene.instances[i], world, cam ); + ms_skeleton_bone *sb = &skele->bones[i]; + m4x3f inverse; + m3x3_identity( inverse ); + v3_negate( sb->co, inverse[3] ); + m4x3_mul( final_mtx[i], inverse, final_mtx[i] ); } } -void _cutscene_gui( ui_context *ctx ) +/* + * Apply all IK modifiers (2 bone ik reference from blender is supported) + */ +void skeleton_apply_ik_pass( ms_skeleton *skele, m4x3f *final_mtx ) { - if( _cutscene.subtitle ) - { - ctx->font = &vgf_default_small; - ctx->kern[1] = 16; - ui_px scale = 2; - ui_rect box = { 0,0, 1000, 80*2 }; - ui_rect_center( (ui_rect){0,0,vg.window_x,vg.window_y}, box ); - box[1] = vg.window_y - (box[3] + 8); - - i32 lines = 1; - - const char *_c = _cutscene.subtitle; - u8 c; - - i32 length = 0; - ui_px y = box[1]; - - while(1) - { - c = *(_c ++); - - /* TODO: This is pasted straight from vg_ui, maybe create a vg_ui_text_iter() ...? */ - if( c == '\x1B' ) - { - while( (c = *(_c ++)) ) - { - if( c == 'm' ) - break; - } - - if( c == 0 ) - break; - else - continue; - } - - if( c >= 32 ) - length ++; - else if( c == '\n' || c == '\0' ) - { - ui_px w = length * ctx->font->sx*scale + 16; - ui_rect background_rect = { vg.window_x/2 - w/2, y-8, w, ctx->font->sy*scale+16 }; - - ui_fill( ctx, background_rect, ui_opacity( GUI_COL_DARK, 0.75f ) ); - y += (ctx->font->sy)*scale + 16; - length = 0; - lines ++; - } - - if( c == '\0' ) - break; - } - - ui_text( ctx, box, _cutscene.subtitle, scale, k_ui_align_center, 0 ); - ctx->font = &vgf_default_small; - ctx->kern[1] = 0; + for( u32 i=0; iik_count; i++ ) + { + ms_skeleton_ik *ik = &skele->ik[i]; + v3f v0, /* base -> target */ + v1, /* base -> pole */ + vaxis; + + v3f co_base, + co_target, + co_pole; + + v3_copy( final_mtx[ik->lower][3], co_base ); + v3_copy( final_mtx[ik->target][3], co_target ); + v3_copy( final_mtx[ik->pole][3], co_pole ); + + v3_sub( co_target, co_base, v0 ); + v3_sub( co_pole, co_base, v1 ); + v3_cross( v0, v1, vaxis ); + v3_normalize( vaxis ); + v3_normalize( v0 ); + v3_cross( vaxis, v0, v1 ); + + /* localize problem into [x:v0,y:v1] 2d plane */ + v2f base = { v3_dot( v0, co_base ), v3_dot( v1, co_base ) }, + end = { v3_dot( v0, co_target ), v3_dot( v1, co_target ) }, + knee; + + /* Compute angles (basic trig)*/ + v2f delta; + v2_sub( end, base, delta ); + + f32 l1 = v3_length( skele->bones[ik->lower].end ), + l2 = v3_length( skele->bones[ik->upper].end ), + d = vg_clampf( v2_length(delta), fabsf(l1 - l2), l1+l2-0.00001f ), + c = acosf( (l1*l1 + d*d - l2*l2) / (2.0f*l1*d) ), + rot = atan2f( delta[1], delta[0] ) + c - VG_PIf/2.0f; + + knee[0] = sinf(-rot) * l1; + knee[1] = cosf(-rot) * l1; + + m4x3_identity( final_mtx[ik->lower] ); + m4x3_identity( final_mtx[ik->upper] ); + + /* create rotation matrix */ + v3f co_knee; + v3_muladds( co_base, v0, knee[0], co_knee ); + v3_muladds( co_knee, v1, knee[1], co_knee ); + vg_line( co_base, co_knee, 0xff00ff00 ); + + m4x3f transform; + v3_copy( vaxis, transform[0] ); + v3_muls( v0, knee[0], transform[1] ); + v3_muladds( transform[1], v1, knee[1], transform[1] ); + v3_normalize( transform[1] ); + v3_cross( transform[0], transform[1], transform[2] ); + v3_copy( co_base, transform[3] ); + + m3x3_mul( transform, ik->ia, transform ); + m4x3_copy( transform, final_mtx[ik->lower] ); + + /* upper/knee bone */ + v3_copy( vaxis, transform[0] ); + v3_sub( co_target, co_knee, transform[1] ); + v3_normalize( transform[1] ); + v3_cross( transform[0], transform[1], transform[2] ); + v3_copy( co_knee, transform[3] ); + + m3x3_mul( transform, ik->ib, transform ); + m4x3_copy( transform, final_mtx[ik->upper] ); } } -/* cutscene magi - * ---------------------------------------------------------------------------- +/* + * Applies the typical operations that you want for an IK rig: + * Pose, IK, Pose(deferred), Inverses, Transform */ +void skeleton_apply_standard( ms_skeleton *skele, ms_keyframe *pose, m4x3f transform, m4x3f *final_mtx ) +{ + skeleton_apply_pose( skele, pose, k_anim_apply_defer_ik, final_mtx ); + skeleton_apply_ik_pass( skele, final_mtx ); + skeleton_apply_pose( skele, pose, k_anim_apply_deffered_only, final_mtx ); + skeleton_apply_inverses( skele, final_mtx ); + skeleton_apply_transform( skele, transform, final_mtx ); +} -static void cb_cutscene_view( ui_context *ctx, ui_rect rect, struct vg_magi_panel *magi ) +void skeleton_alloc_from( ms_skeleton *skele, vg_stack_allocator *stack, vg_model *model, mdl_armature *armature ) { - if( _cutscene.state == k_cutscene_state_none ) - { - ui_text( ctx, rect, "No cutscene loaded.", 1, k_ui_align_middle_center, 0 ); - return; - } + skele->bone_count = armature->bone_count+1; + skele->ik_count = 0; + skele->collider_count = 0; - if( _cutscene.state == k_cutscene_state_loading ) + for( u32 i=0; ibone_count; i++ ) { - ui_text( ctx, rect, "Cutscene loading..", 1, k_ui_align_middle_center, 0 ); - return; + mdl_bone *bone = &model->bones[ armature->bone_start+i ]; + if( bone->flags & k_bone_flag_ik ) + skele->ik_count ++; + if( bone->collider ) + skele->collider_count ++; } - if( _cutscene.state == k_cutscene_state_unloading ) - { - ui_text( ctx, rect, "Cutscene UN-loading..", 1, k_ui_align_middle_center, 0 ); - return; - } + u32 bone_size = sizeof(ms_skeleton_bone) * skele->bone_count, + ik_size = sizeof(ms_skeleton_ik) * skele->ik_count; - ms_strip *usage[8]; - for( u32 i=0; ibones = vg_stack_allocate( stack, bone_size, 8, NULL ); + skele->ik = vg_stack_allocate( stack, ik_size, 8, NULL ); - ui_rect panel_l, panel_r; - ui_split( rect, k_ui_axis_v, 400, 4, panel_l, panel_r ); + memset( skele->bones, 0, bone_size ); + memset( skele->ik, 0, ik_size ); +} - if( ui_clip( rect, panel_l, panel_l ) ) - { - ui_px root[2] = { panel_l[0]+8, panel_l[1]+8 }; - ui_rect box = { root[0], root[1], panel_l[2]-16, 16 }; +/* Setup a skeleton from model. mdl's metadata should stick around */ +void skeleton_setup( ms_skeleton *skele, vg_model *model, u32 index, vg_stack_allocator *stack ) +{ + u32 ik_count = 0, collider_count = 0; + skele->bone_count = 0; + skele->bones = NULL; - for( u32 i=0; i<_cutscene.unique_refs; i ++ ) - { - struct model_ref *mref = &_cutscene.refs[i]; + if( !model->armature_count ) + vg_fatal_error( "No skeleton in model\n" ); - char inf[128]; - snprintf( inf, sizeof(inf), "%s (%u references)", mref->name, mref->reference_count ); - ui_text( ctx, box, inf, 1, k_ui_align_middle_left, 0 ); - box[1] += 16; - } - } + mdl_armature *armature = &model->armatures[ index ]; + skeleton_alloc_from( skele, stack, model, armature ); - if( ui_clip( rect, panel_r, panel_r ) ) + for( u32 i=0; ibone_count; i++ ) { - ui_px root[2] = { panel_r[0]+8, panel_r[1]+8 }; + mdl_bone *bone = &model->bones[ armature->bone_start+i ]; + ms_skeleton_bone *sb = &skele->bones[i+1]; + + v3_copy( bone->co, sb->co ); + v3_copy( bone->end, sb->end ); - for( u32 i=0; iparent = bone->parent; + sb->name = af_str( model->packed_strings, bone->pstr_name ); + sb->flags = bone->flags; + sb->collider = bone->collider; + sb->orig_bone = bone; + + if( sb->flags & k_bone_flag_ik ) { - ms_strip *strip = af_arritm(&_cutscene.meta.strips, i ); - - if( !(strip->mode & k_ms_strip_mode_animation) ) - { - ui_rect box = { root[0]+strip->offset, root[1], 1, panel_r[3]-16 }; - ui_fill( ctx, box, 0xff00ff00 ); - - box[1] += box[3] -16; - box[2] = 200; - box[3] = 16; - - if( ui_clip( panel_r, box, box ) ) - { - if( strip->mode == k_ms_strip_mode_camera ) - ui_text( ctx, box, "Camera", 1, k_ui_align_middle_left, 0 ); - if( strip->mode == k_ms_strip_mode_subtitle ) - ui_text( ctx, box, "\"", 1, k_ui_align_middle_left, 0 ); - if( strip->mode == k_ms_strip_mode_fadeout ) - ui_text( ctx, box, "\\", 1, k_ui_align_middle_left, 0 ); - } - continue; - } + skele->bones[ sb->parent ].flags |= k_bone_flag_ik; - u32 layer = 0; - for( u32 k=0; koffset + (i32)usage[k]->strip.length < strip->offset ) - usage[k] = NULL; - - if( !usage[k] ) - { - usage[k] = strip; - layer = k; - break; - } - } - - ui_rect box = { strip->offset, layer*32, (i32)strip->strip.length, 30 }; - box[0] += root[0]; - box[1] += root[1]; - - if( ui_clip( panel_r, box, box ) ) - { - u32 colour = af_str_hash( &_cutscene.meta.af, strip->strip.pstr_name ); - ui_fill( ctx, box, colour | 0xff000000 ); - ui_text( ctx, box, af_str( &_cutscene.meta.af, strip->strip.pstr_name ), 1, k_ui_align_middle_center, 0 ); - } + if( ik_count == skele->ik_count ) + vg_fatal_error( "Too many ik bones, corrupt model file\n" ); + + ms_skeleton_ik *ik = &skele->ik[ ik_count ++ ]; + ik->upper = i+1; + ik->lower = bone->parent; + ik->target = bone->ik_target; + ik->pole = bone->ik_pole; } - ui_rect cursor = { (f32)_cutscene.time*_cutscene.meta.info.framerate, 0, 1, VG_ARRAY_LEN(usage)*32 }; - cursor[0] += root[0]; - cursor[1] += root[1]; - if( ui_clip( panel_r, cursor, cursor ) ) - ui_fill( ctx, cursor, 0xffffffff ); + box_copy( bone->hitbox, sb->hitbox ); + + if( bone->collider ) + { + if( collider_count == skele->collider_count ) + vg_fatal_error( "Too many collider bones\n" ); + collider_count ++; + } } -} -static int cmd_cutscene_play( int argc, const char *argv[] ) -{ - if( argc == 1 ) - _cutscene_load_and_play( argv[0], 0, 0 ); - return 1; -} + /* fill in implicit root bone */ + v3_zero( skele->bones[0].co ); + v3_copy( (v3f){0.0f,1.0f,0.0f}, skele->bones[0].end ); + skele->bones[0].parent = 0xffffffff; + skele->bones[0].flags = 0; + skele->bones[0].name = "[root]"; -static int cmd_cutscene_inspector( int argc, const char *argv[] ) -{ - ui_px w = 800, h = 400; - struct vg_magi_panel *magi = _vg_magi_open( w, h, VG_MAGI_ALL ); - magi->title = "Cutscene Inpsector"; - magi->data = NULL; - magi->ui_cb = cb_cutscene_view; - magi->close_cb = NULL; - return 1; + skeleton_create_inverses( skele ); + vg_success( "Loaded skeleton with %u bones\n", skele->bone_count ); + vg_success( " %u colliders\n", skele->collider_count ); } -void cutscene_register(void) +void skeleton_debug( ms_skeleton *skele, m4x3f *final_mtx ) { - vg_console_reg_cmd( "cutscene_play", cmd_cutscene_play, NULL ); - vg_console_reg_cmd( "cutscene_inspector", cmd_cutscene_inspector, NULL ); + for( u32 i=1; ibone_count; i ++ ) + { + ms_skeleton_bone *sb = &skele->bones[i]; + v3f p0, p1; + v3_copy( sb->co, p0 ); + v3_add( p0, sb->end, p1 ); + + m4x3_mulv( final_mtx[i], p0, p0 ); + m4x3_mulv( final_mtx[i], p1, p1 ); + + if( sb->flags & k_bone_flag_deform ) + { + if( sb->flags & k_bone_flag_ik ) + vg_line( p0, p1, 0xff0000ff ); + else + vg_line( p0, p1, 0xffcccccc ); + } + else + vg_line( p0, p1, 0xff00ffff ); + } } diff --git a/src/metascene.h b/src/metascene.h index 4e1211b..df51d41 100644 --- a/src/metascene.h +++ b/src/metascene.h @@ -1,12 +1,12 @@ -#pragma once -#include "model.h" -#include "world.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/metascene.c" +#else #define MS_VERSION_NR 2 #define MS_VERSION_MIN 2 +typedef struct metascene metascene; typedef struct ms_scene_info ms_scene_info; -typedef struct ms_context ms_context; typedef struct ms_instance ms_instance; typedef struct ms_override ms_override; typedef struct ms_strip ms_strip; @@ -21,9 +21,9 @@ struct ms_scene_info u32 end_frame; }; -struct ms_context +struct metascene { - array_file_context af; + const void *packed_strings; ms_scene_info info; struct array_file_ptr infos, @@ -115,112 +115,85 @@ struct ms_curve_keyframe v2f co, l, r; }; -struct cs_instance -{ - bool disable_render; - u32 ref_id; - m4x3f *skinning_data; -}; - -struct cs_subtitle -{ - const char *key, *value; -}; +/* skeletons + * ------------------------------------------------------------------------------------------------------------------ */ -#include "skeleton.h" +typedef struct ms_skeleton ms_skeleton; +typedef struct ms_skeleton_bone ms_skeleton_bone; +typedef struct ms_skeleton_ik ms_skeleton_ik; -struct _cutscene +struct ms_skeleton { - ms_context meta; - vg_stack_allocator stack; - - enum cutscene_state + struct ms_skeleton_bone { - k_cutscene_state_none, - k_cutscene_state_loading, - k_cutscene_state_unloading, - k_cutscene_state_ready, - k_cutscene_state_playing, - k_cutscene_state_done, - } - state; + v3f co, end; + u32 parent; - struct model_ref - { - const char *name; - u32 name_hash; - u32 reference_count; + u32 flags; + int defer; - mdl_context mdl; - - struct cs_skeleton - { - struct skeleton sk; - u32 skinning_offset; - } - *skeletons; - u32 total_skinning_bones; + //ms_keyframe kf; + mdl_bone *orig_bone; + u32 collider; // TODO: SOA + boxf hitbox; // TODO: SOA + const char *name; // TODO: SOA } - * refs; - u32 unique_refs; - - struct cs_instance *instances; - u32 instance_count; + *bones; + u32 bone_count; - struct cs_sampler + struct ms_skeleton_ik { - ms_strip *strip; - ms_override *override; - union - { - struct - { - ms_track *track; - f32 *target; - u32 keyframe; - u32 semantic; - } - curves; - - struct - { - struct skeleton *ref_sk; - m4x3f *skinning_data; - } - skeleton; - }; + u32 lower, upper, target, pole; + m3x3f ia, ib; } - samplers[32]; - u32 active_samplers; + *ik; + u32 ik_count; - ent_camera *active_camera; - struct cs_instance *player_binding; + u32 collider_count, + bindable_count; +}; - u32 strip; - f32 time; +void metascene_load( metascene *ms, const c8 *path, vg_stack_allocator *stack ); - bool fadeout; - u8 skipped; - f32 fadeout_start, fadeout_cooldown; +void keyframe_copy_pose( ms_keyframe *kfa, ms_keyframe *kfb, int num ); +void keyframe_rotate_around( ms_keyframe *kf, v3f origin, v3f offset, v4f q ); +void keyframe_lerp( ms_keyframe *kfa, ms_keyframe *kfb, f32 t, ms_keyframe *kfd ); +void keyframe_lerp_pose( ms_keyframe *kfa, ms_keyframe *kfb, float t, ms_keyframe *kfd, int count ); - const char *marker_this_frame; - const char *subtitle; - bool subtitle_length_warning; +void skeleton_alloc_from( ms_skeleton *skele, vg_stack_allocator *stack, vg_model *model, mdl_armature *armature ); +u32 skeleton_bone_id( ms_skeleton *skele, const char *name ); +void skeleton_lerp_pose( ms_skeleton *skele, ms_keyframe *kfa, ms_keyframe *kfb, float t, ms_keyframe *kfd ); +void skeleton_copy_pose( ms_skeleton *skele, ms_keyframe *kfa, ms_keyframe *kfd ); - bool freeze_player; +typedef struct ms_skeletal_animation ms_skeletal_animation; +struct ms_skeletal_animation +{ + ms_strip *strip; + ms_keyframe *keyframes_base; + f32 framerate; +}; - u32 raiser_entity; +void skeleton_sample_anim( ms_skeleton *skele, ms_skeletal_animation *anim, f32 time, ms_keyframe *output ); +int skeleton_sample_anim_clamped( ms_skeleton *skele, ms_skeletal_animation *anim, f32 time, ms_keyframe *output ); + +typedef enum anim_apply +{ + k_anim_apply_always, + k_anim_apply_defer_ik, + k_anim_apply_deffered_only, + k_anim_apply_absolute } -extern _cutscene; - -void metascene_load( ms_context *ms, const char *path, void *alloc ); -void cutscene_register(void); -void cutscene_render( world_instance *world, vg_camera *cam ); -void cutscene_render_fadeout(void); -bool _cutscene_load_and_play( const char *path, bool freeze_player, u32 raiser_entity ); -void _cutscene_unload(void); -void cutscene_update( f32 delta ); -ent_camera *_cutscene_active_camera(void); -void _cutscene_gui( ui_context *ctx ); - -struct cs_instance *_cutscene_get_first_model_instance( const char *mdl_name ); +anim_apply; + +void skeleton_apply_pose( ms_skeleton *skele, ms_keyframe *pose, anim_apply passtype, m4x3f *final_mtx ); +void skeleton_decompose_mtx_absolute( ms_skeleton *skele, ms_keyframe *anim, m4x3f *final_mtx ); +void skeleton_inverse_for_ik( ms_skeleton *skele, v3f ivaxis, u32 id, m3x3f inverse ); +void skeleton_create_inverses( ms_skeleton *skele ); +void skeleton_apply_transform( ms_skeleton *skele, m4x3f transform, m4x3f *final_mtx ); +void skeleton_apply_inverses( ms_skeleton *skele, m4x3f *final_mtx ); +void skeleton_apply_ik_pass( ms_skeleton *skele, m4x3f *final_mtx ); +void skeleton_apply_standard( ms_skeleton *skele, ms_keyframe *pose, m4x3f transform, m4x3f *final_mtx ); +void skeleton_setup( ms_skeleton *skele, vg_model *model, u32 index, vg_stack_allocator *stack ); +void skeleton_debug( ms_skeleton *skele, m4x3f *final_mtx ); + +#endif diff --git a/src/model.c b/src/model.c index 6345cd2..187b491 100644 --- a/src/model.c +++ b/src/model.c @@ -1,305 +1,282 @@ -/* - * Copyright (C) 2021-2025 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#pragma once - -#include "vg/vg_io.h" - -#ifdef VG_3D -#include "vg/vg_tex.h" -#endif - -#include "vg/vg_msg.h" -#include "vg/vg_string.h" -#include -#include -#include -#include "model.h" -#include "shader_props.h" -#include "array_file.h" - /* * Model implementation */ -void mdl_fread_pack_file( mdl_context *mdl, mdl_file *info, void *dst ) +VG_TIER_0 vg_stream *vg_model_stream_pack_stream( vg_model_stream_context *ctx, mdl_file *file ) { - if( !info->pack_size ) + if( !file->pack_size ) { - vg_info( "Packed file is only a header; it is not packed" ); - vg_info( "path: %s\n", af_str( &mdl->af, info->pstr_path ) ); - vg_fatal_error( "" ); + vg_fatal_error( "Packed file is only a header; it is not packed" + "path: %s\n", af_str( &ctx->model->packed_strings, file->pstr_path ) ); } - - fseek( mdl->af.fp, mdl->pack_base_offset + info->pack_offset, SEEK_SET ); - u64 l = fread( dst, info->pack_size, 1, mdl->af.fp ); - - if( l != 1 ) - { - af_close( &mdl->af ); - vg_fatal_error( "Pack data corruption\n" ); - } -} - -void mdl_load_mesh_block( mdl_context *mdl, vg_stack_allocator *stack ) -{ - struct array_file_ptr ptr; - AF_LOAD_ARRAY_STRUCT( &mdl->af, &ptr, mdl_vert, stack ); - mdl->verts = ptr.data; - mdl->vert_count = ptr.count; - - AF_LOAD_ARRAY_STRUCT( &mdl->af, &ptr, mdl_indice, stack ); - mdl->indices = ptr.data; - mdl->indice_count = ptr.count; + vg_stream_seek( &ctx->stream, ctx->model->pack_base_offset + file->pack_offset ); + ctx->stream.byte_limit = ctx->model->pack_base_offset + file->pack_offset + file->pack_size; + return &ctx->stream; } -void mdl_load_metadata_block( mdl_context *mdl, vg_stack_allocator *stack ) +/* This also compiles them */ +VG_TIER_2 static void vg_model_stream_materials( vg_model_stream_context *ctx, vg_stack_allocator *stack ) { - struct array_file_ptr ptr; - AF_LOAD_ARRAY_STRUCT( &mdl->af, &ptr, mdl_mesh, stack ); - mdl->meshes = ptr.data; - mdl->mesh_count = ptr.count; - - AF_LOAD_ARRAY_STRUCT( &mdl->af, &ptr, mdl_submesh, stack ); - mdl->submeshes = ptr.data; - mdl->submesh_count = ptr.count; - - AF_LOAD_ARRAY_STRUCT( &mdl->af, &ptr, mdl_texture, stack ); - mdl->textures = ptr.data; - mdl->texture_count = ptr.count; + array_file_ptr mats_ptr; + AF_LOAD_ARRAY_STRUCT( &ctx->af, &mats_ptr, mdl_material, stack ); + ctx->model->materials = mats_ptr.data; + ctx->model->material_count = mats_ptr.count; + + u32 size = sizeof(union shader_props) * mats_ptr.count; + ctx->model->shader_props = vg_stack_allocate( stack, size, 8, "Compiled shader properties" ); + + /* + * Step 0: + * Acquiring the data source + * + * Step 1: + * Converting into formal KV structure + * We have 3 different modes; + * v101+: old simple binary structures, requires 'generating' correct kvs + * v106+: deprecated 'vg_msg' similar to kvs, only requires conversion + * v110+: text KV's, direct parsing into vg_kvs + * + * Step 2: + * Formal KV structure is then compiled into the binary union + */ + + /* step0 ----------------------------- */ + u32 temp_frame = _vg_start_temp_frame(); + { + array_file_ptr v101_materials; + array_file_ptr v106_data; + array_file_ptr v110_data; - AF_LOAD_ARRAY_STRUCT( &mdl->af, &ptr, mdl_armature, stack ); - mdl->armatures = ptr.data; - mdl->armature_count = ptr.count; +#if (VG_MODEL_VERSION_MIN <= 105) + if( ctx->model->version <= 105 ) + af_load_array( &ctx->af, &v101_materials, "mdl_material", _vg_temp_stack(), sizeof(struct mdl_material_v101) ); + else +#endif + if( ctx->model->version <= 109 ) + af_load_array( &ctx->af, &v106_data, "shader_data", _vg_temp_stack(), 1 ); + else + af_load_array( &ctx->af, &v110_data, "shader_props", _vg_temp_stack(), 1 ); - AF_LOAD_ARRAY_STRUCT( &mdl->af, &ptr, mdl_bone, stack ); - mdl->bones = ptr.data; - mdl->bone_count = ptr.count; + vg_kvs kvs; + vg_kvs_init( &kvs, _vg_temp_stack() ); - mdl_load_materials( mdl, stack ); -} + /* step1 ----------------------------- */ +#if (VG_MODEL_VERSION_MIN <= 105) + if( ctx->model->version <= 105 ) + { + for( u32 i=0; imodel->material_count; i ++ ) + { + mdl_material *mat = &ctx->model->materials[ i ]; + struct mdl_material_v101 *old = af_arritm( &v101_materials, i ); + + mat->props.kv_root = vg_kv_append( &kvs, 0, NULL, NULL ); + + vg_kv_append( &kvs, mat->props.kv_root, "version", "101" ); + vg_kv_append_vu32( &kvs, mat->props.kv_root, "tex_diffuse", &old->tex_diffuse, 1 ); + + if( mat->shader == k_shader_cubemap ) + { + vg_kv_append_vu32( &kvs, mat->props.kv_root, "cubemap", &old->tex_none0, 1 ); + vg_kv_append_vf32( &kvs, mat->props.kv_root, "tint", old->colour, 4 ); + } + else if( mat->shader == k_shader_terrain_blend ) + { + vg_kv_append_vf32( &kvs, mat->props.kv_root, "sand_colour", old->colour, 4 ); + vg_kv_append_vf32( &kvs, mat->props.kv_root, "blend_offset", old->colour1, 2 ); + } + else if( mat->shader == k_shader_standard_vertex_blend ) + { + vg_kv_append_vf32( &kvs, mat->props.kv_root, "blend_offset", old->colour1, 2 ); + } + else if( mat->shader == k_shader_water ) + { + vg_kv_append_vf32( &kvs, mat->props.kv_root, "shore_colour", old->colour, 4 ); + vg_kv_append_vf32( &kvs, mat->props.kv_root, "deep_colour", old->colour1, 4 ); + } + } + } -static void *mdl_shader_standard( vg_msg *msg, vg_stack_allocator *stack ) -{ - struct shader_props_standard *props = VG_STACK_ALLOCATE_STRUCT( stack, struct shader_props_standard ); - vg_msg_getkvintg( msg, "tex_diffuse", k_vg_msg_u32, &props->tex_diffuse, NULL ); - vg_msg_getkvintg( msg, "render_flags", k_vg_msg_u32, &props->render_flags, NULL ); - return props; -} + else +#endif -static void *mdl_shader_terrain( vg_msg *msg, vg_stack_allocator *stack ) -{ - struct shader_props_terrain *props = VG_STACK_ALLOCATE_STRUCT( stack, struct shader_props_terrain ); - vg_msg_getkvintg( msg, "tex_diffuse", k_vg_msg_u32, &props->tex_diffuse, NULL ); - vg_msg_getkvvecf( msg, "sand_colour", k_vg_msg_v4f, props->sand_colour, (v4f){ 0.79, 0.63, 0.48, 1.0 } ); - vg_msg_getkvvecf( msg, "blend_offset", k_vg_msg_v2f, props->blend_offset, (v2f){ 0.5, 0.0 } ); + if( ctx->model->version <= 109 ) + { + for( u32 i=0; imodel->material_count; i ++ ) + { + mdl_material *mat = &ctx->model->materials[ i ]; + mat->props.kv_root = vg_kv_append( &kvs, 0, NULL, NULL ); + vg_kv_append( &kvs, mat->props.kv_root, "version", "106" ); - return props; -} + void *buffer = NULL; + if( v106_data.data ) + buffer = v106_data.data + mat->props.kvs.offset; -static void *mdl_shader_vertex_blend( vg_msg *msg, vg_stack_allocator *stack ) -{ - struct shader_props_vertex_blend *props = VG_STACK_ALLOCATE_STRUCT( stack, struct shader_props_vertex_blend ); - vg_msg_getkvintg( msg, "tex_diffuse", k_vg_msg_u32, &props->tex_diffuse, NULL ); - vg_msg_getkvvecf( msg, "blend_offset", k_vg_msg_v2f, props->blend_offset, (v2f){ 0.5, 0.0 } ); - return props; -} + vg_kvs_append_from_legacy_msg2( &kvs, mat->props.kv_root, buffer, mat->props.kvs.size ); + } + } + else + { + for( u32 i=0; imodel->material_count; i ++ ) + { + mdl_material *mat = &ctx->model->materials[ i ]; + mat->props.kv_root = vg_kv_append( &kvs, 0, NULL, NULL ); + vg_kv_append( &kvs, mat->props.kv_root, "version", "110" ); -static void *mdl_shader_water( vg_msg *msg, vg_stack_allocator *stack ) -{ - struct shader_props_water *props = VG_STACK_ALLOCATE_STRUCT( stack, struct shader_props_water ); - vg_msg_getkvvecf( msg, "shore_colour", k_vg_msg_v4f, props->shore_colour, (v4f){0.03,0.32,0.61,1.0} ); - vg_msg_getkvvecf( msg, "deep_colour", k_vg_msg_v4f, props->deep_colour, (v4f){0.0,0.006,0.03,1.0} ); - vg_msg_getkvintg( msg, "fog_scale", k_vg_msg_f32, &props->fog_scale, (f32[]){0.04} ); - vg_msg_getkvintg( msg, "fresnel", k_vg_msg_f32, &props->fresnel, (f32[]){5.0} ); - vg_msg_getkvintg( msg, "water_scale", k_vg_msg_f32, &props->water_sale, (f32[]){ 0.008 } ); - vg_msg_getkvvecf( msg, "wave_speed", k_vg_msg_v4f, props->wave_speed, (v4f){0.008,0.006,0.003,0.03} ); - return props; -} + const c8 *buffer = NULL; + if( v110_data.data ) + buffer = v110_data.data + mat->props.kvs.offset; -void *mdl_shader_cubemapped( vg_msg *msg, vg_stack_allocator *stack ) -{ - struct shader_props_cubemapped *props = VG_STACK_ALLOCATE_STRUCT( stack, struct shader_props_cubemapped ); - vg_msg_getkvintg( msg, "tex_diffuse", k_vg_msg_u32, &props->tex_diffuse, NULL ); - vg_msg_getkvintg( msg, "cubemap_entity", k_vg_msg_u32, &props->cubemap_entity, NULL ); - vg_msg_getkvvecf( msg, "tint", k_vg_msg_v4f, props->tint, (v4f){1.0,1.0,1.0,1.0} ); - return props; -} + vg_stream kv_stream; + vg_buffer_stream_open( &kv_stream, buffer, mat->props.kvs.size, VG_STREAM_READ ); -// TODO: Shitty place for this to be -const char *_shader_prop_workshop_keys[] = -{ - [k_workshop_shader_part_truck1 ] = "truck1", - [k_workshop_shader_part_truck2 ] = "truck2", - [k_workshop_shader_part_wheel1 ] = "wheel1", - [k_workshop_shader_part_wheel2 ] = "wheel2", - [k_workshop_shader_part_wheel3 ] = "wheel3", - [k_workshop_shader_part_wheel4 ] = "wheel4", - [k_workshop_shader_part_edge ] = "edge", - [k_workshop_shader_part_griptape] = "griptape", - [k_workshop_shader_part_deck ] = "deck" -}; + vg_kv_parser parser; + vg_kv_parser_init( &parser, &kvs, mat->props.kv_root ); + vg_kv_parse_stream( &parser, &kv_stream ); + } + } -void *mdl_shader_workshop( vg_msg *msg, vg_stack_allocator *stack ) -{ - struct shader_props_workshop *props = VG_STACK_ALLOCATE_STRUCT( stack, struct shader_props_workshop ); - for( u32 i=0; itex_all[i], NULL ); + vg_kv_write wtest = { .fp = stdout, .depth = 0 }; + vg_kv_print_tree( &wtest, &kvs, 0 ); - return props; + /* step2 ----------------------------- */ + for( u32 i=0; imodel->material_count; i ++ ) + { + mdl_material *mat = &ctx->model->materials[ i ]; + u32 root = mat->props.kv_root; + union shader_props *props = &ctx->model->shader_props[ i ]; + + if( mat->shader == k_shader_standard || + mat->shader == k_shader_standard_cutout || + mat->shader == k_shader_foliage || + mat->shader == k_shader_fxglow ) + { + vg_kv_read_vu32( &kvs, root, "tex_diffuse", (u32[]){0}, &props->standard.tex_diffuse, 1 ); + vg_kv_read_vu32( &kvs, root, "render_flags", (u32[]){0}, &props->standard.render_flags, 1 ); + } + else if( mat->shader == k_shader_standard_vertex_blend ) + { + vg_kv_read_vu32( &kvs, root, "tex_diffuse", (u32[]){0}, &props->vertex_blend.tex_diffuse, 1 ); + vg_kv_read_vf32( &kvs, root, "blend_offset", (v2f){ 0.5, 0.0 }, props->vertex_blend.blend_offset, 2 ); + } + else if( mat->shader == k_shader_cubemap ) + { + vg_kv_read_vu32( &kvs, root, "tex_diffuse", (u32[]){0}, &props->cubemapped.tex_diffuse, 1 ); + vg_kv_read_vu32( &kvs, root, "cubemap_entity", (u32[]){0}, &props->cubemapped.cubemap_entity, 1 ); + vg_kv_read_vf32( &kvs, root, "tint", (v4f){1.0,1.0,1.0,1.0}, props->cubemapped.tint, 4 ); + } + else if( mat->shader == k_shader_terrain_blend ) + { + vg_kv_read_vu32( &kvs, root, "tex_diffuse", (u32[]){0}, &props->terrain.tex_diffuse, 1 ); + vg_kv_read_vf32( &kvs, root, "sand_colour", (v4f){ 0.79, 0.63, 0.48, 1.0 }, props->terrain.sand_colour, 4 ); + vg_kv_read_vf32( &kvs, root, "blend_offset", (v2f){ 0.5, 0.0 }, props->terrain.blend_offset, 2 ); + } + else if( mat->shader == k_shader_water ) + { + vg_kv_read_vf32( &kvs, root, "shore_colour", (v4f){0.03,0.32,0.61,1.0}, props->water.shore_colour, 4 ); + vg_kv_read_vf32( &kvs, root, "deep_colour", (v4f){0.0,0.006,0.03,1.0}, props->water.deep_colour, 4 ); + vg_kv_read_vf32( &kvs, root, "fog_scale", (f32[]){0.04}, &props->water.fog_scale, 1 ); + vg_kv_read_vf32( &kvs, root, "fresnel", (f32[]){5.0}, &props->water.fresnel, 1 ); + vg_kv_read_vf32( &kvs, root, "water_scale", (f32[]){ 0.008 }, &props->water.water_sale, 1 ); + vg_kv_read_vf32( &kvs, root, "wave_speed", (v4f){0.008,0.006,0.003,0.03}, props->water.wave_speed, 4 ); + } + else if( mat->shader == k_shader_workshop ) + { + const c8 *_shader_prop_workshop_keys[] = + { + [k_workshop_shader_part_truck1 ] = "truck1", + [k_workshop_shader_part_truck2 ] = "truck2", + [k_workshop_shader_part_wheel1 ] = "wheel1", + [k_workshop_shader_part_wheel2 ] = "wheel2", + [k_workshop_shader_part_wheel3 ] = "wheel3", + [k_workshop_shader_part_wheel4 ] = "wheel4", + [k_workshop_shader_part_edge ] = "edge", + [k_workshop_shader_part_griptape] = "griptape", + [k_workshop_shader_part_deck ] = "deck" + }; + + for( u32 j=0; jworkshop.tex_all[j], 1 ); + } + } + } + _vg_end_temp_frame( temp_frame ); } -static bool mdl_legacy_v105_properties( struct mdl_material_v105 *mat, vg_msg *dst ) +VG_TIER_2 void vg_model_stream_metadata( vg_model_stream_context *ctx, vg_stack_allocator *stack ) { - vg_msg_wkvnum( dst, "tex_diffuse", k_vg_msg_u32, 1, &mat->tex_diffuse ); + array_file_ptr strings; + af_load_array( &ctx->af, &strings, "strings", stack, 1 ); + ctx->model->packed_strings = strings.data; + ctx->model->flags |= VG_MODEL_CPU_METADATA; - if( mat->shader == k_shader_cubemap ) - { - vg_msg_wkvnum( dst, "cubemap", k_vg_msg_u32, 1, &mat->tex_none0 ); - vg_msg_wkvnum( dst, "tint", k_vg_msg_f32, 4, mat->colour ); - } - else if( mat->shader == k_shader_terrain_blend ) - { - vg_msg_wkvnum( dst, "sand_colour", k_vg_msg_f32, 4, mat->colour ); - vg_msg_wkvnum( dst, "blend_offset", k_vg_msg_f32, 2, mat->colour1 ); - } - else if( mat->shader == k_shader_standard_vertex_blend ) - { - vg_msg_wkvnum( dst, "blend_offset", k_vg_msg_f32, 2, mat->colour1 ); - } - else if( mat->shader == k_shader_water ) - { - vg_msg_wkvnum( dst, "shore_colour", k_vg_msg_f32, 4, mat->colour ); - vg_msg_wkvnum( dst, "deep_colour", k_vg_msg_f32, 4, mat->colour1 ); - } + array_file_meta *pack = af_find_array( &ctx->af, "pack" ); + if( pack ) ctx->model->pack_base_offset = pack->file_offset; + else ctx->model->pack_base_offset = 0; - return 1; -} + struct array_file_ptr ptr; + AF_LOAD_ARRAY_STRUCT( &ctx->af, &ptr, mdl_mesh, stack ); + ctx->model->meshes = ptr.data; + ctx->model->mesh_count = ptr.count; -void mdl_load_materials( mdl_context *mdl, vg_stack_allocator *stack ) -{ - array_file_ptr mats_ptr; - AF_LOAD_ARRAY_STRUCT( &mdl->af, &mats_ptr, mdl_material, stack ); - mdl->materials = mats_ptr.data; - mdl->material_count = mats_ptr.count; - -#if (MDL_VERSION_MIN <= 105) - array_file_ptr legacy_materials; - if( mdl->version <= 105 ) - af_load_array( &mdl->af, &legacy_materials, "mdl_material", stack, sizeof(struct mdl_material_v105) ); -#endif + AF_LOAD_ARRAY_STRUCT( &ctx->af, &ptr, mdl_submesh, stack ); + ctx->model->submeshes = ptr.data; + ctx->model->submesh_count = ptr.count; - array_file_ptr data; - af_load_array( &mdl->af, &data, "shader_data", stack, 1 ); + AF_LOAD_ARRAY_STRUCT( &ctx->af, &ptr, mdl_texture, stack ); + ctx->model->textures = ptr.data; + ctx->model->texture_count = ptr.count; - for( u32 i=0; imaterial_count; i ++ ) - { - mdl_material *mat = &mdl->materials[ i ]; - vg_msg msg; + AF_LOAD_ARRAY_STRUCT( &ctx->af, &ptr, mdl_armature, stack ); + ctx->model->armatures = ptr.data; + ctx->model->armature_count = ptr.count; -#if (MDL_VERSION_MIN <= 105) - u8 legacy_buf[512]; - if( mdl->version <= 105 ) - { - vg_msg_init( &msg, legacy_buf, sizeof(legacy_buf) ); - mdl_legacy_v105_properties( af_arritm( &legacy_materials,i ), &msg ); - vg_msg_init( &msg, legacy_buf, msg.cur.co ); - } - else -#endif - { - vg_msg_init( &msg, data.data? (data.data + mat->props.kvs.offset): NULL, mat->props.kvs.size ); - } + AF_LOAD_ARRAY_STRUCT( &ctx->af, &ptr, mdl_bone, stack ); + ctx->model->bones = ptr.data; + ctx->model->bone_count = ptr.count; - if( mat->shader == k_shader_standard || - mat->shader == k_shader_standard_cutout || - mat->shader == k_shader_foliage || - mat->shader == k_shader_fxglow ) - { - mat->props.compiled = mdl_shader_standard( &msg, stack ); - } - else if( mat->shader == k_shader_standard_vertex_blend ) - { - mat->props.compiled = mdl_shader_vertex_blend( &msg, stack ); - } - else if( mat->shader == k_shader_cubemap ) - { - mat->props.compiled = mdl_shader_cubemapped( &msg, stack ); - } - else if( mat->shader == k_shader_terrain_blend ) - { - mat->props.compiled = mdl_shader_terrain( &msg, stack ); - } - else if( mat->shader == k_shader_water ) - { - mat->props.compiled = mdl_shader_water( &msg, stack ); - } - else if( mat->shader == k_shader_workshop ) - { - mat->props.compiled = mdl_shader_workshop( &msg, stack ); - } - else - mat->props.compiled = NULL; - } + vg_model_stream_materials( ctx, stack ); } -/* - * if calling mdl_open, and the file does not exist, the game will fatal quit - */ -void mdl_open( mdl_context *mdl, const char *path, vg_stack_allocator *stack ) +VG_TIER_2 void vg_model_stream_meshes_cpu( vg_model_stream_context *ctx, vg_stack_allocator *stack ) { - memset( mdl, 0, sizeof( mdl_context ) ); - af_open( &mdl->af, path, MDL_VERSION_MIN, MDL_VERSION_NR, stack ); - mdl->version = mdl->af.header.version; - - array_file_meta *pack = af_find_array( &mdl->af, "pack" ); - if( pack ) - mdl->pack_base_offset = pack->file_offset; - else - mdl->pack_base_offset = 0; -} + VG_ASSERT( ctx->model->flags & VG_MODEL_CPU_METADATA ); + ctx->model->flags |= VG_MODEL_CPU_MESHES; -/* - * close file handle - */ -void mdl_close( mdl_context *mdl ) -{ - af_close( &mdl->af ); -} - -/* useful things you can do with the model */ + struct array_file_ptr ptr; + AF_LOAD_ARRAY_STRUCT( &ctx->af, &ptr, mdl_vert, stack ); + ctx->model->verts = ptr.data; + ctx->model->vert_count = ptr.count; -void mdl_transform_m4x3( mdl_transform *transform, m4x3f mtx ) -{ - q_m3x3( transform->q, mtx ); - v3_muls( mtx[0], transform->s[0], mtx[0] ); - v3_muls( mtx[1], transform->s[1], mtx[1] ); - v3_muls( mtx[2], transform->s[2], mtx[2] ); - v3_copy( transform->co, mtx[3] ); + AF_LOAD_ARRAY_STRUCT( &ctx->af, &ptr, mdl_indice, stack ); + ctx->model->indices = ptr.data; + ctx->model->indice_count = ptr.count; } -/* - * Simple mesh interface for OpenGL - * ---------------------------------------------------------------------------- - */ +#if defined( VG_ENGINE ) +struct model_upload_task +{ + vg_model *model; + mdl_vert *vert_buffer; + u32 *indice_buffer; +}; -#ifdef VG_3D -static void mesh_upload( glmesh *mesh, mdl_vert *verts, u32 vert_count, u32 *indices, u32 indice_count ) +VG_TIER_0 static void vg_model_upload_task( struct model_upload_task *in_args ) { - glGenVertexArrays( 1, &mesh->vao ); - glGenBuffers( 1, &mesh->vbo ); - glGenBuffers( 1, &mesh->ebo ); - glBindVertexArray( mesh->vao ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); - size_t stride = sizeof(mdl_vert); + glGenVertexArrays( 1, &in_args->model->vao ); + glBindVertexArray( in_args->model->vao ); + glGenBuffers( 1, &in_args->model->vbo ); + glGenBuffers( 1, &in_args->model->ebo ); - glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo ); - glBufferData( GL_ARRAY_BUFFER, vert_count*stride, verts, GL_STATIC_DRAW ); + u32 stride = sizeof(mdl_vert); + glBindBuffer( GL_ARRAY_BUFFER, in_args->model->vbo ); + glBufferData( GL_ARRAY_BUFFER, in_args->model->vert_count*stride, in_args->vert_buffer, GL_STATIC_DRAW ); - glBindVertexArray( mesh->vao ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, indice_count*sizeof(u32), indices, GL_STATIC_DRAW ); + glBindVertexArray( in_args->model->vao ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, in_args->model->ebo ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, in_args->model->indice_count*sizeof(u32), + in_args->indice_buffer, GL_STATIC_DRAW ); /* 0: coordinates */ glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 ); @@ -324,119 +301,45 @@ static void mesh_upload( glmesh *mesh, mdl_vert *verts, u32 vert_count, u32 *ind /* 5: groups */ glVertexAttribIPointer( 5, 4, GL_UNSIGNED_BYTE, stride, (void *)offsetof(mdl_vert, groups) ); glEnableVertexAttribArray( 5 ); - - mesh->indice_count = indice_count; - mesh->loaded = 1; -} - -void mesh_bind( glmesh *mesh ) -{ - glBindVertexArray( mesh->vao ); -} - -void mesh_drawn( u32 start, u32 count ) -{ - glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT, (void *)(start*sizeof(u32)) ); -} - -void mesh_draw( glmesh *mesh ) -{ - mesh_drawn( 0, mesh->indice_count ); -} - -void mesh_free( glmesh *mesh ) -{ - if( mesh->loaded ) - { - glDeleteVertexArrays( 1, &mesh->vao ); - glDeleteBuffers( 1, &mesh->ebo ); - glDeleteBuffers( 1, &mesh->vbo ); - mesh->loaded = 0; - } -} - -void mdl_draw_submesh( mdl_submesh *sm ) -{ - mesh_drawn( sm->indice_start, sm->indice_count ); } #endif -i32 mdl_get_mesh_index( mdl_context *mdl, const char *name ) +#if defined( VG_ENGINE ) +VG_TIER_2 void vg_model_stream_meshes_gpu( vg_model_stream_context *ctx, u32 *fixup_table ) { - u32 hash = vg_strdjb2( name ); - for( u32 i=0; imesh_count; i++ ) - { - mdl_mesh *mesh = &mdl->meshes[ i ]; - if( af_str_eq( &mdl->af, mesh->pstr_name, name, hash ) ) - return i; - } - return -1; -} + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + VG_ASSERT( ctx->model->flags & VG_MODEL_CPU_METADATA ); + ctx->model->flags |= VG_MODEL_GPU_MESHES; -i32 mdl_get_submesh_index( mdl_context *mdl, const char *mesh_name ) -{ - i32 mesh_index = mdl_get_mesh_index( mdl, mesh_name ); - if( mesh_index == -1 ) - return -1; - - mdl_mesh *mesh = &mdl->meshes[ mesh_index ]; - if( !mesh->submesh_count ) - return -1; + /* NOTE: We could check here if we already have CPU meshes and use those buffers. + * In very rare instances (1 time) we use both paths. */ - return mesh->submesh_start; -} - -#ifdef VG_3D -struct payload_glmesh_load -{ - mdl_vert *verts; - u32 *indices; - - u32 vertex_count, - indice_count; - - glmesh *mesh; -}; - -static void _sync_mdl_load_glmesh( vg_async_task *task ) -{ - THREAD_0; - - struct payload_glmesh_load *job = (void *)task->data; - mesh_upload( job->mesh, job->verts, job->vertex_count, job->indices, job->indice_count ); -} - -void mdl_async_load_glmesh( mdl_context *mdl, glmesh *mesh, u32 *fixup_table ) -{ - THREAD_1; - - array_file_meta *arr_vertices = af_find_array( &mdl->af, "mdl_vert" ); - array_file_meta *arr_indices = af_find_array( &mdl->af, "mdl_indice" ); + array_file_meta *arr_vertices = af_find_array( &ctx->af, "mdl_vert" ); + array_file_meta *arr_indices = af_find_array( &ctx->af, "mdl_indice" ); if( arr_vertices && arr_indices ) { u32 size_verts = vg_align8(sizeof(mdl_vert)*arr_vertices->item_count), size_indices = vg_align8(sizeof(mdl_indice)*arr_indices->item_count), - size_hdr = vg_align8(sizeof(struct payload_glmesh_load)), + size_hdr = vg_align8(sizeof(struct model_upload_task)), total = size_hdr + size_verts + size_indices; - vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, total, 1 ); - struct payload_glmesh_load *job = (void *)task->data; + struct model_upload_task *out_args = _vg_async_alloc( VG_THREAD_MAIN_ID, total ); + + out_args->model = ctx->model; + out_args->vert_buffer = ((void*)out_args) + size_hdr; + out_args->indice_buffer = ((void*)out_args) + size_hdr + size_verts; + ctx->model->vert_count = arr_vertices->item_count; + ctx->model->indice_count = arr_indices->item_count; - job->mesh = mesh; - job->verts = (void*)(task->data + size_hdr); - job->indices = (void*)(task->data + size_hdr + size_verts); - job->vertex_count = arr_vertices->item_count; - job->indice_count = arr_indices->item_count; - af_load_array_file_buffer( &mdl->af, arr_vertices, job->verts, sizeof(mdl_vert) ); - af_load_array_file_buffer( &mdl->af, arr_indices, job->indices, sizeof(mdl_indice) ); + af_load_array_file_buffer( &ctx->af, arr_vertices, out_args->vert_buffer, sizeof(mdl_vert) ); + af_load_array_file_buffer( &ctx->af, arr_indices, out_args->indice_buffer, sizeof(mdl_indice) ); if( fixup_table ) { - for( u32 i=0; ivertex_count; i ++ ) + for( u32 i=0; imodel->vert_count; i ++ ) { - mdl_vert *vert = &job->verts[i]; - + mdl_vert *vert = &out_args->vert_buffer[i]; for( u32 j=0; j<4; j++ ) vert->groups[j] = fixup_table[vert->groups[j]]; } @@ -446,16 +349,15 @@ void mdl_async_load_glmesh( mdl_context *mdl, glmesh *mesh, u32 *fixup_table ) * Unpack the indices (if there are meshes) * --------------------------------------------------------- */ - - if( mdl->submesh_count ) + if( ctx->model->submesh_count ) { - mdl_submesh *sm = &mdl->submeshes[ 0 ]; + mdl_submesh *sm = &ctx->model->submeshes[ 0 ]; u32 offset = sm->vertex_count; - for( u32 i=1; isubmesh_count; i++ ) + for( u32 i=1; imodel->submesh_count; i++ ) { - mdl_submesh *sm = &mdl->submeshes[ i ]; - u32 *indices = job->indices + sm->indice_start; + mdl_submesh *sm = &ctx->model->submeshes[ i ]; + u32 *indices = out_args->indice_buffer + sm->indice_start; for( u32 j=0; jindice_count; j++ ) indices[j] += offset; @@ -464,44 +366,152 @@ void mdl_async_load_glmesh( mdl_context *mdl, glmesh *mesh, u32 *fixup_table ) } } - /* - * Dispatch - * ------------------------- - */ - - vg_async_task_dispatch( task, _sync_mdl_load_glmesh ); + _vg_async_send( out_args, (vg_async_fn)vg_model_upload_task ); } else vg_fatal_error( "No vertex/indice data in model file\n" ); } -/* uploads the glmesh, and textures. everything is saved into the mdl_context */ -void mdl_async_full_load_std( mdl_context *mdl, u32 *fixup_table ) +VG_TIER_2 void vg_model_stream_textures_gpu( vg_model_stream_context *ctx ) { - THREAD_1; - mdl_async_load_glmesh( mdl, &mdl->mesh, fixup_table ); - - for( u32 i=0; itexture_count; i ++ ) + VG_ASSERT( ctx->model->flags & VG_MODEL_CPU_METADATA ); + ctx->model->flags |= VG_MODEL_GPU_TEXTURES; + for( u32 i=0; imodel->texture_count; i ++ ) + { + mdl_texture *tex = &ctx->model->textures[ i ]; + mdl_file pack_info = tex->file; + _vg_tex_load_stream( &tex->tex, vg_model_stream_pack_stream( ctx, &pack_info ), + VG_TEX_REPEAT | VG_TEX_NEAREST | VG_TEX_NOMIP ); + } +} +#endif + +VG_TIER_1 bool vg_model_stream_open( vg_model_stream_context *ctx, vg_model *model, const c8 *path ) +{ + vg_zero_mem( ctx, sizeof(vg_model_stream_context) ); + vg_zero_mem( model, sizeof(vg_model) ); + if( vg_file_stream_open( &ctx->stream, path, VG_STREAM_READ ) ) { - vg_stack_clear( &vg.scratch ); - mdl_texture *tex = &mdl->textures[ i ]; + ctx->model = model; + ctx->temp_frame = _vg_start_temp_frame(); + if( !af_open_stream( &ctx->af, &ctx->stream, VG_MODEL_VERSION_MIN, VG_MODEL_VERSION_NR, _vg_temp_stack() ) ) + { + vg_file_stream_close( &ctx->stream ); + _vg_end_temp_frame( ctx->temp_frame ); + return 0; + } + ctx->model->version = ctx->af.header.version; + return 1; + } + else return 0; +} + +VG_TIER_0 void vg_model_stream_close( vg_model_stream_context *ctx ) +{ + vg_file_stream_close( &ctx->stream ); + _vg_end_temp_frame( ctx->temp_frame ); +} + +VG_TIER_2 bool vg_model_load( vg_model *model, u32 model_flags, const c8 *path, vg_stack_allocator *stack ) +{ + bool success = 0; + model_flags |= VG_MODEL_CPU_METADATA; + + vg_model_stream_context ctx; + if( vg_model_stream_open( &ctx, model, path ) ) + { + if( model_flags & VG_MODEL_CPU_METADATA ) + vg_model_stream_metadata( &ctx, stack ); + + if( model_flags & VG_MODEL_CPU_MESHES ) + vg_model_stream_meshes_cpu( &ctx, stack ); + +#if defined( VG_ENGINE ) + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + if( model_flags & VG_MODEL_GPU_MESHES ) + vg_model_stream_meshes_gpu( &ctx, NULL ); + + if( model_flags & VG_MODEL_GPU_TEXTURES ) + vg_model_stream_textures_gpu( &ctx ); +#endif - void *data = vg_stack_allocate( &vg.scratch, tex->file.pack_size, 8, "MDL Pack Data" ); - mdl_fread_pack_file( mdl, &tex->file, data ); - vg_tex2d_load_qoi_async( data, tex->file.pack_size, VG_TEX2D_CLAMP|VG_TEX2D_NEAREST, &tex->glname ); + vg_model_stream_close( &ctx ); + success = 1; } + return success; } -void mdl_sync_std_unload( mdl_context *mdl ) +#if defined( VG_ENGINE ) +VG_TIER_0 void vg_model_unload_gpu( vg_model *model ) { - mesh_free( &mdl->mesh ); + if( model->flags & VG_MODEL_GPU_MESHES ) + { + model->flags &= ~(u32)(VG_MODEL_GPU_MESHES); + glDeleteVertexArrays( 1, &model->vao ); + glDeleteBuffers( 1, &model->ebo ); + glDeleteBuffers( 1, &model->vbo ); + } + + if( model->flags & VG_MODEL_GPU_TEXTURES ) + for( u32 i=0; itexture_count; i ++ ) + vg_tex_delete( &model->textures[i].tex ); +} +#endif - for( u32 i=0; itexture_count; i ++ ) - glDeleteTextures( 1, &mdl->textures[i].glname ); +VG_TIER_0 void mdl_transform_m4x3( mdl_transform *transform, m4x3f mtx ) +{ + q_m3x3( transform->q, mtx ); + v3_muls( mtx[0], transform->s[0], mtx[0] ); + v3_muls( mtx[1], transform->s[1], mtx[1] ); + v3_muls( mtx[2], transform->s[2], mtx[2] ); + v3_copy( transform->co, mtx[3] ); +} + +#if defined( VG_ENGINE ) + +VG_TIER_0 void vg_model_bind_mesh( vg_model *model ) +{ + glBindVertexArray( model->vao ); +} + +VG_TIER_0 void vg_model_draw_elements( u32 start, u32 count ) +{ + glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT, (void *)(start*sizeof(u32)) ); +} + +VG_TIER_0 void vg_model_draw_submesh( mdl_submesh *sm ) +{ + vg_model_draw_elements( sm->indice_start, sm->indice_count ); } #endif +VG_TIER_0 i32 vg_model_get_mesh_index( vg_model *model, const c8 *name ) +{ + u32 hash = vg_strdjb2( name ); + for( u32 i=0; imesh_count; i++ ) + { + mdl_mesh *mesh = &model->meshes[ i ]; + if( af_str_eq( model->packed_strings, mesh->pstr_name, name, hash ) ) + return i; + } + return -1; +} + +VG_TIER_0 i32 vg_model_get_submesh_index( vg_model *model, const c8 *mesh_name ) +{ + i32 mesh_index = vg_model_get_mesh_index( model, mesh_name ); + if( mesh_index == -1 ) + return -1; + + mdl_mesh *mesh = &model->meshes[ mesh_index ]; + if( !mesh->submesh_count ) + return -1; + + return mesh->submesh_start; +} + +#if defined( VG_ENGINE ) void mdl_compiler_init( mdl_compiler *compiler ) { vg_stack_init( &compiler->stack, NULL, VG_MB(10), "MDL Compiler" ); @@ -612,23 +622,28 @@ u32 mdl_compiler_compile_texture_qoi( mdl_compiler *compiler, const char *name, u32 texture_id = compiler->textures->element_count + 1; mdl_texture *texture = af_compiler_allocate_items( &compiler->af, compiler->textures, 1 )->data; - texture->glname = 0; mdl_compiler_pack_data( compiler, name, data, data_len, &texture->file ); return texture_id; } -void mdl_compiler_push_shaderdata( mdl_compiler *compiler, u32 shader_id, vg_msg *shader_kvs ) +void mdl_compiler_push_shaderdata( mdl_compiler *compiler, u32 shader_id, vg_kvs *shader_kvs ) { mdl_material *current_material = compiler->materials->last->data; current_material->shader = shader_id; current_material->props.kvs.offset = compiler->shader_data->element_count; + + // FIXME FIXME FIXME FIXME FIXME NEED TO FLATTEN OUT THE KVS INTO STRINGYMABOB!!!!!!!!!!!!!!!! +#if 0 current_material->props.kvs.size = shader_kvs->cur.co; void *dest = af_compiler_allocate_items( &compiler->af, compiler->shader_data, vg_align8(shader_kvs->cur.co) )->data; memcpy( dest, shader_kvs->buf, shader_kvs->cur.co ); +#endif } void mdl_compiler_free( mdl_compiler *compiler ) { vg_stack_free( &compiler->stack ); } + +#endif diff --git a/src/model.h b/src/model.h index f70740d..81d8292 100644 --- a/src/model.h +++ b/src/model.h @@ -1,13 +1,106 @@ -/* - * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ +#if defined( SR_IMPLEMENTATION ) +# include "src/model.c" +#else -#pragma once +#define VG_MODEL_VERSION_MIN 101 +#define VG_MODEL_VERSION_NR 109 + +#define VG_MODEL_CPU_METADATA 0x4 +#define VG_MODEL_CPU_MESHES 0x8 + +#if defined( VG_ENGINE ) +# define VG_MODEL_GPU_TEXTURES 0x1 +# define VG_MODEL_GPU_MESHES 0x2 +# define VG_MODEL_ENGINE_STANDARD (VG_MODEL_CPU_METADATA|VG_MODEL_GPU_TEXTURES|VG_MODEL_GPU_MESHES) +# define VG_MODEL_ENGINE_PROCEDURAL_SOURCE (VG_MODEL_CPU_METADATA|VG_MODEL_GPU_TEXTURES|VG_MODEL_CPU_MESHES) +#endif + +typedef u32 mdl_indice; +typedef struct mdl_vert mdl_vert; +typedef struct mdl_transform mdl_transform; +typedef struct mdl_submesh mdl_submesh; +typedef struct mdl_material mdl_material; +typedef struct mdl_bone mdl_bone; +typedef struct mdl_armature mdl_armature; +typedef struct mdl_animation mdl_animation; +typedef struct mdl_mesh mdl_mesh; +typedef struct mdl_file mdl_file; +typedef union mdl_texture mdl_texture; +typedef struct mdl_header mdl_header; + +typedef struct vg_model vg_model; +typedef struct vg_model_stream_context vg_model_stream_context; + + +/* Load model the easy way */ +VG_TIER_2 bool vg_model_load( vg_model *model, u32 model_flags, const c8 *path, vg_stack_allocator *stack ); + +#if defined( VG_ENGINE ) +VG_TIER_0 void vg_model_unload_gpu( vg_model *model ); +#endif + +/* Sub functions for each part of the load process + * --------------------------------------------------------------------------------------------------------------- */ +struct vg_model_stream_context +{ + vg_stream stream; + array_file_context af; + vg_model *model; + + u32 temp_frame; +}; + +VG_TIER_1 bool vg_model_stream_open( vg_model_stream_context *ctx, vg_model *model, const c8 *path ); +VG_TIER_0 void vg_model_stream_close( vg_model_stream_context *ctx ); + +/* Parts which you might want (currently they all require metadata to be explicitly loaded) */ +VG_TIER_2 void vg_model_stream_metadata( vg_model_stream_context *ctx, vg_stack_allocator *stack ); +VG_TIER_2 void vg_model_stream_meshes_cpu( vg_model_stream_context *ctx, vg_stack_allocator *stack ); + +#if defined( VG_ENGINE ) +VG_TIER_2 void vg_model_stream_meshes_gpu( vg_model_stream_context *ctx, u32 *fixup_table ); +VG_TIER_2 void vg_model_stream_textures_gpu( vg_model_stream_context *ctx ); +#endif + +VG_TIER_0 vg_stream *vg_model_stream_pack_stream( vg_model_stream_context *ctx, mdl_file *file ); -#define MDL_VERSION_MIN 101 -#define MDL_VERSION_NR 109 -#include "array_file.h" + +/* Rendering operations + * ----------------------------------------------------------------------------------------------------------------- */ +#if defined( VG_ENGINE ) +VG_TIER_0 void vg_model_bind_mesh( vg_model *model ); +VG_TIER_0 void vg_model_draw_elements( u32 start, u32 count ); +VG_TIER_0 void vg_model_draw_submesh( mdl_submesh *sm ); +#endif + +VG_TIER_0 i32 vg_model_get_mesh_index( vg_model *model, const c8 *name ); +VG_TIER_0 i32 vg_model_get_submesh_index( vg_model *model, const c8 *mesh_name ); + +VG_TIER_0 void mdl_transform_m4x3( mdl_transform *transform, m4x3f mtx ); + + + +/* model compiler + * ----------------------------------------------------------------------------------------------------------------- */ +#if defined( VG_ENGINE ) +typedef struct mdl_compiler mdl_compiler; +struct mdl_compiler +{ + af_compiler af; + af_compiler_index *meshes, + *submeshes, + *vertices, + *indices, + *bones, + *materials, + *shader_data, + *armatures, + *textures, + *pack_data; + vg_stack_allocator stack; +}; +#endif enum mdl_shader{ k_shader_standard = 0, @@ -67,56 +160,32 @@ struct mdl_vert #pragma pack(pop) -typedef u32 mdl_indice; - -typedef struct mdl_context mdl_context; -typedef struct mdl_vert mdl_vert; -typedef struct mdl_transform mdl_transform; -typedef struct mdl_submesh mdl_submesh; -typedef struct mdl_material mdl_material; -typedef struct mdl_bone mdl_bone; -typedef struct mdl_armature mdl_armature; -typedef struct mdl_animation mdl_animation; -typedef struct mdl_mesh mdl_mesh; -typedef struct mdl_file mdl_file; -typedef struct mdl_texture mdl_texture; -typedef struct mdl_header mdl_header; - -typedef struct glmesh glmesh; -struct glmesh -{ - u32 vao, vbo, ebo; - u32 indice_count; - u32 loaded; -}; - struct mdl_transform { v3f co, s; v4f q; }; -static void transform_identity( mdl_transform *transform ) +VG_TIER_0 static inline void transform_identity( mdl_transform *transform ) { v3_zero( transform->co ); q_identity( transform->q ); v3_fill( transform->s, 1.0f ); } -static void mdl_transform_vector( mdl_transform *transform, v3f vec, v3f dest ) +VG_TIER_0 static inline void mdl_transform_vector( mdl_transform *transform, v3f vec, v3f dest ) { v3_mul( transform->s, vec, dest ); q_mulv( transform->q, dest, dest ); } -static void mdl_transform_point( mdl_transform *transform, v3f co, v3f dest ) +VG_TIER_0 static inline void mdl_transform_point( mdl_transform *transform, v3f co, v3f dest ) { mdl_transform_vector( transform, co, dest ); v3_add( transform->co, dest, dest ); } -static void mdl_transform_mul( mdl_transform *a, mdl_transform *b, - mdl_transform *d ) +VG_TIER_0 static inline void mdl_transform_mul( mdl_transform *a, mdl_transform *b, mdl_transform *d ) { mdl_transform_point( a, b->co, d->co ); q_mul( a->q, b->q, d->q ); @@ -124,15 +193,8 @@ static void mdl_transform_mul( mdl_transform *a, mdl_transform *b, v3_mul( a->s, b->s, d->s ); } -struct mdl_file -{ - u32 pstr_path, - pack_offset, - pack_size; -}; - -#if (MDL_VERSION_MIN <= 105) -struct mdl_material_v105 +#if (VG_MODEL_VERSION_MIN <= 105) +struct mdl_material_v101 { u32 pstr_name, shader, @@ -163,7 +225,7 @@ struct mdl_material /* -> vg_msg containing KV properties */ } kvs; - void *compiled; /* -> shader specific structure for render */ + u32 kv_root; } props; }; @@ -208,14 +270,6 @@ struct mdl_armature pstr_name; // v107+ }; -// struct mdl_animation -// { -// u32 pstr_name, -// length; -// float rate; -// u32 offset; -// }; - struct mdl_submesh { u32 indice_start, @@ -243,16 +297,27 @@ struct mdl_mesh armature_id; }; -struct mdl_texture +struct mdl_file +{ + u32 pstr_path, + pack_offset, + pack_size; +}; + +union mdl_texture { mdl_file file; - u32 glname; + vg_tex tex; }; -struct mdl_context +struct vg_model { - array_file_context af; u32 version; + u32 flags; + + /* VG_MODEL_CPU_METADATA ---------------------- */ + const void *packed_strings; + union shader_props *shader_props; mdl_mesh *meshes; u32 mesh_count; @@ -272,66 +337,18 @@ struct mdl_context mdl_bone *bones; u32 bone_count; + /* VG_MODEL_CPU_MESHES ---------------------- */ mdl_vert *verts; u32 vert_count; - u32 *indices; u32 indice_count; u32 pack_base_offset; - /* runtime */ - glmesh mesh; + /* VG_MODEL_GPU_MESHES ----------------------- */ +#if defined( VG_ENGINE ) + GLuint vao, vbo, ebo; +#endif }; -void mesh_bind( glmesh *mesh ); -void mesh_drawn( u32 start, u32 count ); -void mesh_draw( glmesh *mesh ); -void mesh_free( glmesh *mesh ); - -/* file context management */ -void mdl_open( mdl_context *mdl, const char *path, vg_stack_allocator *stack ); -void mdl_close( mdl_context *mdl ); - -/* pack access */ -void mdl_fread_pack_file( mdl_context *mdl, mdl_file *info, void *dst ); - -/* standard array groups */ -void mdl_load_metadata_block( mdl_context *mdl, vg_stack_allocator *stack ); -void mdl_load_mesh_block( mdl_context *mdl, vg_stack_allocator *stack ); -void mdl_load_materials( mdl_context *mdl, vg_stack_allocator *stack ); - -/* load mesh */ -void mdl_async_load_glmesh( mdl_context *mdl, glmesh *mesh, u32 *fixup_table ); - -/* load textures and mesh */ -void mdl_async_full_load_std( mdl_context *mdl, u32 *fixup_table ); -void mdl_sync_std_unload( mdl_context *mdl ); - -/* rendering */ -void mdl_draw_submesh( mdl_submesh *sm ); -i32 mdl_get_mesh_index( mdl_context *mdl, const char *name ); -i32 mdl_get_submesh_index( mdl_context *mdl, const char *mesh_name ); - -void mdl_transform_m4x3( mdl_transform *transform, m4x3f mtx ); - -/* model compiler - * --------------------------------- */ - -typedef struct mdl_compiler mdl_compiler; -struct mdl_compiler -{ - af_compiler af; - af_compiler_index *meshes, - *submeshes, - *vertices, - *indices, - *bones, - *materials, - *shader_data, - *armatures, - *textures, - *pack_data; - - vg_stack_allocator stack; -}; +#endif diff --git a/src/network.c b/src/network.c index 830413e..7675a3a 100644 --- a/src/network.c +++ b/src/network.c @@ -1,28 +1,3 @@ -#include "skaterift.h" -#include "vg/vg_steam2.h" -#include "player.h" -#include "network.h" -#include "network_msg.h" -#include "network_common.h" -#include "player_remote.h" -#include "world.h" -#include "world_sfd.h" -#include "world_routes.h" -#include "vg/vg_ui/imgui.h" -#include "gui.h" -#include "ent_region.h" -#include "vg/vg_loader.h" -#include "network_requests.h" - -#ifdef _WIN32 - #include - #include -#else - #include - #include - #include -#endif - struct network_client network_client = { .auth_mode = eServerModeAuthentication, @@ -159,7 +134,7 @@ static void network_disconnect(void) void network_status_string( vg_str *str, u32 *colour ) { - if( g_client.demo_mode ) + if( _is_running_demo() ) { vg_strcat( str, "Unavailible in demo" ); *colour = 0xff0000a0; @@ -180,18 +155,24 @@ void network_status_string( vg_str *str, u32 *colour ) vg_strcat( str, "No Connection" ); else if( state == k_ESteamNetworkingConnectionState_Connecting ) { - vg_strcatf( str, "Connecting... %s", network_client.host_adress ); + if( network_client.resolve_state == k_resolve_state_resolving ) + vg_strcatf( str, "Connecting... " ); + else + vg_strcatf( str, "Connecting... %s", network_client.adress ); if( network_client.retries ) { vg_strcat( str, "\n(" ); - vg_strcati32( str, network_client.retries ); + vg_strcati64( str, network_client.retries, 10 ); vg_strcat( str, " retries)" ); } } else if( state == k_ESteamNetworkingConnectionState_Connected ) { - vg_strcatf( str, "Connected to:\n%s", network_client.host_adress ); + if( network_client.resolve_state == k_resolve_state_resolving ) // Should this ever happen? No I dont think so + vg_strcatf( str, "Connected to: " ); + else + vg_strcatf( str, "Connected to: %s", network_client.adress ); *colour = 0xff00a020; } else if( state == k_ESteamNetworkingConnectionState_ClosedByPeer ) @@ -239,8 +220,7 @@ void render_server_status_gui(void) ui_fill( ctx, r, bg ); ui_text( ctx, r, buf, 1, k_ui_align_center, 0 ); ui_flush( ctx, k_ui_shader_colour, NULL ); - - skaterift.rt_textures[ k_skaterift_rt_server_status ] = g_render.fb_network_status->attachments[0].id; + skaterift.rt_textures[ k_skaterift_rt_server_status ] = &g_render.fb_network_status->attachments[0].tex; } void cb_skaterift_connection_changed( SteamNetConnectionStatusChangedCallback_t *info ) @@ -300,8 +280,6 @@ void cb_skaterift_persona_changed( PersonaStateChange_t *info ) if( !network_connected() ) return; - vg_info( "User: " PRINTF_U64 ", change: %u\n", info->m_ulSteamID, info->m_nChangeFlags ); - if( info->m_ulSteamID == SteamAPI_ISteamUser_GetSteamID( _steam_api.pSteamUser ) ) if( info->m_nChangeFlags & k_EPersonaChangeName ) network_send_username(); @@ -317,25 +295,27 @@ void cb_skaterift_persona_changed( PersonaStateChange_t *info ) } } -void network_set_host( const char *host_str, const char *port_str ) +void network_set_host( const c8 *host_str, const c8 *port_str ) { - vg_strncpy( host_str, network_client.host_adress, sizeof(network_client.host_adress), k_strncpy_overflow_fatal ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + VG_ASSERT( network_client.resolve_state != k_resolve_state_resolving ); + vg_strncpy( host_str, network_client.adress, sizeof(network_client.adress), k_strncpy_overflow_fatal ); memset( &network_client.ip, 0, sizeof(network_client.ip) ); network_client.resolve_state = k_resolve_state_no; if( port_str ) { - vg_strncpy( port_str, network_client.host_port, sizeof(network_client.host_port), k_strncpy_overflow_fatal ); + vg_strncpy( port_str, network_client.port, sizeof(network_client.port), k_strncpy_overflow_fatal ); } else { vg_str str; - vg_strnull( &str, network_client.host_port, sizeof(network_client.host_port) ); - vg_strcati32( &str, NETWORK_PORT ); + vg_strnull( &str, network_client.port, sizeof(network_client.port) ); + vg_strcati64( &str, NETWORK_PORT, 10 ); } - network_client.ip.m_port = atoi( network_client.host_port ); + network_client.ip.m_port = atoi( network_client.port ); } static void network_connect(void) @@ -416,143 +396,100 @@ static void poll_remote_connection(void){ } } -struct resolve_info +static void _network_resolve_numeric(void) { - enum resolve_opt - { - k_resolve_opt_resolve, - k_resolve_opt_parse_numeric, - k_resolve_opt_ipv6, - k_resolve_opt_fail - } - opt; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + SteamAPI_SteamNetworkingIPAddr_ParseString( &network_client.ip, network_client.adress ); + network_client.ip.m_port = atoi( network_client.port ); + network_client.resolve_state = k_resolve_state_resolved; +} - union - { - struct - { - char port[8], adress[256]; - } - host; - struct addrinfo *ipv6; - } - alias; +struct network_resolved_info +{ + bool ok; + bool needs_numeric_conversion; }; -static void _network_resolve_host( vg_async_task *co_task ) +static void _network_resolve_complete( struct network_resolved_info *in_args, vg_async_info *async ) { - if( co_task ) + if( in_args->ok ) { - struct resolve_info *co_info = (void *)co_task->data; - if( co_info->opt == k_resolve_opt_resolve ) - { - THREAD_1; + if( in_args->needs_numeric_conversion ) + _network_resolve_numeric(); + network_client.resolve_state = k_resolve_state_resolved; + } + else + network_client.resolve_state = k_resolve_state_no; +} - vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct resolve_info), 1 ); - struct resolve_info *info = (void *)task->data; - vg_info( "Resolving host.. %s (:%s)\n", co_info->alias.host.adress, co_info->alias.host.port ); +static void _network_resolve_host_async( void *_, vg_async_info *async ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); - /* Obtain address(es) matching host/port. */ + /* Obtain address(es) matching host/port. */ + struct addrinfo hints; + memset( &hints, 0, sizeof(hints) ); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; + hints.ai_protocol = 0; - struct addrinfo hints; - memset( &hints, 0, sizeof(hints) ); - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; - hints.ai_protocol = 0; + bool ok = 0, needs_numeric_conversion = 0; - int s = getaddrinfo( co_info->alias.host.adress, co_info->alias.host.port, &hints, &info->alias.ipv6 ); - if( s != 0 ) - { + struct addrinfo *ipv6; + int s = getaddrinfo( network_client.adress, network_client.port, &hints, &ipv6 ); + if( s != 0 ) + { #ifndef _WIN32 - vg_error( "getaddrinfo: %s\n", gai_strerror(s) ); + vg_error( "getaddrinfo: %s\n", gai_strerror(s) ); #endif - if( !strcmp( co_info->alias.host.adress, "skaterift.com" ) ) - { - vg_warn( "getaddrinfo failed for skaterift.com;\n " - "falling back to a hardcoded IPv4. This might be wrong.\n" ); - - strcpy( info->alias.host.adress, "46.101.34.155" ); - strcpy( info->alias.host.port, "27408" ); - info->opt = k_resolve_opt_parse_numeric; - vg_async_task_dispatch( task, _network_resolve_host ); - return; - } - else - { - info->opt = k_resolve_opt_fail; - vg_async_task_dispatch( task, _network_resolve_host ); - return; - } - } - else - { - info->opt = k_resolve_opt_ipv6; - vg_async_task_dispatch( task, _network_resolve_host ); - return; - } - } - else + if( !strcmp( network_client.adress, "skaterift.com" ) ) { - THREAD_0; + vg_warn( "getaddrinfo failed for skaterift.com;\n " + "falling back to a hardcoded IPv4. This might be wrong.\n" ); - if( co_info->opt == k_resolve_opt_fail ) - { - network_client.resolve_state = k_resolve_state_no; - return; - } - else if( co_info->opt == k_resolve_opt_ipv6 ) - { - struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)co_info->alias.ipv6->ai_addr; - memcpy( network_client.ip.m_ipv6, &inaddr->sin6_addr, 16 ); - freeaddrinfo( co_info->alias.ipv6 ); - network_client.resolve_state = k_resolve_state_resolved; - return; - } - else if( co_info->opt == k_resolve_opt_parse_numeric ) - { - strcpy( network_client.host_adress, co_info->alias.host.adress ); - strcpy( network_client.host_port, co_info->alias.host.port ); - goto parse_numeric; - } + strcpy( network_client.adress, "46.101.34.155" ); + strcpy( network_client.port, "27408" ); + ok = 1; + needs_numeric_conversion = 1; } } else { - THREAD_0; - if( (network_client.host_adress[0] >= '0') && (network_client.host_adress[0] <= '9') ) - goto parse_numeric; - else - { - network_client.resolve_state = k_resolve_state_resolving; - vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct resolve_info), 1 ); - struct resolve_info *info = (void *)task->data; - info->opt = k_resolve_opt_resolve; - strcpy( info->alias.host.port, network_client.host_port ); - strcpy( info->alias.host.adress, network_client.host_adress ); - vg_async_task_dispatch( task, _network_resolve_host ); - return; - } + struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)ipv6->ai_addr; + memcpy( network_client.ip.m_ipv6, &inaddr->sin6_addr, 16 ); + freeaddrinfo( ipv6 ); + ok = 1; } - VG_ASSERT(0); -parse_numeric: + struct network_resolved_info *out_args = _vg_async_alloc( VG_THREAD_MAIN_ID, sizeof(struct network_resolved_info) ); + out_args->ok = ok; + out_args->needs_numeric_conversion = needs_numeric_conversion; + _vg_async_send( out_args, (vg_async_fn)_network_resolve_complete ); +} - THREAD_0; - SteamAPI_SteamNetworkingIPAddr_ParseString( &network_client.ip, network_client.host_adress ); - network_client.ip.m_port = atoi( network_client.host_port ); - network_client.resolve_state = k_resolve_state_resolved; +static void _network_resolve_host(void) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + VG_ASSERT( network_client.resolve_state == k_resolve_state_no ); + + if( (network_client.adress[0] >= '0') && (network_client.adress[0] <= '9') ) + _network_resolve_numeric(); + else + { + network_client.resolve_state = k_resolve_state_resolving; + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_network_resolve_host_async ); + } } -void network_update(void) +VG_API void _network_update(void) { if( _steam_api.disabled ) return; - if( g_client.demo_mode ) + if( _is_running_demo() ) return; ESteamNetworkingConnectionState state = network_client.state; - if( network_client.user_intent == k_server_intent_offline ) { if( state != k_ESteamNetworkingConnectionState_None ) @@ -598,7 +535,7 @@ void network_update(void) return; if( network_client.resolve_state == k_resolve_state_no ) - _network_resolve_host(NULL); + _network_resolve_host(); else if( network_client.resolve_state == k_resolve_state_resolved ) network_connect(); @@ -641,20 +578,14 @@ static int cmd_network_send_rcon( int argc, const char *argv[] ) return 0; } -void network_register(void) +VG_API void _network_register(void) { vg_console_reg_var( "auto_connect", &network_client.auto_connect, k_var_dtype_i32, VG_VAR_PERSISTENT ); vg_console_reg_cmd( "rcon", cmd_network_send_rcon, NULL ); } -void network_init(void) +static void _network_end(void) { - _net_requests_init(); -} - -void network_end(void) -{ - /* TODO: Send buffered highscores that were not already */ if( (network_client.state == k_ESteamNetworkingConnectionState_Connected) || (network_client.state == k_ESteamNetworkingConnectionState_Connecting) ) { @@ -663,4 +594,9 @@ void network_end(void) } } -#include "network_requests.c" +VG_API void _network_init(void) +{ + _vg_add_exit_function( _network_end ); + _net_requests_init(); + render_server_status_gui(); +} diff --git a/src/network.h b/src/network.h index 00d54f8..3668621 100644 --- a/src/network.h +++ b/src/network.h @@ -1,16 +1,6 @@ -/* - * Copyright (C) 2021-2025 Mt.ZERO Software, Harry Godden - All Rights Reserved - * All trademarks are property of their respective owners - */ - -#pragma once -#include "vg/vg_platform.h" -#include "vg/vg_steam2.h" -#include "vg/vg_mem_pool.h" -#include "vg/vg_msg.h" -#include "network_common.h" -#include "network_msg.h" -#include "addon_types.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/network.c" +#else /* * Interface @@ -21,15 +11,9 @@ void on_server_connect_status( CallbackMsg_t *msg ); void on_persona_state_change( CallbackMsg_t *msg ); void request_auth_ticket(void); -/* Call it at start; Connects us to the gameserver */ -void network_register(void); -void network_init(void); - -/* Run this from main loop */ -void network_update(void); - -/* Call it at shutdown */ -void network_end(void); +VG_API void _network_register(void); +VG_API void _network_init(void); +VG_API void _network_update(void); /* * Can buffer up a bunch of these by calling many times, they will be @@ -56,7 +40,7 @@ struct network_client i32 auto_connect; SteamNetworkingIPAddr ip; - char host_port[8], host_adress[256]; + c8 port[8], adress[256]; enum resolve_state { @@ -94,3 +78,5 @@ static inline int network_connected(void) void cb_skaterift_connection_changed( SteamNetConnectionStatusChangedCallback_t *info ); void cb_skaterift_persona_changed( PersonaStateChange_t *info ); + +#endif diff --git a/src/network_common.h b/src/network_common.h index 67c3e99..4e2b921 100644 --- a/src/network_common.h +++ b/src/network_common.h @@ -1,6 +1,6 @@ -#pragma once -#include "vg/vg_platform.h" -#include "vg/vg_string.h" +#if defined( SR_IMPLEMENTATION ) +//# include "src/network_common.c" +#else #define NETWORK_USERNAME_MAX 32 #define NETWORK_MAX_PLAYERS 20 @@ -17,8 +17,6 @@ #define NETWORK_PORT 27408 #define NETWORK_PORT_STR(STR, X) STR #X -#include "addon_types.h" - static u32 network_msgstring( const char *src, u32 m_cbSize, u32 base_size, char *buf, u32 buf_size ) { u32 string_len = VG_MIN( m_cbSize - base_size, buf_size ); @@ -37,3 +35,5 @@ static u32 network_pair_index( u32 _a, u32 _b ) return ((N-a)*((N-a)-1))/2 - b + a; } + +#endif diff --git a/src/network_compression.h b/src/network_compression.h index 8af4eac..c5c1465 100644 --- a/src/network_compression.h +++ b/src/network_compression.h @@ -1,8 +1,6 @@ -#ifndef NETWORK_COMPRESSION_H -#define NETWORK_COMPRESSION_H - -#include "vg/vg_platform.h" -#include "vg/vg_m.h" +#if defined( SR_IMPLEMENTATION ) +//# include "src/network_compression.c" +#else typedef struct bitpack_ctx bitpack_ctx; struct bitpack_ctx { @@ -116,4 +114,4 @@ static void bitpack_qquat( bitpack_ctx *ctx, v4f quat ) } } -#endif /* NETWORK_COMPRESSION_H */ +#endif diff --git a/src/network_msg.h b/src/network_msg.h index d9cb3e3..e3267d8 100644 --- a/src/network_msg.h +++ b/src/network_msg.h @@ -1,13 +1,6 @@ -/* - * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#ifndef NETWORK_MSG_H -#define NETWORK_MSG_H - -#include "world_info.h" -#include "vg/vg_platform.h" -; +#if defined( SR_IMPLEMENTATION ) +//# include "src/network_msg.c" +#else #pragma pack(push,1) diff --git a/src/network_requests.c b/src/network_requests.c index db32796..772f02f 100644 --- a/src/network_requests.c +++ b/src/network_requests.c @@ -1,5 +1,3 @@ -#include "network_requests.h" - struct _net_requests _net_requests; const char *request_status_string( enum request_status status ) @@ -62,22 +60,13 @@ static void log_request_status( u16 request_id, const char *comment ) vg_low( "req[%s%s##%hu" KWHT "] State: %s\n", colour, associated_username, request_id, request_state_str ); } -void network_send_request( netmsg_request *packet, vg_msg *body, +void network_send_request( const c8 *body, u32 body_length, void (*callback)( void *data, u32 data_size, u64 userdata, enum request_status status ), u64 userdata ) { - u32 len = 0; - if( body ) - { - len = body->cur.co; - vg_msg_print( body, len ); - - if( body->error != k_vg_msg_error_OK ) - { - vg_error( "Body not OK\n" ); - return; - } - } + VG_ASSERT( body_length <= 512 ); + netmsg_request *packet = alloca( sizeof(netmsg_request) + 512 ); + packet->inetmsg_id = k_inetmsg_request; if( callback ) { @@ -108,12 +97,14 @@ void network_send_request( netmsg_request *packet, vg_msg *body, packet->uid = 0; SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( _steam_api.pSteamNetworkingSockets, network_client.remote, - packet, sizeof(netmsg_request)+len, + packet, sizeof(netmsg_request) + body_length, k_nSteamNetworkingSend_Reliable, NULL ); } static void network_scoreboard_callback( void *data, u32 data_size, u64 userdata, enum request_status status ) { + // FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME//// +#if 0 if( status == k_request_status_ok ) { vg_msg msg; @@ -126,6 +117,7 @@ static void network_scoreboard_callback( void *data, u32 data_size, u64 userdata } else world_routes_recv_scoreboard( &_world.main, NULL, userdata, status ); +#endif } /* mod_uid: world mod uid, @@ -142,6 +134,8 @@ void network_request_scoreboard( const char *mod_uid, const char *route_uid, u32 if( !network_connected() ) return; + // FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME//// +#if 0 netmsg_request *packet = alloca( sizeof(netmsg_request) + 512 ); packet->inetmsg_id = k_inetmsg_request; @@ -152,6 +146,8 @@ void network_request_scoreboard( const char *mod_uid, const char *route_uid, u32 vg_msg_wkvstr( &data, "route", route_uid ); vg_msg_wkvnum( &data, "week", k_vg_msg_u32, 1, &week ); network_send_request( packet, &data, network_scoreboard_callback, userdata ); +#endif + // FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME//// } void network_publish_laptime( const char *mod_uid, const char *route_uid, f64 lap_time ) @@ -164,6 +160,8 @@ void network_publish_laptime( const char *mod_uid, const char *route_uid, f64 la i32 time_centiseconds = lap_time * 100.0; + // FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME//// +#if 0 netmsg_request *packet = alloca( sizeof(netmsg_request) + 512 ); packet->inetmsg_id = k_inetmsg_request; @@ -177,6 +175,8 @@ void network_publish_laptime( const char *mod_uid, const char *route_uid, f64 la f64 time_real = vg.time_real; vg_msg_wkvnum( &data, "end", k_vg_msg_f64, 1, &time_real ); network_send_request( packet, &data, NULL, 0 ); +#endif + // FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME//// } static void _delete_request( u16 request_id ) @@ -310,12 +310,12 @@ void _net_handle_response_message( SteamNetworkingMessage_t *msg ) _net_requests_reset( "Defined server Error (Our end is ok)\n" ); } -void _net_requests_init(void) +VG_API void _net_requests_init(void) { u32 alloc_size = sizeof(net_request)*NETWORK_MAX_REQUESTS; - _net_requests.transfer_buffer = vg_stack_allocate( &vg.rtmem, VG_MB(4), 8, "Request transfer data buffer" ); + _net_requests.transfer_buffer = vg_malloc( VG_MB(4) ); _net_requests.global_uid = time(NULL) ^ 0x35aa3203; - vg_pool_init( &_net_requests.pool, &_net_requests.inactive, NETWORK_MAX_REQUESTS, &vg.rtmem ); + vg_pool_init( &_net_requests.pool, &_net_requests.inactive, NETWORK_MAX_REQUESTS, NULL ); } void _net_requests_update(void) diff --git a/src/network_requests.h b/src/network_requests.h index 7b4444b..f9f6165 100644 --- a/src/network_requests.h +++ b/src/network_requests.h @@ -1,5 +1,6 @@ -#pragma once -#include "network.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/network_requests.c" +#else #define TRANSFER_TIMEOUT_SECONDS 5.0f #define NETWORK_MAX_REQUESTS 8 @@ -39,10 +40,14 @@ struct _net_requests } extern _net_requests; -void network_send_request( netmsg_request *req, vg_msg *body, +VG_API void _net_requests_init(void); + +const char *request_status_string( enum request_status status ); +void network_send_request( const c8 *body, u32 body_length, void (*callback)( void *data, u32 data_size, u64 userdata, enum request_status status ), u64 userdata ); void _net_handle_response_message( SteamNetworkingMessage_t *msg ); -void _net_requests_init(void); void _net_requests_deleteall(void); void _net_requests_update(void); + +#endif diff --git a/src/particle.c b/src/particle.c index 5b25395..d43673f 100644 --- a/src/particle.c +++ b/src/particle.c @@ -1,7 +1,3 @@ -#include "vg/vg_lines.h" -#include "particle.h" -#include "shaders/particle.h" - struct particle_system particles_grind = { .scale = 0.02f, .velocity_scale = 0.001f, @@ -13,6 +9,12 @@ particles_env = { .width = 0.25f }; +VG_API void _particles_init( void ) +{ + particle_system_init( &particles_grind, 300, VG_STACK_USE_HEAP ); + particle_system_init( &particles_env, 200, VG_STACK_USE_HEAP ); +} + void particle_spawn( particle_system *sys, v3f co, v3f v, f32 lifetime, u32 colour ) { if( sys->alive == sys->max ) @@ -70,7 +72,8 @@ iter: if( i == sys->alive ) return; void particle_system_debug( particle_system *sys ) { - for( u32 i=0; ialive; i ++ ){ + for( u32 i=0; ialive; i ++ ) + { particle *p = &sys->array[i]; v3f p1; v3_muladds( p->co, p->v, 0.2f, p1 ); @@ -78,27 +81,39 @@ void particle_system_debug( particle_system *sys ) } } -struct particle_init_args +VG_TIER_2 void particle_system_init( particle_system *sys, u32 max, vg_stack_allocator *stack ) { - particle_system *sys; - u16 indices[]; -}; -static void particle_init_task( vg_async_task *task ) -{ - struct particle_init_args *args = (void *)task->data; - particle_system *sys = args->sys; - - glGenVertexArrays( 1, &sys->vao ); - glGenBuffers( 1, &sys->vbo ); - glGenBuffers( 1, &sys->ebo ); - glBindVertexArray( sys->vao ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + u32 stride = sizeof(particle_vert); - size_t stride = sizeof(particle_vert); + sys->max = max; + sys->array = vg_stack_allocate( stack, max*sizeof(particle), 8, "Particle array" ); + sys->vertices = vg_stack_allocate( stack, max*stride*4, 8, "Particle vertices" ); - glBindBuffer( GL_ARRAY_BUFFER, sys->vbo ); - glBufferData( GL_ARRAY_BUFFER, sys->max*stride*4, NULL, GL_DYNAMIC_DRAW ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, sys->ebo ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, sys->max*sizeof(u16)*6, args->indices, GL_STATIC_DRAW ); + u32 temp_frame = _vg_start_temp_frame(); + { + u16 *indices = vg_stack_allocate( _vg_temp_stack(), sizeof(u16) * max * 6, 8, "Temp indices" ); + for( u32 i=0; ivao ); + glGenBuffers( 1, &sys->vbo ); + glGenBuffers( 1, &sys->ebo ); + glBindVertexArray( sys->vao ); + + glBindBuffer( GL_ARRAY_BUFFER, sys->vbo ); + glBufferData( GL_ARRAY_BUFFER, sys->max*stride*4, NULL, GL_DYNAMIC_DRAW ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, sys->ebo ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, max*sizeof(u16)*6, indices, GL_STATIC_DRAW ); + } + _vg_end_temp_frame( temp_frame ); /* 0: coordinates */ glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 ); @@ -109,30 +124,6 @@ static void particle_init_task( vg_async_task *task ) glEnableVertexAttribArray( 1 ); } -void particle_alloc( particle_system *sys, u32 max ) -{ - size_t stride = sizeof(particle_vert); - - sys->max = max; - sys->array = vg_stack_allocate( &vg.rtmem, max*sizeof(particle), 8, "Particle array" ); - sys->vertices = vg_stack_allocate( &vg.rtmem, max*stride*4, 8, "Particle vertices" ); - - vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(particle_system *) + max*sizeof(u16)*6, 1 ); - struct particle_init_args *init = (void *)task->data; - init->sys = sys; - - for( u32 i=0; iindices[i*6+0] = i*4; - init->indices[i*6+1] = i*4+1; - init->indices[i*6+2] = i*4+2; - init->indices[i*6+3] = i*4; - init->indices[i*6+4] = i*4+2; - init->indices[i*6+5] = i*4+3; - } - vg_async_task_dispatch( task, particle_init_task ); -} - void particle_system_prerender( particle_system *sys ) { for( u32 i=0; ialive; i ++ ){ diff --git a/src/particle.h b/src/particle.h index 6858890..85d90d1 100644 --- a/src/particle.h +++ b/src/particle.h @@ -1,5 +1,6 @@ -#pragma once -#include "skaterift.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/particle.c" +#else typedef struct particle_system particle_system; typedef struct particle particle; @@ -29,14 +30,14 @@ struct particle_system { } extern particles_grind, particles_env; -void particle_alloc( particle_system *sys, u32 max ); +VG_API void _particles_init( void ); +VG_TIER_2 void particle_system_init( particle_system *sys, u32 max, vg_stack_allocator *stack ); + void particle_system_update( particle_system *sys, f32 dt ); void particle_system_debug( particle_system *sys ); void particle_system_prerender( particle_system *sys ); void particle_system_render( particle_system *sys, vg_camera *cam ); -void particle_spawn( particle_system *sys, - v3f co, v3f v, f32 lifetime, u32 colour ); -void particle_spawn_cone( particle_system *sys, - v3f co, v3f dir, f32 angle, f32 speed, - f32 lifetime, u32 colour ); +void particle_spawn( particle_system *sys, v3f co, v3f v, f32 lifetime, u32 colour ); +void particle_spawn_cone( particle_system *sys, v3f co, v3f dir, f32 angle, f32 speed, f32 lifetime, u32 colour ); +#endif diff --git a/src/physics_test.h b/src/physics_test.h deleted file mode 100644 index 243de36..0000000 --- a/src/physics_test.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#ifndef PHYSICS_TEST_H -#define PHYSICS_TEST_H - -#include "rigidbody.h" -#include "player.h" - -rigidbody ground = { .type = k_rb_shape_box, - .bbx = {{-100.0f,-1.0f,-100.0f},{100.0f,0.0f,100.0f}}, - .co = {0.0f, 0.0f, 0.0f}, - .q = {0.0f,0.0f,0.0f,1.0f}, - .is_world = 1 }; - -rigidbody blocky = - { - .type = k_rb_shape_box, - .bbx = {{-2.0f,-1.0f,-3.0f},{2.0f,1.0f,2.0f}}, - .co = {30.0f,2.0f,30.0f}, - .q = {0.0f,0.0f,0.0f,1.0f}, - .is_world = 1 - }; - -rigidbody marko = -{ - .type = k_rb_shape_box, - .bbx = {{-0.5f,-0.5f,-0.5f},{0.5f,0.5f,0.5f}}, - .co = {-36.0f,8.0f,-36.0f}, - .q = {0.0f,0.0f,0.0f,1.0f}, - .is_world = 0 -}; - -scene epic_scene; - -rigidbody epic_scene_rb = -{ - .type = k_rb_shape_scene, - .co = {0.0f,0.0f,0.0f}, - .q = {0.0f,0.0f,0.0f,1.0f}, - .is_world = 1, - .inf.scene = { .pscene = &epic_scene } -}; - -rigidbody funnel[4] = { - { - .type = k_rb_shape_box, - .bbx = {{-20.0f,-1.0f,-20.0f},{20.0f,1.0f,20.0f}}, - .co = {-10.0f,5.0f,0.0f}, - .is_world = 1 - }, - { - .type = k_rb_shape_box, - .bbx = {{-20.0f,-1.0f,-20.0f},{20.0f,1.0f,20.0f}}, - .co = { 10.0f,5.0f,0.0f}, - .is_world = 1 - }, - { - .type = k_rb_shape_box, - .bbx = {{-20.0f,-1.0f,-20.0f},{20.0f,1.0f,20.0f}}, - .co = { 0.0f,5.0f,10.0f}, - .is_world = 1 - }, - { - .type = k_rb_shape_box, - .bbx = {{-20.0f,-1.0f,-20.0f},{20.0f,1.0f,20.0f}}, - .co = {0.0f,5.0f,-10.0f}, - .is_world = 1 - } -}; - -rigidbody jeff1 = { .type = k_rb_shape_capsule, - .inf.capsule = { .radius = 0.75f, .height = 3.0f }, - .co = {30.0f, 4.0f, 30.0f }, - .q = {1.0f,0.0f,0.0f,0.0f} -}; - -rigidbody ball = { .type = k_rb_shape_sphere, - .inf.sphere = { .radius = 2.0f }, - .co = {0.0f,20.0f,2.0f}, - .q = {0.0f,0.0f,0.0f,1.0f}}, - - ball1= { .type = k_rb_shape_sphere, - .inf.sphere = { .radius = 2.0f }, - .co = {0.1f,25.0f,0.2f}, - .q = {0.0f,0.0f,0.0f,1.0f}}; - -rigidbody jeffs[16]; - -static void reorg_jeffs(void) -{ - for( int i=0; inode_count; i++ ) - { - mdl_node *pnode = mdl_node_from_id( mdl, i ); - - for( int j=0; jsubmesh_count; j++ ) - { - mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j ); - scene_add_submesh( &epic_scene, mdl, sm, transform ); - } - } - - vg_free( mdl ); - scene_bh_create( &epic_scene ); - - rb_init( &epic_scene_rb ); - rb_init( &marko ); -} - -static void physics_test_update(void) -{ - player_freecam(); - player_camera_update(); - - for( int i=0; i<4; i++ ) - rb_debug( &funnel[i], 0xff0060e0 ); - rb_debug( &ground, 0xff00ff00 ); - rb_debug( &ball, 0xffe00040 ); - rb_debug( &ball1, 0xff00e050 ); - - rb_debug( &blocky, 0xffcccccc ); - rb_debug( &jeff1, 0xff00ffff ); - - rb_debug( &epic_scene_rb, 0xffcccccc ); - rb_debug( &marko, 0xffffcc00 ); - - { - - rb_solver_reset(); - - for( int i=0; i<4; i++ ) - { - rigidbody *fn = &funnel[i]; - rb_collide( &ball, fn ); - rb_collide( &ball1, fn ); - rb_collide( &jeff1, fn ); - - for( int i=0; i - i32 k_invert_y = 0; struct localplayer localplayer = { @@ -63,7 +41,7 @@ int localplayer_cmd_respawn( int argc, const char *argv[] ) return 1; } -void player_register(void) +VG_API void _player_register(void) { vg_console_reg_var( "player_battery", &localplayer.has_battery, k_var_dtype_i32, 0 ); vg_console_reg_cmd( "respawn", localplayer_cmd_respawn, NULL ); @@ -88,15 +66,6 @@ void player_register(void) } } -void player_init(void) -{ - mdl_context *mdl = &localplayer.battery; - mdl_open( mdl, "models/battery.mdl", &vg.rtmem ); - mdl_load_metadata_block( mdl, &vg.rtmem ); - mdl_async_full_load_std( mdl, NULL ); - mdl_close( mdl ); -} - void player__debugtext( ui_context *ctx, int size, const char *fmt, ... ) { char buffer[ 1024 ]; @@ -120,13 +89,13 @@ void player__use_model( addon_id addon_id ) localplayer.playermodel.cache_slot = addon_cache_create_viewer( k_addon_type_player, addon_id ); } -void player__bind(void) +VG_API void _player_init(void) { for( u32 i=0; ibind ) - sys->bind(); + if( sys && sys->init ) + sys->init(); } } @@ -158,7 +127,7 @@ void player__update(void) glider_physics( (v2f){0,0} ); - if( localplayer.rb.co[1] < _world.main.scene_geo.bbx[0][1] - 40.0f ) + if( localplayer.rb.co[1] < _world.main.scene_geometry.bbx[0][1] - 40.0f ) { ent_spawn *rp = world_find_closest_spawn( &_world.main, localplayer.rb.co ); if( rp ) @@ -225,7 +194,8 @@ void player__pass_gate( u32 id ) _world.copy_of_nonlocal_sender.key = 0; _world.copy_of_nonlocal_sender.submesh_start = 0; _world.copy_of_nonlocal_sender.submesh_count = 0; - vg_strncpy( af_str( &world->meta.af, gate->key ), _world.nonlocal_destination_key, 32, k_strncpy_overflow_fatal ); + vg_strncpy( af_str( world->meta.packed_strings, gate->key ), _world.nonlocal_destination_key, + 32, k_strncpy_overflow_fatal ); player__clean_refs(); skaterift_load_world_start( gate->remote_addon_id, 0 ); return; @@ -265,8 +235,8 @@ void player_apply_transport_to_cam( m4x3f transport ) /* we want the regular transform here no the inversion */ m4x3_expand( transport, transport_4 ); - m4x4_mul( world_gates.cam.mtx.pv, transport_4, world_gates.cam.mtx.pv ); - m4x4_mul( world_gates.cam.mtx.v, transport_4, world_gates.cam.mtx.v ); + m4x4_mul( _world_gates.cam.mtx.pv, transport_4, _world_gates.cam.mtx.pv ); + m4x4_mul( _world_gates.cam.mtx.v, transport_4, _world_gates.cam.mtx.v ); } void player__im_gui( ui_context *ctx ) @@ -274,10 +244,10 @@ void player__im_gui( ui_context *ctx ) if( !k_player_debug_info ) return; ui_rect box = { - vg.window_x - 300, + _vg_window.w - 300, 0, 300, - vg.window_y + _vg_window.h }; ui_fill( ctx, box, (ui_colour(ctx, k_ui_bg)&0x00ffffff)|0x50000000 ); @@ -314,7 +284,8 @@ void player__im_gui( ui_context *ctx ) player__debugtext( ctx, 1, "time_rate: %.4f", skaterift.time_rate ); player__debugtext( ctx, 2, "player" ); - player__debugtext( ctx, 1, "angles: " PRINTF_v3f( localplayer.cam.angles ) ); + player__debugtext( ctx, 1, "angles: %.2f %.2f %.2f", + localplayer.cam.angles[0],localplayer.cam.angles[1],localplayer.cam.angles[2] ); if( player_subsystems[ localplayer.subsystem ]->im_gui ) player_subsystems[ localplayer.subsystem ]->im_gui( ctx ); @@ -332,7 +303,7 @@ void player__setpos( v3f pos ) void player__clean_refs(void) { - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); _world.challenge_target = NULL; _world.challenge_timer = 0.0f; diff --git a/src/player.h b/src/player.h index c4ed1d3..a89e97e 100644 --- a/src/player.h +++ b/src/player.h @@ -1,37 +1,12 @@ -#pragma once -#include "vg/vg_platform.h" - -struct player_cam_controller { - enum camera_mode{ - k_cam_firstperson = 1, - k_cam_thirdperson = 0 - } - camera_mode; - f32 camera_type_blend; - - v3f fpv_offset, /* expressed relative to rigidbody */ - tpv_offset, - tpv_offset_extra, - fpv_viewpoint, /* expressed relative to neck bone inverse final*/ - fpv_offset_smooth, - fpv_viewpoint_smooth, - tpv_offset_smooth, - tpv_lpf, - cam_velocity_smooth; -}; - -#include "player_common.h" -#include "network_compression.h" -#include "player_effects.h" -#include "player_api.h" -#include "player_ragdoll.h" -#include "player_model.h" -#include "player_render.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player.c" +#else struct player_subsystem_interface { void(*system_register)(void); - void(*bind)(void); + void(*init)(void); + void(*load_resources)(void); void(*pre_update)(void); void(*update)(void); void(*post_update)(void); @@ -136,10 +111,10 @@ struct localplayer /* * Rendering */ - mdl_context skeleton_meta; - mdl_context battery; - ms_context animations; - struct skeleton skeleton; + vg_model skeleton_meta; + vg_model battery; + metascene animations; + ms_skeleton skeleton; i32 has_battery; u8 id_hip, @@ -173,10 +148,10 @@ extern struct player_subsystem_interface *player_subsystems[]; * --------------------------------------------------------- */ -void player_register(void); -void player_init(void); +VG_API void _player_init(void); +VG_API void _player_register(void); + void player__debugtext( ui_context *ctx, int size, const char *fmt, ... ); -void player__use_mesh( glmesh *mesh ); void player__use_model( u16 reg_id ); void player__bind(void); @@ -196,12 +171,13 @@ void player__reset(void); void player__kill(void); void player__begin_holdout( v3f offset ); -void player_get_anim( skeleton_anim *out_anim, const char *name ); +void player_get_anim( ms_skeletal_animation *out_anim, const char *name ); int localplayer_cmd_respawn( int argc, const char *argv[] ); void player_apply_transport_to_cam( m4x3f transport ); void player__clear_sfx_buffer(void); -void player__networked_sfx( u8 system, u8 priority, u8 id, - v3f pos, f32 volume ); +void player__networked_sfx( u8 system, u8 priority, u8 id, v3f pos, f32 volume ); void net_sfx_exchange( bitpack_ctx *ctx, struct net_sfx *sfx ); void net_sfx_play( struct net_sfx *sfx ); + +#endif diff --git a/src/player_api.h b/src/player_api.h index cd8a477..7ee07be 100644 --- a/src/player_api.h +++ b/src/player_api.h @@ -1,12 +1,35 @@ -#pragma once -#include "model.h" -#include "metascene.h" +#if defined( SR_IMPLEMENTATION ) +//# include "src/player_api.c" +#else typedef struct player_instance player_instance; typedef struct player_pose player_pose; -struct player_pose{ - enum player_pose_type { +struct player_cam_controller +{ + enum camera_mode + { + k_cam_firstperson = 1, + k_cam_thirdperson = 0 + } + camera_mode; + f32 camera_type_blend; + + v3f fpv_offset, /* expressed relative to rigidbody */ + tpv_offset, + tpv_offset_extra, + fpv_viewpoint, /* expressed relative to neck bone inverse final*/ + fpv_offset_smooth, + fpv_viewpoint_smooth, + tpv_offset_smooth, + tpv_lpf, + cam_velocity_smooth; +}; + +struct player_pose +{ + enum player_pose_type + { k_player_pose_type_ik, /* regular IK animation */ k_player_pose_type_fk_2, } @@ -17,13 +40,15 @@ struct player_pose{ ms_keyframe keyframes[32]; - struct player_board_pose { + struct player_board_pose + { f32 lean; } board; }; -enum player_subsystem{ +enum player_subsystem +{ k_player_subsystem_walk = 0, k_player_subsystem_skate = 1, k_player_subsystem_dead = 2, @@ -33,3 +58,13 @@ enum player_subsystem{ k_player_subsystem_max, k_player_subsystem_invalid = 255 }; + +enum player_die_type +{ + k_player_die_type_generic, + k_player_die_type_head, + k_player_die_type_feet, + k_player_die_type_water +}; + +#endif diff --git a/src/player_basic_info.c b/src/player_basic_info.c index ffc7ae0..78689c6 100644 --- a/src/player_basic_info.c +++ b/src/player_basic_info.c @@ -1,6 +1,3 @@ -#include "player_basic_info.h" -#include "network_compression.h" - struct player_basic_info player_basic_info; struct player_subsystem_interface player_subsystem_basic_info = { diff --git a/src/player_basic_info.h b/src/player_basic_info.h index 815be67..a49bc26 100644 --- a/src/player_basic_info.h +++ b/src/player_basic_info.h @@ -1,6 +1,6 @@ -#pragma once -#include "player.h" -#include "player_api.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player_basic_info.c" +#else struct player_basic_info { @@ -16,3 +16,4 @@ extern struct player_subsystem_interface player_subsystem_basic_info; void player__basic_info_animator_exchange(bitpack_ctx *ctx, void *data); void player__basic_info_pose( void *_animator, player_pose *pose ); +#endif diff --git a/src/player_common.c b/src/player_common.c index 3f1b66d..1fa2fee 100644 --- a/src/player_common.c +++ b/src/player_common.c @@ -1,9 +1,3 @@ -#include "ent_skateshop.h" -#include "player.h" -#include "input.h" -#include "menu.h" -#include "vg/vg_perlin.h" - float player_get_heading_yaw(void) { v3f xz; diff --git a/src/player_common.h b/src/player_common.h index b32faee..1cbee97 100644 --- a/src/player_common.h +++ b/src/player_common.h @@ -1,5 +1,6 @@ -#pragma once -#include "player_api.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player_common.c" +#else static float k_cam_spring = 20.0f, @@ -14,3 +15,6 @@ static ui_rect g_player_debugger; void player_look( v3f angles, float speed ); void player__cam_iterate(void); f32 player_get_heading_yaw(void); +void compute_cam_controller_offsets( enum player_subsystem system, struct player_cam_controller *cc ); + +#endif diff --git a/src/player_dead.c b/src/player_dead.c index 69418b9..8057427 100644 --- a/src/player_dead.c +++ b/src/player_dead.c @@ -1,7 +1,3 @@ -#include "skaterift.h" -#include "player_dead.h" -#include "gui.h" - struct player_dead player_dead; struct player_subsystem_interface player_subsystem_dead = { .update = player__dead_update, @@ -10,7 +6,7 @@ struct player_subsystem_interface player_subsystem_dead = { .pose = player__dead_pose, .post_animate = player__dead_post_animate, .im_gui = player__dead_im_gui, - .bind = player__dead_bind, + .load_resources = player__dead_load_resources, .animator_data = &player_dead.animator, .animator_size = sizeof(player_dead.animator), @@ -76,7 +72,7 @@ void player__dead_post_update(void) } } - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); } } else @@ -90,7 +86,7 @@ void player__dead_post_update(void) { localplayer_cmd_respawn(0,NULL); srinput.state = k_input_state_resume; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); } } } @@ -101,7 +97,7 @@ void player__dead_animate(void) struct player_dead *d = &player_dead; struct player_dead_animator *animator = &d->animator; struct player_ragdoll *rd = &localplayer.ragdoll; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; m4x3f transforms[ 32 ]; @@ -136,7 +132,7 @@ void player__dead_animate(void) /* bones without colliders transforms */ for( u32 i=1; ibone_count; i++ ) { - struct skeleton_bone *sb = &sk->bones[i]; + ms_skeleton_bone *sb = &sk->bones[i]; if( sb->parent && !sb->collider ) { @@ -155,7 +151,7 @@ void player__dead_animate(void) /* measurements */ for( u32 i=1; ibone_count; i++ ) { - struct skeleton_bone *sb = &sk->bones[i]; + ms_skeleton_bone *sb = &sk->bones[i]; v3_zero( animator->transforms[i].co ); q_identity( animator->transforms[i].q ); @@ -176,7 +172,7 @@ void player__dead_pose( void *_animator, player_pose *pose ) { struct player_dead_animator *animator = _animator; struct player_ragdoll *rd = &localplayer.ragdoll; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; pose->type = k_player_pose_type_fk_2; pose->board.lean = 0.0f; @@ -210,7 +206,6 @@ void player__dead_transition( enum player_die_type type ) return; localplayer.fell_since_last_gate = 1; - localplayer.subsystem = k_player_subsystem_dead; copy_localplayer_to_ragdoll( &localplayer.ragdoll, type ); @@ -218,23 +213,18 @@ void player__dead_transition( enum player_die_type type ) v3_copy( part->rb.co, player_dead.co_lpf ); v3_copy( part->rb.v, player_dead.v_lpf ); v3_copy( part->rb.w, player_dead.w_lpf ); - - gui_helper_reset( k_gui_helper_mode_black_bars ); + _gui_helper_reset( k_gui_helper_mode_black_bars ); vg_str str; - if( (player_dead.helper_getup = gui_new_helper(input_button_list[k_srbind_skate], &str) )) + if( (player_dead.helper_getup = _gui_new_helper(input_button_list[k_srbind_skate], &str) )) { vg_strcat( &str, "Get Up" ); - if( (_world.event == k_world_event_challenge) && (_world.challenge_state >= k_challenge_state_running) ) { vg_strcat( &str, " (Exit challenge)" ); - struct gui_helper *helper; - if( (helper = gui_new_helper(input_button_list[k_srbind_reset], &str)) ) - { + if( (helper = _gui_new_helper(input_button_list[k_srbind_reset], &str)) ) vg_strcat( &str, "Retry" ); - } } player_dead.helper_getup->greyed = 1; @@ -244,7 +234,6 @@ void player__dead_transition( enum player_die_type type ) void player__dead_animator_exchange( bitpack_ctx *ctx, void *data ) { struct player_dead_animator *animator = data; - for( u32 i=0; itransforms[i].co ); @@ -252,8 +241,8 @@ void player__dead_animator_exchange( bitpack_ctx *ctx, void *data ) } } -void player__dead_bind(void) +void player__dead_load_resources(void) { - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; player_get_anim( &player_dead.anim_bail, "pose_bail_ball" ); } diff --git a/src/player_dead.h b/src/player_dead.h index 30d9a72..b4518fa 100644 --- a/src/player_dead.h +++ b/src/player_dead.h @@ -1,6 +1,6 @@ -#pragma once -#include "player.h" -#include "player_api.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player_dead.c" +#else struct player_dead { @@ -15,7 +15,7 @@ struct player_dead } animator; - skeleton_anim anim_bail; + ms_skeletal_animation anim_bail; struct gui_helper *helper_getup; } extern player_dead; @@ -27,7 +27,8 @@ void player__dead_animate (void); void player__dead_pose (void *animator, player_pose *pose); void player__dead_post_animate(void); void player__dead_im_gui ( ui_context *ctx ); -void player__dead_bind (void); +void player__dead_load_resources(void); void player__dead_transition ( enum player_die_type type ); void player__dead_animator_exchange( bitpack_ctx *ctx, void *data ); +#endif diff --git a/src/player_drive.c b/src/player_drive.c deleted file mode 100644 index e55a668..0000000 --- a/src/player_drive.c +++ /dev/null @@ -1,87 +0,0 @@ -#include "player_drive.h" -#include "input.h" - -struct player_drive player_drive; -struct player_subsystem_interface player_subsystem_drive = -{ - .pre_update = player__drive_pre_update, - .update = player__drive_update, - .post_update = player__drive_post_update, - .animate = player__drive_animate, - .pose = player__drive_pose, - .post_animate = player__drive_post_animate, - .im_gui = player__drive_im_gui, - .bind = player__drive_bind, - - .animator_data = NULL, - .animator_size = 0, - .name = "Drive" -}; - -void player__drive_pre_update(void) -{ - drivable_vehicle *vehc = player_drive.vehicle; - - v2f steer; - joystick_state( k_srjoystick_steer, steer ); - - vehc->steer = vg_lerpf( vehc->steer, steer[0] * 0.4f, - vg.time_fixed_delta * 8.0f ); - vehc->drive = steer[1]; -} - -void player__drive_update(void){} - -void player__drive_post_update(void) -{ - v3_copy( player_drive.vehicle->rb.co,localplayer.rb.co ); - v3_copy( player_drive.vehicle->rb.v, localplayer.rb.v ); - v4_copy( player_drive.vehicle->rb.q, localplayer.rb.q ); - v3_copy( player_drive.vehicle->rb.w, localplayer.rb.w ); -} - -void player__drive_animate(void){} - -void player__drive_pose( void *animator, player_pose *pose ) -{ - struct skeleton *sk = &localplayer.skeleton; - - skeleton_sample_anim( sk, &player_drive.anim_drive, 0.0f, pose->keyframes ); - v3_copy( localplayer.rb.co, pose->root_co ); - v4_copy( localplayer.rb.q, pose->root_q ); -} - -void player__drive_post_animate(void) -{ - if( localplayer.cam_control.camera_mode == k_cam_firstperson ) - localplayer.cam_velocity_influence = 0.0f; - else - localplayer.cam_velocity_influence = 1.0f; - - rigidbody *rb = &gzoomer.rb; - float yaw = atan2f( -rb->to_world[2][0], rb->to_world[2][2] ), - pitch = atan2f - ( - -rb->to_world[2][1], - sqrtf - ( - rb->to_world[2][0]*rb->to_world[2][0] + - rb->to_world[2][2]*rb->to_world[2][2] - ) - ); - - localplayer.angles[0] = yaw; - localplayer.angles[1] = pitch; -} - -void player__drive_im_gui( ui_context *ctx ) -{ - player__debugtext( ctx, 1, "Nothing here" ); -} - -void player__drive_bind(void) -{ - struct skeleton *sk = &localplayer.skeleton; - player_drive.vehicle = &gzoomer; - player_get_anim( &player_drive.anim_drive, "idle_cycle+y" ); -} diff --git a/src/player_drive.h b/src/player_drive.h deleted file mode 100644 index 772a0d3..0000000 --- a/src/player_drive.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include "player.h" -#include "vehicle.h" - -struct player_drive -{ - drivable_vehicle *vehicle; - skeleton_anim anim_drive; -} -extern player_drive; -extern struct player_subsystem_interface player_subsystem_drive; - -void player__drive_pre_update(void); -void player__drive_update(void); -void player__drive_post_update(void); -void player__drive_animate(void); -void player__drive_pose( void *animator, player_pose *pose ); - -void player__drive_post_animate(void); -void player__drive_im_gui( ui_context *ctx ); -void player__drive_bind(void); diff --git a/src/player_effects.c b/src/player_effects.c index 981c232..b3c2f10 100644 --- a/src/player_effects.c +++ b/src/player_effects.c @@ -1,8 +1,3 @@ -#include "player.h" -#include "player_effects.h" -#include "player_render.h" -#include "particle.h" - void effect_blink_apply( effect_blink *ef, player_pose *pose, f32 dt ) { if( ef->t < 0.0f ){ diff --git a/src/player_effects.h b/src/player_effects.h index f148dbc..bd5d1dd 100644 --- a/src/player_effects.h +++ b/src/player_effects.h @@ -1,6 +1,6 @@ -#pragma once -#include "vg/vg_platform.h" -#include "player_render.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player_effects.c" +#else typedef struct effect_blink effect_blink; typedef struct effect_spark effect_spark; @@ -24,3 +24,5 @@ struct player_effects_data effect_blink blink; effect_spark spark, sand; }; + +#endif diff --git a/src/player_glide.c b/src/player_glide.c index 2063040..e6e2176 100644 --- a/src/player_glide.c +++ b/src/player_glide.c @@ -1,14 +1,3 @@ -#include "player_glide.h" -#include "vg/vg_rigidbody.h" -#include "scene_rigidbody.h" -#include "shaders/model_board_view.h" -#include "shaders/model_entity.h" -#include "input.h" -#include "skaterift.h" - -#include "player_dead.h" -#include "player_skate.h" - trail_system trails_glider[] = { { .width = 0.035f, @@ -63,7 +52,8 @@ struct player_subsystem_interface player_subsystem_glide = .post_animate = player_glide_post_animate, .network_animator_exchange = player_glide_animator_exchange, .im_gui = player_glide_im_gui, - .bind = player_glide_bind, + .load_resources = player_glide_load_resources, + .init = player_glide_init, .system_register = player_glide_register, .animator_data = &player_glide.animator, @@ -93,8 +83,7 @@ void player_glide_pre_update(void) player_skate.state.activity_prev = k_skate_activity_air; q_mulv( localplayer.rb.q, (v3f){0.0f,1.0f,0.0f}, player_skate.state.cog ); - v3_add( player_skate.state.cog, localplayer.rb.co, - player_skate.state.cog ); + v3_add( player_skate.state.cog, localplayer.rb.co, player_skate.state.cog ); v3_copy( localplayer.rb.v, player_skate.state.cog_v ); player__begin_holdout( (v3f){0.0f,0.0f,0.0f} ); @@ -106,7 +95,8 @@ void player_glide_pre_update(void) } } -static void massless_accel( rigidbody *rb, v3f delta, v3f impulse ){ +static void massless_accel( rigidbody *rb, v3f delta, v3f impulse ) +{ /* linear */ v3_muladds( rb->v, impulse, vg.time_fixed_delta, rb->v ); @@ -116,9 +106,8 @@ static void massless_accel( rigidbody *rb, v3f delta, v3f impulse ){ v3_muladds( rb->w, wa, vg.time_fixed_delta, rb->w ); } -static void calculate_lift( v3f vl, f32 aoa_bias, - v3f axis, v3f back, f32 power, - v3f out_force ){ +static void calculate_lift( v3f vl, f32 aoa_bias, v3f axis, v3f back, f32 power, v3f out_force ) +{ v3f up; v3_cross( back, axis, up ); @@ -135,11 +124,11 @@ static void calculate_lift( v3f vl, f32 aoa_bias, v3_cross( wind, axis, lift_dir ); /* this is where induced drag (from the flappy things) would go */ - v3_muls( lift_dir, L, out_force ); } -static void calculate_drag( v3f vl, f32 cd, v3f out_force ){ +static void calculate_drag( v3f vl, f32 cd, v3f out_force ) +{ f32 v2 = v3_length2( vl ); v3f dir; v3_copy( vl, dir ); @@ -160,17 +149,14 @@ bool glider_physics( v2f steer ) m3x3_mulv( rb->to_local, rb->w, wl ); v3f F, Flift, Fslip, Fdrag, FslipW, FliftW; - - calculate_lift( vl, steer[1]*k_glide_steer, - (v3f){1,0,0}, + calculate_lift( vl, steer[1]*k_glide_steer, (v3f){1,0,0}, (v3f){0,sinf(k_glide_wing_orient),cosf(k_glide_wing_orient)}, k_glide_cl, Flift ); + v3_copy( Flift, player_glide.info_lift ); v3_cross( (v3f){0,0,0}, Flift, FliftW ); - calculate_lift( vl, 0.0f, - (v3f){0,1,0},(v3f){0,0,1}, - k_glide_cs, Fslip ); + calculate_lift( vl, 0.0f, (v3f){0,1,0},(v3f){0,0,1}, k_glide_cs, Fslip ); v3_copy( Fslip, player_glide.info_slip ); v3_cross( (v3f){0,k_glide_lift_pitch,k_glide_slip_yaw}, Fslip, FslipW ); @@ -180,13 +166,15 @@ bool glider_physics( v2f steer ) v3f balance = {0.0f,-k_glide_balance,0.0f}; m3x3_mulv( rb->to_local, balance, balance ); - v3f Fw = { + v3f Fw = + { steer[1]*k_glide_steer - balance[2], 0.0f, -steer[0]*k_glide_steer + balance[0], }; - if( player_glide.ticker ){ + if( player_glide.ticker ) + { player_glide.ticker --; return 0; } @@ -216,51 +204,47 @@ bool glider_physics( v2f steer ) rigidbody _null = {0}; _null.inv_mass = 0.0f; m3x3_zero( _null.iI ); - for( u32 i=0; i < VG_ARRAY_LEN(player_glide.parts); i ++ ){ + for( u32 i=0; i < VG_ARRAY_LEN(player_glide.parts); i ++ ) + { m4x3f mmdl; m4x3_mul( rb->to_world, player_glide.parts[i].mdl, mmdl ); - if( player_glide.parts[i].shape == k_rb_shape_capsule ){ - vg_line_capsule( mmdl, - player_glide.parts[i].inf.r, - player_glide.parts[i].inf.h, - VG__BLACK ); + if( player_glide.parts[i].shape == k_rb_shape_capsule ) + { + vg_line_capsule( mmdl, player_glide.parts[i].inf.r, player_glide.parts[i].inf.h, VG__BLACK ); } - else if( player_glide.parts[i].shape == k_rb_shape_sphere ){ + else if( player_glide.parts[i].shape == k_rb_shape_sphere ) vg_line_sphere( mmdl, player_glide.parts[i].r, 0 ); - } - if( rb_global_has_space() ){ + if( rb_global_has_space() ) + { rb_ct *buf = rb_global_buffer(); - u32 l = 0; - if( player_glide.parts[i].shape == k_rb_shape_capsule ){ - l = rb_capsule__scene( mmdl, &player_glide.parts[i].inf, - NULL, world->geo_bh, buf, + if( player_glide.parts[i].shape == k_rb_shape_capsule ) + { + l = rb_capsule__scene( mmdl, &player_glide.parts[i].inf, NULL, &world->geometry_bh, buf, k_material_flag_ghosts ); } - else if( player_glide.parts[i].shape == k_rb_shape_sphere ){ - l = rb_sphere__scene( mmdl, player_glide.parts[i].r, - NULL, world->geo_bh, buf, + else if( player_glide.parts[i].shape == k_rb_shape_sphere ) + { + l = rb_sphere__scene( mmdl, player_glide.parts[i].r, NULL, &world->geometry_bh, buf, k_material_flag_ghosts ); } - if( player_glide.parts[i].is_damage && l ){ + if( player_glide.parts[i].is_damage && l ) bottom_hit = 1; - } - for( u32 j=0; jtype = k_player_pose_type_ik; pose->board.lean = 0.0f; @@ -367,14 +351,16 @@ void player_glide_im_gui( ui_context *ctx ) void player_glide_equip_glider(void) { - if( !localplayer.have_glider ){ + if( !localplayer.have_glider ) + { localplayer.have_glider = 1; localplayer.glider_orphan = 0; player_glide.t = -1.0f; } } -static int ccmd_player_glider_spawn( int argc, const char *argv[] ){ +static int ccmd_player_glider_spawn( int argc, const char *argv[] ) +{ if( vg_console.cheats ){ player_glide_equip_glider(); } @@ -399,14 +385,14 @@ void player_glide_register(void) vg_console_reg_cmd( "spawn_glider", ccmd_player_glider_spawn, NULL ); } -void player_glide_bind(void) +void player_glide_init(void) { - THREAD_1; f32 mass = 0.0f,k_density = 8.0f; m3x3f I; m3x3_zero( I ); - for( u32 i=0; iaf, &markers, ent_marker, &vg.scratch ); - mdl_close( mdl ); - + AF_LOAD_ARRAY_STRUCT( &ctx.af, &markers, ent_marker, _vg_temp_stack() ); for( u32 i=0; itransform.co, player_glide.trail_positions[ player_glide.trail_count ++ ] ); - if( player_glide.trail_count == VG_ARRAY_LEN(trails_glider) ) break; } - - /* allocate effects */ - for( u32 i=0; imesh ); + vg_model_bind_mesh( model ); - for( u32 i=0; imesh_count; i ++ ) + for( u32 i=0; imesh_count; i ++ ) { - mdl_mesh *mesh = &mdl->meshes[ i ]; + mdl_mesh *mesh = &model->meshes[ i ]; m4x3f mmmdl; mdl_transform_m4x3( &mesh->transform, mmmdl ); @@ -535,7 +525,7 @@ void render_glider_model( vg_camera *cam, world_instance *world, m4x3f mmdl, enu for( u32 j=0; jsubmesh_count; j ++ ) { - mdl_submesh *sm = &mdl->submeshes[ mesh->submesh_start+j ]; + mdl_submesh *sm = &model->submeshes[ mesh->submesh_start+j ]; if( !sm->material_id ) { vg_error( "Invalid material ID 0\n" ); @@ -544,23 +534,23 @@ void render_glider_model( vg_camera *cam, world_instance *world, m4x3f mmdl, enu if( sm->material_id != current_mat ) { - mdl_material *mat = &mdl->materials[ sm->material_id-1 ]; + mdl_material *mat = &model->materials[ sm->material_id-1 ]; GLuint tex = vg.tex_missing; if( mat->shader == k_shader_standard ) { - struct shader_props_standard *props = mat->props.compiled; - - u32 index = props->tex_diffuse-1; - mdl_texture *ptex = &mdl->textures[ index ]; - tex = ptex->glname; + union shader_props *props = &model->shader_props[ sm->material_id-1 ]; + u32 index = props->standard.tex_diffuse-1; + mdl_texture *mdl_tex = &model->textures[ index ]; + vg_tex_bind( GL_TEXTURE_2D, &mdl_tex->tex, 0 ); } + else + vg_tex_bind( GL_TEXTURE_2D, NULL, 0 ); - glBindTexture( GL_TEXTURE_2D, tex ); current_mat = sm->material_id; } - mdl_draw_submesh( sm ); + vg_model_draw_submesh( sm ); } } } @@ -590,7 +580,7 @@ void player_glide_render( vg_camera *cam, world_instance *world, player_pose *po shader_model_board_view_uInverseRatioMain, cam ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_board_view ); + WORLD_LINK_LIGHTING( world, model_board_view ); ms_keyframe kf_res; if( localplayer.glider_orphan ) @@ -613,7 +603,7 @@ void player_glide_render( vg_camera *cam, world_instance *world, player_pose *po vg_slewf( &player_glide.t, target, vg.time_frame_delta * 4.0f ); ms_keyframe kf_backpack; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; m4x3_mulv( localplayer.final_mtx[localplayer.id_chest ], sk->bones[localplayer.id_chest].co, kf_backpack.co ); v4f qyaw, qpitch, qchest, q; diff --git a/src/player_glide.h b/src/player_glide.h index f189cc6..36ee8a2 100644 --- a/src/player_glide.h +++ b/src/player_glide.h @@ -1,11 +1,10 @@ -#pragma once -#include "player.h" -#include "player_render.h" -#include "trail.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player_glide.c" +#else struct player_glide { - struct skeleton_anim anim_glide; + ms_skeletal_animation anim_glide; struct player_glide_animator { @@ -33,11 +32,12 @@ struct player_glide f32 t; - struct { + struct + { v3f co, euler; m4x3f mdl; - - union { + union + { rb_capsule inf; f32 r; }; @@ -50,12 +50,15 @@ struct player_glide u32 trail_count; v3f trail_positions[2]; - mdl_context glider, battery; + vg_model glider, battery; } extern player_glide; extern struct player_subsystem_interface player_subsystem_glide; void player_glide_register(void); +void player_glide_init(void); +void player_glide_pre_update(void); +void player_glide_load_resources(void); void player_glide_pre_update(void); void player_glide_update(void); void player_glide_post_update(void); @@ -68,10 +71,10 @@ void player_glide_bind(void); void player_glide_transition(void); bool glider_physics( v2f steer ); void player_glide_animator_exchange( bitpack_ctx *ctx, void *data ); -void player_glide_render( vg_camera *cam, world_instance *world, - player_pose *pose ); -void render_glider_model( vg_camera *cam, world_instance *world, m4x3f mmdl, enum board_shader shader, mdl_context *mdl ); +void player_glide_render( vg_camera *cam, world_instance *world, player_pose *pose ); +void render_glider_model( vg_camera *cam, world_instance *world, m4x3f mmdl, enum board_shader shader, vg_model *model ); void player_glide_remote_animator_exchange( bitpack_ctx *ctx, void *data ); void player_glide_equip_glider(void); void player_glide_render_effects( vg_camera *cam ); +#endif diff --git a/src/player_model.h b/src/player_model.h deleted file mode 100644 index 8d5dd80..0000000 --- a/src/player_model.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#pragma once -#include "model.h" -#include "skeleton.h" -#include "player_ragdoll.h" - -#include "shaders/model_character_view.h" diff --git a/src/player_ragdoll.c b/src/player_ragdoll.c index 5ef3ebd..4e8e481 100644 --- a/src/player_ragdoll.c +++ b/src/player_ragdoll.c @@ -1,13 +1,3 @@ -#pragma once -#include "vg/vg_rigidbody.h" -#include "vg/vg_rigidbody_collision.h" -#include "vg/vg_rigidbody_constraints.h" -#include "scene_rigidbody.h" - -#include "player.h" -#include "player_dead.h" -#include "audio.h" - static float k_ragdoll_floatyiness = 20.0f, k_ragdoll_floatydrag = 1.0f, k_ragdoll_limit_scale = 1.0f, @@ -57,7 +47,7 @@ static int dev_ragdoll_saveload(int argc, const char *argv[]){ return 0; } -void player_ragdoll_register(void) +VG_API void _player_ragdoll_register(void) { VG_VAR_F32( k_ragdoll_active_threshold ); VG_VAR_F32( k_ragdoll_angular_drag ); @@ -71,8 +61,7 @@ void player_ragdoll_register(void) vg_console_reg_cmd( "ragdoll", dev_ragdoll_saveload, NULL ); } -void player_init_ragdoll_bone_collider( struct skeleton_bone *bone, - struct ragdoll_part *rp ) +void player_init_ragdoll_bone_collider( ms_skeleton_bone *bone, struct ragdoll_part *rp ) { f32 k_density = 8.0f, k_inertia_scale = 2.0f; @@ -157,8 +146,7 @@ u32 ragdoll_bone_parent( struct player_ragdoll *rd, u32 bone_id ) /* * Setup ragdoll colliders from skeleton */ -void setup_ragdoll_from_skeleton( struct skeleton *sk, - struct player_ragdoll *rd ) +void setup_ragdoll_from_skeleton( ms_skeleton *sk, struct player_ragdoll *rd ) { rd->part_count = 0; @@ -168,8 +156,9 @@ void setup_ragdoll_from_skeleton( struct skeleton *sk, rd->position_constraints_count = 0; rd->cone_constraints_count = 0; - for( u32 i=1; ibone_count; i ++ ){ - struct skeleton_bone *bone = &sk->bones[i]; + for( u32 i=1; ibone_count; i ++ ) + { + ms_skeleton_bone *bone = &sk->bones[i]; /* * Bones with colliders @@ -203,9 +192,9 @@ void setup_ragdoll_from_skeleton( struct skeleton *sk, struct rb_constr_pos *c = &rd->position_constraints[ conid ]; - struct skeleton_bone *bj = &sk->bones[rp->bone_id]; + ms_skeleton_bone *bj = &sk->bones[rp->bone_id]; struct ragdoll_part *pp = &rd->parts[rp->parent]; - struct skeleton_bone *bp = &sk->bones[pp->bone_id]; + ms_skeleton_bone *bp = &sk->bones[pp->bone_id]; rd->constraint_associations[conid][0] = rp->parent; rd->constraint_associations[conid][1] = part_id; @@ -275,10 +264,12 @@ void copy_ragdoll_pose_to_localplayer( struct player_ragdoll *rd ) localplayer.final_mtx[part->bone_id] ); } - for( u32 i=1; iparent && !sb->collider ){ + if( sb->parent && !sb->collider ) + { v3f delta; v3_sub( localplayer.skeleton.bones[i].co, localplayer.skeleton.bones[sb->parent].co, delta ); @@ -362,36 +353,37 @@ void player_ragdoll_iter( struct player_ragdoll *rd ) rb_solver_reset(); - float contact_velocities[256]; + f32 contact_velocities[256]; rigidbody _null = {0}; _null.inv_mass = 0.0f; m3x3_zero( _null.iI ); - for( int i=0; ipart_count; i ++ ){ + for( int i=0; ipart_count; i ++ ) + { v4_copy( rd->parts[i].rb.q, rd->parts[i].prev_q ); v3_copy( rd->parts[i].rb.co, rd->parts[i].prev_co ); - if( rb_global_has_space() ){ + if( rb_global_has_space() ) + { rb_ct *buf = rb_global_buffer(); - int l; - if( rd->parts[i].type == k_bone_collider_capsule ){ - l = rb_capsule__scene( rd->parts[i].rb.to_world, - &rd->parts[i].inf.capsule, - NULL, world->geo_bh, buf, - k_material_flag_ghosts ); + if( rd->parts[i].type == k_bone_collider_capsule ) + { + l = rb_capsule__scene( rd->parts[i].rb.to_world, &rd->parts[i].inf.capsule, + NULL, &world->geometry_bh, buf, k_material_flag_ghosts ); } - else if( rd->parts[i].type == k_bone_collider_box ){ - l = rb_box__scene( rd->parts[i].rb.to_world, - rd->parts[i].inf.box, - NULL, world->geo_bh, buf, - k_material_flag_ghosts ); + else if( rd->parts[i].type == k_bone_collider_box ) + { + l = rb_box__scene( rd->parts[i].rb.to_world, rd->parts[i].inf.box, + NULL, &world->geometry_bh, buf, k_material_flag_ghosts ); } - else continue; + else + continue; - for( int j=0; jparts[i].rb; buf[j].rbb = &_null; } @@ -403,9 +395,12 @@ void player_ragdoll_iter( struct player_ragdoll *rd ) /* * self-collision */ - for( int i=0; ipart_count-1; i ++ ){ - for( int j=i+1; jpart_count; j ++ ){ - if( rd->parts[j].parent != i ){ + for( int i=0; ipart_count-1; i ++ ) + { + for( int j=i+1; jpart_count; j ++ ) + { + if( rd->parts[j].parent != i ) + { if( !rb_global_has_space() ) break; @@ -423,7 +418,8 @@ void player_ragdoll_iter( struct player_ragdoll *rd ) &rd->parts[j].inf.capsule, buf ); - for( int k=0; kparts[i].rb; buf[k].rbb = &rd->parts[j].rb; } @@ -440,93 +436,79 @@ void player_ragdoll_iter( struct player_ragdoll *rd ) struct ragdoll_part *pj = &rd->parts[j]; if( run_sim ) - { - rb_effect_simple_bouyency( &pj->rb, world->water.plane, - k_ragdoll_floatyiness, - k_ragdoll_floatydrag ); - } + rb_effect_simple_bouyency( &pj->rb, world->water.plane, k_ragdoll_floatyiness, k_ragdoll_floatydrag ); } } /* * PRESOLVE */ - for( u32 i=0; ico, ct->rba->co, ra ); v3_sub( ct->co, ct->rbb->co, rb ); rb_rcv( ct->rba, ct->rbb, ra, rb, rv ); - float vn = v3_dot( rv, ct->n ); - + f32 vn = v3_dot( rv, ct->n ); contact_velocities[i] = vn; } - rb_presolve_contacts( rb_contact_buffer, vg.time_fixed_delta, - rb_contact_count ); - rb_presolve_swingtwist_constraints( rd->cone_constraints, - rd->cone_constraints_count ); + rb_presolve_contacts( rb_contact_buffer, vg.time_fixed_delta, rb_contact_count ); + rb_presolve_swingtwist_constraints( rd->cone_constraints, rd->cone_constraints_count ); /* * DEBUG */ - if( k_ragdoll_debug_collider ){ - for( u32 i=0; ipart_count; i ++ ){ + if( k_ragdoll_debug_collider ) + { + for( u32 i=0; ipart_count; i ++ ) + { struct ragdoll_part *rp = &rd->parts[i]; - if( rp->type == k_bone_collider_capsule ){ - vg_line_capsule( rp->rb.to_world, - rp->inf.capsule.r, rp->inf.capsule.h, rp->colour ); - } - else if( rp->type == k_bone_collider_box ){ - vg_line_boxf_transformed( rp->rb.to_world, - rp->inf.box, rp->colour ); - } + if( rp->type == k_bone_collider_capsule ) + vg_line_capsule( rp->rb.to_world, rp->inf.capsule.r, rp->inf.capsule.h, rp->colour ); + else if( rp->type == k_bone_collider_box ) + vg_line_boxf_transformed( rp->rb.to_world, rp->inf.box, rp->colour ); } } - if( k_ragdoll_debug_constraints ){ - rb_debug_position_constraints( rd->position_constraints, - rd->position_constraints_count ); - - rb_debug_swingtwist_constraints( rd->cone_constraints, - rd->cone_constraints_count ); + if( k_ragdoll_debug_constraints ) + { + rb_debug_position_constraints( rd->position_constraints, rd->position_constraints_count ); + rb_debug_swingtwist_constraints( rd->cone_constraints, rd->cone_constraints_count ); } /* * SOLVE CONSTRAINTS & Integrate */ - if( run_sim ){ + if( run_sim ) + { /* the solver is not very quickly converging so... */ - for( int i=0; i<40; i++ ){ - if( i<20 ){ + for( int i=0; i<40; i++ ) + { + if( i<20 ) + { rb_solve_contacts( rb_contact_buffer, rb_contact_count ); - rb_solve_swingtwist_constraints( rd->cone_constraints, - rd->cone_constraints_count ); - rb_postsolve_swingtwist_constraints( rd->cone_constraints, - rd->cone_constraints_count ); + rb_solve_swingtwist_constraints( rd->cone_constraints, rd->cone_constraints_count ); + rb_postsolve_swingtwist_constraints( rd->cone_constraints, rd->cone_constraints_count ); } - rb_solve_position_constraints( rd->position_constraints, - rd->position_constraints_count ); + rb_solve_position_constraints( rd->position_constraints, rd->position_constraints_count ); } - rb_correct_position_constraints( rd->position_constraints, - rd->position_constraints_count, - k_ragdoll_correction * 0.5f ); - rb_correct_swingtwist_constraints( rd->cone_constraints, - rd->cone_constraints_count, - k_ragdoll_correction * 0.25f ); + rb_correct_position_constraints( rd->position_constraints, rd->position_constraints_count, k_ragdoll_correction * 0.5f ); + rb_correct_swingtwist_constraints( rd->cone_constraints, rd->cone_constraints_count, k_ragdoll_correction * 0.25f ); - for( int i=0; ipart_count; i++ ){ + for( int i=0; ipart_count; i++ ) + { rb_iter( &rd->parts[i].rb ); v3f w; v3_copy( rd->parts[i].rb.w, w ); - if( v3_length2( w ) > 0.00001f ){ + if( v3_length2( w ) > 0.00001f ) + { v3_normalize( w ); - v3_muladds( rd->parts[i].rb.w, w, -k_ragdoll_angular_drag, - rd->parts[i].rb.w ); + v3_muladds( rd->parts[i].rb.w, w, -k_ragdoll_angular_drag, rd->parts[i].rb.w ); } } @@ -535,19 +517,19 @@ void player_ragdoll_iter( struct player_ragdoll *rd ) } rb_ct *stress = NULL; - float max_stress = 1.0f; - - for( u32 i=0; ico, ct->rba->co, ra ); v3_sub( ct->co, ct->rbb->co, rb ); rb_rcv( ct->rba, ct->rbb, ra, rb, rv ); - float vn = v3_dot( rv, ct->n ); - - float s = fabsf(vn - contact_velocities[i]); - if( s > max_stress ){ + f32 vn = v3_dot( rv, ct->n ); + f32 s = fabsf(vn - contact_velocities[i]); + if( s > max_stress ) + { stress = ct; max_stress = s; } @@ -558,14 +540,13 @@ void player_ragdoll_iter( struct player_ragdoll *rd ) /* * motorized joints */ - if( run_sim && - (v3_length2(player_dead.v_lpf)>(k_ragdoll_active_threshold* - k_ragdoll_active_threshold)) ){ + if( run_sim && (v3_length2(player_dead.v_lpf)>(k_ragdoll_active_threshold*k_ragdoll_active_threshold)) ) + { ms_keyframe anim[32]; - skeleton_sample_anim( &localplayer.skeleton, &player_dead.anim_bail, - 0.0f, anim ); + skeleton_sample_anim( &localplayer.skeleton, &player_dead.anim_bail, 0.0f, anim ); - for( u32 i=0; icone_constraints_count; i ++ ){ + for( u32 i=0; icone_constraints_count; i ++ ) + { rb_constr_swingtwist *st = &rd->cone_constraints[i]; rb_constr_pos *pc = &rd->position_constraints[i]; @@ -615,7 +596,8 @@ void player_ragdoll_iter( struct player_ragdoll *rd ) } } - if( temp_filter ){ + if( temp_filter ) + { temp_filter --; return; } diff --git a/src/player_ragdoll.h b/src/player_ragdoll.h index b47bdca..4dfad90 100644 --- a/src/player_ragdoll.h +++ b/src/player_ragdoll.h @@ -1,15 +1,6 @@ -#pragma once - -/* - * Copyright (C) 2021-2024 Mt.ZERO Software - All Rights Reserved - * - * Ragdoll system - */ - -#include "player_api.h" -#include "skeleton.h" -#include "vg/vg_rigidbody.h" -#include "vg/vg_rigidbody_constraints.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player_ragdoll.c" +#else struct player_ragdoll{ struct ragdoll_part{ @@ -51,22 +42,15 @@ struct player_ragdoll{ int shoes[2]; }; -enum player_die_type { - k_player_die_type_generic, - k_player_die_type_head, - k_player_die_type_feet, - k_player_die_type_water -}; +VG_API void _player_ragdoll_register(void); -void player_ragdoll_register(void); -void player_init_ragdoll_bone_collider( struct skeleton_bone *bone, - struct ragdoll_part *rp ); +void player_init_ragdoll_bone_collider( ms_skeleton_bone *bone, struct ragdoll_part *rp ); u32 ragdoll_bone_parent( struct player_ragdoll *rd, u32 bone_id ); -void setup_ragdoll_from_skeleton( struct skeleton *sk, - struct player_ragdoll *rd ); +void setup_ragdoll_from_skeleton( ms_skeleton *sk, struct player_ragdoll *rd ); void copy_ragdoll_pose_to_localplayer( struct player_ragdoll *rd ); -void copy_localplayer_to_ragdoll( struct player_ragdoll *rd, - enum player_die_type type ); +void copy_localplayer_to_ragdoll( struct player_ragdoll *rd, enum player_die_type type ); void player_debug_ragdoll(void); void player_ragdoll_iter( struct player_ragdoll *rd ); + +#endif diff --git a/src/player_remote.c b/src/player_remote.c index a72e970..3b3b0b0 100644 --- a/src/player_remote.c +++ b/src/player_remote.c @@ -1,16 +1,3 @@ -#include "player_remote.h" -#include "skeleton.h" -#include "player_render.h" -#include "player_api.h" -#include "network_common.h" -#include "addon.h" -#include "font.h" -#include "gui.h" -#include "ent_region.h" -#include "shaders/model_entity.h" -#include "vg/vg_steam2.h" -#include "vg/vg_magi.h" - struct global_netplayers netplayers; static i32 k_show_own_name = 0; @@ -34,7 +21,7 @@ static void player_remote_clear( u32 player_index ) { menu_close(); /* sets state to default */ menu_open( k_menu_page_quick ); - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); localplayer.immobile = 0; } } @@ -493,7 +480,7 @@ void pose_remote_player( f64 pose_time, struct interp_frame *i0, struct interp_f struct player_effects_data *out_effects, bool *out_render_glider, vg_camera *out_camera ) { - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; struct player_subsystem_interface *sys0 = player_subsystems[i0->subsystem], *sys1 = NULL; @@ -658,7 +645,7 @@ void animate_remote_player( u32 index ) } struct network_player *player = &netplayers.list[ index ]; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; m4x3f *final_mtx = &netplayers.final_mtx[ sk->bone_count*index ]; v3f *glider_mtx = netplayers.glider_mtx[ index ]; struct player_board_pose *board_pose = &netplayers.board_poses[index]; @@ -724,7 +711,7 @@ void render_remote_players( world_instance *world, vg_camera *cam ) gliders ++; } - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; for( u32 j=0; jtransform[3] ); shader_model_entity_uPv( cam->mtx.pv ); - - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_entity ); + WORLD_LINK_LIGHTING( world, model_entity ); for( u32 j=0; jroot_co of remote player */ -static void remote_player_position( int id, v3f out_co ){ - struct skeleton *sk = &localplayer.skeleton; +static void remote_player_position( int id, v3f out_co ) +{ + ms_skeleton *sk = &localplayer.skeleton; m4x3f *final_mtx = &netplayers.final_mtx[ sk->bone_count*id ]; v3_copy( final_mtx[0][3], out_co ); } @@ -851,8 +838,8 @@ static int player_tag_position( m4x4f pv, v3f root_co, ui_point out_point ){ float k_max = 32000.0f; - out_point[0] = vg_clampf(wpos[0] * vg.window_x, -k_max, k_max ); - out_point[1] = vg_clampf((1.0f-wpos[1]) * vg.window_y, -k_max, k_max ); + out_point[0] = vg_clampf(wpos[0] * _vg_window.w, -k_max, k_max ); + out_point[1] = vg_clampf((1.0f-wpos[1]) * _vg_window.h, -k_max, k_max ); return 1; } else @@ -921,7 +908,7 @@ static void remote_player_nametag( ui_context *ctx, ui_point tag_root, #if 0 vg_strcatch( &str, (char)k_SRglyph_vg_circle ); #endif - vg_strcati32( &str, player->medals[i] ); + vg_strcati64( &str, player->medals[i], 10 ); ui_text( ctx, col, buf, 1, k_ui_align_middle_center, ui_colour( ctx, (enum ui_scheme_colour[]){ @@ -995,7 +982,7 @@ void remote_players_imgui_lobby( ui_context *ctx ) return; ui_px y = 50, width = 200, height = 42, gap = 2, - x = vg.window_x - width; + x = _vg_window.w - width; ctx->font = &vgf_default_large; ui_text( ctx, (ui_rect){ x, 0, width, height }, "In World", 1, k_ui_align_middle_center, 0 ); @@ -1097,7 +1084,7 @@ void remote_players_chat_imgui( ui_context *ctx ) if( netplayers.chatting == 1 ) { ui_rect box = { 0, 0, 400, 40 }, - window = { 0, 0, vg.window_x, vg.window_y }; + window = { 0, 0, _vg_window.w, _vg_window.h }; ui_rect_center( window, box ); struct ui_textbox_callbacks callbacks = @@ -1243,14 +1230,14 @@ static int cmd_network_info( int argc, const char *argv[] ) return 1; } -void remote_players_register(void) +VG_API void _remote_players_register(void) { vg_console_reg_cmd( "network_info", cmd_network_info, NULL ); vg_console_reg_cmd( "add_test_players", remote_players_randomize, NULL ); vg_console_reg_var( "k_show_own_name", &k_show_own_name, k_var_dtype_i32, 0 ); } -void remote_players_init(void) +VG_API void _remote_players_init(void) { for( u32 i=0; iactive || !player->same_world ) { - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); localplayer.immobile = 0; skaterift.activity = k_skaterift_default; return; diff --git a/src/player_remote.h b/src/player_remote.h index d411978..125cc0e 100644 --- a/src/player_remote.h +++ b/src/player_remote.h @@ -1,16 +1,6 @@ -#pragma once -#include "player.h" -#include "network.h" -#include "network_common.h" -#include "player_render.h" -#include "player_effects.h" -#include "player_api.h" - -#include "player_skate.h" -#include "player_walk.h" -#include "player_dead.h" -#include "player_basic_info.h" -#include "player_glide.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player_remote.c" +#else #define NETWORK_SFX_QUEUE_LENGTH 12 @@ -51,7 +41,8 @@ struct global_netplayers u32 spectate_index; vg_camera spectate_camera; - struct interp_buffer { + struct interp_buffer + { /* collect the most recent 6 frames of animation data */ struct interp_frame { @@ -96,6 +87,9 @@ struct global_netplayers } extern netplayers; +VG_API void _remote_players_register(void); +VG_API void _remote_players_init(void); + void player_remote_rx_200_300( SteamNetworkingMessage_t *msg ); void remote_player_debug_update(void); void remote_player_send_playerframe(void); @@ -104,8 +98,6 @@ void animate_remote_players(void); void render_remote_players( world_instance *world, vg_camera *cam ); void relink_all_remote_player_worlds(void); void player_remote_update_friendflags( struct network_player *remote ); -void remote_players_register(void); -void remote_players_init(void); void remote_sfx_pre_update(void); void remote_players_imgui_world( ui_context *ctx, world_instance *world, m4x4f pv, f32 max_dist, int geo_cull ); void remote_players_imgui_lobby( ui_context *ctx ); @@ -120,3 +112,5 @@ void pose_remote_player( f64 pose_time, struct interp_frame *f0, struct interp_f void decode_playerframe( netmsg_playerframe *frame, u32 data_length, struct interp_frame *dest, struct net_sfx *sfx_buffer, u32 *inout_sfx_buffer_len ); void _network_get_spectate_cam( vg_camera *cam ); + +#endif diff --git a/src/player_render.c b/src/player_render.c index 62d2cfd..28e5319 100644 --- a/src/player_render.c +++ b/src/player_render.c @@ -1,58 +1,10 @@ -#include "player.h" -#include "player_render.h" -#include "vg/vg_camera.h" -#include "player_model.h" -#include "ent_skateshop.h" -#include "audio.h" -#include "input.h" - -#include "shaders/model_character_view.h" -#include "shaders/model_board_view.h" -#include "shaders/model_entity.h" -#include "shaders/model_board_view.h" -#include "depth_compare.h" - -#include "network.h" -#include "player_remote.h" -#include "player_glide.h" -#include "metascene.h" - -void player_load_animations( const char *path ) +static void _player_render_load_content_async( void *_, vg_async_info *async ) { - metascene_load( &localplayer.animations, path, &vg.rtmem ); -} - -void player_get_anim( skeleton_anim *out_anim, const char *name ) -{ - ms_context *ms = &localplayer.animations; - u32 hash = vg_strdjb2( name ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); - for( u32 i=0; istrips ); i ++ ) - { - ms_strip *strip = af_arritm( &ms->strips, i ); - if( strip->mode != k_ms_strip_mode_keyframes ) - continue; - - if( af_str_eq( &ms->af, strip->strip.pstr_name, name, hash ) ) - { - out_anim->strip = strip; - out_anim->framerate = localplayer.animations.info.framerate; - out_anim->keyframes_base = af_arritm( &localplayer.animations.keyframes, strip->strip.start ); - return; - } - } - vg_fatal_error( "Failed to find animation '%s' in metascene.\n", name ); -} - -void player_load_animation_reference( const char *path ) -{ - mdl_context *meta = &localplayer.skeleton_meta; - mdl_open( meta, path, &vg.rtmem ); - mdl_load_metadata_block( meta, &vg.rtmem ); - mdl_close( meta ); - - struct skeleton *sk = &localplayer.skeleton; - skeleton_setup( sk, meta, 0, &vg.rtmem ); + vg_model_load( &localplayer.skeleton_meta, VG_MODEL_CPU_METADATA, "models/ch_none.mdl", NULL ); + ms_skeleton *sk = &localplayer.skeleton; + skeleton_setup( sk, &localplayer.skeleton_meta, 0, VG_STACK_USE_HEAP ); localplayer.id_world = skeleton_bone_id( sk, "world" ); localplayer.id_hip = skeleton_bone_id( sk, "hips" ); @@ -73,27 +25,29 @@ void player_load_animation_reference( const char *path ) localplayer.id_ik_knee_r = skeleton_bone_id( sk, "knee.R" ); localplayer.id_eyes = skeleton_bone_id( sk, "eyes" ); - for( i32 i=0; ibone_count; i ++ ){ + for( i32 i=0; ibone_count; i ++ ) localplayer.skeleton_mirror[i] = 0; - } - - for( i32 i=1; ibone_count-1; i ++ ){ - struct skeleton_bone *si = &sk->bones[i]; + for( i32 i=1; ibone_count-1; i ++ ) + { + ms_skeleton_bone *si = &sk->bones[i]; char tmp[64]; vg_str str; vg_strnull( &str, tmp, 64 ); vg_strcat( &str, si->name ); char *L = vg_strch( &str, 'L' ); - if( !L ) continue; + if( !L ) + continue; u32 len = L-tmp; - for( i32 j=i+1; jbone_count; j ++ ){ - struct skeleton_bone *sj = &sk->bones[j]; - - if( !strncmp( si->name, sj->name, len ) ){ - if( sj->name[len] == 'R' ){ + for( i32 j=i+1; jbone_count; j ++ ) + { + ms_skeleton_bone *sj = &sk->bones[j]; + if( !strncmp( si->name, sj->name, len ) ) + { + if( sj->name[len] == 'R' ) + { localplayer.skeleton_mirror[i] = j; localplayer.skeleton_mirror[j] = i; break; @@ -101,87 +55,132 @@ void player_load_animation_reference( const char *path ) } } } - setup_ragdoll_from_skeleton( sk, &localplayer.ragdoll ); - /* allocate matrix buffers for localplayer and remote players */ + /* allocate matrix buffers for localplayer and remote players. uh this is a bit crappy? */ u32 mtx_size = sizeof(m4x3f)*sk->bone_count; - localplayer.final_mtx = vg_stack_allocate( &vg.rtmem, mtx_size, 8, "Final MTX" ); - netplayers.final_mtx = vg_stack_allocate( &vg.rtmem, mtx_size*NETWORK_MAX_PLAYERS, 8, "Network final MTX" ); - netplayers.glider_mtx = vg_stack_allocate( &vg.rtmem, sizeof(m4x3f)*NETWORK_MAX_PLAYERS, 8, "Glider MTX" ); + localplayer.final_mtx = vg_stack_allocate( VG_STACK_USE_HEAP, mtx_size, 8, "Final MTX" ); + netplayers.final_mtx = vg_stack_allocate( VG_STACK_USE_HEAP, mtx_size*NETWORK_MAX_PLAYERS, 8, "Network final MTX" ); + netplayers.glider_mtx = vg_stack_allocate( VG_STACK_USE_HEAP, sizeof(m4x3f)*NETWORK_MAX_PLAYERS, 8, "Glider MTX" ); + _replay2.final_mtx = vg_stack_allocate( VG_STACK_USE_HEAP, mtx_size, 8, "Replay Final MTX" ); + metascene_load( &localplayer.animations, "metascenes/skater.ms", NULL ); + + player_model_load( &localplayer.fallback_model, "models/ch_none.mdl", VG_STACK_USE_HEAP ); + player_board_load( &localplayer.fallback_board, "models/board_none.mdl", VG_STACK_USE_HEAP ); + vg_model_load( &localplayer.battery, VG_MODEL_ENGINE_STANDARD, "models/battery.mdl", VG_STACK_USE_HEAP ); + + for( u32 i=0; iload_resources ) + sys->load_resources(); + } +} + +VG_API void _player_render_init(void) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_player_render_load_content_async ); +} + +void player_get_anim( ms_skeletal_animation *out_anim, const char *name ) +{ + metascene *ms = &localplayer.animations; + u32 hash = vg_strdjb2( name ); + + for( u32 i=0; istrips ); i ++ ) + { + ms_strip *strip = af_arritm( &ms->strips, i ); + if( strip->mode != k_ms_strip_mode_keyframes ) + continue; + + if( af_str_eq( ms->packed_strings, strip->strip.pstr_name, name, hash ) ) + { + out_anim->strip = strip; + out_anim->framerate = localplayer.animations.info.framerate; + out_anim->keyframes_base = af_arritm( &localplayer.animations.keyframes, strip->strip.start ); + return; + } + } + vg_fatal_error( "Failed to find animation '%s' in metascene.\n", name ); } /* TODO: allow error handling */ -void player_board_load( player_board *board, const char *path, void *arena ) +void player_board_load( player_board *board, const c8 *path, vg_stack_allocator *stack ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); - mdl_open( &board->mdl, path, arena ); - mdl_load_metadata_block( &board->mdl, arena ); - mdl_async_full_load_std( &board->mdl, NULL ); + vg_model_stream_context ctx; + VG_ASSERT( vg_model_stream_open( &ctx, &board->model, path ) ); + vg_model_stream_metadata( &ctx, stack ); + vg_model_stream_meshes_gpu( &ctx, NULL ); + vg_model_stream_textures_gpu( &ctx ); array_file_ptr markers; - AF_LOAD_ARRAY_STRUCT( &board->mdl.af, &markers, ent_marker, &vg.scratch ); - + AF_LOAD_ARRAY_STRUCT( &ctx.af, &markers, ent_marker, _vg_temp_stack() ); for( int i=0; i<4; i++ ) board->wheels[i].indice_count = 0; for( int i=0; i<2; i++ ) board->trucks[i].indice_count = 0; board->board.indice_count = 0; - for( u32 i=0; imdl.mesh_count; i++ ) + for( u32 i=0; imodel.mesh_count; i++ ) { - mdl_mesh *mesh = &board->mdl.meshes[ i ]; - + mdl_mesh *mesh = &board->model.meshes[ i ]; if( mdl_entity_id_type( mesh->entity_id ) != k_ent_marker ) continue; u32 index = mdl_entity_id_id( mesh->entity_id ); ent_marker *marker = af_arritm( &markers, index ); - mdl_submesh *sm0 = &board->mdl.submeshes[ mesh->submesh_start ]; + mdl_submesh *sm0 = &board->model.submeshes[ mesh->submesh_start ]; - const char *alias = af_str( &board->mdl.af, marker->pstr_alias ); + const char *alias = af_str( board->model.packed_strings, marker->pstr_alias ); u32 lr = marker->transform.co[0] > 0.0f? 1: 0, fb = marker->transform.co[2] > 0.0f? 0: 1; - if( !strcmp( alias, "wheel" ) ){ + if( !strcmp( alias, "wheel" ) ) + { u32 id = fb<<1 | lr; board->wheels[ id ] = *sm0; v3_copy( marker->transform.co, board->wheel_positions[ id ] ); } - else if( !strcmp( alias, "board" ) ){ + else if( !strcmp( alias, "board" ) ) + { board->board = *sm0; v3_copy( marker->transform.co, board->board_position ); } - else if( !strcmp( alias, "truck" ) ){ + else if( !strcmp( alias, "truck" ) ) + { board->trucks[ fb ] = *sm0; v3_copy( marker->transform.co, board->truck_positions[ fb ] ); } } - mdl_close( &board->mdl ); + vg_model_stream_close( &ctx ); } void player_board_unload( struct player_board *board ) { - THREAD_0; - mdl_sync_std_unload( &board->mdl ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + vg_model_unload_gpu( &board->model ); } -void player_model_load( player_model *pm, const char *path, void *arena ) +void player_model_load( player_model *pm, const c8 *path, vg_stack_allocator *stack ) { + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); pm->flags = 0x0; - mdl_open( &pm->mdl, path, arena ); - mdl_load_metadata_block( &pm->mdl, arena ); - AF_LOAD_ARRAY_STRUCT( &pm->mdl.af, &pm->editer_property, editer_property, arena ); - AF_LOAD_ARRAY_STRUCT( &pm->mdl.af, &pm->editer_item, editer_item, arena ); + vg_model_stream_context ctx; + VG_ASSERT( vg_model_stream_open( &ctx, &pm->model, path ) ); + vg_model_stream_metadata( &ctx, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &pm->editer_property, editer_property, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &pm->editer_item, editer_item, stack ); if( af_arrcount( &pm->editer_item ) ) pm->flags |= PLAYER_MODEL_FLAG_CUSTOMIZABLE; - VG_ASSERT( pm->mdl.armature_count ); - mdl_armature *armature = &pm->mdl.armatures[ 0 ]; + VG_ASSERT( pm->model.armature_count ); + mdl_armature *armature = &pm->model.armatures[ 0 ]; u32 fixup_table[ armature->bone_count+1 ]; for( u32 i=0; ibone_count+1; i ++ ) @@ -189,16 +188,16 @@ void player_model_load( player_model *pm, const char *path, void *arena ) for( u32 i=1; iname ); bool found = 0; for( u32 j=1; jbone_count; j ++ ) { - mdl_bone *bone = &pm->mdl.bones[ armature->bone_start+j ]; + mdl_bone *bone = &pm->model.bones[ armature->bone_start+j ]; - if( af_str_eq( &pm->mdl.af, bone->pstr_name, sb->name, hash ) ) + if( af_str_eq( pm->model.packed_strings, bone->pstr_name, sb->name, hash ) ) { fixup_table[j+1] = i; found = 1; @@ -210,34 +209,33 @@ void player_model_load( player_model *pm, const char *path, void *arena ) vg_low( "Reference skeleton has a bone called '%s', retargetee has no such bone..\n", sb->name ); } - mdl_async_full_load_std( &pm->mdl, fixup_table ); - mdl_close( &pm->mdl ); + vg_model_stream_meshes_gpu( &ctx, fixup_table ); + vg_model_stream_close( &ctx ); } void player_model_unload( player_model *pm ) { - THREAD_0; - mdl_sync_std_unload( &pm->mdl ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + vg_model_unload_gpu( &pm->model ); } -void apply_full_skeleton_pose( struct skeleton *sk, player_pose *pose, - m4x3f *final_mtx ){ +void apply_full_skeleton_pose( ms_skeleton *sk, player_pose *pose, m4x3f *final_mtx ) +{ m4x3f transform; q_m3x3( pose->root_q, transform ); v3_copy( pose->root_co, transform[3] ); - if( pose->type == k_player_pose_type_ik ){ - skeleton_apply_pose( sk, pose->keyframes, - k_anim_apply_defer_ik, final_mtx ); + if( pose->type == k_player_pose_type_ik ) + { + skeleton_apply_pose( sk, pose->keyframes, k_anim_apply_defer_ik, final_mtx ); skeleton_apply_ik_pass( sk, final_mtx ); - skeleton_apply_pose( sk, pose->keyframes, - k_anim_apply_deffered_only, final_mtx ); + skeleton_apply_pose( sk, pose->keyframes, k_anim_apply_deffered_only, final_mtx ); skeleton_apply_inverses( sk, final_mtx ); skeleton_apply_transform( sk, transform, final_mtx ); } - else if( pose->type == k_player_pose_type_fk_2 ){ - skeleton_apply_pose( sk, pose->keyframes, - k_anim_apply_always, final_mtx ); + else if( pose->type == k_player_pose_type_fk_2 ) + { + skeleton_apply_pose( sk, pose->keyframes, k_anim_apply_always, final_mtx ); skeleton_apply_inverses( sk, final_mtx ); skeleton_apply_transform( sk, transform, final_mtx ); } @@ -255,7 +253,7 @@ void player__animate(void) player_pose *pose = &localplayer.pose; sys->pose( sys->animator_data, pose ); - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; if( localplayer.holdout_time > 0.0f ) { @@ -298,7 +296,7 @@ static void player_copy_frame_animator( replay_frame *frame ) void lerp_player_pose( player_pose *pose0, player_pose *pose1, f32 t, player_pose *posed ) { - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; v3_lerp( pose0->root_co, pose1->root_co, t, posed->root_co ); q_nlerp( pose0->root_q, pose1->root_q, t, posed->root_q ); @@ -341,7 +339,7 @@ void player__pre_render(void) v3_zero( vp1 ); } - struct ub_world_lighting *ubo = &_world.main.ub_lighting; + struct ub_world_lighting *ubo = &world_render.ub_lighting; v3f *board_mtx = localplayer.final_mtx[ localplayer.id_board ]; m4x3_mulv( board_mtx, vp0, ubo->g_board_0 ); m4x3_mulv( board_mtx, vp1, ubo->g_board_1 ); @@ -350,7 +348,7 @@ void player__pre_render(void) void render_board( vg_camera *cam, world_instance *world, struct player_board *board, m4x3f root, struct player_board_pose *pose, - enum board_shader shader ) +enum board_shader shader ) { if( !board ) board = &localplayer.fallback_board; @@ -360,11 +358,8 @@ void render_board( vg_camera *cam, world_instance *world, */ v3f inverse; - - VG_ASSERT( board->mdl.texture_count ); - - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, board->mdl.textures[0].glname ); + VG_ASSERT( board->model.texture_count ); + vg_tex_bind( GL_TEXTURE_2D, &board->model.textures[0].tex, 0 ); if( shader == k_board_shader_player ) { @@ -380,7 +375,7 @@ void render_board( vg_camera *cam, world_instance *world, shader_model_board_view_uInverseRatioMain, cam ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_board_view ); + WORLD_LINK_LIGHTING( world, model_board_view ); } else if( shader == k_board_shader_entity ) { @@ -389,11 +384,10 @@ void render_board( vg_camera *cam, world_instance *world, shader_model_entity_uCamera( cam->transform[3] ); shader_model_entity_uPv( cam->mtx.pv ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_entity ); + WORLD_LINK_LIGHTING( world, model_entity ); } - mesh_bind( &board->mdl.mesh ); - + vg_model_bind_mesh( &board->model ); m4x4f m4mdl; if( board->board.indice_count ) @@ -424,8 +418,7 @@ void render_board( vg_camera *cam, world_instance *world, } else shader_model_board_view_uMdl( mlocal ); - - mdl_draw_submesh( &board->board ); + vg_model_draw_submesh( &board->board ); } for( int i=0; i<2; i++ ){ @@ -437,7 +430,8 @@ void render_board( vg_camera *cam, world_instance *world, v3_copy( board->truck_positions[i], mlocal[3] ); m4x3_mul( root, mlocal, mlocal ); - if( shader == k_board_shader_entity ){ + if( shader == k_board_shader_entity ) + { m4x3_expand( mlocal, m4mdl ); m4x4_mul( cam->mtx_prev.pv, m4mdl, m4mdl ); shader_model_entity_uPvmPrev( m4mdl ); @@ -446,7 +440,7 @@ void render_board( vg_camera *cam, world_instance *world, else shader_model_board_view_uMdl( mlocal ); - mdl_draw_submesh( &board->trucks[i] ); + vg_model_draw_submesh( &board->trucks[i] ); } for( int i=0; i<4; i++ ){ @@ -458,7 +452,8 @@ void render_board( vg_camera *cam, world_instance *world, v3_copy( board->wheel_positions[i], mlocal[3] ); m4x3_mul( root, mlocal, mlocal ); - if( shader == k_board_shader_entity ){ + if( shader == k_board_shader_entity ) + { m4x3_expand( mlocal, m4mdl ); m4x4_mul( cam->mtx_prev.pv, m4mdl, m4mdl ); shader_model_entity_uPvmPrev( m4mdl ); @@ -467,14 +462,14 @@ void render_board( vg_camera *cam, world_instance *world, else shader_model_board_view_uMdl( mlocal ); - mdl_draw_submesh( &board->wheels[i] ); + vg_model_draw_submesh( &board->wheels[i] ); } } void render_playermodel( vg_camera *cam, world_instance *world, int depth_compare, player_model_view *view, - struct skeleton *skeleton, + ms_skeleton *skeleton, m4x3f *final_mtx ) { bool fallback = 0; @@ -489,9 +484,8 @@ void render_playermodel( vg_camera *cam, world_instance *world, shader_model_character_view_use(); - glActiveTexture( GL_TEXTURE0 ); - VG_ASSERT( model->mdl.texture_count ); - glBindTexture( GL_TEXTURE_2D, model->mdl.textures[0].glname ); + VG_ASSERT( model->model.texture_count ); + vg_tex_bind( GL_TEXTURE_2D, &model->model.textures[0].tex, 0 ); shader_model_character_view_uTexMain( 0 ); shader_model_character_view_uCamera( cam->transform[3] ); @@ -509,15 +503,10 @@ void render_playermodel( vg_camera *cam, world_instance *world, cam ); } - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_character_view ); - - glUniformMatrix4x3fv( _uniform_model_character_view_uTransforms, - skeleton->bone_count, - 0, - (const GLfloat *)final_mtx ); + WORLD_LINK_LIGHTING( world, model_character_view ); + shader_model_character_view_uTransforms( final_mtx, skeleton->bone_count ); - mesh_bind( &model->mdl.mesh ); - + vg_model_bind_mesh( &model->model ); if( !fallback && (model->flags & PLAYER_MODEL_FLAG_CUSTOMIZABLE) ) { if( view->cpart_dirty ) @@ -536,13 +525,23 @@ void render_playermodel( vg_camera *cam, world_instance *world, if( (0x1 << j) & item->discard_mask & view->discard ) continue; - mdl_submesh *sm = &model->mdl.submeshes[ item->submesh_start + j ]; - mdl_draw_submesh( sm ); + mdl_submesh *sm = &model->model.submeshes[ item->submesh_start + j ]; + vg_model_draw_submesh( sm ); } } } else - mesh_draw( &model->mdl.mesh ); + { + for( u32 i=0; imodel.mesh_count; i ++ ) + { + mdl_mesh *mesh = &model->model.meshes[ i ]; + for( u32 j=0; jsubmesh_count; j ++ ) + { + mdl_submesh *sm = &model->model.submeshes[ mesh->submesh_start+j ]; + vg_model_draw_submesh( sm ); + } + } + } } void player__render( vg_camera *cam ) @@ -560,7 +559,7 @@ void player__render( vg_camera *cam ) if( localplayer.has_battery ) { ms_keyframe kf_backpack; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; m4x3_mulv( localplayer.final_mtx[localplayer.id_chest ], sk->bones[localplayer.id_chest].co, kf_backpack.co ); v4f qyaw, qpitch, qchest, q; @@ -585,8 +584,7 @@ void player__render( vg_camera *cam ) void player_mirror_pose( ms_keyframe pose[32], ms_keyframe mirrored[32] ) { ms_keyframe temp[32]; - - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; for( u32 i=1; ibone_count; i ++ ) { ms_keyframe *dest = &temp[i-1]; @@ -660,7 +658,7 @@ void playermodel_create_binary_configuration( player_model_view *view, struct pl view->property_values[i]._f32 = ((f32)(c - (u8)'A') / (f32)((u8)'Z' - (u8)'A')) * prop->max._f32; else if( prop->ui_type == k_editer_type_selecter ) { - const char *options = af_str( &model->mdl.af, prop->max.pstr_options ); + const char *options = af_str( model->model.packed_strings, prop->max.pstr_options ); bool valid = 0; for( u32 j=0; options[j]; j ++ ) { @@ -686,7 +684,7 @@ void playermodel_create_binary_configuration( player_model_view *view, struct pl for( u32 i=0; iediter_item ); i ++ ) { editer_item *item = af_arritm( &model->editer_item, i ); - const char *visibility_string = af_str( &model->mdl.af, item->pstr_visibility ); + const char *visibility_string = af_str( model->model.packed_strings, item->pstr_visibility ); bool visible = 1; u32 hash; @@ -738,9 +736,9 @@ void playermodel_create_binary_configuration( player_model_view *view, struct pl if( prop->ui_type == k_editer_type_slider ) continue; - if( af_str_hash( &model->mdl.af, prop->pstr_alias ) == hash ) + if( af_str_hash( model->model.packed_strings, prop->pstr_alias ) == hash ) { - const char *alias = af_str( &model->mdl.af, prop->pstr_alias ); + const c8 *alias = af_str( model->model.packed_strings, prop->pstr_alias ); bool matched = 1; for( u32 l=0; l < (j-token_j); l ++ ) { diff --git a/src/player_render.h b/src/player_render.h index f3c57ac..0d2a75e 100644 --- a/src/player_render.h +++ b/src/player_render.h @@ -1,10 +1,6 @@ -#pragma once -#include "model.h" -#include "skeleton.h" -#include "vg/vg_camera.h" -#include "world.h" -#include "player_render.h" -#include "player_api.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player_render.c" +#else enum eboard_truck{ k_board_truck_back = 0, @@ -21,8 +17,7 @@ enum eboard_wheel{ typedef struct player_board player_board; struct player_board { - mdl_context mdl; - + vg_model model; v4f wheel_positions[4], truck_positions[2], board_position; @@ -37,7 +32,7 @@ struct player_board typedef struct player_model player_model; struct player_model { - mdl_context mdl; + vg_model model; u32 flags; array_file_ptr editer_property, editer_item; u32 list_id_heads; @@ -75,10 +70,12 @@ enum board_shader{ k_board_shader_entity }; -void player_board_load( player_board *board, const char *path, void *arena ); +VG_API void _player_render_init(void); + +void player_board_load( player_board *board, const c8 *path, vg_stack_allocator *stack ); void player_board_unload( player_board *mdl ); -void player_model_load( player_model *pm, const char *path, void *arena ); +void player_model_load( player_model *pm, const c8 *path, vg_stack_allocator *stack ); void player_model_unload( player_model *pm ); void render_board( vg_camera *cam, world_instance *world, @@ -89,9 +86,9 @@ void render_board( vg_camera *cam, world_instance *world, void render_playermodel( vg_camera *cam, world_instance *world, int depth_compare, player_model_view *playermodel, - struct skeleton *skeleton, + ms_skeleton *skeleton, m4x3f *final_mtx ); -void apply_full_skeleton_pose( struct skeleton *sk, player_pose *pose, m4x3f *final_mtx ); +void apply_full_skeleton_pose( ms_skeleton *sk, player_pose *pose, m4x3f *final_mtx ); void lerp_player_pose( player_pose *pose0, player_pose *pose1, f32 t, player_pose *posed ); void player_mirror_pose( ms_keyframe pose[32], ms_keyframe mirrored[32] ); void player__observe_system( enum player_subsystem id ); @@ -105,3 +102,5 @@ void playermodel_get_cpart( player_model_view *view, struct player_model *model, void playermodel_use_cpart( player_model_view *model, const char cpart[ ADDON_CPART_MAX ] ); void playermodel_create_binary_configuration( player_model_view *view, struct player_model *model ); void playermodel_set_from_uid( player_model_view *model, const char uid[ ADDON_UID_MAX ] ); + +#endif diff --git a/src/player_skate.c b/src/player_skate.c index 29e3b35..339ee19 100644 --- a/src/player_skate.c +++ b/src/player_skate.c @@ -1,26 +1,8 @@ -#include "player_skate.h" -#include "player.h" -#include "audio.h" -#include "vg/vg_perlin.h" -#include "vg/vg_lines.h" -#include "menu.h" -#include "ent_skateshop.h" -#include "addon.h" -#include "input.h" -#include "ent_tornado.h" - -#include "vg/vg_rigidbody.h" -#include "scene_rigidbody.h" -#include "player_glide.h" -#include "player_dead.h" -#include "player_walk.h" -#include - struct player_skate player_skate; struct player_subsystem_interface player_subsystem_skate = { .system_register = player__skate_register, - .bind = player__skate_bind, + .load_resources = player__skate_load_resources, .pre_update = player__skate_pre_update, .update = player__skate_update, .transport = player__skate_transport, @@ -40,12 +22,13 @@ struct player_subsystem_interface player_subsystem_skate = .name = "Skate" }; -void player__skate_bind(void){ - struct skeleton *sk = &localplayer.skeleton; - rb_update_matrices( &localplayer.rb ); - - struct { struct skeleton_anim *anim; const char *name; } - bindings[] = { +void player__skate_load_resources(void) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + ms_skeleton *sk = &localplayer.skeleton; + struct { ms_skeletal_animation *anim; const char *name; } + bindings[] = + { { &player_skate.anim_grind, "pose_grind" }, { &player_skate.anim_grind_jump, "pose_grind_jump" }, { &player_skate.anim_stand, "pose_stand" }, @@ -64,6 +47,11 @@ void player__skate_bind(void){ player_get_anim( bindings[i].anim, bindings[i].name ); } +void player__skate_init(void) +{ + rb_update_matrices( &localplayer.rb ); +} + void player__skate_kill_audio(void) { vg_audio_lock(); @@ -96,17 +84,16 @@ static int skate_collide_smooth( m4x3f mtx, f32 r, rb_ct *man ){ world_instance *world = &_world.main; int len = 0; - len = rb_sphere__scene( mtx, r, NULL, world->geo_bh, man, - k_material_flag_walking ); - - for( int i=0; igeometry_bh, man, k_material_flag_walking ); + for( int i=0; i 1 ){ + if( len > 1 ) + { rb_manifold_filter_backface( man, len ); rb_manifold_filter_joint_edges( man, len, 0.03f ); rb_manifold_filter_pairs( man, len, 0.03f ); @@ -158,8 +145,9 @@ static int skate_grind_scansq( v3f pos, v3f dir, float r, bh_iter_init_box( 0, &it, box ); i32 idx; - while( bh_next( world->geo_bh, &it, &idx ) ){ - u32 *ptri = &world->scene_geo.arrindices[ idx*3 ]; + while( bh_next( &world->geometry_bh, &it, &idx ) ) + { + u32 *ptri = &world->scene_geometry.indice_buffer[ idx*3 ]; v3f tri[3]; struct world_surface *surf = world_tri_index_surface(world,ptri[0]); @@ -167,7 +155,7 @@ static int skate_grind_scansq( v3f pos, v3f dir, float r, continue; for( int j=0; j<3; j++ ) - v3_copy( world->scene_geo.arrvertices[ptri[j]].co, tri[j] ); + v3_copy( world->scene_geometry.vertex_buffer[ptri[j]].co, tri[j] ); for( int j=0; j<3; j++ ){ int i0 = j, @@ -468,7 +456,7 @@ void player__approximate_best_trajectory(void) v3f closest={0.0f,0.0f,0.0f}; if( search_for_grind ) { - if( bh_closest_point(trace_world->geo_bh,co1,closest,1.0f) != -1 ) + if( bh_closest_point( &trace_world->geometry_bh,co1,closest,1.0f ) != -1 ) { float min_dist = 0.75f; min_dist *= min_dist; @@ -552,7 +540,7 @@ void player__approximate_best_trajectory(void) v3_copy( co, inf->log[ inf->log_length ++ ] ); v3_copy( n, inf->n ); - u32 *tri = &trace_world->scene_geo.arrindices[ idx*3 ]; + u32 *tri = &trace_world->scene_geometry.indice_buffer[ idx*3 ]; struct world_surface *surf = world_tri_index_surface( trace_world, tri[0] ); @@ -1198,18 +1186,18 @@ static enum trick_type player_skate_trick_input(void){ (button_press( k_srbind_trick2 ) ); } -void player__skate_pre_update(void){ +void player__skate_pre_update(void) +{ struct player_skate_state *state = &player_skate.state; - if( state->activity == k_skate_activity_handplant ){ + if( state->activity == k_skate_activity_handplant ) + { state->handplant_t += vg.time_delta; ms_keyframe hpose[32]; - struct skeleton_anim *anim = &player_skate.anim_handplant; + ms_skeletal_animation *anim = &player_skate.anim_handplant; - int end = !skeleton_sample_anim_clamped( - &localplayer.skeleton, anim, - state->handplant_t, hpose ); + int end = !skeleton_sample_anim_clamped( &localplayer.skeleton, anim, state->handplant_t, hpose ); if( state->reverse < 0.0f ) player_mirror_pose( hpose, hpose ); @@ -1619,14 +1607,14 @@ int skate_compute_surface_alignment( v3f ra, u32 colour, else{ /* fallback: use the closes point to the trucks */ v3f closest; - int idx = bh_closest_point( world->geo_bh, midpoint, closest, 0.1f ); - - if( idx != -1 ){ - u32 *tri = &world->scene_geo.arrindices[ idx * 3 ]; + int idx = bh_closest_point( &world->geometry_bh, midpoint, closest, 0.1f ); + if( idx != -1 ) + { + u32 *tri = &world->scene_geometry.indice_buffer[ idx * 3 ]; v3f verts[3]; for( int j=0; j<3; j++ ) - v3_copy( world->scene_geo.arrvertices[ tri[j] ].co, verts[j] ); + v3_copy( world->scene_geometry.vertex_buffer[ tri[j] ].co, verts[j] ); v3f vert0, vert1, n; v3_sub( verts[1], verts[0], vert0 ); @@ -1638,8 +1626,7 @@ int skate_compute_surface_alignment( v3f ra, u32 colour, return 0; v3_cross( n, localplayer.rb.to_world[2], v0 ); - v3_muladds( v0, localplayer.rb.to_world[2], - -v3_dot( localplayer.rb.to_world[2], v0 ), v0 ); + v3_muladds( v0, localplayer.rb.to_world[2], -v3_dot( localplayer.rb.to_world[2], v0 ), v0 ); v3_normalize( v0 ); v3f t; @@ -2325,15 +2312,16 @@ void player__skate_update(void) float slap = 0.0f; - if( state->activity <= k_skate_activity_air_to_grind ){ + if( state->activity <= k_skate_activity_air_to_grind ) + { float min_dist = 0.6f; - for( int i=0; i<2; i++ ){ + for( int i=0; i<2; i++ ) + { v3f wpos, closest; m4x3_mulv( localplayer.rb.to_world, wheels[i].pos, wpos ); - if( bh_closest_point( world->geo_bh, wpos, closest, min_dist ) != -1 ){ + if( bh_closest_point( &world->geometry_bh, wpos, closest, min_dist ) != -1 ) min_dist = vg_minf( min_dist, v3_dist( closest, wpos ) ); - } } min_dist -= 0.2f; float vy = vg_maxf( 0.0f, localplayer.rb.v[1] ); @@ -2603,7 +2591,7 @@ begin_collision:; /* board capsule */ rb_ct *cman = &manifold[manifold_len]; - int l = rb_capsule__scene( mtx, &capsule, NULL, world->geo_bh, cman, k_material_flag_walking ); + int l = rb_capsule__scene( mtx, &capsule, NULL, &world->geometry_bh, cman, k_material_flag_walking ); /* weld joints */ for( int i=0; ihandplant_t = state->handplant_t; } -void player__skate_pose( void *_animator, player_pose *pose ){ - struct skeleton *sk = &localplayer.skeleton; +void player__skate_pose( void *_animator, player_pose *pose ) +{ + ms_skeleton *sk = &localplayer.skeleton; struct player_skate_animator *animator = _animator; pose->type = k_player_pose_type_ik; @@ -3258,19 +3247,15 @@ void player__skate_pose( void *_animator, player_pose *pose ){ skeleton_lerp_pose( sk, bpose, mirrored, animator->z, bpose ); skeleton_lerp_pose( sk, apose, bpose, animator->slide, apose ); - if( animator->reverse > 0.0f ){ - skeleton_sample_anim( sk, &player_skate.anim_push, animator->push_time, - bpose ); - } - else{ - skeleton_sample_anim( sk, &player_skate.anim_push_reverse, - animator->push_time, bpose ); - } + if( animator->reverse > 0.0f ) + skeleton_sample_anim( sk, &player_skate.anim_push, animator->push_time, bpose ); + else + skeleton_sample_anim( sk, &player_skate.anim_push_reverse, animator->push_time, bpose ); skeleton_lerp_pose( sk, apose, bpose, animator->push, apose ); - struct skeleton_anim *jump_anim = animator->jump_dir? - &player_skate.anim_ollie: - &player_skate.anim_ollie_reverse; + ms_skeletal_animation *jump_anim = animator->jump_dir? + &player_skate.anim_ollie: + &player_skate.anim_ollie_reverse; f32 setup_blend = vg_minf( animator->jump, 1.0f ); skeleton_sample_anim_clamped( sk, jump_anim, animator->jump_time, bpose ); @@ -3348,7 +3333,7 @@ void player__skate_pose( void *_animator, player_pose *pose ){ if( animator->activity == k_skate_activity_handplant ) { - struct skeleton_anim *anim = &player_skate.anim_handplant; + ms_skeletal_animation *anim = &player_skate.anim_handplant; ms_keyframe hpose[32]; skeleton_sample_anim_clamped( sk, anim, animator->handplant_t, hpose ); @@ -3537,7 +3522,7 @@ void player__skate_effects( void *_animator, m4x3f *final_mtx, struct player_board *board, struct player_effects_data *effect_data ) { - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; struct player_skate_animator *animator = _animator; v3f vp0, vp1, vpc; diff --git a/src/player_skate.h b/src/player_skate.h index 207873c..4b0dc3d 100644 --- a/src/player_skate.h +++ b/src/player_skate.h @@ -1,7 +1,6 @@ -#pragma once -#include "vg/vg_audio.h" -#include "player.h" -#include "player_api.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player_skate.c" +#else typedef struct jump_info jump_info; @@ -151,12 +150,12 @@ struct player_skate{ /* animation /audio * --------------------------------------------------------------*/ - struct skeleton_anim anim_stand, anim_highg, anim_slide, - anim_air, anim_grind, anim_grind_jump, - anim_push, anim_push_reverse, - anim_ollie, anim_ollie_reverse, - anim_grabs, anim_stop, - anim_handplant; + ms_skeletal_animation anim_stand, anim_highg, anim_slide, + anim_air, anim_grind, anim_grind_jump, + anim_push, anim_push_reverse, + anim_ollie, anim_ollie_reverse, + anim_grabs, anim_stop, + anim_handplant; /* vectors representing the direction of the axels in localspace */ v3f truckv0[2]; @@ -305,7 +304,7 @@ static void player__skate_register(void) VG_VAR_F32( k_anim_transition, flags=VG_VAR_CHEAT ); } -void player__skate_bind (void); +void player__skate_load_resources(void); void player__skate_pre_update (void); void player__skate_update (void); void player__skate_transport( m4x3f transport ); @@ -325,3 +324,5 @@ void player__skate_reset_animator(void); void player__approximate_best_trajectory(void); void player__skate_comp_audio( void *animator ); void player__skate_kill_audio(void); + +#endif diff --git a/src/player_walk.c b/src/player_walk.c index ff43934..526660e 100644 --- a/src/player_walk.c +++ b/src/player_walk.c @@ -1,19 +1,8 @@ -#include "vg/vg_rigidbody_collision.h" - -#include "skaterift.h" -#include "player_walk.h" -#include "player_skate.h" -#include "player_dead.h" -#include "player.h" -#include "input.h" -#include "audio.h" -#include "scene_rigidbody.h" - struct player_walk player_walk; struct player_subsystem_interface player_subsystem_walk = { .system_register = player__walk_register, - .bind = player__walk_bind, + .load_resources = player__walk_load_resources, .pre_update = player__walk_pre_update, .update = player__walk_update, .transport = player__walk_transport, @@ -246,7 +235,7 @@ static int player_walk_scan_for_drop_in(void){ return 0; } -static bool player__preupdate_anim( struct skeleton_anim *anim, f32 *t, f32 speed ) +static bool player__preupdate_anim( ms_skeletal_animation *anim, f32 *t, f32 speed ) { f32 length = (f32)(anim->strip->strip.length-1) / anim->framerate; *t += (vg.time_delta * speed) / length; @@ -502,7 +491,7 @@ static void player_walk_update_generic(void) * Collision detection */ - len = rb_capsule__scene( mtx, &w->collider, NULL, world->geo_bh, manifold, 0 ); + len = rb_capsule__scene( mtx, &w->collider, NULL, &world->geometry_bh, manifold, 0 ); for( u32 i=0; ient_prop ); i ++ ) { @@ -854,7 +843,7 @@ static void player_walk_animate_drop_in(void) { struct player_walk *w = &player_walk; struct player_walk_animator *animator = &w->animator; - struct skeleton_anim *anim = &w->anim_drop_in; + ms_skeletal_animation *anim = &w->anim_drop_in; f32 length = (f32)(anim->strip->strip.length-1) / anim->framerate, time = w->state.transition_t; @@ -986,7 +975,7 @@ static void player_walk_pose_sit( struct player_walk_animator *animator, player_ ms_keyframe bpose[32]; struct player_walk *w = &player_walk; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; f32 t = animator->transition_t, st = t * ((f32)(w->anim_sit.strip->strip.length-1)/30.0f); @@ -1016,14 +1005,14 @@ enum walk_transition_type { }; static void player_walk_pose_transition( - struct player_walk_animator *animator, struct skeleton_anim *anim, + struct player_walk_animator *animator, ms_skeletal_animation *anim, enum walk_transition_type type, ms_keyframe apose[32], f32 *mask, player_pose *pose ){ ms_keyframe bpose[32]; struct player_walk *w = &player_walk; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; f32 length = (f32)(anim->strip->strip.length-1) / anim->framerate, t = animator->transition_t * length, @@ -1058,7 +1047,7 @@ static void player_walk_pose_transition( void player__walk_pose( void *_animator, player_pose *pose ){ struct player_walk *w = &player_walk; struct player_walk_animator *animator = _animator; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; v3_copy( animator->root_co, pose->root_co ); v4_copy( animator->root_q, pose->root_q ); @@ -1193,10 +1182,10 @@ void player__walk_im_gui( ui_context *ctx ) [w->surface] ); } -void player__walk_bind(void) +void player__walk_load_resources(void) { struct player_walk *w = &player_walk; - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; player_get_anim( &w->anim_idle, "idle_cycle+y" ); player_get_anim( &w->anim_walk, "walk+y" ); diff --git a/src/player_walk.h b/src/player_walk.h index 50c1a7c..b315623 100644 --- a/src/player_walk.h +++ b/src/player_walk.h @@ -1,7 +1,6 @@ -#pragma once -#include "player.h" -#include "player_api.h" -#include "vg/vg_rigidbody.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/player_walk.c" +#else #define PLAYER_JUMP_EPSILON 0.1 /* 100ms jump allowance */ @@ -49,9 +48,9 @@ struct player_walk f32 move_speed; enum mdl_surface_prop surface; - struct skeleton_anim anim_walk, anim_run, anim_idle, anim_jump, - anim_jump_to_air, anim_drop_in, anim_intro, - anim_sit, anim_popoff; + ms_skeletal_animation anim_walk, anim_run, anim_idle, anim_jump, + anim_jump_to_air, anim_drop_in, anim_intro, + anim_sit, anim_popoff; struct player_walk_animator { v3f root_co; @@ -106,10 +105,12 @@ void player__walk_animate (void); void player__walk_pose (void *animator, player_pose *pose); void player__walk_post_animate(void); void player__walk_im_gui ( ui_context *ctx ); -void player__walk_bind (void); +void player__walk_load_resources(void); void player__walk_reset (void); void player__walk_restore (void); void player__walk_animator_exchange( bitpack_ctx *ctx, void *data ); void player__walk_transition( bool grounded, f32 board_yaw ); void player__walk_sfx_oneshot( u8 id, v3f pos, f32 volume ); void player__walk_upright(void); + +#endif diff --git a/src/render.c b/src/render.c index 3223835..97f8e65 100644 --- a/src/render.c +++ b/src/render.c @@ -1,77 +1,17 @@ -#include "render.h" -#include "vg/vg_engine.h" -#include "vg/vg_platform.h" -#include "vg/vg_framebuffer.h" - -static void async_render_init( void *userdata ) -{ - THREAD_0; - f32 rh = 0x1p-4f, ih = 0.3f; - - float quad[] = { - 0.00f,0.00f, 1.00f,1.00f, 0.00f,1.00f, /* fsquad */ - 0.00f,0.00f, 1.00f,0.00f, 1.00f,1.00f, - - 0.00f,0.00f, 1.00f,rh, 0.00f,rh, /* fsquad1 */ - 0.00f,0.00f, 1.00f,0.00f, 1.00f,rh, - 0.00f,1.00f, 0.00f,1.0f-rh,1.00f,1.0f-rh, - 0.00f,1.00f, 1.00f,1.0f-rh,1.00f,1.0f, - - /* 9x9 debug grid */ - /* row0 */ - 0.00f,0.00f, 0.30f,0.30f, 0.00f,0.30f, - 0.00f,0.00f, 0.30f,0.00f, 0.30f,0.30f, - 0.30f,0.00f, 0.60f,0.30f, 0.30f,0.30f, - 0.30f,0.00f, 0.60f,0.00f, 0.60f,0.30f, - 0.60f,0.00f, 0.90f,0.30f, 0.60f,0.30f, - 0.60f,0.00f, 0.90f,0.00f, 0.90f,0.30f, - /* row1 */ - 0.00f,0.30f, 0.30f,0.60f, 0.00f,0.60f, - 0.00f,0.30f, 0.30f,0.30f, 0.30f,0.60f, - 0.30f,0.30f, 0.60f,0.60f, 0.30f,0.60f, - 0.30f,0.30f, 0.60f,0.30f, 0.60f,0.60f, - 0.60f,0.30f, 0.90f,0.60f, 0.60f,0.60f, - 0.60f,0.30f, 0.90f,0.30f, 0.90f,0.60f, - /* row2 */ - 0.00f,0.60f, 0.30f,0.90f, 0.00f,0.90f, - 0.00f,0.60f, 0.30f,0.60f, 0.30f,0.90f, - 0.30f,0.60f, 0.60f,0.90f, 0.30f,0.90f, - 0.30f,0.60f, 0.60f,0.60f, 0.60f,0.90f, - 0.60f,0.60f, 0.90f,0.90f, 0.60f,0.90f, - 0.60f,0.60f, 0.90f,0.60f, 0.90f,0.90f, - - 0.00f,ih, 1.00f,ih+rh, 0.00f,ih+rh, /* fsquad2 */ - 0.00f,ih, 1.00f,ih, 1.00f,ih+rh, - }; - - glGenVertexArrays( 1, &g_render.fsquad.vao ); - glGenBuffers( 1, &g_render.fsquad.vbo ); - glBindVertexArray( g_render.fsquad.vao ); - glBindBuffer( GL_ARRAY_BUFFER, g_render.fsquad.vbo ); - glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW ); - glBindVertexArray( g_render.fsquad.vao ); - glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, - sizeof(float)*2, (void*)0 ); - glEnableVertexAttribArray( 0 ); - - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - g_render.ready = 1; -} - -void render_register(void) +VG_API void _render_register(void) { vg_console_reg_var( "fov", &k_fov, k_var_dtype_f32, VG_VAR_PERSISTENT ); vg_console_reg_var( "cam_height", &k_cam_height, k_var_dtype_f32, VG_VAR_PERSISTENT ); } -void render_init(void) +VG_API void _render_init(void) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); /* * Workshop preview */ - g_render.fb_workshop_preview = vg_framebuffer_allocate( &vg.rtmem, 2, 1 ); + g_render.fb_workshop_preview = _vg_framebuffer_alloc( NULL, 2, 1 ); g_render.fb_workshop_preview->display_name = "workshop_preview"; g_render.fb_workshop_preview->resolution_div = 0; g_render.fb_workshop_preview->fixed_w = WORKSHOP_PREVIEW_WIDTH; @@ -90,12 +30,12 @@ void render_init(void) .internalformat = GL_DEPTH24_STENCIL8, .attachment = GL_DEPTH_STENCIL_ATTACHMENT }; - vg_framebuffer_create( g_render.fb_workshop_preview ); + vg_framebuffer_init( g_render.fb_workshop_preview ); /* * Network status */ - g_render.fb_network_status = vg_framebuffer_allocate( &vg.rtmem, 1, 1 ); + g_render.fb_network_status = _vg_framebuffer_alloc( VG_STACK_USE_HEAP, 1, 1 ); g_render.fb_network_status->display_name = "network_status_ui"; g_render.fb_network_status->resolution_div = 0; g_render.fb_network_status->fixed_w = 128; @@ -108,9 +48,9 @@ void render_init(void) .type = GL_UNSIGNED_BYTE, .attachment = GL_COLOR_ATTACHMENT0 }; - vg_framebuffer_create( g_render.fb_network_status ); + vg_framebuffer_init( g_render.fb_network_status ); - g_render.fb_compass = vg_framebuffer_allocate( &vg.rtmem, 1, 1 ); + g_render.fb_compass = _vg_framebuffer_alloc( VG_STACK_USE_HEAP, 1, 1 ); g_render.fb_compass->display_name = "compass"; g_render.fb_compass->resolution_div = 0; g_render.fb_compass->fixed_w = 800; @@ -123,28 +63,75 @@ void render_init(void) .type = GL_UNSIGNED_BYTE, .attachment = GL_COLOR_ATTACHMENT0 }; - vg_framebuffer_create( g_render.fb_compass ); + vg_framebuffer_init( g_render.fb_compass ); + + f32 rh = 0x1p-4f, ih = 0.3f; + + /* TODO: Is this duplicated with vg_render? */ + f32 quad[] = + { + 0.00f,0.00f, 1.00f,1.00f, 0.00f,1.00f, /* fsquad */ + 0.00f,0.00f, 1.00f,0.00f, 1.00f,1.00f, + + 0.00f,0.00f, 1.00f,rh, 0.00f,rh, /* fsquad1 */ + 0.00f,0.00f, 1.00f,0.00f, 1.00f,rh, + 0.00f,1.00f, 0.00f,1.0f-rh,1.00f,1.0f-rh, + 0.00f,1.00f, 1.00f,1.0f-rh,1.00f,1.0f, + + /* 9x9 debug grid */ + /* row0 */ + 0.00f,0.00f, 0.30f,0.30f, 0.00f,0.30f, + 0.00f,0.00f, 0.30f,0.00f, 0.30f,0.30f, + 0.30f,0.00f, 0.60f,0.30f, 0.30f,0.30f, + 0.30f,0.00f, 0.60f,0.00f, 0.60f,0.30f, + 0.60f,0.00f, 0.90f,0.30f, 0.60f,0.30f, + 0.60f,0.00f, 0.90f,0.00f, 0.90f,0.30f, + /* row1 */ + 0.00f,0.30f, 0.30f,0.60f, 0.00f,0.60f, + 0.00f,0.30f, 0.30f,0.30f, 0.30f,0.60f, + 0.30f,0.30f, 0.60f,0.60f, 0.30f,0.60f, + 0.30f,0.30f, 0.60f,0.30f, 0.60f,0.60f, + 0.60f,0.30f, 0.90f,0.60f, 0.60f,0.60f, + 0.60f,0.30f, 0.90f,0.30f, 0.90f,0.60f, + /* row2 */ + 0.00f,0.60f, 0.30f,0.90f, 0.00f,0.90f, + 0.00f,0.60f, 0.30f,0.60f, 0.30f,0.90f, + 0.30f,0.60f, 0.60f,0.90f, 0.30f,0.90f, + 0.30f,0.60f, 0.60f,0.60f, 0.60f,0.90f, + 0.60f,0.60f, 0.90f,0.90f, 0.60f,0.90f, + 0.60f,0.60f, 0.90f,0.60f, 0.90f,0.90f, + + 0.00f,ih, 1.00f,ih+rh, 0.00f,ih+rh, /* fsquad2 */ + 0.00f,ih, 1.00f,ih, 1.00f,ih+rh, + }; - vg_async_call( &vg.main_tasks, async_render_init, NULL ); + glGenVertexArrays( 1, &g_render.fsq_vao ); + glBindVertexArray( g_render.fsq_vao ); + glGenBuffers( 1, &g_render.fsq_vbo ); + glBindBuffer( GL_ARRAY_BUFFER, g_render.fsq_vbo ); + glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW ); + glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, sizeof(float)*2, (void*)0 ); + glEnableVertexAttribArray( 0 ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); } /* - * Utility + * Utility (TODO: ARE THESE DUPED WITH VG CODE???????????????????????) */ void render_fsquad(void) { - glBindVertexArray( g_render.fsquad.vao ); + glBindVertexArray( g_render.fsq_vao ); glDrawArrays( GL_TRIANGLES, 0, 6 ); } void render_fsquad1(void) { - glBindVertexArray( g_render.fsquad.vao ); + glBindVertexArray( g_render.fsq_vao ); glDrawArrays( GL_TRIANGLES, 6, 6+6 ); } void render_fsquad2(void) { - glBindVertexArray( g_render.fsquad.vao ); + glBindVertexArray( g_render.fsq_vao ); glDrawArrays( GL_TRIANGLES, 66+6,6 ); } diff --git a/src/render.h b/src/render.h index 3024f21..2607e46 100644 --- a/src/render.h +++ b/src/render.h @@ -1,16 +1,6 @@ -/* - * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ -#pragma once -#include "common.h" -#include "model.h" -#include "shader_props.h" -#include "vg/vg_framebuffer.h" -#include "vg/vg_camera.h" - -#include "shaders/blitblur.h" -#include "shaders/blitcolour.h" -#include "shaders/blit_transition.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/render.c" +#else #define WORKSHOP_PREVIEW_WIDTH 504 #define WORKSHOP_PREVIEW_HEIGHT 336 @@ -23,21 +13,22 @@ static f32 k_cam_height = 0.8f; */ struct pipeline { - glmesh fsquad; + GLuint fsq_vao, fsq_vbo; vg_framebuffer *fb_workshop_preview, *fb_network_status, *fb_compass; - int ready; - v2f blur_override; vg_camera cam; } static g_render; -void render_register(void); -void render_init(void); +void _render_register(void); +VG_API void _render_init(void); + void render_fsquad(void); void render_fsquad1(void); void render_fsquad2(void); void postprocess_to_screen( vg_framebuffer *fb ); + +#endif diff --git a/src/replay2.c b/src/replay2.c index 9ff3302..ff9340a 100644 --- a/src/replay2.c +++ b/src/replay2.c @@ -1,7 +1,115 @@ -#include "replay2.h" +struct _replay2 +{ + enum replay_type type; + + vg_queue buffer; + + /* TODO: Modifiers / keyframes lane */ + + u32 cursor_frame_offset; + f64 cursor; + enum replay_control { + k_replay_control_scrub = 0x00, + k_replay_control_play = 0x01, + k_replay_control_resume= 0x02 + } + replay_control; + f32 track_velocity; + + bool cursor_decoded; + + struct net_sfx sfx_queue[ 8 ]; + u32 sfx_queue_length; + f64 sfx_basetime; + + vg_camera replay_freecam, playback_cam; + bool use_freecam; + bool hide_ui; + v3f freecam_v, freecam_w; + + f64 start_t, end_t; + bool highlight; + f64 highlight_start, highlight_length; + + bool animation_dirty; + addon_cache_id board_cache_id; + player_model_view playermodel; + + struct player_effects_data effect_data; + bool render_glider; + m4x3f *final_mtx, glider_mtx; + struct player_board_pose board_pose; +} +_replay2; + +f32 _replay2_playback_velocity(void) +{ + return _replay2.track_velocity; +} + +struct _remote_replay +{ + u32 total_chunks, + chunks_downloaded; + + u64 steamid; + struct remote_replay_chunk + { + u32 minute; + enum chunk_state + { + k_chunk_state_none, + k_chunk_state_cache_check, + k_chunk_state_downloading, + k_chunk_state_processed, + k_chunk_state_broken + } + state; + } + chunks[8]; + f64 min_frame_t; + + enum remote_replay_state + { + k_remote_replay_state_none, + + k_remote_replay_state_init, + k_remote_replay_state_getinfo, + + k_remote_replay_state_waitnext, + k_remote_replay_state_downloading, + k_remote_replay_state_failed, + k_remote_replay_state_ready, + } + state; + i64 last_second; + f64 end_offset, start_offset; /* from the download */ + + struct interp_frame interp0, interp1; + vg_queue buffer; +} +_remote_replay; -struct _remote_replay _remote_replay; -struct _replay2 _replay2; +void _remote_replay_reset( u32 centiseconds, i64 last_second, u64 steamid ) +{ + u32 minutes_span = (centiseconds+(200*60)) / (100*60); + u32 last_minute = (u32)( last_second / 60 ); + + vg_queue_clear( &_remote_replay.buffer ); + _remote_replay.min_frame_t = 0.0; + _remote_replay.total_chunks = minutes_span; + _remote_replay.chunks_downloaded = 0; + _remote_replay.steamid = steamid; + _remote_replay.state = k_remote_replay_state_init; + _remote_replay.last_second = last_second; + + for( u32 i=0; iminute = last_minute - minutes_span + 1 + i; + chunk->state = k_chunk_state_none; + } +} static int cmd_replay2_manual_download( int argc, const char *argv[] ) { @@ -41,30 +149,23 @@ static int cmd_replay2_manual_download( int argc, const char *argv[] ) chunk->state = k_chunk_state_none; } - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); _replay2_open_player( k_replay_type_network, 0 ); return 1; } -void _replay2_register(void) +VG_API void _replay2_register(void) { vg_console_reg_cmd( "replay2_watch", cmd_replay2_manual_download, NULL ); } -void _replay2_init(void) +VG_API void _replay2_init(void) { - u32 MB = 1024*1024, - size = 4*MB; - - _remote_replay.buffer.buffer = vg_stack_allocate( &vg.rtmem, size, 8, "Remote replay buffer" ); - _remote_replay.buffer.size = size; + _remote_replay.buffer.buffer = vg_stack_allocate( NULL, VG_MB(4), 8, "Remote replay buffer" ); + _remote_replay.buffer.size = VG_MB(4); - _replay2.buffer.buffer = vg_stack_allocate( &vg.rtmem, size*2, 8, "Replay buffer" ); - _replay2.buffer.size = size*2; - - struct skeleton *sk = &localplayer.skeleton; - u32 mtx_size = sizeof(m4x3f)*sk->bone_count; - _replay2.final_mtx = vg_stack_allocate( &vg.rtmem, mtx_size, 8, "Replay Final MTX" ); + _replay2.buffer.buffer = vg_stack_allocate( NULL, VG_MB(8), 8, "Replay buffer" ); + _replay2.buffer.size = VG_MB(8); } void _replay2_clear_local_buffer(void) @@ -125,12 +226,29 @@ void replay2_close_player(void) localplayer.immobile = 0; } +static void replay_file_path( c8 path[1024], u64 steamid, i64 last_second, u32 minute, enum remote_replay_state state ) +{ + vg_str path_str; + vg_strnull( &path_str, path, 1024 ); + vg_strcat( &path_str, "replaydata/" ); + vg_strcatu64( &path_str, steamid, 16 ); + vg_strcat( &path_str, "@" ); + + if( state == k_remote_replay_state_getinfo ) + { + vg_strcati64( &path_str, last_second, 16 ); + vg_strcat( &path_str, ".kv" ); + } + else + vg_strcatu64( &path_str, minute, 16 ); +} + /* remote replay downloader * ------------------------------------------------------------------ */ static void replay_download_callback( void *data, u32 data_size, u64 userdata, enum request_status status ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); bool is_from_network = userdata; @@ -148,10 +266,9 @@ static void replay_download_callback( void *data, u32 data_size, u64 userdata, e { char path[1024]; if( _remote_replay.state == k_remote_replay_state_getinfo ) - snprintf( path, sizeof(path), "replaydata/" PRINTF_X64 "@" PRINTF_X64 ".bkv", - _remote_replay.steamid, _remote_replay.last_second ); + replay_file_path( path, _remote_replay.steamid, _remote_replay.last_second, 0, _remote_replay.state ); else - snprintf( path, sizeof(path), "replaydata/" PRINTF_X64 "@%x", _remote_replay.steamid, chunk->minute ); + replay_file_path( path, _remote_replay.steamid, 0, chunk->minute, _remote_replay.state ); FILE *fp = fopen( path, "wb" ); if( fp ) @@ -168,40 +285,51 @@ static void replay_download_callback( void *data, u32 data_size, u64 userdata, e if( _remote_replay.state == k_remote_replay_state_getinfo ) { - vg_msg kvs; - vg_msg_init( &kvs, data, data_size ); - - u32 centiseconds = 0; - vg_msg_getkvintg( &kvs, "centiseconds", k_vg_msg_u32, ¢iseconds, NULL ); - u32 end_offset_seconds = 0; - vg_msg_getkvintg( &kvs, "end_offset", k_vg_msg_u32, &end_offset_seconds, NULL ); - _remote_replay.end_offset = end_offset_seconds; - _remote_replay.start_offset = _remote_replay.end_offset + ((f64)centiseconds / 100.0); - - vg_info( "end_offset: -%f\n", _remote_replay.end_offset ); - vg_info( "start_offset: -%f\n", _remote_replay.start_offset ); - - vg_msg_cursor orig = kvs.cur; - if( vg_msg_seekframe( &kvs, "playerinfo" ) ) + u32 temp_frame = _vg_start_temp_frame(); { - const char *board_str = vg_msg_getkvstr( &kvs, "board" ); - const char *playermodel_str = vg_msg_getkvstr( &kvs, "player" ); + /* TODO This is like, totally duplicated code man */ + vg_stream kv_stream; + vg_buffer_stream_open( &kv_stream, data, data_size, VG_STREAM_READ ); + vg_kvs kvs; + vg_kvs_init( &kvs, _vg_temp_stack() ); + vg_kv_parser parser; + vg_kv_parser_init( &parser, &kvs, 0 ); + vg_kv_parse_stream( &parser, &kv_stream ); - vg_info( "board_str: %s\n", board_str ); - vg_info( "playermodel_str: %s\n", playermodel_str ); + u32 centiseconds = 0; + vg_kv_read_vu32( &kvs, 0, "centiseconds", NULL, ¢iseconds, 1 ); - if( playermodel_str ) - { - addon_cache_unwatch( k_addon_type_player, _replay2.playermodel.cache_slot ); - playermodel_set_from_uid( &_replay2.playermodel, playermodel_str ); - } + u32 end_offset_seconds = 0; + vg_kv_read_vu32( &kvs, 0, "end_offset", NULL, &end_offset_seconds, 1 ); + + _remote_replay.end_offset = end_offset_seconds; + _remote_replay.start_offset = _remote_replay.end_offset + ((f64)centiseconds / 100.0); - if( board_str ) + vg_info( "end_offset: -%f\n", _remote_replay.end_offset ); + vg_info( "start_offset: -%f\n", _remote_replay.start_offset ); + + u32 player_info_block = vg_kv_find( &kvs, 0, "playerinfo" ); + if( player_info_block ) { - addon_cache_unwatch( k_addon_type_board, _replay2.board_cache_id ); - _replay2.board_cache_id = addon_cache_create_viewer_from_uid( k_addon_type_board, board_str ); + const c8 *board_str = vg_kv_value( &kvs, vg_kv_find( &kvs, player_info_block, "board" ), NULL ); + const c8 *playermodel_str = vg_kv_value( &kvs, vg_kv_find( &kvs, player_info_block, "player" ), NULL ); + vg_info( "board_str: %s\n", board_str ); + vg_info( "playermodel_str: %s\n", playermodel_str ); + + if( playermodel_str ) + { + addon_cache_unwatch( k_addon_type_player, _replay2.playermodel.cache_slot ); + playermodel_set_from_uid( &_replay2.playermodel, playermodel_str ); + } + + if( board_str ) + { + addon_cache_unwatch( k_addon_type_board, _replay2.board_cache_id ); + _replay2.board_cache_id = addon_cache_create_viewer_from_uid( k_addon_type_board, board_str ); + } } } + _vg_end_temp_frame( temp_frame ); _remote_replay.state = k_remote_replay_state_waitnext; return; @@ -238,7 +366,7 @@ static void replay_download_callback( void *data, u32 data_size, u64 userdata, e } _remote_replay.min_frame_t = playerframe->timestamp; - replay2_frame *dst_frame = vg_queue_alloc( buffer, sizeof(replay2_frame) + snm->msg_size, NULL ); + replay2_frame *dst_frame = vg_queue_alloc( buffer, sizeof(replay2_frame) + snm->msg_size ); if( !dst_frame ) { vg_error( "Out of mem adding frame!\n" ); @@ -319,17 +447,15 @@ struct async_cache_check_result u32 data_length; u8 data[]; }; -static void async_cache_check_result( vg_async_task *task ) +static void async_cache_check_result( struct async_cache_check_result *in_args, vg_async_info *async ) { - THREAD_0; - struct async_cache_check_result *result = (void *)task->data; - - if( result->found_in_cache ) + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + if( in_args->found_in_cache ) { - if( result->broken ) + if( in_args->broken ) replay_download_callback( NULL, 0, 0, k_request_status_not_found ); else - replay_download_callback( result->data, result->data_length, 0, k_request_status_ok ); + replay_download_callback( in_args->data, in_args->data_length, 0, k_request_status_ok ); } else { @@ -338,6 +464,8 @@ static void async_cache_check_result( vg_async_task *task ) vg_make_directory( "replaydata" ); + // FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME//// +#if 0 netmsg_request *packet = alloca( sizeof(netmsg_request) + 512 ); packet->inetmsg_id = k_inetmsg_request; @@ -354,6 +482,8 @@ static void async_cache_check_result( vg_async_task *task ) else vg_msg_wkvnum( &data, "lastsec", k_vg_msg_i64, 1, &_remote_replay.last_second ); network_send_request( packet, &data, replay_download_callback, 1 ); +#endif + // FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME//// } } @@ -361,43 +491,37 @@ static void async_cache_check_result( vg_async_task *task ) static const u32 k_download_option_preparing = 0x00; static const u32 k_download_option_data = 0x00; -static void _remote_replay_cache_check( void *userdata ) +static void _remote_replay_cache_check( void *_, vg_async_info *async ) { char path[1024]; if( _remote_replay.state == k_remote_replay_state_getinfo ) - { - snprintf( path, sizeof(path), "replaydata/" PRINTF_X64 "@" PRINTF_X64 ".bvk", - _remote_replay.steamid, _remote_replay.last_second ); - } + replay_file_path( path, _remote_replay.steamid, _remote_replay.last_second, 0, _remote_replay.state ); else { struct remote_replay_chunk *chunk = &_remote_replay.chunks[ _remote_replay.chunks_downloaded ]; - snprintf( path, sizeof(path), "replaydata/" PRINTF_X64 "@%x", _remote_replay.steamid, chunk->minute ); + replay_file_path( path, _remote_replay.steamid, 0, chunk->minute, _remote_replay.state ); } - vg_async_task *result_task = - vg_allocate_async_task( &vg.main_tasks, sizeof(struct async_cache_check_result) + 8*1024*1024, 1 ); - struct async_cache_check_result *result = (void *)result_task->data; - result->broken = 0; + struct async_cache_check_result *out_args = + _vg_async_alloc( VG_THREAD_MAIN_ID, sizeof(struct async_cache_check_result) + 8*1024*1024 ); + out_args->broken = 0; FILE *fp = fopen( path, "rb" ); if( fp ) { - result->found_in_cache = 1; - result->data_length = fread( result->data, 1, 20*1024*1024, fp ); - + out_args->found_in_cache = 1; + out_args->data_length = fread( out_args->data, 1, 20*1024*1024, fp ); if( !feof( fp ) ) - result->broken = 1; - + out_args->broken = 1; fclose( fp ); } else { - result->found_in_cache = 0; - result->data_length = 0; + out_args->found_in_cache = 0; + out_args->data_length = 0; } - vg_async_task_dispatch( result_task, async_cache_check_result ); + _vg_async_send( out_args, (vg_async_fn)async_cache_check_result ); } static void _remote_replay_pre_update(void) @@ -405,7 +529,7 @@ static void _remote_replay_pre_update(void) if( _remote_replay.state == k_remote_replay_state_init ) { _remote_replay.state = k_remote_replay_state_getinfo; - vg_async_call( &vg.loader_tasks, _remote_replay_cache_check, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_remote_replay_cache_check ); } else if( _remote_replay.state == k_remote_replay_state_waitnext ) { @@ -415,7 +539,7 @@ static void _remote_replay_pre_update(void) if( chunk->state == k_chunk_state_none ) { chunk->state = k_chunk_state_cache_check; - vg_async_call( &vg.loader_tasks, _remote_replay_cache_check, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_remote_replay_cache_check ); } } } @@ -503,7 +627,39 @@ void _replay2_pre_update(void) } if( _replay2.use_freecam ) - freecam_preupdate(); + { + vg_camera *cam = &_replay2.replay_freecam; + v3f angles; + v3_copy( cam->angles, angles ); + player_look( angles, 1.0f ); + + f32 decay = vg_maxf(0.0f,1.0f-vg.time_frame_delta*10.0f); + + v3f d; + v3_sub( angles, cam->angles, d ); + v3_muladds( _replay2.freecam_w, d, 20.0f, _replay2.freecam_w ); + v3_muls( _replay2.freecam_w, decay, _replay2.freecam_w ); + v3_muladds( cam->angles, _replay2.freecam_w, vg.time_frame_delta, cam->angles ); + cam->angles[1] = vg_clampf( cam->angles[1], -VG_PIf*0.5f,VG_PIf*0.5f); + + vg_camera_update_transform( cam ); + + v3f lookdir = { 0.0f, 0.0f, -1.0f }, + sidedir = { 1.0f, 0.0f, 0.0f }; + + m3x3_mulv( cam->transform, lookdir, lookdir ); + m3x3_mulv( cam->transform, sidedir, sidedir ); + + v2f input; + joystick_state( k_srjoystick_steer, input ); + v2_muls( input, vg.time_frame_delta*6.0f*20.0f, input ); + + v3_muladds( _replay2.freecam_v, lookdir, -input[1], _replay2.freecam_v ); + v3_muladds( _replay2.freecam_v, sidedir, input[0], _replay2.freecam_v ); + + v3_muls( _replay2.freecam_v, decay, _replay2.freecam_v ); + v3_muladds( cam->pos,_replay2.freecam_v, vg.time_frame_delta, cam->pos ); + } if( _replay2.animation_dirty ) { @@ -633,16 +789,16 @@ void _replay2_pre_update(void) } } -void _replay2_render_player( world_instance *world, vg_camera *cam ) +void _replay2_render_player( vg_camera *cam ) { if( skaterift.activity != k_skaterift_replay ) return; - struct skeleton *sk = &localplayer.skeleton; - render_playermodel( cam, world, 0, &_replay2.playermodel, sk, _replay2.final_mtx ); + ms_skeleton *sk = &localplayer.skeleton; + render_playermodel( cam, &_world.main, 0, &_replay2.playermodel, sk, _replay2.final_mtx ); struct player_board *board = addon_cache_item_data( k_addon_type_board, _replay2.board_cache_id, 1 ); - render_board( cam, world, board, _replay2.final_mtx[localplayer.id_board], + render_board( cam, &_world.main, board, _replay2.final_mtx[localplayer.id_board], &_replay2.board_pose, k_board_shader_player ); #if 0 @@ -654,7 +810,7 @@ void _replay2_render_player( world_instance *world, vg_camera *cam ) shader_model_entity_uCamera( cam->transform[3] ); shader_model_entity_uPv( cam->mtx.pv ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_entity ); + WORLD_LINK_LIGHTING( world, model_entity ); for( u32 j=0; jallocation_count < 2 ) { ctx->font = &vgf_default_large; - ui_rect box = { vg.window_x/2 - 200, 40, 400, ctx->font->sy }; + ui_rect box = { _vg_window.w/2 - 200, 40, 400, ctx->font->sy }; ui_text( ctx, box, KRED "\x06\x02--- Corrupt replay ---", 1, k_ui_align_center, 0 ); // TODO return; @@ -888,7 +1044,7 @@ void _replay2_imgui( ui_context *ctx ) cur = (_replay2.cursor - start) / len; /* mainbar */ - ui_rect timeline = { 8, vg.window_y-(32+8), vg.window_x-16, 32 }; + ui_rect timeline = { 8, _vg_window.h-(32+8), _vg_window.w-16, 32 }; ui_rect start_box; ui_split( timeline, k_ui_axis_v, 32, 8, start_box, timeline ); @@ -958,7 +1114,7 @@ void _replay2_imgui( ui_context *ctx ) /* helpers */ ctx->font = &vgf_default_large; - ui_rect helper_list_l = { 10, timeline[1] - (ctx->font->sy+8), vg.window_x/2, ctx->font->sy }; + ui_rect helper_list_l = { 10, timeline[1] - (ctx->font->sy+8), _vg_window.w/2, ctx->font->sy }; char buf[256]; vg_str str; vg_strnull( &str, buf, sizeof(buf) ); @@ -985,7 +1141,7 @@ void _replay2_imgui( ui_context *ctx ) ui_text( ctx, helper_list_l, buf, 1, k_ui_align_left, 0 ); helper_list_l[1] -= helper_list_l[3]+2; - ui_rect helper_list_r = { vg.window_x/2, timeline[1] - (ctx->font->sy+8), vg.window_x/2-10, ctx->font->sy }; + ui_rect helper_list_r = { _vg_window.w/2, timeline[1] - (ctx->font->sy+8), _vg_window.w/2-10, ctx->font->sy }; vg_strnull( &str, buf, sizeof(buf) ); vg_input_string( &str, input_button_list[k_srbind_mback], 1 ); vg_strcat( &str, "\x07 Exit Replay" ); @@ -994,7 +1150,7 @@ void _replay2_imgui( ui_context *ctx ) if( _replay2.use_freecam ) { - ui_rect box = { vg.window_x/2 - 200, 40, 400, ctx->font->sy }; + ui_rect box = { _vg_window.w/2 - 200, 40, 400, ctx->font->sy }; ui_text( ctx, box, KYEL "\x06\x02--- Freecam Enabled ---", 1, k_ui_align_center, 0 ); } @@ -1047,13 +1203,13 @@ void _replay2_record_local_frame(void) sfx_size = vg_align8( localplayer.local_sfx_buffer_count * sizeof(struct net_sfx) ), total_size = sizeof(replay2_frame) + animator_size + glider_size + sfx_size; - replay2_frame *dest_frame = vg_queue_alloc( buffer, total_size, NULL ); + replay2_frame *dest_frame = vg_queue_alloc( buffer, total_size ); if( !dest_frame ) { while( buffer->allocation_count ) { vg_queue_pop( buffer ); - dest_frame = vg_queue_alloc( buffer, total_size, NULL ); + dest_frame = vg_queue_alloc( buffer, total_size ); if( dest_frame ) break; } diff --git a/src/replay2.h b/src/replay2.h index 872de7e..94802d6 100644 --- a/src/replay2.h +++ b/src/replay2.h @@ -1,6 +1,12 @@ -#pragma once -#include "vg/vg_mem_queue.h" -#include "player_effects.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/replay2.c" +#else + +enum replay_type +{ + k_replay_type_local, + k_replay_type_network +}; typedef struct replay2_frame replay2_frame; struct replay2_frame @@ -35,106 +41,20 @@ struct replay_glider_data v4f q; }; -struct _remote_replay -{ - u32 total_chunks, - chunks_downloaded; - - u64 steamid; - struct remote_replay_chunk - { - u32 minute; - enum chunk_state - { - k_chunk_state_none, - k_chunk_state_cache_check, - k_chunk_state_downloading, - k_chunk_state_processed, - k_chunk_state_broken - } - state; - } - chunks[8]; - f64 min_frame_t; - - enum remote_replay_state - { - k_remote_replay_state_none, - - k_remote_replay_state_init, - k_remote_replay_state_getinfo, - - k_remote_replay_state_waitnext, - k_remote_replay_state_downloading, - k_remote_replay_state_failed, - k_remote_replay_state_ready, - } - state; - i64 last_second; - f64 end_offset, start_offset; /* from the download */ +VG_API void _replay2_register(void); +VG_API void _replay2_init(void); - struct interp_frame interp0, interp1; - vg_queue buffer; -} -extern _remote_replay; +f32 _replay2_playback_velocity(void); -struct _replay2 -{ - enum replay_type - { - k_replay_type_local, - k_replay_type_network - } - type; - - vg_queue buffer; - - /* TODO: Modifiers / keyframes lane */ - - u32 cursor_frame_offset; - f64 cursor; - enum replay_control { - k_replay_control_scrub = 0x00, - k_replay_control_play = 0x01, - k_replay_control_resume= 0x02 - } - replay_control; - f32 track_velocity; - - bool cursor_decoded; - - struct net_sfx sfx_queue[ 8 ]; - u32 sfx_queue_length; - f64 sfx_basetime; - - vg_camera replay_freecam, playback_cam; - bool use_freecam; - bool hide_ui; - v3f freecam_v, freecam_w; - - f64 start_t, end_t; - bool highlight; - f64 highlight_start, highlight_length; - - bool animation_dirty; - addon_cache_id board_cache_id; - player_model_view playermodel; - - struct player_effects_data effect_data; - bool render_glider; - m4x3f *final_mtx, glider_mtx; - struct player_board_pose board_pose; -} -extern _replay2; - -void _replay2_register(void); -void _replay2_init(void); +void _remote_replay_reset( u32 centiseconds, i64 last_second, u64 steamid ); void _replay2_pre_update(void); void _replay2_imgui( ui_context *ctx ); void _replay2_open_player( enum replay_type type, bool end ); -void _replay2_render_player( world_instance *world, vg_camera *cam ); +void _replay2_render_player( vg_camera *cam ); void _replay2_seek( f64 t, bool play_sounds ); void _replay2_get_camera( vg_camera *cam ); void _replay2_decode(void); void _replay2_record_local_frame(void); void _replay2_clear_local_buffer(void); + +#endif diff --git a/src/save.c b/src/save.c index 15519da..8116d5c 100644 --- a/src/save.c +++ b/src/save.c @@ -1,17 +1,9 @@ -#include "skaterift.h" -#include "save.h" -#include "addon.h" -#include "vg/vg_msg.h" -#include "vg/vg_log.h" -#include "vg/vg_loader.h" -#include "world.h" -#include "player.h" - -static const char *str_skaterift_main_save = "save.bkv"; +static const char *str_skaterift_main_save = "save.kv"; static f64 _last_autosave; void savedata_file_write( savedata_file *file ) { +#if 0 savedata_file *sav = file; FILE *fp = fopen( sav->path, "wb" ); if( fp ) @@ -22,6 +14,7 @@ void savedata_file_write( savedata_file *file ) } else vg_error( "Error writing savedata (%s)\n", sav->path ); +#endif } static void savedata_file_write_task( vg_async_task *task ) @@ -31,6 +24,8 @@ static void savedata_file_write_task( vg_async_task *task ) void savedata_file_read( savedata_file *file ) { + vg_zero_mem( &file->kvs, sizeof(vg_kvs) ); +#if 0 FILE *fp = fopen( file->path, "rb" ); if( fp ) { @@ -43,37 +38,45 @@ void savedata_file_read( savedata_file *file ) vg_msg_init( &file->msg, file->buf, 0 ); vg_warn( "Error reading savedata (%s)\n", file->path ); } +#endif } static void skaterift_write_addon( vg_msg *msg, const char *key, addon_id id ) { +#if 0 char uid[ ADDON_UID_MAX ]; addon_make_uid( id, uid ); vg_msg_wkvstr( msg, key, uid ); +#endif } static void skaterift_write_viewslot( vg_msg *msg, const char *key, enum addon_type type, u16 cache_id ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); if( !cache_id ) return; +#if 0 addon_cache_entry *entry = get_addon_cache_entry( type, cache_id ); char uid[ ADDON_UID_MAX ]; addon_make_uid_cpart( entry->addon_id, uid, entry->local_cpart ); vg_msg_wkvstr( msg, key, uid ); +#endif } void init_savefile( savedata_file *file, const char *path ) { memset( file, 0, sizeof(savedata_file) ); strcpy( file->path, path ); +#if 0 vg_msg_init( &file->msg, file->buf, sizeof(file->buf) ); +#endif } void write_savefile( savedata_file *file, bool async ) { +#if 0 if( async ) { vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(savedata_file), 1 ); @@ -82,10 +85,12 @@ void write_savefile( savedata_file *file, bool async ) } else savedata_file_write( file ); +#endif } void skaterift_write_all_savedata( bool async ) { +#if 0 savedata_file file; /* main file */ @@ -141,20 +146,25 @@ void skaterift_write_all_savedata( bool async ) vg_msg_end_frame( &file.msg ); write_savefile( &file, async ); } +#endif } void skaterift_autosave_synchronous(void) { +#if 0 skaterift_write_all_savedata( 0 ); +#endif } void skaterift_autosave_update( void ) { +#if 0 if( (vg.time - _last_autosave) > 60.0 ) { skaterift_write_all_savedata(1); _last_autosave = vg.time; } +#endif } struct equip_saved_items_info @@ -166,7 +176,7 @@ struct equip_saved_items_info }; static void equip_async( vg_async_task *task ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); struct equip_saved_items_info *info = (void *)task->data; localplayer.board_view_slot = addon_cache_create_viewer( k_addon_type_board, info->board_id ); @@ -184,7 +194,9 @@ static void equip_async( vg_async_task *task ) void skaterift_load_mainsave(void) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + +#if 0 savedata_file file; strcpy( file.path, str_skaterift_main_save ); @@ -237,4 +249,5 @@ void skaterift_load_mainsave(void) vg_info( "Starting new story!\n" ); _world.load_addon = _addon_mount_from_folder_path( "maps/dev_heaven", k_addon_type_world, ".mdl" ); } +#endif } diff --git a/src/save.h b/src/save.h index 8ea303a..e5095f5 100644 --- a/src/save.h +++ b/src/save.h @@ -1,15 +1,13 @@ -#pragma once -#include "vg/vg_platform.h" -#include "vg/vg_msg.h" -#include "addon.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/save.c" +#else typedef struct savedata_file savedata_file; struct savedata_file { char path[256]; - u8 buf[2048]; - vg_msg msg; + vg_kvs kvs; }; void savedata_file_read( savedata_file *file ); @@ -22,3 +20,5 @@ void skaterift_load_mainsave(void); void init_savefile( savedata_file *file, const char *path ); void write_savefile( savedata_file *file, bool async ); + +#endif diff --git a/src/save2.c b/src/save2.c new file mode 100644 index 0000000..ee49a84 --- /dev/null +++ b/src/save2.c @@ -0,0 +1,178 @@ +/* How many save files can be 'open' at once */ +#define MAX_SAVE_FILES 3 + +// In the future +// #define MAX_SAVE_SLOTS 4 + +VG_API void _skaterift_autosave_post_update( void ) +{ + VG_ASSERT(0); +} + +#if 0 + +struct +{ + struct savefile + { + bool ready; + vg_stack_allocator stack; + vg_kvs kvs; + + u16 addon_id; /* 0 for main save */ + } + files[ MAX_SAVE_FILES ]; + vg_pool pool; + vg_pool_chain inactive, active; +} +_savedata; + +void _savedata_init(void) +{ + vg_pool_init( &_savedata.pool, &_savedata.inactive, MAX_SAVE_FILES, &vg.rtmem ); +} + + +// Loading +while( ... ) +{ + if( stage == init ) + { + world->savefile = savedata_handle( world->addon ); + if( world->savefile ) + stage = read_save; + } + else if( stage == read_save ) + { + if( savedata_loaded( world->savefile ) ) + { + // read save + stage = ready; + } + } +} + + +// Game loop +if( autosave_timer() ) +{ + world_autosave(); -> savedata_sync( world->savefile ); +} + +// Unload +savedata_sync( world->savefile ); +savedata_release_handle( world->addon ); + + + + + + + +static u16 _savedata_handle_fork( u16 save_handle ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + if( vg_pool_reference( &_savedata.pool, save_handle, 1 ) == 1 ) + vg_pool_switch( &_savedata.pool, &_savedata.inactive, &_savedata.active ); + + return save_handle; +} + +void _savedata_handle_release( u16 save_handle ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + if( vg_pool_reference( &_savedata.pool, save_handle, 0 ) == 0 ) + vg_pool_switch( &_savedata.pool, &_savedata.active, &_savedata.inactive ); +} + +struct savedata_async_info +{ + u16 save_handle; +}; +static savedata_async( vg_async_queue *queue, void( *fn )(u16), u16 handle ) +{ + vg_async_task *task = vg_allocate_async_task( queue, sizeof(struct savedata_async_info), 1 ); + struct savedata_async_info *info = (void *)complete_task->data; + info->save_handle = handle; + vg_async_task_dispatch( task, savedata_load ); +} + +static savedata_task_complete( vg_async_task *task ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + struct savedata_async_info *info = (void *)task->data; + struct savefile *sf = &_savedata.files[ vg_pool_index( &_savedata.pool, info->save_handle ) ]; + sf->ready = 1; + _savedata_handle_release( info->save_handle ); +} + +void savedata_load( vg_async_task *task ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + struct savedata_async_info *info = (void *)task->data; + struct savefile *sf = &_savedata.files[ vg_pool_index( &_savedata.pool, info->save_handle ) ]; + + vg_stack_clear( &sf->stack ); + vg_kvs_init( &sf->kvs, &sf->stack ); + + c8 path[ 256 ]; + addon_make_savedata_path( sf->addon_id, path ); + + vg_file file; + if( vg_file_stream_open( &file, path ) ) + { + vg_kv_parser parser; + vg_kv_parser_init( &parser, &sf->kvs, 0 ); + + c8 chunk[ 1024 ]; +read_more:; + u32 l = vg_file_stream( &file, chunk, sizeof(chunk) ); + vg_kv_parse_buffer( &parser, chunk, l ); + + if( l == sizeof(chunk) ) + goto read_more; + + vg_file_stream_close( &file ); + } + else + vg_low( "Savefile '%s' did not exist yet. Creating.\n" ); + + vg_async_task *complete_task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct savedata_async_info), 1 ); + struct savedata_async_info *info = (void *)complete_task->data; + info->save_handle = info->save + vg_async_task_dispatch( load_task, savedata_load ); +} + +u16 _savedata_handle( addon_id addon ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + + u16 save_handle = _savedata.active.head; + while( save_handle ) + { + if( _savedata.files[ vg_pool_index( &_savedata.pool, save_handle ) ].addon_id == addon ) + return _savedata_handle_fork( save_handle ); + + save_handle = vg_pool_next( &_savedata.pool, save_handle, 1 ); + } + + save_handle = _savedata.inactive.tail; + if( save_handle ) + { + vg_async_task *load_task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct savedata_async_info), 1 ); + struct savedata_async_info *info = (void *)load_task->data; + info->save_handle = _savedata_handle_fork( save_handle ); + vg_async_task_dispatch( load_task, savedata_load ); + return _savedata_handle_fork( save_handle ); + } + + return 0; +} + +bool _savedata_ready( u16 save_handle ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + return _savedata.files[ vg_pool_index( &_savedata.pool, save_handle ) ].ready; +} + +#endif diff --git a/src/save2.h b/src/save2.h new file mode 100644 index 0000000..9fc2689 --- /dev/null +++ b/src/save2.h @@ -0,0 +1,7 @@ +#if defined( SR_IMPLEMENTATION ) +# include "src/save2.c" +#else + +VG_API void _skaterift_autosave_post_update( void ); + +#endif diff --git a/src/scene.c b/src/scene.c index e204006..5baf159 100644 --- a/src/scene.c +++ b/src/scene.c @@ -1,37 +1,29 @@ -#include "scene.h" - -u32 scene_mem_required( scene_context *ctx ) -{ - u32 vertex_length = vg_align8(ctx->max_vertices * sizeof(scene_vert)), - index_length = vg_align8(ctx->max_indices * sizeof(u32)); - - return vertex_length + index_length; -} - -void scene_init( scene_context *ctx, u32 max_vertices, u32 max_indices ) +VG_TIER_2 void scene_builder_init( scene_builder_context *ctx, u32 max_vertices, u32 max_indices, vg_stack_allocator *stack ) { - ctx->vertex_count = 0; - ctx->indice_count = 0; - ctx->max_vertices = max_vertices; - ctx->max_indices = max_indices; - ctx->arrindices = NULL; /* must be filled out by user */ - ctx->arrvertices = NULL; - - memset( &ctx->submesh, 0, sizeof(mdl_submesh) ); - - v3_fill( ctx->bbx[0], 999999.9f ); - v3_fill( ctx->bbx[1], -999999.9f ); + vg_zero_mem( ctx, sizeof(scene_builder_context) ); + u32 vertex_block_size = vg_align8( max_vertices * sizeof(scene_vert) ), + indice_block_size = vg_align8( max_indices * sizeof(u32) ); + ctx->base_buffer_size = vertex_block_size + indice_block_size; + ctx->base_buffer = vg_stack_allocate( stack, ctx->base_buffer_size, 8, "Scene data" ); + vg_stack_init( &ctx->vertex_stack, ctx->base_buffer, vertex_block_size, "Scene vertices" ); + vg_stack_init( &ctx->indice_stack, ctx->base_buffer + vertex_block_size, indice_block_size, "Scene indices" ); + v3_fill( ctx->scene.bbx[0], 999999.9f ); + v3_fill( ctx->scene.bbx[1], -999999.9f ); } -void scene_supply_buffer( scene_context *ctx, void *buffer ) +VG_TIER_2 void scene_builder_compact_memory( scene_builder_context *ctx, vg_stack_allocator *stack ) { - u32 vertex_length = vg_align8( ctx->max_vertices * sizeof(scene_vert) ); - - ctx->arrvertices = buffer; - ctx->arrindices = (u32*)(((u8*)buffer) + vertex_length); + void *new_indice_location = ctx->base_buffer + vg_align8( ctx->vertex_stack.offset ); + memmove( new_indice_location, ctx->indice_stack.data, ctx->indice_stack.offset ); + ctx->vertex_stack.capacity = ctx->vertex_stack.offset; + ctx->indice_stack.capacity = ctx->indice_stack.offset; + ctx->indice_stack.data = new_indice_location; + u32 new_size = vg_align8( ctx->vertex_stack.capacity ) + vg_align8( ctx->indice_stack.capacity ); + vg_stack_extend_last( stack, (i32)new_size - (i32)ctx->base_buffer_size ); + ctx->base_buffer_size = new_size; } -void scene_vert_pack_norm( scene_vert *vert, v3f norm, f32 blend ) +VG_TIER_0 void scene_vert_pack_norm( scene_vert *vert, v3f norm, f32 blend ) { v3f n; v3_muls( norm, 127.0f, n ); @@ -43,35 +35,19 @@ void scene_vert_pack_norm( scene_vert *vert, v3f norm, f32 blend ) vert->norm[3] = blend * 127.0f; } -/* - * Append a model into the scene with a given transform - */ -void scene_add_mdl_submesh( scene_context *ctx, mdl_context *mdl, - mdl_submesh *sm, m4x3f transform ) +VG_TIER_0 void scene_builder_add_model_submesh( scene_builder_context *ctx, vg_model *model, mdl_submesh *sm, m4x3f transform ) { - if( ctx->vertex_count + sm->vertex_count > ctx->max_vertices ){ - vg_fatal_error( "Scene vertex buffer overflow (%u exceeds %u)\n", - ctx->vertex_count + sm->vertex_count, - ctx->max_vertices ); - } - - if( ctx->indice_count + sm->indice_count > ctx->max_indices ){ - vg_fatal_error( "Scene index buffer overflow (%u exceeds %u)\n", - ctx->indice_count + sm->indice_count, - ctx->max_indices ); - } - - mdl_vert *src_verts = mdl->verts + sm->vertex_start; - scene_vert *dst_verts = &ctx->arrvertices[ ctx->vertex_count ]; - - u32 *src_indices = mdl->indices + sm->indice_start, - *dst_indices = &ctx->arrindices[ ctx->indice_count ]; + VG_ASSERT( model->flags & VG_MODEL_CPU_MESHES ); + mdl_vert *src_verts = model->verts + sm->vertex_start; + scene_vert *dst_verts = vg_stack_allocate( &ctx->vertex_stack, sizeof(scene_vert)*sm->vertex_count, 1, "Verts (submesh)" ); + u32 *src_indices = model->indices + sm->indice_start, + *dst_indices = vg_stack_allocate( &ctx->indice_stack, sizeof(u32)*sm->indice_count, 1, "Indices (submesh)" ); /* Transform and place vertices */ boxf bbxnew; box_init_inf( bbxnew ); m4x3_expand_aabb_aabb( transform, bbxnew, sm->bbx ); - box_concat( ctx->bbx, bbxnew ); + box_concat( ctx->scene.bbx, bbxnew ); m3x3f normal_matrix; m3x3_copy( transform, normal_matrix ); @@ -79,124 +55,107 @@ void scene_add_mdl_submesh( scene_context *ctx, mdl_context *mdl, v3_normalize( normal_matrix[1] ); v3_normalize( normal_matrix[2] ); - for( u32 i=0; ivertex_count; i++ ){ + for( u32 i=0; ivertex_count; i++ ) + { mdl_vert *src = &src_verts[i]; scene_vert *pvert = &dst_verts[i]; - m4x3_mulv( transform, src->co, pvert->co ); v3f normal; m3x3_mulv( normal_matrix, src->norm, normal ); scene_vert_pack_norm( pvert, normal, src->colour[0]*(1.0f/255.0f) ); - v2_copy( src->uv, pvert->uv ); } u32 real_indices = 0; - for( u32 i=0; iindice_count/3; i++ ){ + for( u32 i=0; iindice_count/3; i++ ) + { u32 *src = &src_indices[i*3], *dst = &dst_indices[real_indices]; - v3f ab, ac, tn; v3_sub( src_verts[src[2]].co, src_verts[src[0]].co, ab ); v3_sub( src_verts[src[1]].co, src_verts[src[0]].co, ac ); v3_cross( ac, ab, tn ); - #if 0 if( v3_length2( tn ) <= 0.00001f ) continue; #endif - - dst[0] = src[0] + ctx->vertex_count; - dst[1] = src[1] + ctx->vertex_count; - dst[2] = src[2] + ctx->vertex_count; + dst[0] = src[0] + ctx->scene.vertex_count; + dst[1] = src[1] + ctx->scene.vertex_count; + dst[2] = src[2] + ctx->scene.vertex_count; real_indices += 3; } - if( real_indices != sm->indice_count ) vg_warn( "Zero area triangles in model\n" ); - - ctx->vertex_count += sm->vertex_count; - ctx->indice_count += real_indices; + ctx->scene.vertex_count += sm->vertex_count; + ctx->scene.indice_count += real_indices; } /* * One by one adders for simplified access (mostly procedural stuff) */ -void scene_push_tri( scene_context *ctx, u32 tri[3] ) +VG_TIER_0 void scene_builder_push_tri( scene_builder_context *ctx, u32 tri[3] ) { - if( ctx->indice_count + 3 > ctx->max_indices ) - vg_fatal_error( "Scene indice buffer overflow (%u exceeds %u)\n", - ctx->indice_count+3, ctx->max_indices ); - - u32 *dst = &ctx->arrindices[ ctx->indice_count ]; - + u32 *dst = vg_stack_allocate( &ctx->indice_stack, sizeof(u32)*3, 1, "Indices (single tri)" ); dst[0] = tri[0]; dst[1] = tri[1]; dst[2] = tri[2]; - - ctx->indice_count += 3; + ctx->scene.indice_count += 3; } -void scene_push_vert( scene_context *ctx, scene_vert *v ) +VG_TIER_0 void scene_builder_push_vert( scene_builder_context *ctx, scene_vert *v ) { - if( ctx->vertex_count + 1 > ctx->max_vertices ) - vg_fatal_error( "Scene vertex buffer overflow (%u exceeds %u)\n", - ctx->vertex_count+1, ctx->max_vertices ); - - scene_vert *dst = &ctx->arrvertices[ ctx->vertex_count ]; + scene_vert *dst = vg_stack_allocate( &ctx->vertex_stack, sizeof(scene_vert), 1, "Single vert" ); *dst = *v; - - ctx->vertex_count ++; + ctx->scene.vertex_count ++; } -void scene_copy_slice( scene_context *ctx, mdl_submesh *sm ) +VG_TIER_0 void scene_builder_get_submesh( scene_builder_context *ctx, mdl_submesh *sm ) { - sm->indice_start = ctx->submesh.indice_start; - sm->indice_count = ctx->indice_count - sm->indice_start; - - sm->vertex_start = ctx->submesh.vertex_start; - sm->vertex_count = ctx->vertex_count - sm->vertex_start; - - ctx->submesh.indice_start = ctx->indice_count; - ctx->submesh.vertex_start = ctx->vertex_count; + vg_zero_mem( sm, sizeof(mdl_submesh) ); + sm->indice_start = ctx->current_submesh.indice_start; + sm->indice_count = ctx->scene.indice_count - sm->indice_start; + sm->vertex_start = ctx->current_submesh.vertex_start; + sm->vertex_count = ctx->scene.vertex_count - sm->vertex_start; + ctx->current_submesh.indice_start = ctx->scene.indice_count; + ctx->current_submesh.vertex_start = ctx->scene.vertex_count; } -void scene_set_vertex_flags( scene_context *ctx, - u32 start, u32 count, u16 flags ) +VG_TIER_0 void scene_builder_set_vertex_flags( scene_builder_context *ctx, u32 start, u32 count, u16 flags ) { + scene_vert *verts = vg_stack_pointer( &ctx->vertex_stack, sizeof(scene_vert)*start ); for( u32 i=0; iarrvertices[ start + i ].flags = flags; + verts[ start + i ].flags = flags; } -struct scene_upload_info{ - scene_context *ctx; - glmesh *mesh; -}; - -void async_scene_upload( vg_async_task *task ) +VG_TIER_0 void scene_builder_save_scene( scene_builder_context *ctx, vg_scene *out_scene ) { - THREAD_0; - - struct scene_upload_info *info = (void *)task->data; - - glmesh *mesh = info->mesh; - scene_context *ctx = info->ctx; - - glGenVertexArrays( 1, &mesh->vao ); - glGenBuffers( 1, &mesh->vbo ); - glGenBuffers( 1, &mesh->ebo ); - glBindVertexArray( mesh->vao ); - - size_t stride = sizeof(scene_vert); - - glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo ); - glBufferData( GL_ARRAY_BUFFER, ctx->vertex_count*stride, ctx->arrvertices, GL_STATIC_DRAW ); + *out_scene = ctx->scene; + out_scene->vertex_buffer = vg_stack_pointer( &ctx->vertex_stack, 0 ); + out_scene->indice_buffer = vg_stack_pointer( &ctx->indice_stack, 0 ); +} - glBindVertexArray( mesh->vao ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, ctx->indice_count*sizeof(u32), ctx->arrindices, GL_STATIC_DRAW ); +struct scene_upload_task +{ + vg_scene scene; + scene_mesh *out_mesh; +}; +static void scene_upload_task( struct scene_upload_task *in_args ) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + + glGenVertexArrays( 1, &in_args->out_mesh->vao ); + glBindVertexArray( in_args->out_mesh->vao ); + glGenBuffers( 1, &in_args->out_mesh->vbo ); + glGenBuffers( 1, &in_args->out_mesh->ebo ); + + u32 stride = sizeof(scene_vert); + glBindBuffer( GL_ARRAY_BUFFER, in_args->out_mesh->vbo ); + glBufferData( GL_ARRAY_BUFFER, in_args->scene.vertex_count*stride, in_args->scene.vertex_buffer, GL_STATIC_DRAW ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, in_args->out_mesh->ebo ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, in_args->scene.indice_count * sizeof(u32), + in_args->scene.indice_buffer, GL_STATIC_DRAW ); /* 0: coordinates */ glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 ); @@ -210,55 +169,48 @@ void async_scene_upload( vg_async_task *task ) glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE, stride, (void *)offsetof(scene_vert, uv) ); glEnableVertexAttribArray( 2 ); - mesh->indice_count = ctx->indice_count; - mesh->loaded = 1; - - vg_info( "Scene upload ( XYZ_f32 UV_f32 XYZW_i8 )[ u32 ]\n" ); - vg_info( " indices:%u\n", ctx->indice_count ); - vg_info( " verts:%u\n", ctx->vertex_count ); + vg_info( "Scene uploadd ( XYZ_f32 UV_f32 XYZW_i8 )[ u32 ]\n" ); + vg_info( " indices:%u\n", in_args->scene.indice_count ); + vg_info( " verts:%u\n", in_args->scene.vertex_count ); } -vg_async_task *scene_alloc_async( scene_context *scene, glmesh *mesh, u32 max_vertices, u32 max_indices ) +VG_TIER_2 void scene_builder_upload_async( scene_builder_context *ctx, scene_mesh *out_mesh ) { - THREAD_1; - - scene_init( scene, max_vertices, max_indices ); - u32 buf_size = scene_mem_required( scene ); - - u32 hdr_size = vg_align8(sizeof(struct scene_upload_info)); - vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, hdr_size + buf_size, 1 ); - - struct scene_upload_info *info = (void *)task->data; - - info->mesh = mesh; - info->ctx = scene; - scene_supply_buffer( scene, task->data + hdr_size ); - return task; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + u32 task_args_size = vg_align8( sizeof(struct scene_upload_task) ), + vertex_buffer_size = vg_align8( sizeof(scene_vert) * ctx->scene.vertex_count ), + index_buffer_size = vg_align8( sizeof(u32) * ctx->scene.indice_count ), + total = task_args_size + vertex_buffer_size + index_buffer_size; + struct scene_upload_task *out_args = _vg_async_alloc( VG_THREAD_MAIN_ID, total ); + out_args->scene.vertex_buffer = ((void *)out_args) + task_args_size; + out_args->scene.indice_buffer = ((void *)out_args) + task_args_size + vertex_buffer_size; + out_args->scene.vertex_count = ctx->scene.vertex_count; + out_args->scene.indice_count = ctx->scene.indice_count; + out_args->out_mesh = out_mesh; + memcpy( out_args->scene.vertex_buffer, ctx->scene.vertex_buffer, sizeof(scene_vert) * ctx->scene.vertex_count ); + memcpy( out_args->scene.indice_buffer, ctx->scene.indice_buffer, sizeof(u32) * ctx->scene.indice_count ); + _vg_async_send( out_args, (vg_async_fn)scene_upload_task ); } /* * BVH implementation */ -static void scene_bh_expand_bound( void *user, boxf bound, u32 item_index ) +static void scene_bh_expand_bound( vg_scene *scene, boxf bound, u32 item_index ) { - scene_context *s = user; - scene_vert *pa = &s->arrvertices[ s->arrindices[item_index*3+0] ], - *pb = &s->arrvertices[ s->arrindices[item_index*3+1] ], - *pc = &s->arrvertices[ s->arrindices[item_index*3+2] ]; - + scene_vert *pa = &scene->vertex_buffer[ scene->indice_buffer[item_index*3+0] ], + *pb = &scene->vertex_buffer[ scene->indice_buffer[item_index*3+1] ], + *pc = &scene->vertex_buffer[ scene->indice_buffer[item_index*3+2] ]; box_addpt( bound, pa->co ); box_addpt( bound, pb->co ); box_addpt( bound, pc->co ); } -static float scene_bh_centroid( void *user, u32 item_index, int axis ) +static f32 scene_bh_centroid( vg_scene *scene, u32 item_index, i32 axis ) { - scene_context *s = user; - scene_vert *pa = &s->arrvertices[ s->arrindices[item_index*3+0] ], - *pb = &s->arrvertices[ s->arrindices[item_index*3+1] ], - *pc = &s->arrvertices[ s->arrindices[item_index*3+2] ]; - + scene_vert *pa = &scene->vertex_buffer[ scene->indice_buffer[item_index*3+0] ], + *pb = &scene->vertex_buffer[ scene->indice_buffer[item_index*3+1] ], + *pc = &scene->vertex_buffer[ scene->indice_buffer[item_index*3+2] ]; #if 0 float min, max; @@ -275,12 +227,10 @@ static float scene_bh_centroid( void *user, u32 item_index, int axis ) #endif } -static void scene_bh_swap( void *user, u32 ia, u32 ib ) +static void scene_bh_swap( vg_scene *scene, u32 ia, u32 ib ) { - scene_context *s = user; - - u32 *ti = &s->arrindices[ia*3]; - u32 *tj = &s->arrindices[ib*3]; + u32 *ti = &scene->indice_buffer[ia*3]; + u32 *tj = &scene->indice_buffer[ib*3]; u32 temp[3]; temp[0] = ti[0]; @@ -296,76 +246,72 @@ static void scene_bh_swap( void *user, u32 ia, u32 ib ) tj[2] = temp[2]; } -static void scene_bh_debug( void *user, u32 item_index ) +static void scene_bh_debug( vg_scene *scene, u32 item_index ) { - scene_context *s = user; u32 idx = item_index*3; - scene_vert *pa = &s->arrvertices[ s->arrindices[ idx+0 ] ], - *pb = &s->arrvertices[ s->arrindices[ idx+1 ] ], - *pc = &s->arrvertices[ s->arrindices[ idx+2 ] ]; - + scene_vert *pa = &scene->vertex_buffer[ scene->indice_buffer[item_index*3+0] ], + *pb = &scene->vertex_buffer[ scene->indice_buffer[item_index*3+1] ], + *pc = &scene->vertex_buffer[ scene->indice_buffer[item_index*3+2] ]; vg_line( pa->co, pb->co, 0xff0000ff ); vg_line( pb->co, pc->co, 0xff0000ff ); vg_line( pc->co, pa->co, 0xff0000ff ); } -static void scene_bh_closest( void *user, u32 index, v3f point, v3f closest ) +static void scene_bh_closest( vg_scene *scene, u32 index, v3f point, v3f closest ) { - scene_context *s = user; - v3f positions[3]; - u32 *tri = &s->arrindices[ index*3 ]; + u32 *tri = &scene->indice_buffer[ index*3 ]; for( int i=0; i<3; i++ ) - v3_copy( s->arrvertices[tri[i]].co, positions[i] ); - + v3_copy( scene->vertex_buffer[tri[i]].co, positions[i] ); closest_on_triangle_1( point, positions, closest ); } -bh_system bh_system_scene = +static bh_system bh_system_scene = { - .expand_bound = scene_bh_expand_bound, - .item_centroid = scene_bh_centroid, - .item_closest = scene_bh_closest, - .item_swap = scene_bh_swap, - .item_debug = scene_bh_debug, + .expand_bound = (bh_expand_fn)scene_bh_expand_bound, + .item_centroid = (bh_centroid_fn)scene_bh_centroid, + .item_closest = (bh_closest_fn)scene_bh_closest, + .item_swap = (bh_swap_fn)scene_bh_swap, + .item_debug = (bh_debug_fn)scene_bh_debug, }; /* * An extra step is added onto the end to calculate the hit normal */ -int scene_raycast( scene_context *s, bh_tree *bh, - v3f co, v3f dir, ray_hit *hit, u16 ignore ) +VG_TIER_0 i32 scene_raycast( vg_scene *scene, bh_tree *bh, v3f co, v3f dir, ray_hit *hit, u16 ignore ) { hit->tri = NULL; - bh_iter it; bh_iter_init_ray( 0, &it, co, dir, hit->dist ); i32 idx; - while( bh_next( bh, &it, &idx ) ){ - u32 *tri = &s->arrindices[ idx*3 ]; - - if( s->arrvertices[tri[0]].flags & ignore ) continue; + while( bh_next( bh, &it, &idx ) ) + { + u32 *tri = &scene->indice_buffer[ idx*3 ]; + if( scene->vertex_buffer[tri[0]].flags & ignore ) + continue; v3f vs[3]; for( u32 i=0; i<3; i++ ) - v3_copy( s->arrvertices[tri[i]].co, vs[i] ); + v3_copy( scene->vertex_buffer[tri[i]].co, vs[i] ); f32 t; - if( ray_tri( vs, co, dir, &t, 0 ) ){ - if( t < hit->dist ){ + if( ray_tri( vs, co, dir, &t, 0 ) ) + { + if( t < hit->dist ) + { hit->dist = t; hit->tri = tri; } } } - if( hit->tri ){ + if( hit->tri ) + { v3f v0, v1; - - float *pa = s->arrvertices[hit->tri[0]].co, - *pb = s->arrvertices[hit->tri[1]].co, - *pc = s->arrvertices[hit->tri[2]].co; + f32 *pa = scene->vertex_buffer[hit->tri[0]].co, + *pb = scene->vertex_buffer[hit->tri[1]].co, + *pc = scene->vertex_buffer[hit->tri[2]].co; v3_sub( pa, pb, v0 ); v3_sub( pc, pb, v1 ); @@ -377,8 +323,20 @@ int scene_raycast( scene_context *s, bh_tree *bh, return hit->tri?1:0; } -bh_tree *scene_bh_create( void *lin_alloc, scene_context *s ) +VG_TIER_1 void scene_bh_create( vg_scene *scene, bh_tree *bh, vg_stack_allocator *stack ) +{ + u32 triangle_count = scene->indice_count / 3; + return bh_create( bh, &bh_system_scene, scene, triangle_count, 2, stack ); +} + +VG_TIER_0 void scene_mesh_bind( scene_mesh *mesh ) +{ + glBindVertexArray( mesh->vao ); +} + +VG_TIER_0 void scene_mesh_free( scene_mesh *mesh ) { - u32 triangle_count = s->indice_count / 3; - return bh_create( lin_alloc, &bh_system_scene, s, triangle_count, 2 ); + glDeleteVertexArrays( 1, &mesh->vao ); + glDeleteBuffers( 1, &mesh->ebo ); + glDeleteBuffers( 1, &mesh->vbo ); } diff --git a/src/scene.h b/src/scene.h index c2ba3a9..afe1d9b 100644 --- a/src/scene.h +++ b/src/scene.h @@ -1,10 +1,11 @@ -#pragma once -#include "vg/vg_bvh.h" -#include "common.h" -#include "model.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/scene.c" +#else -typedef struct scene_context scene_context; +typedef struct scene_builder_context scene_builder_context; typedef struct scene_vert scene_vert; +typedef struct scene_mesh scene_mesh; +typedef struct vg_scene vg_scene; #pragma pack(push,1) @@ -21,35 +22,44 @@ struct scene_vert #pragma pack(pop) -/* - * 1. this should probably be a CONTEXT based approach unlike this mess. - * take a bit of the mdl_context ideas and redo this header. its messed up - * pretty bad right now. - */ - -struct scene_context +struct vg_scene { - scene_vert *arrvertices; - u32 *arrindices; + scene_vert *vertex_buffer; + u32 *indice_buffer; + u32 vertex_count, indice_count; + boxf bbx; +}; - u32 vertex_count, indice_count, - max_vertices, max_indices; +struct scene_builder_context +{ + vg_scene scene; + u32 base_buffer_size; + void *base_buffer; + vg_stack_allocator vertex_stack, indice_stack; + mdl_submesh current_submesh; +}; +struct scene_mesh +{ boxf bbx; - mdl_submesh submesh; + GLuint vao, vbo, ebo; }; -extern bh_system bh_system_scene; -bh_tree *scene_bh_create( void *lin_alloc, scene_context *s ); -int scene_raycast( scene_context *s, bh_tree *bh, v3f co, v3f dir, ray_hit *hit, u16 ignore ); -vg_async_task *scene_alloc_async( scene_context *scene, glmesh *mesh, u32 max_vertices, u32 max_indices ); -void scene_copy_slice( scene_context *ctx, mdl_submesh *sm ); -void scene_push_vert( scene_context *ctx, scene_vert *v ); -void scene_vert_pack_norm( scene_vert *vert, v3f norm, f32 blend ); -void scene_push_tri( scene_context *ctx, u32 tri[3] ); -void scene_add_mdl_submesh( scene_context *ctx, mdl_context *mdl, mdl_submesh *sm, m4x3f transform ); -void scene_set_vertex_flags( scene_context *ctx, u32 start, u32 count, u16 flags ); -void scene_supply_buffer( scene_context *ctx, void *buffer ); -void scene_init( scene_context *ctx, u32 max_vertices, u32 max_indices ); -u32 scene_mem_required( scene_context *ctx ); -void async_scene_upload( vg_async_task *task ); +VG_TIER_2 void scene_builder_init( scene_builder_context *ctx, u32 max_vertices, u32 max_indices, vg_stack_allocator *stack ); +VG_TIER_2 void scene_builder_compact_memory( scene_builder_context *ctx, vg_stack_allocator *stack ); +VG_TIER_0 void scene_vert_pack_norm( scene_vert *vert, v3f norm, f32 blend ); +VG_TIER_0 void scene_builder_add_model_submesh( scene_builder_context *ctx, vg_model *model, mdl_submesh *sm, m4x3f transform ); +VG_TIER_0 void scene_builder_push_tri( scene_builder_context *ctx, u32 tri[3] ); +VG_TIER_0 void scene_builder_push_vert( scene_builder_context *ctx, scene_vert *v ); +VG_TIER_0 void scene_builder_get_submesh( scene_builder_context *ctx, mdl_submesh *sm ); +VG_TIER_0 void scene_builder_set_vertex_flags( scene_builder_context *ctx, u32 start, u32 count, u16 flags ); +VG_TIER_2 void scene_builder_upload_async( scene_builder_context *ctx, scene_mesh *out_mesh ); +VG_TIER_0 void scene_builder_save_scene( scene_builder_context *ctx, vg_scene *out_scene ); + +VG_TIER_0 void scene_mesh_bind( scene_mesh *mesh ); +VG_TIER_0 void scene_mesh_free( scene_mesh *mesh ); + +VG_TIER_0 i32 scene_raycast( vg_scene *scene, bh_tree *bh, v3f co, v3f dir, ray_hit *hit, u16 ignore ); +VG_TIER_1 void scene_bh_create( vg_scene *scene, bh_tree *bh, vg_stack_allocator *stack ); + +#endif diff --git a/src/scene_rigidbody.c b/src/scene_rigidbody.c new file mode 100644 index 0000000..d63f778 --- /dev/null +++ b/src/scene_rigidbody.c @@ -0,0 +1,245 @@ +VG_TIER_0 i32 rb_sphere__scene( m4x3f mtxA, f32 r, + m4x3f mtxB, bh_tree *scene_bh, + rb_ct *buf, u16 ignore ) +{ + vg_scene *scene = scene_bh->user; + i32 count = 0; + + boxf box; + v3_sub( mtxA[3], (v3f){ r,r,r }, box[0] ); + v3_add( mtxA[3], (v3f){ r,r,r }, box[1] ); + + bh_iter it; + i32 idx; + bh_iter_init_box( 0, &it, box ); + + while( bh_next( scene_bh, &it, &idx ) ) + { + u32 *ptri = &scene->indice_buffer[ idx*3 ]; + v3f tri[3]; + + if( scene->vertex_buffer[ptri[0]].flags & ignore ) + continue; + + for( u32 j=0; j<3; j++ ) + v3_copy( scene->vertex_buffer[ptri[j]].co, tri[j] ); + buf[ count ].element_id = ptri[0]; + + vg_line( tri[0],tri[1],0x70ff6000 ); + vg_line( tri[1],tri[2],0x70ff6000 ); + vg_line( tri[2],tri[0],0x70ff6000 ); + + i32 contact = rb_sphere__triangle( mtxA, r, tri, &buf[count] ); + count += contact; + + if( count == 16 ) + { + vg_warn( "Exceeding sphere_vs_scene capacity. Geometry too dense!\n" ); + return count; + } + } + return count; +} + +VG_TIER_0 i32 rb_box__scene( m4x3f mtxA, boxf bbx, + m4x3f mtxB, bh_tree *scene_bh, + rb_ct *buf, u16 ignore ) +{ + vg_scene *scene = scene_bh->user; + v3f tri[3]; + + v3f extent, center; + v3_sub( bbx[1], bbx[0], extent ); + v3_muls( extent, 0.5f, extent ); + v3_add( bbx[0], extent, center ); + + f32 r = v3_length(extent); + boxf world_bbx; + v3_fill( world_bbx[0], -r ); + v3_fill( world_bbx[1], r ); + for( u32 i=0; i<2; i++ ) + { + v3_add( center, world_bbx[i], world_bbx[i] ); + v3_add( mtxA[3], world_bbx[i], world_bbx[i] ); + } + + m4x3f to_local; + m4x3_invert_affine( mtxA, to_local ); + + bh_iter it; + bh_iter_init_box( 0, &it, world_bbx ); + i32 idx; + i32 count = 0; + + vg_line_boxf( world_bbx, VG__RED ); + + while( bh_next( scene_bh, &it, &idx ) ) + { + u32 *ptri = &scene->indice_buffer[ idx*3 ]; + if( scene->vertex_buffer[ptri[0]].flags & ignore ) + continue; + + for( u32 j=0; j<3; j++ ) + v3_copy( scene->vertex_buffer[ptri[j]].co, tri[j] ); + + if( rb_box_triangle_sat( extent, center, to_local, tri ) ) + { + vg_line(tri[0],tri[1],0xff50ff00 ); + vg_line(tri[1],tri[2],0xff50ff00 ); + vg_line(tri[2],tri[0],0xff50ff00 ); + } + else + { + vg_line(tri[0],tri[1],0xff0000ff ); + vg_line(tri[1],tri[2],0xff0000ff ); + vg_line(tri[2],tri[0],0xff0000ff ); + continue; + } + + v3f v0,v1,n; + v3_sub( tri[1], tri[0], v0 ); + v3_sub( tri[2], tri[0], v1 ); + v3_cross( v0, v1, n ); + + if( v3_length2( n ) <= 0.00001f ) + { +#ifdef RIGIDBODY_CRY_ABOUT_EVERYTHING + vg_error( "Zero area triangle!\n" ); +#endif + return 0; + } + v3_normalize( n ); + + /* find best feature */ + f32 best = v3_dot( mtxA[0], n ); + i32 axis = 0; + + for( i32 i=1; i<3; i++ ) + { + f32 c = v3_dot( mtxA[i], n ); + if( fabsf(c) > fabsf(best) ) + { + best = c; + axis = i; + } + } + + v3f manifold[4]; + if( axis == 0 ) + { + f32 px = best > 0.0f? bbx[0][0]: bbx[1][0]; + manifold[0][0] = px; + manifold[0][1] = bbx[0][1]; + manifold[0][2] = bbx[0][2]; + manifold[1][0] = px; + manifold[1][1] = bbx[1][1]; + manifold[1][2] = bbx[0][2]; + manifold[2][0] = px; + manifold[2][1] = bbx[1][1]; + manifold[2][2] = bbx[1][2]; + manifold[3][0] = px; + manifold[3][1] = bbx[0][1]; + manifold[3][2] = bbx[1][2]; + } + else if( axis == 1 ) + { + f32 py = best > 0.0f? bbx[0][1]: bbx[1][1]; + manifold[0][0] = bbx[0][0]; + manifold[0][1] = py; + manifold[0][2] = bbx[0][2]; + manifold[1][0] = bbx[1][0]; + manifold[1][1] = py; + manifold[1][2] = bbx[0][2]; + manifold[2][0] = bbx[1][0]; + manifold[2][1] = py; + manifold[2][2] = bbx[1][2]; + manifold[3][0] = bbx[0][0]; + manifold[3][1] = py; + manifold[3][2] = bbx[1][2]; + } + else + { + f32 pz = best > 0.0f? bbx[0][2]: bbx[1][2]; + manifold[0][0] = bbx[0][0]; + manifold[0][1] = bbx[0][1]; + manifold[0][2] = pz; + manifold[1][0] = bbx[1][0]; + manifold[1][1] = bbx[0][1]; + manifold[1][2] = pz; + manifold[2][0] = bbx[1][0]; + manifold[2][1] = bbx[1][1]; + manifold[2][2] = pz; + manifold[3][0] = bbx[0][0]; + manifold[3][1] = bbx[1][1]; + manifold[3][2] = pz; + } + + for( u32 j=0; j<4; j++ ) + m4x3_mulv( mtxA, manifold[j], manifold[j] ); + + vg_line( manifold[0], manifold[1], 0xffffffff ); + vg_line( manifold[1], manifold[2], 0xffffffff ); + vg_line( manifold[2], manifold[3], 0xffffffff ); + vg_line( manifold[3], manifold[0], 0xffffffff ); + + for( u32 j=0; j<4; j++ ) + { + rb_ct *ct = buf+count; + v3_copy( manifold[j], ct->co ); + v3_copy( n, ct->n ); + + f32 l0 = v3_dot( tri[0], n ), + l1 = v3_dot( manifold[j], n ); + + ct->p = (l0-l1)*0.5f; + if( ct->p < 0.0f ) + continue; + + ct->type = k_contact_type_default; + count ++; + + if( count >= 12 ) + return count; + } + } + return count; +} + +/* mtxB is defined only for tradition; it is not used currently */ +VG_TIER_0 i32 rb_capsule__scene( m4x3f mtxA, rb_capsule *c, + m4x3f mtxB, bh_tree *scene_bh, + rb_ct *buf, u16 ignore ) +{ + vg_scene *scene = scene_bh->user; + i32 count = 0; + boxf bbx; + v3_sub( mtxA[3], (v3f){ c->h, c->h, c->h }, bbx[0] ); + v3_add( mtxA[3], (v3f){ c->h, c->h, c->h }, bbx[1] ); + + + bh_iter it; + bh_iter_init_box( 0, &it, bbx ); + i32 idx; + while( bh_next( scene_bh, &it, &idx ) ) + { + u32 *ptri = &scene->indice_buffer[ idx*3 ]; + if( scene->vertex_buffer[ptri[0]].flags & ignore ) + continue; + + v3f tri[3]; + for( u32 j=0; j<3; j++ ) + v3_copy( scene->vertex_buffer[ptri[j]].co, tri[j] ); + + buf[ count ].element_id = ptri[0]; + i32 contact = rb_capsule__triangle( mtxA, c, tri, &buf[count] ); + count += contact; + + if( count >= 16 ) + { + vg_warn("Exceeding capsule_vs_scene capacity. Geometry too dense!\n"); + return count; + } + } + + return count; +} diff --git a/src/scene_rigidbody.h b/src/scene_rigidbody.h index 57ff1ff..e219255 100644 --- a/src/scene_rigidbody.h +++ b/src/scene_rigidbody.h @@ -1,247 +1,18 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/scene_rigidbody.c" +#else -/* - * Copyright (C) 2021-2024 Mt.ZERO Software - All Rights Reserved - * - * Describes intereactions between vg rigidbody objects and skaterift's scene - * description - */ +VG_TIER_0 i32 rb_sphere__scene( m4x3f mtxA, f32 r, + m4x3f mtxB, bh_tree *scene_bh, + rb_ct *buf, u16 ignore ); -#include "scene.h" -#include "vg/vg_rigidbody.h" -#include "vg/vg_rigidbody_collision.h" - -static int rb_sphere__scene( m4x3f mtxA, f32 r, - m4x3f mtxB, bh_tree *scene_bh, rb_ct *buf, - u16 ignore ){ - scene_context *sc = scene_bh->user; - - int count = 0; - - boxf box; - v3_sub( mtxA[3], (v3f){ r,r,r }, box[0] ); - v3_add( mtxA[3], (v3f){ r,r,r }, box[1] ); - - bh_iter it; - i32 idx; - bh_iter_init_box( 0, &it, box ); - - while( bh_next( scene_bh, &it, &idx ) ){ - u32 *ptri = &sc->arrindices[ idx*3 ]; - v3f tri[3]; - - if( sc->arrvertices[ptri[0]].flags & ignore ) continue; - - for( int j=0; j<3; j++ ) - v3_copy( sc->arrvertices[ptri[j]].co, tri[j] ); - - buf[ count ].element_id = ptri[0]; - - vg_line( tri[0],tri[1],0x70ff6000 ); - vg_line( tri[1],tri[2],0x70ff6000 ); - vg_line( tri[2],tri[0],0x70ff6000 ); - - int contact = rb_sphere__triangle( mtxA, r, tri, &buf[count] ); - count += contact; - - if( count == 16 ){ - vg_warn( "Exceeding sphere_vs_scene capacity. Geometry too dense!\n" ); - return count; - } - } - - return count; -} - -static int rb_box__scene( m4x3f mtxA, boxf bbx, - m4x3f mtxB, bh_tree *scene_bh, - rb_ct *buf, u16 ignore ){ - scene_context *sc = scene_bh->user; - v3f tri[3]; - - v3f extent, center; - v3_sub( bbx[1], bbx[0], extent ); - v3_muls( extent, 0.5f, extent ); - v3_add( bbx[0], extent, center ); - - f32 r = v3_length(extent); - boxf world_bbx; - v3_fill( world_bbx[0], -r ); - v3_fill( world_bbx[1], r ); - for( int i=0; i<2; i++ ){ - v3_add( center, world_bbx[i], world_bbx[i] ); - v3_add( mtxA[3], world_bbx[i], world_bbx[i] ); - } - - m4x3f to_local; - m4x3_invert_affine( mtxA, to_local ); - - bh_iter it; - bh_iter_init_box( 0, &it, world_bbx ); - int idx; - int count = 0; - - vg_line_boxf( world_bbx, VG__RED ); - - while( bh_next( scene_bh, &it, &idx ) ){ - u32 *ptri = &sc->arrindices[ idx*3 ]; - if( sc->arrvertices[ptri[0]].flags & ignore ) continue; - - for( int j=0; j<3; j++ ) - v3_copy( sc->arrvertices[ptri[j]].co, tri[j] ); - - if( rb_box_triangle_sat( extent, center, to_local, tri ) ){ - vg_line(tri[0],tri[1],0xff50ff00 ); - vg_line(tri[1],tri[2],0xff50ff00 ); - vg_line(tri[2],tri[0],0xff50ff00 ); - } - else{ - vg_line(tri[0],tri[1],0xff0000ff ); - vg_line(tri[1],tri[2],0xff0000ff ); - vg_line(tri[2],tri[0],0xff0000ff ); - continue; - } - - v3f v0,v1,n; - v3_sub( tri[1], tri[0], v0 ); - v3_sub( tri[2], tri[0], v1 ); - v3_cross( v0, v1, n ); - - if( v3_length2( n ) <= 0.00001f ){ -#ifdef RIGIDBODY_CRY_ABOUT_EVERYTHING - vg_error( "Zero area triangle!\n" ); -#endif - return 0; - } - - v3_normalize( n ); - - /* find best feature */ - f32 best = v3_dot( mtxA[0], n ); - int axis = 0; - - for( int i=1; i<3; i++ ){ - f32 c = v3_dot( mtxA[i], n ); - - if( fabsf(c) > fabsf(best) ){ - best = c; - axis = i; - } - } - - v3f manifold[4]; - - if( axis == 0 ){ - f32 px = best > 0.0f? bbx[0][0]: bbx[1][0]; - manifold[0][0] = px; - manifold[0][1] = bbx[0][1]; - manifold[0][2] = bbx[0][2]; - manifold[1][0] = px; - manifold[1][1] = bbx[1][1]; - manifold[1][2] = bbx[0][2]; - manifold[2][0] = px; - manifold[2][1] = bbx[1][1]; - manifold[2][2] = bbx[1][2]; - manifold[3][0] = px; - manifold[3][1] = bbx[0][1]; - manifold[3][2] = bbx[1][2]; - } - else if( axis == 1 ){ - f32 py = best > 0.0f? bbx[0][1]: bbx[1][1]; - manifold[0][0] = bbx[0][0]; - manifold[0][1] = py; - manifold[0][2] = bbx[0][2]; - manifold[1][0] = bbx[1][0]; - manifold[1][1] = py; - manifold[1][2] = bbx[0][2]; - manifold[2][0] = bbx[1][0]; - manifold[2][1] = py; - manifold[2][2] = bbx[1][2]; - manifold[3][0] = bbx[0][0]; - manifold[3][1] = py; - manifold[3][2] = bbx[1][2]; - } - else{ - f32 pz = best > 0.0f? bbx[0][2]: bbx[1][2]; - manifold[0][0] = bbx[0][0]; - manifold[0][1] = bbx[0][1]; - manifold[0][2] = pz; - manifold[1][0] = bbx[1][0]; - manifold[1][1] = bbx[0][1]; - manifold[1][2] = pz; - manifold[2][0] = bbx[1][0]; - manifold[2][1] = bbx[1][1]; - manifold[2][2] = pz; - manifold[3][0] = bbx[0][0]; - manifold[3][1] = bbx[1][1]; - manifold[3][2] = pz; - } - - for( int j=0; j<4; j++ ) - m4x3_mulv( mtxA, manifold[j], manifold[j] ); - - vg_line( manifold[0], manifold[1], 0xffffffff ); - vg_line( manifold[1], manifold[2], 0xffffffff ); - vg_line( manifold[2], manifold[3], 0xffffffff ); - vg_line( manifold[3], manifold[0], 0xffffffff ); - - for( int j=0; j<4; j++ ){ - rb_ct *ct = buf+count; - - v3_copy( manifold[j], ct->co ); - v3_copy( n, ct->n ); - - f32 l0 = v3_dot( tri[0], n ), - l1 = v3_dot( manifold[j], n ); - - ct->p = (l0-l1)*0.5f; - if( ct->p < 0.0f ) - continue; - - ct->type = k_contact_type_default; - count ++; - - if( count >= 12 ) - return count; - } - } - return count; -} +VG_TIER_0 i32 rb_box__scene( m4x3f mtxA, boxf bbx, + m4x3f mtxB, bh_tree *scene_bh, + rb_ct *buf, u16 ignore ); /* mtxB is defined only for tradition; it is not used currently */ -static int rb_capsule__scene( m4x3f mtxA, rb_capsule *c, - m4x3f mtxB, bh_tree *scene_bh, - rb_ct *buf, u16 ignore ){ - int count = 0; - - boxf bbx; - v3_sub( mtxA[3], (v3f){ c->h, c->h, c->h }, bbx[0] ); - v3_add( mtxA[3], (v3f){ c->h, c->h, c->h }, bbx[1] ); - - scene_context *sc = scene_bh->user; - - bh_iter it; - bh_iter_init_box( 0, &it, bbx ); - i32 idx; - while( bh_next( scene_bh, &it, &idx ) ){ - u32 *ptri = &sc->arrindices[ idx*3 ]; - if( sc->arrvertices[ptri[0]].flags & ignore ) continue; - - v3f tri[3]; - for( int j=0; j<3; j++ ) - v3_copy( sc->arrvertices[ptri[j]].co, tri[j] ); - - buf[ count ].element_id = ptri[0]; - - int contact = rb_capsule__triangle( mtxA, c, tri, &buf[count] ); - count += contact; - - if( count >= 16 ){ - vg_warn("Exceeding capsule_vs_scene capacity. Geometry too dense!\n"); - return count; - } - } - - return count; -} +VG_TIER_0 i32 rb_capsule__scene( m4x3f mtxA, rb_capsule *c, + m4x3f mtxB, bh_tree *scene_bh, + rb_ct *buf, u16 ignore ); +#endif diff --git a/src/scripts/board_maker.c b/src/scripts/board_maker.c index 6788e1a..12629d6 100644 --- a/src/scripts/board_maker.c +++ b/src/scripts/board_maker.c @@ -4,7 +4,7 @@ static bool _skaterift_script_board_maker( ent_script_event *event ) { struct script_event_world_io *inf = event->info; world_instance *world = &_world.main; - if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "open" ) ) + if( AF_STR_EQ( world->meta.packed_strings, inf->event->pstr_recieve_event, "open" ) ) { // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you) if( inf->event->flags & k_ent_event_data_const_entity_id ) @@ -22,7 +22,7 @@ static bool _skaterift_script_board_maker( ent_script_event *event ) while( _ent_list_iter( &iter ) ) { ent_marker *marker = af_arritm( &world->ent_marker, iter.index ); - const char *alias = af_str( &world->meta.af, marker->pstr_alias ); + const char *alias = af_str( world->meta.packed_strings, marker->pstr_alias ); if( !strcmp( alias, "$board_position" ) ) v3_copy( marker->transform.co, _board_maker.origin ); diff --git a/src/scripts/boost.c b/src/scripts/boost.c index 2f3fb42..6a0a3ed 100644 --- a/src/scripts/boost.c +++ b/src/scripts/boost.c @@ -4,7 +4,7 @@ static bool _script_boost( ent_script_event *event ) { struct script_event_world_io *inf = event->info; world_instance *world = &_world.main; - if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "boost" ) ) + if( AF_STR_EQ( world->meta.packed_strings, inf->event->pstr_recieve_event, "boost" ) ) { // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you) if( inf->event->flags & k_ent_event_data_const_entity_id ) diff --git a/src/scripts/explode.c b/src/scripts/explode.c index d5de82d..b9b1488 100644 --- a/src/scripts/explode.c +++ b/src/scripts/explode.c @@ -4,7 +4,7 @@ static bool _skaterift_script_explode( ent_script_event *event ) { struct script_event_world_io *inf = event->info; world_instance *world = &_world.main; - if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "explode" ) ) + if( AF_STR_EQ( world->meta.packed_strings, inf->event->pstr_recieve_event, "explode" ) ) { // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you) if( inf->event->flags & k_ent_event_data_const_entity_id ) diff --git a/src/scripts/generic.c b/src/scripts/generic.c index 2480cf9..394151c 100644 --- a/src/scripts/generic.c +++ b/src/scripts/generic.c @@ -4,17 +4,17 @@ static bool _skaterift_script_generic( ent_script_event *event ) { struct script_event_world_io *inf = event->info; world_instance *world = &_world.main; - if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "unlock_mtzero" ) ) + if( AF_STR_EQ( world->meta.packed_strings, inf->event->pstr_recieve_event, "unlock_mtzero" ) ) { - gui_notify( "\xb8 Mt.Zero Unlocked!", 8.0f, k_ui_green ); + _gui_notify( "\xb8 Mt.Zero Unlocked!", 8.0f, k_ui_green ); } - if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "unlock_city" ) ) + if( AF_STR_EQ( world->meta.packed_strings, inf->event->pstr_recieve_event, "unlock_city" ) ) { - gui_notify( "\xb8 Downtown Unlocked!", 8.0f, k_ui_green ); + _gui_notify( "\xb8 Downtown Unlocked!", 8.0f, k_ui_green ); } - if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "unlock_valley" ) ) + if( AF_STR_EQ( world->meta.packed_strings, inf->event->pstr_recieve_event, "unlock_valley" ) ) { - gui_notify( "\xb8 Valley Unlocked!", 8.0f, k_ui_green ); + _gui_notify( "\xb8 Valley Unlocked!", 8.0f, k_ui_green ); } } return 1; diff --git a/src/scripts/l1_speed.c b/src/scripts/l1_speed.c index ca1f3ee..b144e63 100644 --- a/src/scripts/l1_speed.c +++ b/src/scripts/l1_speed.c @@ -8,7 +8,7 @@ static bool _script_l1_speed( ent_script_event *event ) if( event->type == k_escript_event_allocate ) { struct script_event_allocate *event_info = event->info; - struct script_speed *s = VG_STACK_ALLOCATE_STRUCT( event_info->heap, struct script_speed ); + struct script_speed *s = vg_stack_allocate( event_info->heap, sizeof(struct script_speed), 8, "Script data" ); s->ok = 0; s->init = 0; event_info->userdata = s; diff --git a/src/scripts/tutorial_island.c b/src/scripts/tutorial_island.c index eff9853..1bfd76a 100644 --- a/src/scripts/tutorial_island.c +++ b/src/scripts/tutorial_island.c @@ -9,7 +9,7 @@ static bool _skaterift_script_volc( ent_script_event *event ) if( event->type == k_escript_event_allocate ) { struct script_event_allocate *event_info = event->info; - struct script_volcano *v = VG_STACK_ALLOCATE_STRUCT( event_info->heap, struct script_volcano ); + struct script_volcano *v = vg_stack_allocate( event_info->heap, sizeof(struct script_volcano), 8, "Script data" ); v->docks_wait = 0; v->stopped_timer = 0.0f; event_info->userdata = v; @@ -22,7 +22,7 @@ static bool _skaterift_script_volc( ent_script_event *event ) struct script_event_world_io *inf = event->info; world_instance *world = &_world.main; - if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "unlock_docks" ) ) + if( AF_STR_EQ( world->meta.packed_strings, inf->event->pstr_recieve_event, "unlock_docks" ) ) { v->docks_wait = 1; } diff --git a/src/serialized_replay.h b/src/serialized_replay.h deleted file mode 100644 index c5e76c6..0000000 --- a/src/serialized_replay.h +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "network_msg.h" diff --git a/src/shader_props.h b/src/shader_props.h index 43cf6ff..33ab07d 100644 --- a/src/shader_props.h +++ b/src/shader_props.h @@ -1,47 +1,12 @@ -#pragma once -#include "vg/vg_platform.h" +#if defined( SR_IMPLEMENTATION ) +//# include "src/shader_props.c" +#else enum material_render_flag { k_material_render_additive = 0x20 }; -struct shader_props_standard -{ - u32 tex_diffuse; - u32 render_flags; -}; - -struct shader_props_terrain -{ - u32 tex_diffuse; - v2f blend_offset; - v4f sand_colour; -}; - -struct shader_props_vertex_blend -{ - u32 tex_diffuse; - v2f blend_offset; -}; - -struct shader_props_water -{ - v4f shore_colour; - v4f deep_colour; - f32 fog_scale; - f32 fresnel; - f32 water_sale; - v4f wave_speed; -}; - -struct shader_props_cubemapped -{ - u32 tex_diffuse; - u32 cubemap_entity; - v4f tint; -}; - enum workshop_shader_part { k_workshop_shader_part_truck1, @@ -55,8 +20,57 @@ enum workshop_shader_part k_workshop_shader_part_deck, k_workshop_shader_part_max }; -struct shader_props_workshop + +union shader_props { - u32 tex_all[k_workshop_shader_part_max]; + struct shader_props_standard + { + u32 tex_diffuse; + u32 render_flags; + } + standard; + + struct shader_props_terrain + { + u32 tex_diffuse; + v2f blend_offset; + v4f sand_colour; + } + terrain; + + struct shader_props_vertex_blend + { + u32 tex_diffuse; + v2f blend_offset; + } + vertex_blend; + + struct shader_props_water + { + v4f shore_colour; + v4f deep_colour; + f32 fog_scale; + f32 fresnel; + f32 water_sale; + v4f wave_speed; + } + water; + + struct shader_props_cubemapped + { + u32 tex_diffuse; + u32 cubemap_entity; + v4f tint; + } + cubemapped; + + struct shader_props_workshop + { + u32 tex_all[k_workshop_shader_part_max]; + } + workshop; }; + extern const char *_shader_prop_workshop_keys[k_workshop_shader_part_max]; + +#endif diff --git a/src/skaterift.c b/src/skaterift.c index e4652e7..e69de29 100644 --- a/src/skaterift.c +++ b/src/skaterift.c @@ -1,721 +0,0 @@ -/* - * ============================================================================= - * - * Copyright . . . -----, ,----- ,---. .---. - * 2021-2025 |\ /| | / | | | | /| - * | \ / | +-- / +----- +---' | / | - * | \ / | | / | | \ | / | - * | \/ | | / | | \ | / | - * ' ' '--' [] '----- '----- ' ' '---' SOFTWARE - * - * ============================================================================= - */ - -#define SR_ALLOW_REWIND_HUB - -#ifdef _WIN32 - #include -#endif - -/* - * system headers - * --------------------- */ - -#include "vg/vg_opt.h" -#include "vg/vg_loader.h" -#include "vg/vg_io.h" - -#include "skaterift.h" -#include "render.h" -#include "world.h" -#include "font.h" -#include "player.h" -#include "network.h" -#include "menu.h" -#include "save.h" -#include "player_remote.h" -#include "particle.h" -#include "trail.h" -#include "freecam.h" -#include "ent_tornado.h" -#include "ent_skateshop.h" -#include "ent_camera.h" -#include "world_map.h" -#include "gui.h" -#include "workshop.h" -#include "audio.h" -#include "player_render.h" -#include "control_overlay.h" -#include "client.h" -#include "skaterift_script.h" -#include "ent_challenge.h" -#include "ent_script.h" -#include "board_maker.h" -#include "compass.h" -#include "replay2.h" -#include "user_profile.h" -#include "ent_route.h" -#include "ent_npc.h" -#include "ent_list.h" -#include "ent_atom.h" - -struct skaterift_globals skaterift = -{ - .time_rate = 1.0f, -}; - -static void skaterift_load_player_content(void) -{ - particle_alloc( &particles_grind, 300 ); - particle_alloc( &particles_env, 200 ); - - player_load_animation_reference( "models/ch_none.mdl" ); - player_load_animations( "metascenes/skater.ms" ); - player_model_load( &localplayer.fallback_model, "models/ch_none.mdl", &vg.rtmem ); - player__bind(); - player_board_load( &localplayer.fallback_board, "models/board_none.mdl", &vg.rtmem ); -} - -int skaterift_quit_command( int argc, const char *argv[] ) -{ - if( argc >= 1 ) - if( !strcmp( argv[0], "1" ) ) - skaterift.no_save_location = 1; - - vg.window_should_close = 1; - return 1; -} - -static void game_load_co( vg_coroutine *co ) -{ - if( co_begin( co ) ) - { - co_thread( co, 0, &vg.main_tasks ); - co_thread( co, 1, &vg.loader_tasks ); - } - - if( co_step( co, 1 ) ) - { - vg_loader_step( render_init, NULL ); - - /* please forgive me! */ - if( g_client.demo_mode != 2 ) - { - u32 sz; char *drm; - if( (drm = vg_file_read( &vg.scratch, "DRM", &sz, 1 )) ) - if( !strcmp(drm, "blibby!") ) - g_client.demo_mode = 0; - } - - vg_loader_step( remote_players_init, NULL ); - - vg_loader_step( network_init, network_end ); - vg_loader_set_user_information( "Initializing subsystems" ); - vg_loader_step( menu_init, NULL ); - vg_loader_step( _user_profile_init, NULL ); - vg_loader_step( control_overlay_init, NULL ); - vg_loader_step( world_init, NULL ); - vg_loader_step( gui_init, NULL ); - vg_loader_step( compass_init, NULL ); - - vg_loader_step( player_init, NULL ); - - /* content stuff */ - vg_loader_step( addon_system_init, NULL ); - vg_loader_step( skateshop_init, NULL ); - vg_loader_step( world_map_init, NULL ); - vg_loader_step( skaterift_load_player_content, NULL ); - vg_loader_step( _replay2_init, NULL ); - vg_loader_step( _ent_npc_init, NULL ); - - vg_loader_set_user_information( "Compiling shaders" ); - vg_bake_shaders(); - - vg_loader_set_user_information( "Loading content files" ); - vg_loader_step( audio_init, NULL ); - - _world.default_hub_addon = _addon_mount_from_folder_path( "maps/dev_hub", k_addon_type_world, ".mdl" ); - VG_ASSERT( _world.default_hub_addon ); - - vg_loader_set_user_information( "Mounting addons" ); - _addon_mount_content_folder( k_addon_type_player, "playermodels", ".mdl" ); - _addon_mount_content_folder( k_addon_type_board, "boards", ".mdl" ); - _addon_mount_content_folder( k_addon_type_world, "maps", ".mdl" ); - } - - if( co_step( co, 0 ) ) - { - _mount_workshop_addons( NULL ); - _ent_atom_init(); - } - - /* stalling for workshop to complete */ - if( co_step( co, 1 ) ){} - if( co_step( co, 0 ) ){} - - if( co_step( co, 1 ) ) - { - /* initializing / loading world. */ - vg_loader_set_user_information( "Loading savedata" ); - skaterift_load_mainsave(); - - if( skaterift.override_load_world ) - _world.load_addon = _addon_mount_from_folder_path( skaterift.override_load_world, k_addon_type_world, ".mdl" ); - - _world.loader_instance = &_world.main; - _world.loader_preview_mode = 0; - _world.loader_stack = _world.stack; - - if( !_world.load_addon ) - { - vg_warn( "Falling back to default hub world...\n" ); - _world.load_addon = _world.default_hub_addon; - } - - _world_loader_set_addon( _world.load_addon ); - } - - if( co_step( co, 0 ) ) - { - _world.loader_state = k_world_loader_ready; - - if( network_client.auto_connect ) - network_client.user_intent = k_server_intent_online; - menu_at_begin(); - } - - if( co_step( co, 1 ) ) - { - vg_loader_step( NULL, skaterift_autosave_synchronous ); - _vg_tower_set_flag( vg.sig_client, 1 ); - } - - co_end( co ); -} - -/* - * UPDATE LOOP - * ---------------------------------------------------------------------------*/ - -static void draw_origin_axis(void) -{ - vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 ); - vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 ); - vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff ); -} -void skaterift_change_client_world_preupdate(void); - -void vg_pre_update(void) -{ - if( !_vg_tower_clearence( _vg_tower_mask(vg.sig_engine)|_vg_tower_mask(vg.sig_client) ) ) - return; - - skaterift_preupdate_inputs(); - world_switcher_update(); - - if( !_vg_tower_clearence( skaterift.full_ready_mask ) ) - return; - - //draw_origin_axis(); - //_skaterift_script_update(); - _addon_system_pre_update(); - network_update(); - - /* time rate */ - f32 target = 1; - if( skaterift.activity & k_skaterift_replay ) - target = 0; - - if( skaterift.activity == k_skaterift_spectate ) - { - if( button_down( k_srbind_mback ) ) - { - vg_audio_lock(); - vg_audio_oneshot( &audio_ui[3], 1.0f, 0.0f, 0, 0 ); - vg_audio_unlock(); - menu_close(); /* sets tate to default*/ - menu_open( k_menu_page_quick ); - gui_helper_reset( k_gui_helper_mode_clear ); - localplayer.immobile = 0; - } - } - - world_update( &_world.main, localplayer.rb.co ); - _board_maker_pre_update(); - - cutscene_update( vg.time_rate * vg.time_frame_delta ); - - if( !((skaterift.activity == k_skaterift_menu) && (menu.page != k_menu_page_quick)) ) - player__pre_update(); - - _replay2_pre_update(); - remote_sfx_pre_update(); - - v3f listen_co; - v3_copy( localplayer.rb.co, listen_co ); - if( skaterift.activity & k_skaterift_menu ) - { - if( menu.page != k_menu_page_quick ) - { - if( menu.bg_cam ) - v3_copy( menu.bg_cam->co, listen_co ); - else target = 0; - } - } - audio_ambient_sprites_update( &_world.main, listen_co ); - - vg_slewf( &skaterift.time_rate, target, vg.time_frame_delta * (1.0f/0.3f) ); - vg.time_rate = vg_smoothstepf( skaterift.time_rate ); -} - -void vg_fixed_update(void) -{ - if( !_vg_tower_clearence( skaterift.full_ready_mask ) ) - return; - - world_routes_fixedupdate( &_world.main ); - player__update(); -} - -void vg_post_update(void) -{ - if( !_vg_tower_clearence( skaterift.full_ready_mask ) ) - return; - - player__post_update(); - - float dist; - int sample_index; - world_audio_sample_distances( localplayer.rb.co, &sample_index, &dist ); - - vg_audio_lock(); - vg_dsp.echo_distances[sample_index] = dist; - - v3f ears = { 1.0f,0.0f,0.0f }; - m3x3_mulv( g_render.cam.transform, ears, ears ); - v3_copy( ears, _vg_audio.controls.listener_right_ear_direction ); - v3_copy( g_render.cam.transform[3], _vg_audio.controls.listener_position ); - - if( localplayer.gate_waiting ) - m4x3_mulv( localplayer.gate_waiting->transport, _vg_audio.controls.listener_position, _vg_audio.controls.listener_position ); - - v3_copy( localplayer.rb.v, _vg_audio.controls.listener_velocity ); - vg_audio_unlock(); - - skaterift_autosave_update(); - - localplayer.immunity = 0; -} - -/* - * RENDERING - * ---------------------------------------------------------------------------*/ - -static void render_player_transparent(void) -{ - if( (skaterift.activity == k_skaterift_menu) && - (menu.page == k_menu_page_main) && - (menu.main_index == k_menu_main_guide) ) - { - return; - } - - if( skaterift.activity == k_skaterift_replay ) - return; - - static vg_camera small_cam; /* DOES NOT NEED TO BE STATIC BUT MINGW - SAIS OTHERWISE */ - - m4x3_copy( g_render.cam.transform, small_cam.transform ); - - small_cam.fov = g_render.cam.fov; - small_cam.nearz = 0.05f; - small_cam.farz = 60.0f; - - vg_camera_update_view( &small_cam ); - vg_camera_update_projection( &small_cam, vg.window_x, vg.window_y ); - vg_camera_finalize( &small_cam ); - - /* Draw player to window buffer and blend background ontop */ - player__render( &small_cam ); -} - -static void render_scene(void) -{ -} - -static void skaterift_composite_maincamera(void) -{ - /* world entity driven camera - * ------------------------------------------------------------------------------ */ - if( _world.entity_set_camera ) - { - _world.entity_set_camera = 0; - _world.entity_camera_modulate = vg_minf( 1.0f, _world.entity_camera_modulate+vg.time_frame_delta ); - } - else - { - _world.entity_camera_modulate = vg_maxf( 0.0f, _world.entity_camera_modulate-vg.time_frame_delta ); - } - - vg_camera_lerp( &localplayer.cam, &_world.entity_driven_camera, - vg_smoothstepf(_world.entity_camera_modulate), &g_render.cam ); - - /* replay camera - * ------------------------------------------------------------------ */ - if( skaterift.activity == k_skaterift_replay ) - { - _replay2_get_camera( &g_render.cam ); - } - - if( skaterift.activity == k_skaterift_spectate ) - { - _network_get_spectate_cam( &g_render.cam ); - } - - g_render.cam.nearz = 0.1f; - g_render.cam.farz = 2100.0f; - - /* menu override camera - * -------------------------------------------------------------------- */ - if( (skaterift.activity == k_skaterift_menu) && menu.bg_cam ) - { - ent_camera_unpack( menu.bg_cam, &g_render.cam ); - } - - /* cutscene camera TODO: Fix the action camera - * ---------------------------------------------------------------- */ - ent_camera *cs_cam = _cutscene_active_camera(); - if( cs_cam ) - ent_camera_unpack( cs_cam, &g_render.cam ); - - world_map_get_transition_cam( &g_render.cam ); - - vg_camera_update_transform( &g_render.cam ); - - vg_camera_update_view( &g_render.cam ); - vg_camera_update_projection( &g_render.cam, vg.window_x, vg.window_y ); - vg_camera_finalize( &g_render.cam ); -} - -static void render_main_game(void) -{ - if( (_cutscene.state >= k_cutscene_state_ready) && _cutscene.player_binding ) - { - struct cs_instance *inst = _cutscene.player_binding; - struct skeleton *sk = &localplayer.skeleton; - for( u32 i=0; ibone_count; i ++ ) - m4x3_copy( inst->skinning_data[i], localplayer.final_mtx[i] ); - } - else if( skaterift.activity == k_skaterift_replay ){} - else - { - player__animate(); - _replay2_record_local_frame(); - } - - animate_remote_players(); - player__pre_render(); - - skaterift_composite_maincamera(); - - bool render_actual_game = !menu_viewing_map(); - bool render_stenciled = 0; - - if( render_actual_game ) - { - world_instance *world = &_world.main; - render_world_cubemaps( world ); - } - - /* variable res target */ - vg_framebuffer_bind( _vg_render.fb_main, _vg_render.scale ); - glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); - - if( !render_actual_game ) - { - render_world_map(); - - if( world_map_get_transition_cam(NULL) ) - { - glEnable( GL_STENCIL_TEST ); - glDisable( GL_DEPTH_TEST ); - glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); - glStencilFunc( GL_ALWAYS, 1, 0xFF ); - glStencilMask( 0xFF ); - - shader_blit_transition_use(); - shader_blit_transition_uInverseRatio( (v2f){1.0f,1.0f} ); - shader_blit_transition_uT( -(sqrtf(2)+0.5f) * world_map.spawn_timer ); - render_fsquad(); - render_stenciled = 1; - render_actual_game = 1; - } - } - - if( render_actual_game ) - { - /* Draw world */ - glEnable( GL_DEPTH_TEST ); - world_prerender( &_world.main ); - - render_world( &_world.main, &g_render.cam, render_stenciled, 0, 1, 1, _vg_render.fb_main ); - - particle_system_update( &particles_grind, vg.time_delta ); - //particle_system_debug( &particles_grind ); - particle_system_prerender( &particles_grind ); - particle_system_render( &particles_grind, &g_render.cam ); - - ent_tornado_pre_update(); - particle_system_update( &particles_env, vg.time_delta ); - particle_system_prerender( &particles_env ); - particle_system_render( &particles_env, &g_render.cam ); - - player_glide_render_effects( &g_render.cam ); - } - - glEnable( GL_DEPTH_TEST ); - - /* full res target */ - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - glViewport( 0,0, vg.window_x, vg.window_y ); - - if( render_actual_game && !render_stenciled ) - { - render_player_transparent(); /* needs to read the depth buffer before we fuck - it up with the oblique rendering inside the - portals */ - - /* continue with variable rate */ - vg_framebuffer_bind( _vg_render.fb_main, _vg_render.scale ); - render_world_gates( &_world.main, &g_render.cam, _vg_render.fb_main ); - } - - /* composite */ - if( (skaterift.activity == k_skaterift_menu) && menu.bg_blur ) - v2_muls( (v2f){ 0.04f, 0.001f }, 1.0f-skaterift.time_rate, g_render.blur_override ); - else - v2_zero( g_render.blur_override ); - - vg_postprocess_to_screen( _vg_render.fb_main ); - cutscene_render_fadeout(); - - if( gui.helper_count == 0 ) - control_overlay_render(); -} - -void vg_render(void) -{ - if( !_vg_tower_clearence( skaterift.full_ready_mask ) ) - { - vg_loader_render(); - return; - } - - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - - glViewport( 0,0, vg.window_x, vg.window_y ); - glDisable( GL_DEPTH_TEST ); - glDisable( GL_BLEND ); - - glClearColor( 1.0f, 0.0f, 0.0f, 0.0f ); - glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); - - render_main_game(); - m4x4_copy( g_render.cam.mtx.pv, vg.pv ); - - /* Other shite */ - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - vg_lines_drawall(); - glViewport( 0,0, vg.window_x, vg.window_y ); - - gui_render_icons(); - - compass_render_texture(); -} - -void vg_gui( ui_context *ctx ) -{ - if( !_vg_tower_clearence( skaterift.full_ready_mask ) ) - return; - - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - glViewport( 0,0, vg.window_x, vg.window_y ); - - gui_draw( ctx ); - compass_render_imgui( ctx ); - - if( k_light_editor ) - imgui_world_light_edit( ctx, &_world.main ); - - vg_ui.tex_bg = _vg_render.fb_main->attachments[0].id; - vg_framebuffer_inverse_ratio( _vg_render.fb_main, vg_ui.bg_inverse_ratio ); - - _cutscene_gui( ctx ); - _board_maker_ui( ctx ); - menu_gui( ctx ); - player__im_gui( ctx ); - world_instance *world = &_world.main; - - if( skaterift.activity != k_skaterift_replay ) - { - world_routes_imgui( ctx, world ); - _ent_route_imgui( ctx ); - } - _replay2_imgui( ctx ); - workshop_form_gui( ctx ); - world_gui( ctx, world ); - - if( menu_viewing_map() ) - { - remote_players_imgui_world( ctx, &_world.main, vg.pv, 2000.0f, 0 ); - //remote_players_imgui_lobby( ctx ); - } - else - { - remote_players_chat_imgui( ctx ); /* TODO: conditional */ - remote_players_imgui_world( ctx, &_world.main, vg.pv, 100.0f, 1 ); - } -} - -void vg_framebuffer_resize( int w, int h ) -{ -} - -#include "vg/vg_ui/filebrowser.c" -#include "addon.c" -#include "addon_types.c" -#include "audio.c" -#include "ent_challenge.c" -#include "ent_glider.c" -#include "entity.c" -#include "ent_objective.c" -#include "ent_region.c" -#include "ent_relay.c" -#include "ent_route.c" -#include "ent_skateshop.c" -#include "ent_tornado.c" -#include "ent_traffic.c" -#include "ent_prop.c" -#include "ent_script.c" -#include "freecam.c" -#include "menu.c" -#include "network.c" -#include "particle.c" -#include "player_basic_info.c" -#include "player.c" -#include "player_common.c" -#include "player_dead.c" -#include "player_effects.c" -#include "player_glide.c" -#include "player_ragdoll.c" -#include "player_remote.c" -#include "player_render.c" -#include "player_skate.c" -#include "player_walk.c" -#include "render.c" -#include "save.c" -#include "scene.c" -#include "trail.c" -#include "workshop.c" -#include "world_audio.c" -#include "world.c" -#include "world_entity.c" -#include "world_gate.c" -#include "world_gen.c" -#include "world_load.c" -#include "world_map.c" -#include "world_physics.c" -#include "world_render.c" -#include "world_routes.c" -#include "world_routes_ui.c" -#include "world_sfd.c" -#include "world_volumes.c" -#include "world_water.c" -#include "array_file.c" -#include "model.c" -#include "metascene.c" -#include "control_overlay.c" -#include "ent_camera.c" -#include "skaterift_script.c" -#include "board_maker.c" -#include "compass.c" -#include "replay2.c" -#include "user_profile.c" -#include "ent_npc.c" -#include "ent_list.c" -#include "ent_cutscene.c" -#include "ent_atom.c" - -static void _handle_vg_signal( vg_signal_id id, bool state ) -{ - if( (id == vg.sig_engine) && state ) - { - //vg_audio.always_keep_compressed = 1; - co_run( game_load_co, NULL ); - } -} - -int main( int argc, const char *argv[] ) -{ - vg_init( argc, argv, "Voyager Game Engine" ); - vg_stack_init( &vg.rtmem, NULL, VG_MB(200), "RT Memory" ); - vg_stack_set_flags( &vg.rtmem, VG_STACK_ALLOCATOR_METADATA ); - vg_stack_init( &vg.scratch, NULL, VG_MB(10), "Scratch" ); - - network_set_host( "skaterift.com", NULL ); - - { - const char *arg; - if( vg_long_opt( "noauth", "Disable server authentication" ) ) - network_client.auth_mode = eServerModeNoAuthentication; - - if( (arg = vg_long_opt_arg( "server", "Specify server address" )) ) - network_set_host( arg, NULL ); - - if( vg_long_opt( "demo", "Turn demo mode on" ) ) - g_client.demo_mode = 2; - - if( (arg = vg_long_opt_arg( "world", "Specify path to world to load" )) ) - skaterift.override_load_world = arg; - } - - skaterift.sig_world = _vg_tower_create_signal( "World Loaded" ); - skaterift.full_ready_mask = _vg_tower_mask( skaterift.sig_world ) | - _vg_tower_mask( vg.sig_engine ) | - _vg_tower_mask( vg.sig_client ); - _vg_tower_register_trigger( _vg_tower_mask( vg.sig_engine ), _handle_vg_signal ); - - vg_console_reg_cmd( "quit", skaterift_quit_command, NULL ); - vg_console_reg_cmd( "load_world", skaterift_load_world_command, NULL ); - vg_console_reg_var( "immobile", &localplayer.immobile, k_var_dtype_i32, 0 ); - vg_console_reg_var( "allow_resume", &skaterift.allow_replay_resume, k_var_dtype_i32, VG_VAR_CHEAT ); - vg_console_reg_var( "boost_scale", &skaterift.boost_scale, k_var_dtype_f32, VG_VAR_CHEAT ); - - /* TODO Modules that do this automatically.... */ - render_register(); - remote_players_register(); - network_register(); - menu_register(); - control_overlay_register(); - world_render_register(); - gui_register(); - compass_register(); - player_register(); - player_ragdoll_register(); - cutscene_register(); - workshop_register(); - ent_tornado_register(); - _replay2_register(); - _ent_atom_register(); - _ent_challenge_register(); - - _steam_api.demo_mode = g_client.demo_mode; // FIXME Fuck you - _steam_api.cb_connection_changed = cb_skaterift_connection_changed; - _steam_api.cb_persona_changed = cb_skaterift_persona_changed; - - vg_run(); - return 0; -} diff --git a/src/skaterift.h b/src/skaterift.h deleted file mode 100644 index ed5ee37..0000000 --- a/src/skaterift.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#define SKATERIFT -#define SKATERIFT_APPID 2103940 - -#define SKATERIFT_WORLD_READY 0x10000 - -#include "vg/vg_engine.h" -#include "vg/vg_camera.h" - -enum skaterift_rt -{ - k_skaterift_rt_workshop_preview, - k_skaterift_rt_server_status, - k_skaterift_rt_max -}; - -struct skaterift_globals -{ - f32 time_rate; - - enum skaterift_activity { - k_skaterift_default = 0x00, /* regular playing */ - k_skaterift_replay = 0x01, - k_skaterift_spectate = 0x02, - k_skaterift_menu = 0x04, - k_skaterift_activity_max = 0x8 - } - activity; - - GLuint rt_textures[k_skaterift_rt_max]; - - u32 achievements; - i32 allow_replay_resume; - vg_signal_id sig_world; - u64 full_ready_mask; - - const char *override_load_world; - - f32 boost_scale; - bool no_save_location; -} -extern skaterift; diff --git a/src/skaterift.hconf b/src/skaterift.hconf new file mode 100644 index 0000000..902d157 --- /dev/null +++ b/src/skaterift.hconf @@ -0,0 +1,121 @@ +#if defined( _WIN32 ) + #include + #include +#else + #include + #include + #include +#endif + +/* Core system level ------------------------------------------------------------------------------------------------ */ + +#if defined( SR_ALL ) +# include "addon_types.h" +# include "addon.h" +#endif + +#if defined( SR_MODEL ) || defined( SR_ALL ) +# include "array_file.h" +# include "shader_props.h" +# include "model.h" +#endif + +#if defined( SR_ALL ) +/* TODO: entity needs to be split -> model.h + some kind of helper logic file */ +# include "entity.h" + +# include "client.h" +# include "demo_check.h" + +/* graphics */ +# include "render.h" +# include "depth_compare.h" +# include "particle.h" +# include "trail.h" +# include "font.h" +# include "scene.h" +# include "scene_rigidbody.h" +# include "metascene.h" + +# include "atom.h" +# include "audio.h" +# include "compass.h" +# include "control_overlay.h" +# include "input.h" +# include "cutscene.h" +# include "gui.h" + +# include "network_msg.h" +# include "network_common.h" +# include "network.h" +# include "network_compression.h" +# include "network_requests.h" + +# include "replay2.h" +# include "save2.h" +# include "user_profile.h" + +/* World level ------------------------------------------------------------------------------------------------------ */ +# include "world.h" +# include "world_audio.h" +# include "world_entity.h" +# include "world_gate.h" +# include "world_gen.h" +# include "world_info.h" +# include "world_load.h" +# include "world_map.h" +# include "world_physics.h" +# include "world_render.h" +# include "world_routes.h" +# include "world_routes_ui.h" +# include "world_sfd.h" +# include "world_volumes.h" +# include "world_water.h" + +# include "ent_atom.h" +# include "ent_camera.h" +# include "ent_challenge.h" +# include "ent_cutscene.h" +# include "ent_glider.h" +# include "ent_list.h" +# include "ent_npc.h" +# include "ent_objective.h" +# include "ent_prop.h" +# include "ent_region.h" +# include "ent_relay.h" +# include "ent_route.h" +# include "ent_script.h" +# include "ent_skateshop.h" +# include "ent_tornado.h" +# include "ent_traffic.h" + +# include "board_maker.h" + +/* Player lavel ----------------------------------------------------------------------------------------------------- */ +# include "player_api.h" +# include "player_basic_info.h" +# include "player_common.h" +# include "player_render.h" +# include "player_effects.h" + +# include "player_dead.h" +# include "player_glide.h" +# include "player_ragdoll.h" +# include "player_skate.h" +# include "player_walk.h" + +# include "player.h" +# include "player_remote.h" + +# include "menu.h" +# include "workshop.h" +#endif + +#if defined( SR_GAMESERVER ) +# include "gameserver.h" +# include "gameserver_database.h" +# include "gameserver_db.h" +# include "gameserver_monitor.h" +# include "gameserver_replay.h" +# include "gameserver_requests.h" +#endif diff --git a/src/skaterift_script.c b/src/skaterift_script.c deleted file mode 100644 index 4b22e1c..0000000 --- a/src/skaterift_script.c +++ /dev/null @@ -1,521 +0,0 @@ -#if 0 - -#include "ent_script.h" - -const char *_script_linear_story[] = -{ - "start", - "volc", - "volc:tutorial", - "volc:leaving", - - "mz", - /* NOTES: we need to block the player in to force them to talk to mike so they don't get lost? Or at least put - * mike right in the way of where you gotta go. Perhaps on the docks. - */ - - "mz:town_region", - "mz:battery_jump", - "mz:leaving_pt1", - "mz:start_pt2", - "mz:megapark_region", - "mz:leaving_pt2", - - "city", - "city:main_region", - "city:finale", - "city:leaving", - - "valley", - "valley:main_region", - "valley:rocket_inspection", - "valley:cave", - "valley:finale", - "valley:leaving", - - NULL -}; - -struct script_save_atom -{ - const char *alias; - - enum save_atom_type - { - k_atom_type_numeric, - k_atom_type_enum - } - type; - - const char **enum_values; - u64 status; -} -_skaterift_script_savedata[] = -{ - { "story", k_atom_type_enum, _script_linear_story }, - { "unlock_docks_view" }, - - { "unlock_valley_view" }, - { "unlock_mtzero_view" }, - { "unlock_city_view" }, - - { "board_maker_unlock" }, - { "board_maker_hub_view" }, - - { "ch1s3_view" }, - { "ch1s3b_view" }, - { "ch1s4_view" }, - { "ch1s5_view" }, - -#if 0 - { "board_maker_unlock" }, - { "board_maker_hub_view" }, - { "intro_view" }, - { "hub_info_view" }, - - { "ch1s2_view" }, - { "ch1s3_view" }, - { "ch1s3b_view" }, - { "ch1s4_view" }, - { "ch1s5_view" }, - { "ch1s6a_view" }, - { "unlock_docks_view" }, - - { "unlock_mtzero" }, - { "ch2s1_view" }, - { "ch2s2_view" }, - { "ch2s3_view" }, - { "battery_jump_view" }, - { "ch2s4_view" }, - { "ch2s5_view" }, /* is the trigger for the second map */ - { "ch2s6_view" }, - { "ch2e1_view" }, - - { "unlock_city" }, - { "unlock_city_view" }, - { "ch3s1_view" }, - { "ch3s2_view" }, - { "ch3s3_view" }, - { "city_finale" }, - - { "unlock_valley" }, - - { "valley_progress" }, - - { "ch4s1a_view" }, - { "ch4s2_view" }, - { "valley_cave" }, - { "ch4s1_view" }, - { "valley_finale" }, - { "ch4s3_view" }, - { "rocket_launch_view" }, - - { "unlock_venus" }, -#endif -}; - -struct script_save_atom *_skaterift_get_atom( const char *alias ) -{ - for( u32 i=0; ialias ) ) - return atom; - } - return NULL; -} - -u64 _skaterift_atom_enum_index( const char *atom_alias, const char *value, u64 fallback_value ) -{ - struct script_save_atom *atom = _skaterift_get_atom( atom_alias ); - if( !atom ) - { - vg_error( "No atom aliased '%s'\n", atom_alias ); - return 0; - } - - VG_ASSERT( atom->type == k_atom_type_enum ); - if( value ) - { - for( u32 i=0; i<32; i ++ ) - { - if( !atom->enum_values[i] ) - { - vg_warn( "Atom '%s' does't contain the value '%s'\n", atom->alias, value ); - return fallback_value; - } - if( !strcmp( atom->enum_values[i], value ) ) - return i; - } - vg_warn( "Atom '%s' exceeds max enum values (%u)\n", atom->alias, 32 ); - } - return fallback_value; -} - -u64 _skaterift_atom_status( const char *atom_alias ) -{ - struct script_save_atom *atom = _skaterift_get_atom( atom_alias ); - if( !atom ) - { - vg_error( "No atom aliased '%s'\n", atom_alias ); - return 0; - } - else return atom->status; -} - -void _skaterift_atom_set( const char *atom_alias, u64 value ) -{ - struct script_save_atom *atom = _skaterift_get_atom( atom_alias ); - if( !atom ) - { - vg_error( "No atom aliased '%s'\n", atom_alias ); - return; - } - - atom->status = value; - -#if 0 - struct script_event_atom_changed info; - info.alias = atom_alias; - info.value = value; - struct ent_script_event event; - event.type = k_escript_event_atom_changed; - event.info = &info; - ent_script_propogate_event( &_world.main, &event ); -#endif -} - -void _skaterift_atom_set_enum( const char *atom_alias, const char *value ) -{ - _skaterift_atom_set( atom_alias, _skaterift_atom_enum_index( atom_alias, value, 0 ) ); -} - -void _skaterift_script_write_savedata( vg_msg *sav ) -{ - for( u32 i=0; itype == k_atom_type_numeric ) - vg_msg_wkvnum( sav, atom->alias, k_vg_msg_u64, 1, &atom->status ); - else - vg_msg_wkvstr( sav, atom->alias, atom->enum_values[ atom->status ] ); - } -} - -void _skaterift_script_load_savedata( vg_msg *sav ) -{ - for( u32 i=0; itype == k_atom_type_numeric ) - vg_msg_getkvintg( sav, atom->alias, k_vg_msg_u64, &atom->status, NULL ); - else - atom->status = _skaterift_atom_enum_index( atom->alias, vg_msg_getkvstr( sav, atom->alias ), 0 ); - } -} - -/* script events - * ------------------------------------------------------------------------------------------------------------- */ - -bool on_cutscene_marker( ent_script_event *event, const char *marker ) -{ - if( event->type != k_escript_event_allocate ) - { - if( _cutscene.state == k_cutscene_state_playing ) - { - if( _cutscene.marker_this_frame ) - { - if( vg_str_eq( marker, _cutscene.marker_this_frame ) ) - return 1; - } - } - } - return 0; -} - -bool on_world_start( ent_script_event *event ) -{ - return event->type == k_escript_event_world_start; -} - -bool on_atom_changed( ent_script_event *event, const char *atom_alias, u64 *out_value ) -{ - if( event->type == k_escript_event_atom_changed ) - { - struct script_event_atom_changed *atom_info = event->info; - if( !strcmp( atom_alias, atom_info->alias ) ) - { - *out_value = atom_info->value; - return 1; - } - } - else if( event->type == k_escript_event_world_start ) - { - *out_value = _skaterift_atom_status( atom_alias ); - return 1; - } - - return 0; -} - -#if 0 -bool on_function_trigger( ent_script_event *event, i32 function_id ) -{ - if( event->type == k_escript_event_call ) - { - struct script_event_call *call_info = event->info; - if( call_info->function_id == function_id ) - return 1; - } - - return 0; -} - -bool on_atom_once( ent_script_event *event, const char *atom_alias ) -{ - if( event->type != k_escript_event_allocate ) - { - if( _skaterift_atom_status( atom_alias ) != 1 ) - { - _skaterift_atom_set( atom_alias, 1 ); - return 1; - } - } - - return 0; -} -#endif - -#include "scripts/generic.c" -#include "scripts/blocker_break.c" - -#include "scripts/heaven.c" -#include "scripts/hub.c" -#include "scripts/tutorial_island.c" -#include "scripts/mtzero.c" -#include "scripts/city.c" -#include "scripts/valley.c" - -#include "scripts/cutscene.c" -#include "scripts/explode.c" - -/* console eventts - * ------------------------------------------------------------------------------------------------------------- */ - -static int _skaterift_script_ccmd( int argc, const char *argv[] ) -{ - if( argc < 2 ) - { - vg_error( "Usage: script \n" ); - return 0; - } - - bool all = 0; - if( !strcmp( argv[1], "all" ) ) - all = 1; - - world_instance *world = &_world.main; - - if( !strcmp( argv[0], "atom" ) ) - { - for( u32 i=0; ialias ) ) - { - if( argc==3 ) - { - u64 value = 0; - if( atom->type == k_atom_type_numeric ) - value = atol(argv[2]); - else - value = _skaterift_atom_enum_index( atom->alias, argv[2], atom->status ); - _skaterift_atom_set( atom->alias, value ); - } - else - { - if( atom->type == k_atom_type_numeric ) - vg_info( "%s: %lu\n", atom->alias, atom->status ); - else - vg_info( "%s: '%s' (%lu)\n", atom->alias, atom->enum_values[ atom->status ], atom->status ); - } - } - } - - return 1; - } - else if( !strcmp( argv[0], "challenge" ) ) - { - u32 index = 0; - for( u32 i=0; ient_challenge ); i ++ ) - { - ent_challenge *challenge = af_arritm( &world->ent_challenge, i ); - const char *alias = af_str( &world->meta.af, challenge->pstr_alias ); - - if( all || (atoi( argv[1] ) == index) ) - { - if( argc==3 ) - { - challenge->status = atoi( argv[2] ); - ent_region_re_eval( world ); - - struct ent_script_event event; - struct script_event_completion_changed inf = { - .entity_id = mdl_entity_id( k_ent_challenge, i ), - .completion_flags = 0 - }; - event.type = k_escript_event_completion_changed; - event.info = &inf; - ent_script_propogate_event( world, &event ); - } - else - vg_info( "[challenge %u '%s'] %u\n", index, alias, challenge->status ); - } - - index ++; - } - for( u32 i=0; ient_route ); i ++ ) - { - ent_route *route = af_arritm( &world->ent_route, i ); - const char *alias = af_str( &world->meta.af, route->pstr_name ); - - if( all || (atoi( argv[1] ) == index) ) - { - if( argc==3 ) - { - route->flags &= ~((u32)(k_ent_route_flag_achieve_gold|k_ent_route_flag_achieve_silver)); - - if( !strcmp( argv[2], "silver" ) ) - route->flags |= (u32)(k_ent_route_flag_achieve_silver); - - if( !strcmp( argv[2], "gold" ) ) - route->flags |= (u32)(k_ent_route_flag_achieve_gold|k_ent_route_flag_achieve_silver); - ent_region_re_eval( world ); - - struct ent_script_event event; - struct script_event_completion_changed inf = { - .entity_id = mdl_entity_id( k_ent_route, i ), - .completion_flags = route->flags - }; - event.type = k_escript_event_completion_changed; - event.info = &inf; - ent_script_propogate_event( world, &event ); - } - else - vg_info( "[route %u '%s'] %s%s\n", index, alias, - (route->flags & k_ent_route_flag_achieve_silver? "SILVER": "_____"), - (route->flags & k_ent_route_flag_achieve_gold? "_GOLD": "_____" ) ); - } - - index ++; - } - return 1; - } - else if( !strcmp( argv[0], "trigger" ) ) - { - if( !strcmp( argv[1], "start" ) ) - { - ent_script_start( &_world.main ); - return 1; - } - else - { - vg_error( "Dont know event '%s'.\n", argv[1] ); - return 0; - } - } - else - { - vg_error( "'%s' is not a command\n", argv[0] ); - return 0; - } -} - -static void _skaterift_script_ccmd_poll( int argc, const char *argv[] ) -{ - const char *term = argv[argc-1]; - world_instance *world = &_world.main; - - if( argc == 1 ) - { - console_suggest_score_text( "atom", term, 0 ); - console_suggest_score_text( "trigger", term, 0 ); - console_suggest_score_text( "challenge", term, 0 ); - } - else if( argc == 2 ) - { - if( !strcmp( argv[0], "atom" ) ) - { - console_suggest_score_text( "all", term, 0 ); - for( u32 i=0; ialias, term, 0 ); - } - } - else if( !strcmp( argv[0], "trigger" ) ) - { - console_suggest_score_text( "start", term, 0 ); - } - else if( !strcmp( argv[0], "challenge" ) ) - { - // CANT DO THIS WHILE WE DONT HAVE STRING ESCAPING IN THE CONSOLE -#if 0 - for( u32 i=0; ient_challenge ); i ++ ) - { - ent_challenge *challenge = af_arritm( &world->ent_challenge, i ); - console_suggest_score_text( af_str( &world->meta.af, challenge->pstr_alias ), term, 0 ); - } - for( u32 i=0; ient_route ); i ++ ) - { - ent_route *route = af_arritm( &world->ent_route, i ); - console_suggest_score_text( af_str( &world->meta.af, route->pstr_name ), term, 0 ); - } -#endif - } - } - else if( argc == 3 ) - { - if( !strcmp( argv[0], "atom" ) ) - { - if( strcmp( argv[1], "all" ) ) - { - struct script_save_atom *atom = _skaterift_get_atom( argv[1] ); - if( atom->type == k_atom_type_enum ) - { - for( u32 i=0; i<32; i ++ ) - { - if( !atom->enum_values[i] ) - break; - console_suggest_score_text( atom->enum_values[i], term, 0 ); - } - } - } - } - else if( !strcmp( argv[0], "challenge" ) ) - { - // CANT DO THIS WHILE WE DONT HAVE STRING ESCAPING IN THE CONSOLE -#if 0 - for( u32 i=0; ient_route ); i ++ ) - { - ent_route *route = af_arritm( &world->ent_route, i ); - const char *alias = af_str( &world->meta.af, route->pstr_name ); - if( !strcmp( argv[1], alias ) ) - { - console_suggest_score_text( "silver", term, 0 ); - console_suggest_score_text( "gold", term, 0 ); - break; - } - } -#endif - } - } -} - -void _skaterift_script_init(void) -{ - vg_console_reg_cmd( "script", _skaterift_script_ccmd, _skaterift_script_ccmd_poll ); -} - - -#endif diff --git a/src/skaterift_script.h b/src/skaterift_script.h deleted file mode 100644 index e4332d1..0000000 --- a/src/skaterift_script.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#if 0 -#include "ent_script.h" -#define ATOM_MAX 0xfffffffffffffffflu - -void _skaterift_script_init(void); -void _skaterift_script_write_savedata( vg_msg *sav ); -void _skaterift_script_load_savedata( vg_msg *sav ); - -u64 _skaterift_atom_status( const char *atom_alias ); -u64 _skaterift_atom_enum_index( const char *atom_alias, const char *value, u64 fallback_value ); -void _skaterift_atom_set( const char *atom_alias, u64 value ); -void _skaterift_atom_set_enum( const char *atom_alias, const char *value ); - -bool on_world_start( ent_script_event *event ); -bool on_atom_changed( ent_script_event *event, const char *atom_alias, u64 *out_value ); -bool on_cutscene_marker( ent_script_event *event, const char *marker ); -bool on_function_trigger( ent_script_event *event, i32 function_id ); -bool on_atom_once( ent_script_event *event, const char *atom_alias ); -bool on_advancement( ent_script_event *event ); -#endif diff --git a/src/skeleton.h b/src/skeleton.h deleted file mode 100644 index 87780af..0000000 --- a/src/skeleton.h +++ /dev/null @@ -1,531 +0,0 @@ -/* - * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#pragma once -#include "vg/vg_lines.h" -#include "model.h" -#include "metascene.h" - -struct skeleton -{ - struct skeleton_bone - { - v3f co, end; - u32 parent; - - u32 flags; - int defer; - - //ms_keyframe kf; - mdl_bone *orig_bone; - - u32 collider; - boxf hitbox; - const char *name; - } - *bones; - u32 bone_count; - - struct skeleton_ik - { - u32 lower, upper, target, pole; - m3x3f ia, ib; - } - *ik; - u32 ik_count; - - u32 collider_count, - bindable_count; -}; - -typedef struct skeleton_anim skeleton_anim; -struct skeleton_anim -{ - ms_strip *strip; - ms_keyframe *keyframes_base; - f32 framerate; -}; - -static u32 skeleton_bone_id( struct skeleton *skele, const char *name ) -{ - for( u32 i=1; ibone_count; i++ ) - if( !strcmp( skele->bones[i].name, name )) - return i; - - vg_error( "skeleton_bone_id( *, \"%s\" );\n", name ); - vg_fatal_error( "Bone does not exist\n" ); - - return 0; -} - -static void keyframe_copy_pose( ms_keyframe *kfa, ms_keyframe *kfb, int num ) -{ - for( int i=0; ico, offset, co ); - v3_sub( co, origin, v0 ); - q_mulv( q, v0, v0 ); - v3_add( v0, origin, co ); - v3_sub( co, offset, kf->co ); - - q_mul( q, kf->q, kf->q ); - q_normalize( kf->q ); -} - -static void keyframe_lerp( ms_keyframe *kfa, ms_keyframe *kfb, f32 t, ms_keyframe *kfd ) -{ - v3_lerp( kfa->co, kfb->co, t, kfd->co ); - q_nlerp( kfa->q, kfb->q, t, kfd->q ); - v3_lerp( kfa->s, kfb->s, t, kfd->s ); -} - -/* - * Lerp between two sets of keyframes and store in dest. Rotations use Nlerp. - */ -static void keyframe_lerp_pose( ms_keyframe *kfa, ms_keyframe *kfb, float t, ms_keyframe *kfd, int count ) -{ - if( t <= 0.0001f ) - { - keyframe_copy_pose( kfa, kfd, count ); - return; - } - else if( t >= 0.9999f ) - { - keyframe_copy_pose( kfb, kfd, count ); - return; - } - - for( int i=0; ibone_count-1 ); -} - -static void skeleton_copy_pose( struct skeleton *skele, ms_keyframe *kfa, ms_keyframe *kfd ) -{ - keyframe_copy_pose( kfa, kfd, skele->bone_count-1 ); -} - -/* - * Sample animation between 2 closest frames using time value. Output is a - * keyframe buffer that is allocated with an appropriate size - * - * Time is in SECONDS - */ -void skeleton_sample_anim( struct skeleton *skele, skeleton_anim *anim, f32 time, ms_keyframe *output ) -{ - ms_strip *strip = anim->strip; - f32 animtime = fmodf( time*anim->framerate, (f32)strip->strip.length ), - animframe = floorf( animtime ), - t = animtime - animframe; - - u32 frame = (u32)animframe % strip->strip.length, - next = (frame+1) % strip->strip.length; - - ms_keyframe *base = anim->keyframes_base + strip->strip.count*frame, - *nbase = anim->keyframes_base + strip->strip.count*next; - - skeleton_lerp_pose( skele, base, nbase, t, output ); -} - -/* time is in SECONDS */ -int skeleton_sample_anim_clamped( struct skeleton *skele, skeleton_anim *anim, f32 time, ms_keyframe *output ) -{ - ms_strip *strip = anim->strip; - f32 end = (strip->strip.length-1)/anim->framerate; - skeleton_sample_anim( skele, anim, vg_minf( end, time ), output ); - - if( time > end ) return 0; - else return 1; -} - -typedef enum anim_apply -{ - k_anim_apply_always, - k_anim_apply_defer_ik, - k_anim_apply_deffered_only, - k_anim_apply_absolute -} -anim_apply; - -static int should_apply_bone( struct skeleton *skele, u32 id, anim_apply type ) -{ - struct skeleton_bone *sb = &skele->bones[ id ], - *sp = &skele->bones[ sb->parent ]; - - if( type == k_anim_apply_defer_ik ) - { - if( ((sp->flags & k_bone_flag_ik) && !(sb->flags & k_bone_flag_ik)) || sp->defer ) - { - sb->defer = 1; - return 0; - } - else - { - sb->defer = 0; - return 1; - } - } - else if( type == k_anim_apply_deffered_only ) - { - if( sb->defer ) - return 1; - else - return 0; - } - - return 1; -} - -/* - * Apply block of keyframes to skeletons final pose - */ -static void skeleton_apply_pose( struct skeleton *skele, ms_keyframe *pose, anim_apply passtype, m4x3f *final_mtx ) -{ - if( passtype == k_anim_apply_absolute ) - { - for( u32 i=1; ibone_count; i++ ) - { - ms_keyframe *kf = &pose[i-1]; - - v3f *posemtx = final_mtx[i]; - - q_m3x3( kf->q, posemtx ); - m3x3_scale( posemtx, kf->s ); - v3_copy( kf->co, posemtx[3] ); - } - return; - } - - m4x3_identity( final_mtx[0] ); - skele->bones[0].defer = 0; - skele->bones[0].flags &= ~k_bone_flag_ik; - - for( u32 i=1; ibone_count; i++ ) - { - struct skeleton_bone *sb = &skele->bones[i], - *sp = &skele->bones[sb->parent]; - if( !should_apply_bone( skele, i, passtype ) ) - continue; - - sb->defer = 0; - - /* process pose */ - m4x3f posemtx; - - v3f temp_delta; - v3_sub( skele->bones[i].co, skele->bones[sb->parent].co, temp_delta ); - - /* pose matrix */ - ms_keyframe *kf = &pose[i-1]; - q_m3x3( kf->q, posemtx ); - m3x3_scale( posemtx, kf->s ); - v3_copy( kf->co, posemtx[3] ); - v3_add( temp_delta, posemtx[3], posemtx[3] ); - - /* final matrix */ - m4x3_mul( final_mtx[ sb->parent ], posemtx, final_mtx[i] ); - } -} - -/* - * Take the final matrices and decompose it into an absolute positioned anim - */ -static void skeleton_decompose_mtx_absolute( struct skeleton *skele, ms_keyframe *anim, m4x3f *final_mtx ) -{ - for( u32 i=1; ibone_count; i++ ) - { - struct skeleton_bone *sb = &skele->bones[i]; - ms_keyframe *kf = &anim[i-1]; - m4x3_decompose( final_mtx[i], kf->co, kf->q, kf->s ); - } -} - -/* - * creates the reference inverse matrix for an IK bone, as it has an initial - * intrisic rotation based on the direction that the IK is setup.. - */ -static void skeleton_inverse_for_ik( struct skeleton *skele, v3f ivaxis, u32 id, m3x3f inverse ) -{ - v3_copy( ivaxis, inverse[0] ); - v3_copy( skele->bones[id].end, inverse[1] ); - v3_normalize( inverse[1] ); - v3_cross( inverse[0], inverse[1], inverse[2] ); - m3x3_transpose( inverse, inverse ); -} - -/* - * Creates inverse rotation matrices which the IK system uses. - */ -static void skeleton_create_inverses( struct skeleton *skele ) -{ - /* IK: inverse 'plane-bone space' axis '(^axis,^bone,...)[base] */ - for( u32 i=0; iik_count; i++ ) - { - struct skeleton_ik *ik = &skele->ik[i]; - m4x3f inverse; - v3f iv0, iv1, ivaxis; - v3_sub( skele->bones[ik->target].co, skele->bones[ik->lower].co, iv0 ); - v3_sub( skele->bones[ik->pole].co, skele->bones[ik->lower].co, iv1 ); - v3_cross( iv0, iv1, ivaxis ); - v3_normalize( ivaxis ); - - skeleton_inverse_for_ik( skele, ivaxis, ik->lower, ik->ia ); - skeleton_inverse_for_ik( skele, ivaxis, ik->upper, ik->ib ); - } -} - -/* - * Apply a model matrix to all bones, should be done last - */ -static void skeleton_apply_transform( struct skeleton *skele, m4x3f transform, m4x3f *final_mtx ) -{ - for( u32 i=0; ibone_count; i++ ) - { - struct skeleton_bone *sb = &skele->bones[i]; - m4x3_mul( transform, final_mtx[i], final_mtx[i] ); - } -} - -/* - * Apply an inverse matrix to all bones which maps vertices from bind space into - * bone relative positions - */ -static void skeleton_apply_inverses( struct skeleton *skele, m4x3f *final_mtx ) -{ - for( u32 i=0; ibone_count; i++ ) - { - struct skeleton_bone *sb = &skele->bones[i]; - m4x3f inverse; - m3x3_identity( inverse ); - v3_negate( sb->co, inverse[3] ); - m4x3_mul( final_mtx[i], inverse, final_mtx[i] ); - } -} - -/* - * Apply all IK modifiers (2 bone ik reference from blender is supported) - */ -static void skeleton_apply_ik_pass( struct skeleton *skele, m4x3f *final_mtx ) -{ - for( u32 i=0; iik_count; i++ ) - { - struct skeleton_ik *ik = &skele->ik[i]; - v3f v0, /* base -> target */ - v1, /* base -> pole */ - vaxis; - - v3f co_base, - co_target, - co_pole; - - v3_copy( final_mtx[ik->lower][3], co_base ); - v3_copy( final_mtx[ik->target][3], co_target ); - v3_copy( final_mtx[ik->pole][3], co_pole ); - - v3_sub( co_target, co_base, v0 ); - v3_sub( co_pole, co_base, v1 ); - v3_cross( v0, v1, vaxis ); - v3_normalize( vaxis ); - v3_normalize( v0 ); - v3_cross( vaxis, v0, v1 ); - - /* localize problem into [x:v0,y:v1] 2d plane */ - v2f base = { v3_dot( v0, co_base ), v3_dot( v1, co_base ) }, - end = { v3_dot( v0, co_target ), v3_dot( v1, co_target ) }, - knee; - - /* Compute angles (basic trig)*/ - v2f delta; - v2_sub( end, base, delta ); - - f32 l1 = v3_length( skele->bones[ik->lower].end ), - l2 = v3_length( skele->bones[ik->upper].end ), - d = vg_clampf( v2_length(delta), fabsf(l1 - l2), l1+l2-0.00001f ), - c = acosf( (l1*l1 + d*d - l2*l2) / (2.0f*l1*d) ), - rot = atan2f( delta[1], delta[0] ) + c - VG_PIf/2.0f; - - knee[0] = sinf(-rot) * l1; - knee[1] = cosf(-rot) * l1; - - m4x3_identity( final_mtx[ik->lower] ); - m4x3_identity( final_mtx[ik->upper] ); - - /* create rotation matrix */ - v3f co_knee; - v3_muladds( co_base, v0, knee[0], co_knee ); - v3_muladds( co_knee, v1, knee[1], co_knee ); - vg_line( co_base, co_knee, 0xff00ff00 ); - - m4x3f transform; - v3_copy( vaxis, transform[0] ); - v3_muls( v0, knee[0], transform[1] ); - v3_muladds( transform[1], v1, knee[1], transform[1] ); - v3_normalize( transform[1] ); - v3_cross( transform[0], transform[1], transform[2] ); - v3_copy( co_base, transform[3] ); - - m3x3_mul( transform, ik->ia, transform ); - m4x3_copy( transform, final_mtx[ik->lower] ); - - /* upper/knee bone */ - v3_copy( vaxis, transform[0] ); - v3_sub( co_target, co_knee, transform[1] ); - v3_normalize( transform[1] ); - v3_cross( transform[0], transform[1], transform[2] ); - v3_copy( co_knee, transform[3] ); - - m3x3_mul( transform, ik->ib, transform ); - m4x3_copy( transform, final_mtx[ik->upper] ); - } -} - -/* - * Applies the typical operations that you want for an IK rig: - * Pose, IK, Pose(deferred), Inverses, Transform - */ -static void skeleton_apply_standard( struct skeleton *skele, ms_keyframe *pose, m4x3f transform, m4x3f *final_mtx ) -{ - skeleton_apply_pose( skele, pose, k_anim_apply_defer_ik, final_mtx ); - skeleton_apply_ik_pass( skele, final_mtx ); - skeleton_apply_pose( skele, pose, k_anim_apply_deffered_only, final_mtx ); - skeleton_apply_inverses( skele, final_mtx ); - skeleton_apply_transform( skele, transform, final_mtx ); -} - -static void skeleton_alloc_from( struct skeleton *skele, vg_stack_allocator *stack, mdl_context *mdl, mdl_armature *armature ) -{ - skele->bone_count = armature->bone_count+1; - skele->ik_count = 0; - skele->collider_count = 0; - - for( u32 i=0; ibone_count; i++ ) - { - mdl_bone *bone = &mdl->bones[ armature->bone_start+i ]; - if( bone->flags & k_bone_flag_ik ) - skele->ik_count ++; - if( bone->collider ) - skele->collider_count ++; - } - - u32 bone_size = sizeof(struct skeleton_bone) * skele->bone_count, - ik_size = sizeof(struct skeleton_ik) * skele->ik_count; - - skele->bones = vg_stack_allocate( stack, bone_size, 8, NULL ); - skele->ik = vg_stack_allocate( stack, ik_size, 8, NULL ); - - memset( skele->bones, 0, bone_size ); - memset( skele->ik, 0, ik_size ); -} - -static void skeleton_fatal_err(void) -{ - vg_fatal_error( "Skeleton setup failed" ); -} - -/* Setup a skeleton from model. mdl's metadata should stick around */ -void skeleton_setup( struct skeleton *skele, mdl_context *mdl, u32 index, vg_stack_allocator *stack ) -{ - u32 ik_count = 0, collider_count = 0; - skele->bone_count = 0; - skele->bones = NULL; - - if( !mdl->armature_count ) - { - vg_error( "No skeleton in model\n" ); - skeleton_fatal_err(); - } - - mdl_armature *armature = &mdl->armatures[ index ]; - skeleton_alloc_from( skele, stack, mdl, armature ); - - for( u32 i=0; ibone_count; i++ ) - { - mdl_bone *bone = &mdl->bones[ armature->bone_start+i ]; - struct skeleton_bone *sb = &skele->bones[i+1]; - - v3_copy( bone->co, sb->co ); - v3_copy( bone->end, sb->end ); - - sb->parent = bone->parent; - sb->name = af_str( &mdl->af, bone->pstr_name ); - sb->flags = bone->flags; - sb->collider = bone->collider; - sb->orig_bone = bone; - - if( sb->flags & k_bone_flag_ik ) - { - skele->bones[ sb->parent ].flags |= k_bone_flag_ik; - - if( ik_count == skele->ik_count ) - { - vg_error( "Too many ik bones, corrupt model file\n" ); - skeleton_fatal_err(); - } - - struct skeleton_ik *ik = &skele->ik[ ik_count ++ ]; - ik->upper = i+1; - ik->lower = bone->parent; - ik->target = bone->ik_target; - ik->pole = bone->ik_pole; - } - - box_copy( bone->hitbox, sb->hitbox ); - - if( bone->collider ) - { - if( collider_count == skele->collider_count ) - { - vg_error( "Too many collider bones\n" ); - skeleton_fatal_err(); - } - collider_count ++; - } - } - - /* fill in implicit root bone */ - v3_zero( skele->bones[0].co ); - v3_copy( (v3f){0.0f,1.0f,0.0f}, skele->bones[0].end ); - skele->bones[0].parent = 0xffffffff; - skele->bones[0].flags = 0; - skele->bones[0].name = "[root]"; - - skeleton_create_inverses( skele ); - vg_success( "Loaded skeleton with %u bones\n", skele->bone_count ); - vg_success( " %u colliders\n", skele->collider_count ); -} - -static void skeleton_debug( struct skeleton *skele, m4x3f *final_mtx ) -{ - for( u32 i=1; ibone_count; i ++ ) - { - struct skeleton_bone *sb = &skele->bones[i]; - v3f p0, p1; - v3_copy( sb->co, p0 ); - v3_add( p0, sb->end, p1 ); - - m4x3_mulv( final_mtx[i], p0, p0 ); - m4x3_mulv( final_mtx[i], p1, p1 ); - - if( sb->flags & k_bone_flag_deform ) - { - if( sb->flags & k_bone_flag_ik ) - vg_line( p0, p1, 0xff0000ff ); - else - vg_line( p0, p1, 0xffcccccc ); - } - else - vg_line( p0, p1, 0xff00ffff ); - } -} diff --git a/src/traffic.h b/src/traffic.h deleted file mode 100644 index 004c624..0000000 --- a/src/traffic.h +++ /dev/null @@ -1,222 +0,0 @@ -#ifndef TRAFFIC_H -#define TRAFFIC_H - -#include "common.h" -#include "model.h" -#include "rigidbody.h" -#include "world.h" - -typedef struct traffic_node traffic_node; -typedef struct traffic_driver traffic_driver; - -struct traffic_node -{ - v3f co, h; - - union - { - struct{ traffic_node *next, *next1; }; - struct{ mdl_node *mn_next, *mn_next1; }; - }; -}; - -struct traffic_driver -{ - m4x3f transform; - - traffic_node *current; - int option; - float t, speed; -}; - -static float eval_bezier_length( v3f p0, v3f p1, v3f h0, v3f h1, int res ) -{ - float length = 0.0f, m = 1.0f/(float)res; - v3f l, p; - v3_copy( p0, l ); - - for( int i=0; imn_next ) - tn->next = &system[ tn->mn_next->sub_uid ]; - if( tn->mn_next1 ) - tn->next1 = &system[ tn->mn_next1->sub_uid ]; - } -} - -static void traffic_visualize_link( traffic_node *ta, traffic_node *tb ) -{ - v3f p0, p1, h0, h1, p, l; - - if( !tb ) return; - - v3_copy( ta->co, p0 ); - v3_muladds( ta->co, ta->h, 1.0f, h0 ); - v3_copy( tb->co, p1 ); - v3_muladds( tb->co, tb->h, -1.0f, h1 ); - v3_copy( p0, l ); - - vg_line_pt3( h0, 0.2f, 0xff00ff00 ); - vg_line_pt3( h1, 0.2f, 0xffff00ff ); - vg_line( p0, h0, 0xff000000 ); - vg_line( p1, h1, 0xff000000 ); - - for( int i=0; i<5; i++ ) - { - float t = (float)(i+1)/5.0f; - eval_bezier_time( p0, p1, h0, h1, t, p ); - - vg_line( p, l, 0xffffffff ); - v3_copy( p, l ); - } -} - -static void sample_wheel_floor( v3f pos ) -{ - v3f ground; - v3_copy( pos, ground ); - ground[1] += 4.0f; - - ray_hit hit; - hit.dist = 8.0f; - - if( ray_world( ground, (v3f){0.0f,-1.0f,0.0f}, &hit )) - { - v3_copy( hit.pos, pos ); - } -} - -static void traffic_drive( traffic_driver *driver ) -{ - traffic_node *next, *current = driver->current; - - if( !current ) return; - next = driver->option==0? current->next: current->next1; - - if( driver->t > 1.0f ) - { - driver->t = driver->t - floorf( driver->t ); - driver->current = driver->option==0? current->next: current->next1; - driver->option = 0; - - current = driver->current; - if( !current ) - return; - - if( current->next && current->next1 ) - if( vg_randf() > 0.5f ) - driver->option = 1; - } - - traffic_visualize_link( current, next ); - - /* - * Calculate the speed of the curve at the current point. On the reference - * curve the rate should come out to be exactly 1 ktimestep traveled. - * Dividing this distance by ktimestep gives us the modifier to use. - */ - v3f p0,p1,h0,h1,pc,pn; - - v3_copy( current->co, p0 ); - v3_muladds( current->co, current->h, 1.0f, h0 ); - v3_copy( next->co, p1 ); - v3_muladds( next->co, next->h, -1.0f, h1 ); - - eval_bezier_time( p0,p1,h0,h1, driver->t, pc ); - eval_bezier_time( p0,p1,h0,h1, driver->t + vg.time_delta, pn ); - - float mod = vg.time_delta / v3_dist( pc, pn ); - v3f dir,side,up; - v3_sub( pn, pc, dir ); - v3_normalize(dir); - - /* - * Stick the car on the ground by casting rays where the wheels are - */ - side[0] = -dir[2]; - side[1] = 0.0f; - side[2] = dir[0]; - v3_normalize(side); - - v3f fl, fr, bc; - v3_muladds( pc, dir, 2.0f, fr ); - v3_muladds( pc, dir, 2.0f, fl ); - v3_muladds( pc, dir, -2.0f, bc ); - v3_muladds( fr, side, 1.0f, fr ); - v3_muladds( fl, side, -1.0f, fl ); - - sample_wheel_floor( fl ); - sample_wheel_floor( fr ); - sample_wheel_floor( bc ); - - vg_line( fl, fr, 0xff00ffff ); - vg_line( fr, bc, 0xff00ffff ); - vg_line( bc, fl, 0xff00ffff ); - - v3f norm; - v3f v0, v1; - v3_sub( fr, fl, v0 ); - v3_sub( bc, fl, v1 ); - v3_cross( v1, v0, norm ); - v3_normalize( norm ); - - /* - * Jesus take the wheel - */ - float steer_penalty = 1.0f-v3_dot( dir, driver->transform[0] ); - steer_penalty /= vg.time_delta; - steer_penalty *= 30.0f; - - float target_speed = vg_maxf( 16.0f * (1.0f-steer_penalty), 0.1f ), - accel = target_speed - driver->speed; - driver->speed = stable_force( driver->speed, accel*vg.time_delta*2.0f ); - driver->t += driver->speed*mod*vg.time_delta; - - /* - * Update transform - */ - v3_cross( dir, norm, side ); - v3_copy( dir, driver->transform[0] ); - v3_copy( norm, driver->transform[1] ); - v3_copy( side, driver->transform[2] ); - - v3_add( fl, fr, pc ); - v3_add( bc, pc, pc ); - v3_muls( pc, 1.0f/3.0f, pc ); - v3_copy( pc, driver->transform[3] ); -} - -static void traffic_visualize( traffic_node *system, int count ) -{ - for( int i=0; inext ); - traffic_visualize_link( tn, tn->next1 ); - } -} - -static void traffic_visualize_car( traffic_driver *driver ) -{ - vg_line_boxf_transformed( driver->transform, - (boxf){{-1.0f,0.0f,-0.5f}, - { 1.0f,0.0f, 0.5f}}, 0xff00ff00 ); -} - -#endif /* TRAFFIC_H */ diff --git a/src/trail.c b/src/trail.c index fa123c1..24d9b4e 100644 --- a/src/trail.c +++ b/src/trail.c @@ -1,19 +1,8 @@ -#pragma once -#include "vg/vg_engine.h" -#include "vg/vg_platform.h" -#include "vg/vg_m.h" -#include "vg/vg_lines.h" -#include "vg/vg_camera.h" -#include "trail.h" -#include "shaders/particle.h" -#include "shaders/trail.h" - -static void trail_increment( trail_system *sys ){ +static void trail_increment( trail_system *sys ) +{ sys->head ++; - if( sys->head == sys->max ) sys->head = 0; - /* undesirable effect: will remove active points if out of space! */ if( sys->count < sys->max ) sys->count ++; @@ -114,23 +103,19 @@ void trail_system_debug( trail_system *sys ) } } -struct trail_init_args { - trail_system *sys; -}; - -void async_trail_init( vg_async_task *task ) +void trail_alloc( trail_system *sys, u32 max, vg_stack_allocator *stack ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN|VG_THREAD_OWNS_OPENGL ) ); - struct trail_init_args *args = (void *)task->data; - trail_system *sys = args->sys; + u32 stride = sizeof(trail_vert); + sys->max = max; + sys->array = vg_stack_allocate( NULL, max*sizeof(trail_point), 8, "Trail array" ); + sys->vertices = vg_stack_allocate( NULL, max*stride*2, 8, "Trail vertices" ); glGenVertexArrays( 1, &sys->vao ); glGenBuffers( 1, &sys->vbo ); glBindVertexArray( sys->vao ); - size_t stride = sizeof(trail_vert); - glBindBuffer( GL_ARRAY_BUFFER, sys->vbo ); glBufferData( GL_ARRAY_BUFFER, sys->max*stride*2, NULL, GL_DYNAMIC_DRAW ); @@ -139,28 +124,16 @@ void async_trail_init( vg_async_task *task ) glEnableVertexAttribArray( 0 ); } -void trail_alloc( trail_system *sys, u32 max ) -{ - THREAD_1; - - size_t stride = sizeof(trail_vert); - sys->max = max; - sys->array = vg_stack_allocate( &vg.rtmem, max*sizeof(trail_point), 8, "Trail array" ); - sys->vertices = vg_stack_allocate( &vg.rtmem, max*stride*2, 8, "Trail vertices" ); - - vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct trail_init_args), 1 ); - struct trail_init_args *init = (void *)task->data; - init->sys = sys; - vg_async_task_dispatch( task, async_trail_init ); -} - void trail_system_prerender( trail_system *sys ) { - if( sys->count < 2 ) return; + if( sys->count < 2 ) + return; - for( i32 i=0; icount; i ++ ){ + for( i32 i=0; icount; i ++ ) + { i32 i0 = sys->head - sys->count + i; - if( i0 < 0 ) i0 += sys->max; + if( i0 < 0 ) + i0 += sys->max; trail_point *p0 = &sys->array[i0]; trail_vert *v0 = &sys->vertices[i*2+0], @@ -171,17 +144,17 @@ void trail_system_prerender( trail_system *sys ) v0->co[3] = p0->alpha; v1->co[3] = p0->alpha; } - glBindVertexArray( sys->vao ); - size_t stride = sizeof(trail_vert); + u32 stride = sizeof(trail_vert); glBindBuffer( GL_ARRAY_BUFFER, sys->vbo ); glBufferSubData( GL_ARRAY_BUFFER, 0, sys->count*stride*2, sys->vertices ); } void trail_system_render( trail_system *sys, vg_camera *cam ) { - if( sys->count < 2 ) return; + if( sys->count < 2 ) + return; glDisable( GL_CULL_FACE ); glEnable( GL_DEPTH_TEST ); diff --git a/src/trail.h b/src/trail.h index 82c7d60..409eca9 100644 --- a/src/trail.h +++ b/src/trail.h @@ -1,4 +1,6 @@ -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/trail.c" +#else typedef struct trail_system trail_system; typedef struct trail_point trail_point; @@ -25,9 +27,10 @@ struct trail_system { f32 width, lifetime, min_dist; }; -void trail_alloc( trail_system *sys, u32 max ); -void trail_system_update( trail_system *sys, f32 dt, v3f co, - v3f normal, f32 alpha ); +void trail_alloc( trail_system *sys, u32 max, vg_stack_allocator *stack ); +void trail_system_update( trail_system *sys, f32 dt, v3f co, v3f normal, f32 alpha ); void trail_system_debug( trail_system *sys ); void trail_system_prerender( trail_system *sys ); void trail_system_render( trail_system *sys, vg_camera *cam ); + +#endif diff --git a/src/unit_skaterift.c b/src/unit_skaterift.c new file mode 100644 index 0000000..112b94e --- /dev/null +++ b/src/unit_skaterift.c @@ -0,0 +1,8 @@ +#include "vg/vg.hconf" + +#define SR_ALL +#include "src/skaterift.hconf" + +#define SR_IMPLEMENTATION +#include "src/skaterift.hconf" +#undef SR_IMPLEMENTATION diff --git a/src/user_profile.c b/src/user_profile.c index 2209b14..1cecacc 100644 --- a/src/user_profile.c +++ b/src/user_profile.c @@ -1,5 +1,3 @@ -#include "user_profile.h" - struct menu_icon_inf { u16 desc_offset; @@ -14,7 +12,7 @@ struct u32 country_index; - u16 race3, race10; + u32 race3, race10; f32 timer; enum user_profile_state @@ -29,7 +27,7 @@ struct v2f country_coords; bool has_avatar; - GLuint cc_tex, map_tex, icon_tex, no_avatar_tex, avatar_tex; + vg_tex cc_tex, map_tex, icon_tex, no_avatar_tex, avatar_tex; } _user_profile = { .country_coords = {0.5f, 0.5f} }; @@ -41,18 +39,25 @@ struct country #include "cc.h" -void _user_profile_init(void) +static void _user_profile_load_content_async( void *_, vg_async_info *async ) +{ + u32 flags = VG_TEX_CLAMP|VG_TEX_NEAREST; + _vg_tex_load( &_user_profile.cc_tex, "textures/cc.qoi", flags ); + _vg_tex_load( &_user_profile.map_tex, "textures/world_map.qoi", flags ); + _vg_tex_load( &_user_profile.icon_tex, "textures/menu_icons.qoi", flags ); + _vg_tex_load( &_user_profile.no_avatar_tex, "textures/no_avatar.qoi", flags ); + _vg_tex_load( &_user_profile.avatar_tex, "textures/no_avatar.qoi", flags ); +} + +VG_API void _user_profile_init(void) { - vg_tex2d_load_qoi_async_file( "textures/cc.qoi", VG_TEX2D_CLAMP, &_user_profile.cc_tex ); - vg_tex2d_load_qoi_async_file( "textures/world_map.qoi", VG_TEX2D_CLAMP, &_user_profile.map_tex ); - vg_tex2d_load_qoi_async_file( "textures/menu_icons.qoi", VG_TEX2D_CLAMP, &_user_profile.icon_tex ); - vg_tex2d_load_qoi_async_file( "textures/no_avatar.qoi", VG_TEX2D_CLAMP, &_user_profile.no_avatar_tex ); - vg_tex2d_load_qoi_async_file( "textures/no_avatar.qoi", VG_TEX2D_CLAMP, &_user_profile.avatar_tex ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_user_profile_load_content_async ); } static void _profile_download_callback( void *data, u32 data_size, u64 userdata, enum request_status status ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); u64 steamid = userdata; if( steamid != _user_profile.current_steamid ) @@ -66,30 +71,39 @@ static void _profile_download_callback( void *data, u32 data_size, u64 userdata, _user_profile.state = k_user_profile_state_open; - vg_msg body; - vg_msg_init( &body, data, data_size ); + u32 temp_frame = _vg_start_temp_frame(); + { + vg_stream kv_stream; + vg_buffer_stream_open( &kv_stream, data, data_size, VG_STREAM_READ ); - const char *username = vg_msg_getkvstr( &body, "username" ); - vg_strncpy( username, _user_profile.username, sizeof(_user_profile.username), k_strncpy_always_add_null ); + vg_kvs kvs; + vg_kvs_init( &kvs, _vg_temp_stack() ); + vg_kv_parser parser; + vg_kv_parser_init( &parser, &kvs, 0 ); + vg_kv_parse_stream( &parser, &kv_stream ); - vg_msg_getkvintg( &body, "flags", k_vg_msg_u32, &_user_profile.flags, NULL ); - vg_msg_getkvintg( &body, "race3", k_vg_msg_u16, &_user_profile.race3, NULL ); - vg_msg_getkvintg( &body, "race10", k_vg_msg_u16, &_user_profile.race10, NULL ); - _user_profile.country_index = 0; + const c8 *username = vg_kv_value( &kvs, vg_kv_find( &kvs, 0, "username" ), NULL ); + vg_strncpy( username, _user_profile.username, sizeof(_user_profile.username), k_strncpy_always_add_null ); - const char *cc = vg_msg_getkvstr( &body, "cc" ); + vg_kv_read_vu32( &kvs, 0, "flags", NULL, &_user_profile.flags, 1 ); + vg_kv_read_vu32( &kvs, 0, "race3", NULL, &_user_profile.race3, 1 ); + vg_kv_read_vu32( &kvs, 0, "race10", NULL, &_user_profile.race10, 1 ); + _user_profile.country_index = 0; - if( cc && strlen(cc)>=2 ) - { - for( u32 i=0; i=2 ) { - if( (k_country_iso2[i*3+0] == cc[0]) && (k_country_iso2[i*3+1] == cc[1]) ) + for( u32 i=0; iinetmsg_id = k_inetmsg_request; - vg_msg data; vg_msg_init( &data, packet->buffer, 512 ); vg_msg_wkvstr( &data, "endpoint", "profile" ); vg_msg_wkvnum( &data, "steamid", k_vg_msg_u64, 1, &steamid ); - network_send_request( packet, &data, _profile_download_callback, steamid ); + + const c8 *yep_fix_me = "endpoint profile\n" + "steamid 1234\n"; + network_send_request( yep_fix_me, 0, _profile_download_callback, steamid ); +#endif + // FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME////FIXME//// u64 me_id = SteamAPI_ISteamUser_GetSteamID( _steam_api.pSteamUser ); bool isme = 0; @@ -139,7 +157,7 @@ void _user_profile_ui( ui_context *ctx, ui_rect box, u64 steamid ) if( SteamAPI_ISteamUtils_GetImageRGBA( _steam_api.pSteamUtils, avatar_handle, tmp, w*h*4 ) ) { - glBindTexture( GL_TEXTURE_2D, _user_profile.avatar_tex ); + vg_tex_bind( GL_TEXTURE_2D, &_user_profile.avatar_tex, 0 ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, tmp ); _user_profile.has_avatar = 1; } @@ -200,9 +218,7 @@ void _user_profile_ui( ui_context *ctx, ui_rect box, u64 steamid ) x = (i & 0xf)*16, y = ((i>>4) & 0xf)*16; ui_fill_rect( ctx, flag, 0xffffffff, (ui_px[4]){ x,y,x+16,y+16 } ); - - struct ui_batch_shader_data_image inf = { .resource = &_user_profile.cc_tex }; - ui_flush( ctx, k_ui_shader_image, &inf ); + ui_flush( ctx, k_ui_shader_image, &_user_profile.cc_tex ); } ui_image( ctx, pfp, _user_profile.has_avatar? &_user_profile.avatar_tex: &_user_profile.no_avatar_tex, 1 ); @@ -274,9 +290,7 @@ void _user_profile_ui( ui_context *ctx, ui_rect box, u64 steamid ) w = ((icon_index>>3) & 0x7)*32; ui_fill_rect( ctx, medal_box, 0xffffffff, (ui_px[4]){ z,w,z+32,w+32 } ); } - - struct ui_batch_shader_data_image inf = { .resource = &_user_profile.icon_tex }; - ui_flush( ctx, k_ui_shader_image, &inf ); + ui_flush( ctx, k_ui_shader_image, &_user_profile.icon_tex ); x = base; for( u32 i=0; i>4) & 0xf)*16; ui_fill_rect( ctx, min_country_rect, 0xffffffff, (ui_px[4]){ x,y,x+16,y+16 } ); } - - struct ui_batch_shader_data_image inf = { .resource = &_user_profile.cc_tex }; - ui_flush( ctx, k_ui_shader_image, &inf ); + ui_flush( ctx, k_ui_shader_image, &_user_profile.cc_tex ); if( min_country >= 0 ) { @@ -522,13 +532,19 @@ bool _user_profile_country_picker( ui_context *ctx, ui_rect box ) netmsg_request *packet = alloca( sizeof(netmsg_request) + 512 ); packet->inetmsg_id = k_inetmsg_request; - vg_msg data; - vg_msg_init( &data, packet->buffer, 512 ); - vg_msg_wkvstr( &data, "endpoint", "profile" ); + u32 temp_frame = _vg_start_temp_frame(); + { + vg_kvs kvs; + vg_kvs_init( &kvs, _vg_temp_stack() ); + vg_kv_append( &kvs, 0, "endpoint", "profile" ); + u32 index = _user_profile.country_index; + vg_kv_append( &kvs, 0, "cc",index == 0? "00": k_country_iso2+(index-1)*3 ); + } + _vg_end_temp_frame( temp_frame ); - u32 index = _user_profile.country_index; - vg_msg_wkvstr( &data, "cc", index == 0? "00": k_country_iso2+(index-1)*3 ); - network_send_request( packet, &data, _profile_download_callback, 0 ); + VG_ASSERT(0); + // FIXME FIXME FIXME FIXME + //network_send_request( todo, 0, _profile_download_callback, 0 ); } return close; diff --git a/src/user_profile.h b/src/user_profile.h index 6accf55..72b4624 100644 --- a/src/user_profile.h +++ b/src/user_profile.h @@ -1,4 +1,9 @@ -#pragma once -void _user_profile_init(void); +#if defined( SR_IMPLEMENTATION ) +# include "src/user_profile.c" +#else + +VG_API void _user_profile_init(void); void _user_profile_ui( ui_context *ctx, ui_rect box, u64 steamid ); bool _user_profile_country_picker( ui_context *ctx, ui_rect box ); + +#endif diff --git a/src/utest.c b/src/utest.c index 7145bec..b736e80 100644 --- a/src/utest.c +++ b/src/utest.c @@ -78,7 +78,7 @@ void vg_post_update(void){} void vg_render(void) { glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - glViewport( 0,0, vg.window_x, vg.window_y ); + glViewport( 0,0, _vg_window.w, _vg_window.h ); glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); } @@ -87,7 +87,7 @@ void vg_gui( ui_context *ctx ) { ui_capture_mouse( ctx, 1 ); - ui_rect rect = { 8,8, vg.window_x-16, vg.window_y-16 }; + ui_rect rect = { 8,8, _vg_window.w-16, _vg_window.h-16 }; } diff --git a/src/vehicle.c b/src/vehicle.c index 6ce6d2f..502abff 100644 --- a/src/vehicle.c +++ b/src/vehicle.c @@ -1,7 +1,3 @@ -#include "skaterift.h" -#include "vehicle.h" -#include "scene_rigidbody.h" - struct drivable_vehicle gzoomer = { .rb.co = {-2000,-2000,-2000} diff --git a/src/vehicle.h b/src/vehicle.h index 3e60bb7..98acb9f 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -1,8 +1,6 @@ -#pragma once -#include "vg/vg_rigidbody.h" -#include "player.h" -#include "world.h" -#include "world_physics.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/vehicle.c" +#else static float k_car_spring = 1.0f, k_car_spring_damp = 0.001f, @@ -40,3 +38,5 @@ void vehicle_wheel_force( int index ); void vehicle_solve_friction(void); void vehicle_update_fixed(void); void vehicle_update_post(void); + +#endif diff --git a/src/workshop.c b/src/workshop.c index 75d1863..2aaa23f 100644 --- a/src/workshop.c +++ b/src/workshop.c @@ -1,15 +1,3 @@ -#include "vg/vg_engine.h" -#include "vg/vg_tex.h" -#include "vg/vg_image.h" -#include "vg/vg_msg.h" -#include "vg/vg_binstr.h" -#include "vg/vg_loader.h" -#include "vg/vg_io.h" -#include "ent_skateshop.h" - -#include "vg/vg_steam2.h" -#include "workshop.h" - struct workshop_form workshop_form; static struct ui_enum_opt workshop_form_visibility_opts[] = { @@ -158,7 +146,7 @@ static const char *workshop_filetype_folder(void){ */ static void workshop_form_upload_submission( PublishedFileId_t file_id, char *metadata ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); UGCUpdateHandle_t handle = SteamAPI_ISteamUGC_StartItemUpdate( _steam_api.pSteamUGC, SKATERIFT_APPID, file_id ); /* TODO: Handle failure cases for these */ @@ -210,6 +198,8 @@ static void workshop_form_upload_submission( PublishedFileId_t file_id, char *me /* * Steam API call result for when we've created a new item on their network, or * not, if it has failed + * + * FIXME FIXME FIXME FIXME FIXME FIXME FIXME */ static void on_workshop_createitem( void *data, void *user ) { @@ -238,23 +228,25 @@ static void on_workshop_createitem( void *data, void *user ) /* * Starts the workshop upload process through Steam API */ -static void workshop_form_async_submit_begin( void *userdata ) +static void workshop_form_async_submit_begin( void *_, vg_async_info *async ) { + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_OWNS_STEAM ) ); + /* use existing file */ if( workshop_form.submission.file_id ) { - workshop_form_upload_submission( workshop_form.submission.file_id, userdata ); + workshop_form_upload_submission( workshop_form.submission.file_id, "undefined" ); } else { vg_steam_api_call *call = vg_alloc_async_steam_api_call(); - call->userdata = userdata; + call->userdata = "undefined"; call->cb = on_workshop_createitem; call->id = SteamAPI_ISteamUGC_CreateItem( _steam_api.pSteamUGC, SKATERIFT_APPID, k_EWorkshopFileTypeCommunity ); } } -static void _workshop_form_end_op( void *userdata ) +static void _workshop_form_end_op( void *_, vg_async_info *async ) { workshop_form.op = k_workshop_op_none; } @@ -262,7 +254,7 @@ static void _workshop_form_end_op( void *userdata ) /* * Thread which kicks off the upload process */ -static void _workshop_form_submit_t1( void *userdata ) +static void _workshop_form_submit_t1( void *_, vg_async_info *async ) { char path_buf[4096]; vg_str folder; @@ -274,81 +266,77 @@ static void _workshop_form_submit_t1( void *userdata ) if( !vg_strgood(&folder) ) { vg_error( "addon folder path too long\n" ); - vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)_workshop_form_end_op ); return; } - /* - * Create the metadata file - * -----------------------------------------------------------------------*/ - u8 descriptor_buf[ 512 ]; - vg_msg descriptor; - vg_msg_init( &descriptor, descriptor_buf, sizeof(descriptor_buf) ); - vg_stack_clear( &vg.scratch ); - - /* short description */ - vg_msg_frame( &descriptor, "workshop" ); - { - vg_msg_wkvstr( &descriptor, "title", workshop_form.submission.title ); - //vg_msg_wkvstr( &descriptor, "author", "unknown" ); - vg_msg_wkvnum( &descriptor, "type", k_vg_msg_u32, 1, &workshop_form.submission.type ); - vg_msg_wkvstr( &descriptor, "folder", workshop_form.addon_folder ); - } - vg_msg_end_frame( &descriptor ); - //vg_msg_wkvstr( &descriptor, "location", "USA" ); - - char *short_descriptor_str = vg_stack_allocate( &vg.scratch, descriptor.cur.co*2+1, 1, "Descriptor String" ); - vg_bin_str( descriptor_buf, short_descriptor_str, descriptor.cur.co ); - short_descriptor_str[descriptor.cur.co*2] = '\0'; - vg_info( "binstr: %s\n", short_descriptor_str ); - vg_dir dir; if( vg_dir_open( &dir, folder.buffer ) != k_dir_open_ok ) { vg_error( "could not open addon folder '%s'\n", folder.buffer ); - vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)_workshop_form_end_op ); return; } - while( vg_dir_next_entry(&dir) ) + u32 temp_frame = _vg_start_temp_frame(); { - if( vg_dir_entry_type(&dir) == k_vg_entry_type_file ) + vg_kvs kvs; + vg_kvs_init( &kvs, _vg_temp_stack() ); + + while( vg_dir_next_entry(&dir) ) { - const char *d_name = vg_dir_entry_name(&dir); - if( d_name[0] == '.' ) continue; + if( vg_dir_entry_type(&dir) == k_vg_entry_type_file ) + { + const char *d_name = vg_dir_entry_name(&dir); + if( d_name[0] == '.' ) continue; - vg_str file = folder; - vg_strcat( &file, "/" ); - vg_strcat( &file, d_name ); - if( !vg_strgood( &file ) ) continue; + vg_str file = folder; + vg_strcat( &file, "/" ); + vg_strcat( &file, d_name ); + if( !vg_strgood( &file ) ) continue; - char *ext = vg_strch( &file, '.' ); - if( !ext ) continue; - if( strcmp(ext,".mdl") ) continue; + char *ext = vg_strch( &file, '.' ); + if( !ext ) continue; + if( strcmp(ext,".mdl") ) continue; - vg_msg_wkvstr( &descriptor, "content", d_name ); - break; + vg_kv_append( &kvs, 0, "content", d_name ); + break; + } } - } - vg_dir_close(&dir); + vg_dir_close(&dir); - vg_str descriptor_file = folder; - vg_strcat( &descriptor_file, "/addon.inf" ); - if( !vg_strgood(&descriptor_file) ){ - vg_error( "Addon info path too long\n" ); - vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL ); - return; - } - - FILE *fp = fopen( descriptor_file.buffer, "wb" ); - if( !fp ) - { - vg_error( "Could not open addon info file '%s'\n", descriptor_file.buffer ); - vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL ); - return; + u32 workshop_block = vg_kv_append( &kvs, 0, "workshop", NULL ); + vg_kv_append( &kvs, workshop_block, "title", workshop_form.submission.title ); + vg_kv_append_vu32( &kvs, workshop_block, "type", &workshop_form.submission.type, 1 ); + vg_kv_append( &kvs, workshop_block, "folder", workshop_form.addon_folder ); + + + vg_str descriptor_file = folder; + vg_strcat( &descriptor_file, "/addon.kv" ); + if( !vg_strgood(&descriptor_file) ) + { + vg_error( "Addon info path too long\n" ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)_workshop_form_end_op ); + _vg_end_temp_frame( temp_frame ); + return; + } + + // FIXME FIXME FIXME FIXME FIXME + vg_error( "FIXME!!!!!!\n" ); + VG_ASSERT(0); +#if 0 + FILE *fp = fopen( descriptor_file.buffer, "wb" ); + if( !fp ) + { + vg_error( "Could not open addon info file '%s'\n", descriptor_file.buffer ); + vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL ); + return; + } + fwrite( descriptor_buf, descriptor.cur.co, 1, fp ); + fclose( fp ); +#endif } - fwrite( descriptor_buf, descriptor.cur.co, 1, fp ); - fclose( fp ); + _vg_end_temp_frame( temp_frame ); /* Save the preview * -----------------------------------------------------------------------*/ @@ -358,7 +346,7 @@ static void _workshop_form_submit_t1( void *userdata ) if( !vg_strgood(&preview) ) { vg_error( "preview image path too long\n" ); - vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)_workshop_form_end_op ); return; } @@ -369,7 +357,7 @@ static void _workshop_form_submit_t1( void *userdata ) stbi_flip_vertically_on_write(1); stbi_write_jpg( preview.buffer, w,h, 3, workshop_form.img_buffer, 90 ); - vg_async_call( &vg.main_tasks, workshop_form_async_submit_begin, short_descriptor_str ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)workshop_form_async_submit_begin ); } /* @@ -414,8 +402,9 @@ static void workshop_op_submit( ui_context *ctx ) int w, h; vg_framebuffer_get_res( g_render.fb_workshop_preview, &w, &h ); - vg_stack_clear( &vg.scratch ); - workshop_form.img_buffer = vg_stack_allocate( &vg.scratch, w*h*3, 8, "Image buffer" ); + + // FIXME FIXME + //workshop_form.img_buffer = vg_stack_allocate( &vg.scratch, w*h*3, 8, "Image buffer" ); vg_info( "read framebuffer: glReadPixels( %dx%d )\n", w,h ); @@ -426,7 +415,7 @@ static void workshop_op_submit( ui_context *ctx ) workshop_form.img_w = w; workshop_form.img_h = h; - vg_async_call( &vg.loader_tasks, _workshop_form_submit_t1, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_workshop_form_submit_t1 ); } /* @@ -437,9 +426,9 @@ static void workshop_op_submit( ui_context *ctx ) /* * Reciever for completion of the model file load */ -static void workshop_form_loadmodel_async_complete( void *userdata ) +static void workshop_form_loadmodel_async_complete( void *_, vg_async_info *async ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); v2_zero( workshop_form.view_angles ); v3_zero( workshop_form.view_offset ); @@ -454,9 +443,9 @@ static void workshop_form_loadmodel_async_complete( void *userdata ) /* * Thread which loads the model from the disk */ -static void _workshop_form_load_t1( void *userdata ) +static void _workshop_form_load_t1( void *_, vg_async_info *async ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); char path_buf[4096]; vg_str folder; @@ -468,7 +457,7 @@ static void _workshop_form_load_t1( void *userdata ) if( !vg_strgood(&folder) ) { vg_error( "workshop async load failed: path too long\n" ); - vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)_workshop_form_end_op ); return; } @@ -476,7 +465,7 @@ static void _workshop_form_load_t1( void *userdata ) if( vg_dir_open( &dir, folder.buffer ) != k_dir_open_ok ) { vg_error( "workshop async load failed: could not open folder\n" ); - vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)_workshop_form_end_op ); return; } @@ -507,7 +496,7 @@ static void _workshop_form_load_t1( void *userdata ) if( !found_mdl ) { vg_error( "workshop async load failed: no model files found\n" ); - vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)_workshop_form_end_op ); return; } @@ -528,7 +517,7 @@ static void _workshop_form_load_t1( void *userdata ) player_model_load( &workshop_form.player_model, path_buf, &workshop_form.model_stack ); } - vg_async_call( &vg.main_tasks, workshop_form_loadmodel_async_complete, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)workshop_form_loadmodel_async_complete ); } /* @@ -536,7 +525,7 @@ static void _workshop_form_load_t1( void *userdata ) */ static void workshop_op_load_model( ui_context *ctx ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); world_instance *world = &_world.main; workshop_form.view_world = world; @@ -564,7 +553,7 @@ static void workshop_op_load_model( ui_context *ctx ) } workshop_form.op = k_workshop_op_loading_model; - vg_async_call( &vg.loader_tasks, _workshop_form_load_t1, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_workshop_form_load_t1 ); } /* @@ -575,14 +564,16 @@ static void workshop_op_load_model( ui_context *ctx ) /* * The image has been decoded and is ready to slap into the framebuffer */ + +// FIXME FIXME FIXME static void workshop_form_async_imageload( void *data ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); if( data ) { vg_framebuffer_attachment *a = &g_render.fb_workshop_preview->attachments[0]; - glBindTexture( GL_TEXTURE_2D, a->id ); + vg_tex_bind( GL_TEXTURE_2D, &a->tex, 6 ); glTexSubImage2D( GL_TEXTURE_2D, 0,0,0, WORKSHOP_PREVIEW_WIDTH, WORKSHOP_PREVIEW_HEIGHT, a->format, a->type, data ); stbi_image_free( data ); vg_success( "Loaded workshop preview image\n" ); @@ -600,9 +591,9 @@ static void workshop_form_async_imageload( void *data ) /* * Load the image located at ./workshop_preview.jpg into our framebuffer */ -static void _workshop_load_preview_t1( void *userdata ) +static void _workshop_load_preview_t1( void *_, vg_async_info *async ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); char path_buf[ 4096 ]; vg_str path; @@ -621,23 +612,28 @@ static void _workshop_load_preview_t1( void *userdata ) { if( (x == WORKSHOP_PREVIEW_WIDTH) && (y == WORKSHOP_PREVIEW_HEIGHT) ) { - vg_async_call( &vg.main_tasks, workshop_form_async_imageload, rgb ); + //FIXME FIXME + //vg_async_call( &vg.main_tasks, workshop_form_async_imageload, rgb ); } else { vg_error( "Resolution does not match framebuffer, so we can't show it\n" ); stbi_image_free( rgb ); - vg_async_call( &vg.main_tasks, workshop_form_async_imageload, NULL ); + + // FIXME FIXME + //vg_async_call( &vg.main_tasks, workshop_form_async_imageload, NULL ); } } else { - vg_async_call( &vg.main_tasks, workshop_form_async_imageload, NULL ); + // FIXME FIXME + //vg_async_call( &vg.main_tasks, workshop_form_async_imageload, NULL ); } } else { - vg_async_call( &vg.main_tasks, workshop_form_async_imageload, NULL ); + // FIXME FIXME + //vg_async_call( &vg.main_tasks, workshop_form_async_imageload, NULL ); } } @@ -646,7 +642,7 @@ static void _workshop_load_preview_t1( void *userdata ) */ static void workshop_op_download_and_view_submission( int result_index ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); workshop_form.op = k_workshop_op_downloading_submission; SteamUGCDetails_t details; @@ -669,8 +665,10 @@ static void workshop_op_download_and_view_submission( int result_index ) vg_strncpy( details.m_rgchTitle, workshop_form.submission.title, VG_ARRAY_LEN( workshop_form.submission.title ), k_strncpy_always_add_null ); - snprintf( workshop_form.addon_folder, VG_ARRAY_LEN( workshop_form.addon_folder ), - "Steam Cloud ("PRINTF_U64")", details.m_nPublishedFileId ); + vg_str folder_str; + vg_strnull( &folder_str, workshop_form.addon_folder, sizeof(workshop_form.addon_folder) ); + vg_strcat( &folder_str, "Steam Cloud (" ); + vg_strcatu64( &folder_str, details.m_nPublishedFileId, 16 ); workshop_form.submission.file_id = details.m_nPublishedFileId; workshop_form.file_intent = k_workshop_form_file_intent_keep_old; @@ -679,6 +677,8 @@ static void workshop_op_download_and_view_submission( int result_index ) workshop_form.submission.type = k_addon_type_none; workshop_form.submission.submission_type_selection = k_addon_type_none; + // FIXME FIXME FIXME FIXME::::::::::::: +#if 0 if( have_meta ) { u32 len = strlen(metadata_str); @@ -706,14 +706,14 @@ static void workshop_op_download_and_view_submission( int result_index ) { vg_error( "No metadata was returned with this item.\n" ); } +#endif vg_framebuffer_bind( g_render.fb_workshop_preview, 1.0f ); glClearColor( 0.2f, 0.0f, 0.0f, 1.0f ); glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - glViewport( 0,0, vg.window_x, vg.window_y ); - - vg_async_call( &vg.loader_tasks, _workshop_load_preview_t1, NULL ); + glViewport( 0,0, _vg_window.w, _vg_window.h ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_workshop_load_preview_t1 ); } else { @@ -847,7 +847,7 @@ int workshop_submit_command( int argc, const char *argv[] ) return 0; } -void workshop_register(void) +VG_API void _workshop_register(void) { vg_console_reg_cmd( "workshop_submit", workshop_submit_command, NULL ); } @@ -864,7 +864,7 @@ static void workshop_render_world_preview(void) render_world( &_world.main, &g_render.cam, 0, 0, 1, 1, g_render.fb_workshop_preview ); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - glViewport( 0,0, vg.window_x, vg.window_y ); + glViewport( 0,0, _vg_window.w, _vg_window.h ); } /* @@ -878,12 +878,12 @@ static void workshop_render_player_preview(void) glEnable( GL_DEPTH_TEST ); glDisable( GL_BLEND ); - struct skeleton *sk = &localplayer.skeleton; + ms_skeleton *sk = &localplayer.skeleton; player_pose res; res.type = k_player_pose_type_ik; - skeleton_anim anim; + ms_skeletal_animation anim; player_get_anim( &anim, "idle_cycle+y" ); skeleton_sample_anim( sk, &anim, vg.time*0.1f, res.keyframes ); q_axis_angle( res.root_q, (v3f){0.0f,1.0f,0.0f}, VG_PIf ); @@ -919,7 +919,7 @@ static void workshop_render_player_preview(void) render_playermodel( &cam, &_world.main, 0, &workshop_form.playermodel_view, sk, localplayer.final_mtx ); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - glViewport( 0,0, vg.window_x, vg.window_y ); + glViewport( 0,0, _vg_window.w, _vg_window.h ); } /* @@ -997,14 +997,14 @@ static void workshop_render_board_preview(void) * pre-render step, but that includes timer stuff */ struct player_board *board = &workshop_form.board_model; - struct ub_world_lighting *ubo = &world->ub_lighting; + struct ub_world_lighting *ubo = &world_render.ub_lighting; v3f vp0, vp1; v3_copy((v3f){0.0f,0.1f, board->truck_positions[0][2]}, vp0 ); v3_copy((v3f){0.0f,0.1f, board->truck_positions[1][2]}, vp1 ); m4x3_mulv( mmdl1, vp0, ubo->g_board_0 ); m4x3_mulv( mmdl1, vp1, ubo->g_board_1 ); - glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); - glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting), &world->ub_lighting ); + glBindBuffer( GL_UNIFORM_BUFFER, world_render.ubo_lighting ); + glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting), &world_render.ub_lighting ); render_world( world, &cam, 0, 0, 0, 0, g_render.fb_workshop_preview ); struct player_board_pose pose = {0}; @@ -1012,7 +1012,7 @@ static void workshop_render_board_preview(void) render_board( &cam, world, board, mmdl1, &pose, k_board_shader_entity ); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - glViewport( 0,0, vg.window_x, vg.window_y ); + glViewport( 0,0, _vg_window.w, _vg_window.h ); } /* @@ -1091,11 +1091,13 @@ static void workshop_form_gui_draw_preview( ui_context *ctx, ui_rect img_box ) enum addon_type type = workshop_form.submission.type; if( workshop_form.file_intent == k_workshop_form_file_intent_keep_old ) { - ui_image( ctx, img_box, &g_render.fb_workshop_preview->attachments[0].id, 0 ); + // FIXME FIXME + // ui_image( ctx, img_box, &g_render.fb_workshop_preview->attachments[0].id, 0 ); } else if( workshop_form.file_intent == k_workshop_form_file_intent_new ) { - ui_image( ctx, img_box, &g_render.fb_workshop_preview->attachments[0].id, 0 ); + // FIXME FIXME + // ui_image( ctx, img_box, &g_render.fb_workshop_preview->attachments[0].id, 0 ); if( type == k_addon_type_world ) return; @@ -1360,9 +1362,9 @@ static void workshop_form_gui_sidebar( ui_context *ctx, ui_rect sidebar ) vg_str str; vg_strnull( &str, buf, sizeof(buf) ); vg_strcat( &str, "page " ); - vg_strcati32( &str, workshop_form.view_published_page_id+1 ); + vg_strcati64( &str, workshop_form.view_published_page_id+1, 10 ); vg_strcatch( &str, '/' ); - vg_strcati32( &str, workshop_form.view_published_page_count ); + vg_strcati64( &str, workshop_form.view_published_page_count, 10 ); ui_rect_pad( controls, (ui_px[2]){0,4} ); ui_rect info; @@ -1420,7 +1422,7 @@ void workshop_form_gui( ui_context *ctx ) return; ui_rect null; - ui_rect screen = { 0, 0, vg.window_x, vg.window_y }; + ui_rect screen = { 0, 0, _vg_window.w, _vg_window.h }; ui_rect window = { 0, 0, 1000, 700 }; ui_rect_center( screen, window ); ctx->wants_mouse = 1; diff --git a/src/workshop.h b/src/workshop.h index 86dd180..a707191 100644 --- a/src/workshop.h +++ b/src/workshop.h @@ -1,8 +1,6 @@ -#pragma once -#include "addon_types.h" -#include "vg/vg_steam2.h" -#include "skaterift.h" -#include "ent_skateshop.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/workshop.c" +#else struct async_workshop_filepath_info{ PublishedFileId_t id; @@ -129,9 +127,12 @@ struct workshop_form } extern workshop_form; -void workshop_register(void); +VG_API void _workshop_register(void); + int workshop_submit_command( int argc, const char *argv[] ); void async_workshop_get_filepath( void *data, u32 len ); void async_workshop_get_installed_files( void *data, u32 len ); void workshop_load_metadata( const char *path,struct workshop_file_info *info ); void workshop_form_gui( ui_context *ctx ); + +#endif diff --git a/src/world.c b/src/world.c index 21eb5cb..3e331da 100644 --- a/src/world.c +++ b/src/world.c @@ -1,31 +1,16 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#include "skaterift.h" -#include "world.h" -#include "network.h" -#include "vg/vg_loader.h" -#include "vg/vg_mem.h" -#include "save.h" -#include "player.h" -#include "ent_traffic.h" - struct world_static _world; -void world_init(void) +VG_API void _world_init(void) { - vg_loader_step( world_render_init, NULL ); - vg_loader_step( world_sfd_init, NULL ); - vg_loader_step( world_water_init, NULL ); - vg_loader_step( world_gates_init, NULL ); - vg_loader_step( world_routes_init, NULL ); + _world_render_init(); + _world_sfd_init(); + _world_water_init(); + _world_gates_init(); + _world_routes_init(); /* Allocate dynamic world memory arena */ - _world.stack = vg_stack_make_substack( &vg.rtmem, VG_MB(76), "World main data" ); - vg_stack_set_flags( _world.stack, VG_STACK_ALLOCATOR_METADATA ); - _world.preview_stack = vg_stack_make_substack( &vg.rtmem, VG_MB(32), "World preview data" ); - vg_stack_set_flags( _world.preview_stack, VG_STACK_ALLOCATOR_METADATA ); + vg_stack_init( &_world.stack, VG_STACK_USE_HEAP, VG_MB(76), "World main data" ); + vg_stack_init( &_world.preview_stack, VG_STACK_USE_HEAP, VG_MB(32), "World preview data" ); } void world_update( world_instance *world, v3f pos ) @@ -40,13 +25,14 @@ void world_update( world_instance *world, v3f pos ) world_sfd_update( world, pos ); world_volumes_update( world, pos ); ent_skateshop_update(); - ent_challenge_update(); + _ent_challenge_update(); ent_prop_update( world ); + _world_audio_update( pos ); } void world_gui( ui_context *ctx, world_instance *world ) { - ent_skateshop_gui( ctx ); + _ent_skateshop_gui( ctx ); _ent_challenge_ui( ctx ); } diff --git a/src/world.h b/src/world.h index 8f42546..d1a4cf8 100644 --- a/src/world.h +++ b/src/world.h @@ -1,12 +1,6 @@ -/* - * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#pragma once -#include "render.h" -#include "network_msg.h" -#include "addon.h" -#include "scene.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/world.c" +#else /* types */ @@ -28,20 +22,6 @@ struct leaderboard_cache typedef struct world_instance world_instance; -/* submodule headers */ -#include "world_entity.h" -#include "world_gate.h" -#include "world_gen.h" -#include "world_info.h" -#include "world_physics.h" -#include "world_render.h" -#include "world_sfd.h" -#include "world_volumes.h" -#include "world_water.h" -#include "world_audio.h" -#include "world_routes.h" -#include "world_routes_ui.h" - /* console variables */ static f32 k_day_length = 30.0f; /* minutes */ @@ -72,45 +52,6 @@ struct world_instance f64 time; f32 tar_min, tar_max; - - /* STD140 */ - struct ub_world_lighting{ - v4f g_cube_min, - g_cube_inv_range; - - v4f g_water_plane, - g_depth_bounds; - - v4f g_daysky_colour; - v4f g_nightsky_colour; - v4f g_sunset_colour; - v4f g_ambient_colour; - v4f g_sunset_ambient; - v4f g_sun_colour; - v4f g_sun_dir; - v4f g_board_0; - v4f g_board_1; - - float g_water_fog; - float g_time; - float g_realtime; - float g_shadow_length; - float g_shadow_spread; - - float g_time_of_day; - float g_day_phase; - float g_sunset_phase; - - int g_light_preview; - int g_shadow_samples; - - int g_debug_indices; - int g_debug_complexity; - } - ub_lighting; - GLuint ubo_lighting; - int ubo_bind_point; - GLuint tbo_light_entities, tex_light_entities, tex_light_cubes; @@ -118,7 +59,6 @@ struct world_instance float probabilities[3]; v3i light_cubes; - vg_framebuffer *heightmap; /* * Dynamically allocated when world_load is called. @@ -131,13 +71,11 @@ struct world_instance /* * Main world .mdl */ - mdl_context meta; + vg_model meta; - GLuint *textures; - u32 texture_count; - - struct world_surface{ - mdl_material info; + struct world_surface + { + mdl_material info; mdl_submesh sm_geo, sm_no_collide; u32 flags; @@ -181,7 +119,7 @@ struct world_instance ent_atom, ent_cutscene; - GLuint *nonlocal_gates_cubemaps; + vg_tex *nonlocal_gates_cubemaps; u32 nonlocal_gate_count; enum skybox { @@ -197,20 +135,16 @@ struct world_instance */ /* world geometry */ - scene_context scene_geo, - scene_geo_gpu, - scene_no_collide, - scene_lines; + vg_scene scene_geometry; + scene_mesh main_scene_mesh, + line_scene_mesh, + transparent_scene_mesh; /* spacial mappings */ - bh_tree *geo_bh, - *entity_bh; - u32 *entity_list; + bh_tree geometry_bh, + entity_bh; - /* graphics */ - glmesh mesh_route_lines; - glmesh mesh_geo, - mesh_no_collide; + u32 *entity_list; u32 cubemap_cooldown, cubemap_side; /* leaderboards */ @@ -226,7 +160,7 @@ struct world_static * Allocated as system memory * -------------------------------------------------------------------------- */ - vg_stack_allocator *stack, *preview_stack; + vg_stack_allocator stack, preview_stack; u32 current_run_version; f64 last_gate_hit_time; @@ -296,7 +230,7 @@ struct world_static } extern _world; -void world_init(void); +VG_API void _world_init(void); void skaterift_world_load_thread( void *_ ); void world_update( world_instance *world, v3f pos ); @@ -305,3 +239,5 @@ bool world_set_event( enum world_event activity ); bool world_clear_event( enum world_event activity ); void world_set_entity_driven_camera( vg_camera *cam ); void world_gui( ui_context *ctx, world_instance *world ); + +#endif diff --git a/src/world_audio.c b/src/world_audio.c index 3e0fecd..f14002c 100644 --- a/src/world_audio.c +++ b/src/world_audio.c @@ -1,6 +1,3 @@ -#include "audio.h" -#include "world_audio.h" - /* * Trace out a random point, near the player to try and determine water areas */ @@ -43,6 +40,34 @@ enum audio_sprite_type world_audio_sample_sprite_random(v3f origin, v3f output) return k_audio_sprite_type_none; } +void _world_audio_update( v3f co ) +{ + static float accum = 0.0f; + accum += vg.time_delta; + + if( accum > 0.1f ) + accum -= 0.1f; + else return; + + v3f sprite_pos; + enum audio_sprite_type sprite_type = world_audio_sample_sprite_random( co, sprite_pos ); + + if( sprite_type != k_audio_sprite_type_none ) + { + if( sprite_type == k_audio_sprite_type_grass ) + { + audio_ambient_sprite_play( sprite_pos, &audio_grass[vg_randu32(&vg.rand)%4] ); + } + else if( sprite_type == k_audio_sprite_type_water ) + { + if( _world.main.water.enabled ) + { + audio_ambient_sprite_play( sprite_pos, &audio_water[vg_randu32(&vg.rand)%6] ); + } + } + } +} + void world_audio_sample_distances( v3f co, int *index, float *value ) { float inr3 = 0.57735027, diff --git a/src/world_audio.h b/src/world_audio.h index 07d66d1..8b1e678 100644 --- a/src/world_audio.h +++ b/src/world_audio.h @@ -1,7 +1,11 @@ -#pragma once -#include "world.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/world_audio.c" +#else void world_fadeout_audio( world_instance *world ); void world_audio_sample_distances( v3f co, int *index, float *value ); enum audio_sprite_type world_audio_sample_sprite_random( v3f origin, v3f output ); +void _world_audio_update( v3f co ); + +#endif diff --git a/src/world_entity.c b/src/world_entity.c index f354a78..2813a90 100644 --- a/src/world_entity.c +++ b/src/world_entity.c @@ -1,23 +1,3 @@ -#include "vg/vg_steam2.h" -#include "model.h" -#include "entity.h" -#include "world.h" -#include "world_load.h" -#include "save.h" -#include "vg/vg_msg.h" -#include "menu.h" -#include "ent_challenge.h" -#include "ent_skateshop.h" -#include "ent_route.h" -#include "ent_traffic.h" -#include "ent_glider.h" -#include "ent_region.h" -#include "ent_camera.h" -#include "ent_atom.h" -#include "ent_cutscene.h" -#include "input.h" -#include "player_walk.h" - bh_system bh_system_entity_list = { .expand_bound = entity_bh_expand_bound, @@ -42,9 +22,9 @@ _event_system; static void _event_trigger( ent_event *event ); -void world_gen_entities_init( world_instance *world ) +void world_gen_entities_init( world_instance *world, vg_model_stream_context *ctx ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); /* lights */ for( u32 j=0; jent_light); j ++ ) @@ -74,10 +54,9 @@ void world_gen_entities_init( world_instance *world ) if( world->nonlocal_gate_count ) { - world->nonlocal_gates_cubemaps = vg_stack_allocate( world->stack, world->nonlocal_gate_count*sizeof(GLuint), + world->nonlocal_gates_cubemaps = vg_stack_allocate( world->stack, world->nonlocal_gate_count*sizeof(vg_tex), 8, "Non-local cubemaps" ); - for( u32 i=0; inonlocal_gate_count; i ++ ) - world->nonlocal_gates_cubemaps[i] = 0; + vg_zero_mem( world->nonlocal_gates_cubemaps, world->nonlocal_gate_count*sizeof(vg_tex) ); for( u32 j=0; jent_gate); j ++ ) { @@ -87,9 +66,10 @@ void world_gen_entities_init( world_instance *world ) if( gate->remote_addon_id ) { char cubemap_path[256]; - nonlocal_gate_cubemap_path( gate->remote_addon_id, af_str( &world->meta.af, gate->key ), cubemap_path ); - vg_tex2d_load_qoi_async_file( cubemap_path, VG_TEX2D_CUBEMAP, - &world->nonlocal_gates_cubemaps[ gate->cubemap_id ] ); + nonlocal_gate_cubemap_path( gate->remote_addon_id, af_str( world->meta.packed_strings, gate->key ), cubemap_path ); + + u32 flags = VG_TEX_CUBEMAP|VG_TEX_CLAMP|VG_TEX_LINEAR|VG_TEX_NOMIP; + _vg_tex_load( &world->nonlocal_gates_cubemaps[ gate->cubemap_id ], cubemap_path, flags ); } } } @@ -126,33 +106,28 @@ void world_gen_entities_init( world_instance *world ) for( u32 k=0; kclip_count; k++ ) { ent_audio_clip *clip = af_arritm( &world->ent_audio_clip, audio->clip_start+k ); + if( clip->_.file.pack_size ) { u32 size = clip->_.file.pack_size, offset = clip->_.file.pack_offset; - /* embedded files are fine to clear the scratch buffer, only - * external audio uses it */ - - vg_stack_clear( &vg.scratch ); - void *data = vg_stack_allocate( &vg.scratch, clip->_.file.pack_size, 8, "Pack data" ); - - mdl_fread_pack_file( &world->meta, &clip->_.file, data ); + clip->_.clip.any_data = vg_stack_allocate( world->stack, clip->_.file.pack_size, 8, "Pack data" ); + vg_stream_read( vg_model_stream_pack_stream( ctx, &clip->_.file ), clip->_.clip.any_data, clip->_.file.pack_size ); clip->_.clip.path = NULL; clip->_.clip.flags = audio->flags; - clip->_.clip.any_data = data; clip->_.clip.size = size; } else { - clip->_.clip.path = af_str( &world->meta.af, clip->_.file.pstr_path ); + clip->_.clip.path = af_str( world->meta.packed_strings, clip->_.file.pstr_path ); clip->_.clip.flags = audio->flags; clip->_.clip.any_data = NULL; clip->_.clip.size = 0; } - audio_clip_load( &clip->_.clip, world->stack ); + vg_audio_clip_load( &clip->_.clip, world->stack ); } } @@ -174,7 +149,6 @@ void world_gen_entities_init( world_instance *world ) for( u32 i=0; ientity_list = vg_stack_allocate( world->stack, indexed_count*sizeof(u32), 4, "Entity List"); u32 index=0; @@ -185,20 +159,19 @@ void world_gen_entities_init( world_instance *world ) for( u32 j=0; jentity_list[index ++] = mdl_entity_id( type, j ); } - - world->entity_bh = bh_create( world->stack, &bh_system_entity_list, world, indexed_count, 2 ); + bh_create( &world->entity_bh, &bh_system_entity_list, world, indexed_count, 2, world->stack ); /* FIXME: This should be scene geometry instead?????????? */ - world->tar_min = world->entity_bh->nodes[0].bbx[0][1]; - world->tar_max = world->entity_bh->nodes[0].bbx[1][1] + 20.0f; + world->tar_min = world->entity_bh.nodes[0].bbx[0][1]; + world->tar_max = world->entity_bh.nodes[0].bbx[1][1] + 20.0f; for( u32 i=0; ient_marker); i++ ) { ent_marker *marker = af_arritm( &world->ent_marker, i ); - if( AF_STR_EQ( &world->meta.af, marker->pstr_alias, "tar_min" ) ) + if( AF_STR_EQ( world->meta.packed_strings, marker->pstr_alias, "tar_min" ) ) world->tar_min = marker->transform.co[1]; - if( AF_STR_EQ( &world->meta.af, marker->pstr_alias, "tar_max" ) ) + if( AF_STR_EQ( world->meta.packed_strings, marker->pstr_alias, "tar_max" ) ) world->tar_max = marker->transform.co[1]; } } @@ -245,7 +218,7 @@ ent_spawn *world_find_spawn_by_name( world_instance *world, const char *name ) for( u32 i=0; ient_spawn); i++ ) { r = af_arritm( &world->ent_spawn, i ); - if( af_str_eq( &world->meta.af, r->pstr_name, name, hash ) ) + if( af_str_eq( world->meta.packed_strings, r->pstr_name, name, hash ) ) { rp = r; break; @@ -364,7 +337,7 @@ entity_event_result ent_audio_event( ent_event *event ) v3f sound_co; v3_copy( audio->transform.co, sound_co ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "spawn_particle" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "spawn_particle" ) ) { // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you) if( mdl_entity_id_type( event->source_entity_id ) == k_ent_volume ) @@ -384,7 +357,7 @@ entity_event_result ent_audio_event( ent_event *event ) return k_entity_event_result_invalid; } } - else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "play" ) ){} + else if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "play" ) ){} else return k_entity_event_result_unhandled; ent_audio_trigger( audio, sound_co ); @@ -396,7 +369,7 @@ entity_event_result ent_light_event( ent_event *event ) world_instance *world = &_world.main; ent_light *light = af_arritm( &world->ent_light, mdl_entity_id_id( event->recieve_entity_id ) ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "on" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "on" ) ) { if( event->flags & k_ent_event_data_const_i32 ) { @@ -419,10 +392,10 @@ entity_event_result ent_light_event( ent_event *event ) entity_event_result ent_ccmd_event( ent_event *event ) { world_instance *world = &_world.main; - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "exec" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "exec" ) ) { ent_ccmd *ccmd = af_arritm( &world->ent_ccmd, mdl_entity_id_id( event->recieve_entity_id )); - const char *cmd_text = af_str( &world->meta.af, ccmd->pstr_command ); + const char *cmd_text = af_str( world->meta.packed_strings, ccmd->pstr_command ); vg_info( "ccmd: %s\n", cmd_text ); vg_execute_console_input( cmd_text, 0, 1 ); return k_entity_event_result_OK; @@ -626,7 +599,7 @@ void entity_bh_closest( void *user, u32 item_index, v3f point, v3f closest ) vg_fatal_error( "Programming error\n" ); } -void world_entity_start( world_instance *world, vg_msg *sav ) +void world_entity_start( world_instance *world, vg_kvs *savedata ) { vg_info( "Start instance %p\n", world ); k_gravity = 9.6f; @@ -635,7 +608,7 @@ void world_entity_start( world_instance *world, vg_msg *sav ) for( u32 i=0; ient_event ); i ++ ) { ent_event *event = af_arritm( &world->ent_event, i ); - if( AF_STR_EQ( &world->meta.af, event->pstr_source_event, "init" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_source_event, "init" ) ) _event_trigger( event ); } @@ -653,33 +626,35 @@ void world_entity_start( world_instance *world, vg_msg *sav ) for( u32 i=0; ient_challenge); i++ ) { ent_challenge *challenge = af_arritm( &world->ent_challenge, i ); - const char *alias = af_str( &world->meta.af, challenge->pstr_alias ); - vg_msg_getkvintg( sav, alias, k_vg_msg_u32, &challenge->status, NULL ); + const char *alias = af_str( world->meta.packed_strings, challenge->pstr_alias ); + vg_kv_read_vu32( savedata, 0, alias, NULL, &challenge->status, 1 ); _ent_challenge_clear( challenge ); } - vg_msg routes_block = *sav; - if( vg_msg_seekframe( &routes_block, "routes" ) ) + u32 routes_block = vg_kv_find( savedata, 0, "routes" ); + if( routes_block ) { for( u32 i=0; ient_route); i++ ) { ent_route *route = af_arritm( &world->ent_route, i ); - vg_msg route_info = routes_block; - if( vg_msg_seekframe( &route_info, af_str(&world->meta.af,route->pstr_name) ) ) + + u32 route_info = vg_kv_find( savedata, routes_block, af_str(world->meta.packed_strings,route->pstr_name) ); + if( route_info ) { u32 flags; - vg_msg_getkvintg( &route_info, "flags", k_vg_msg_u32, &flags, NULL ); + vg_kv_read_vu32( savedata, route_info, "flags", NULL, &flags, 1 ); route->flags |= flags; - - vg_msg_getkvintg( &route_info, "best_laptime", k_vg_msg_f64, &route->best_laptime, NULL ); + + f32 best_time; + vg_kv_read_vf32( savedata, route_info, "best_laptime", NULL, &best_time, 1 ); + route->best_laptime = best_time; f32 sections[ route->checkpoints_count ]; - vg_msg_cmd cmd; - if( vg_msg_getkvcmd( &route_info, "sections", &cmd ) ) - vg_msg_cast( cmd.value, cmd.code, sections, k_vg_msg_f32 | vg_msg_count_bits(route->checkpoints_count) ); - else - for( u32 j=0; jcheckpoints_count; j ++ ) - sections[j] = 0.0f; + for( u32 j=0; jcheckpoints_count; j ++ ) + sections[j] = 0.0f; + + vg_zero_mem( sections, sizeof(sections) ); + vg_kv_read_vf32( savedata, route_info, "sections", NULL, sections, route->checkpoints_count ); for( u32 j=0; jcheckpoints_count; j ++ ) { @@ -692,16 +667,19 @@ void world_entity_start( world_instance *world, vg_msg *sav ) _atom_list_clear( k_atom_list_world ); - vg_msg_cursor orig = sav->cur; - if( vg_msg_seekframe( sav, "atoms" ) ) + u32 atoms_block = vg_kv_find( savedata, 0, "atoms" ); + if( atoms_block ) { - vg_msg_cmd cmd; - while( vg_msg_next( sav, &cmd ) ) + u32 key = vg_kv_child( savedata, atoms_block, 0 ); + while( key ) { - if( cmd.code == k_vg_msg_endframe ) break; - i32 value = 0; - vg_msg_cast( cmd.value, cmd.code, &value, k_vg_msg_i32 ); - _atom_set( k_atom_list_world, cmd.key, value ); + vg_strp s = { .buffer = vg_kv_value( savedata, key, NULL ) }; + + i64 value; + vg_strp_i64( &s, &value ); + _atom_set( k_atom_list_world, vg_kv_key( savedata, key, NULL ), (i32)value ); + + key = vg_kv_next( savedata, key ); } } @@ -718,7 +696,7 @@ void world_entity_start( world_instance *world, vg_msg *sav ) else { enum e_atom_list list = (atom->flags & k_ent_atom_global)? k_atom_list_global: k_atom_list_world; - value = _atom_get( list, af_str( &world->meta.af, atom->pstr_alias ) ); + value = _atom_get( list, af_str( world->meta.packed_strings, atom->pstr_alias ) ); } _world_raise_event( mdl_entity_id( k_ent_atom, i ), "changed" ); _world_raise_event( mdl_entity_id( k_ent_atom, i ), value? "true": "false" ); @@ -728,43 +706,38 @@ void world_entity_start( world_instance *world, vg_msg *sav ) ent_challenge *challenge = af_arritm( &world->ent_challenge, i ); _world_raise_event( mdl_entity_id( k_ent_challenge, i ), challenge->status? "true": "false" ); } - - sav->cur = orig; } -void world_entity_serialize( world_instance *world, vg_msg *sav ) +void world_entity_serialize( world_instance *world, vg_kvs *savedata ) { for( u32 i=0; ient_challenge); i++ ) { ent_challenge *challenge = af_arritm(&world->ent_challenge,i); - const char *alias = af_str( &world->meta.af, challenge->pstr_alias ); - vg_msg_wkvnum( sav, alias, k_vg_msg_u32, 1, &challenge->status ); + const char *alias = af_str( world->meta.packed_strings, challenge->pstr_alias ); + vg_kv_append_vu32( savedata, 0, alias, &challenge->status, 1 ); } if( af_arrcount(&world->ent_route) ) { - vg_msg_frame( sav, "routes" ); + u32 routes_block = vg_kv_append( savedata, 0, "routes", NULL ); for( u32 i=0; ient_route); i++ ) { ent_route *route = af_arritm( &world->ent_route, i ); - vg_msg_frame( sav, af_str( &world->meta.af, route->pstr_name ) ); + + u32 route_info = vg_kv_append( savedata, routes_block, af_str( world->meta.packed_strings, route->pstr_name ), NULL ); { - vg_msg_wkvnum( sav, "flags", k_vg_msg_u32, 1, &route->flags ); - vg_msg_wkvnum( sav, "best_laptime", k_vg_msg_f64, 1, &route->best_laptime ); + vg_kv_append_vu32( savedata, route_info, "flags", &route->flags, 1 ); + vg_kv_append_vf32( savedata, route_info, "best_laptime", (f32[]){ route->best_laptime }, 1 ); f32 sections[ route->checkpoints_count ]; - for( u32 j=0; jcheckpoints_count; j ++ ) { ent_checkpoint *cp = af_arritm( &world->ent_checkpoint, route->checkpoints_start + j ); sections[j] = cp->best_time; } - - vg_msg_wkvnum( sav, "sections", k_vg_msg_f32, route->checkpoints_count, sections ); + vg_kv_append_vf32( savedata, route_info, "sections", sections, route->checkpoints_count ); } - vg_msg_end_frame( sav ); } - vg_msg_end_frame( sav ); } } @@ -793,7 +766,7 @@ void _world_raise_event( u32 caller, const char *event_alias ) if( event->source_entity_id != caller ) continue; - if( af_str_eq( &world->meta.af, event->pstr_source_event, event_alias, event_alias_hash ) ) + if( af_str_eq( world->meta.packed_strings, event->pstr_source_event, event_alias, event_alias_hash ) ) { if( event->delay > 0.001f ) { @@ -867,29 +840,29 @@ static void _event_trigger( ent_event *event ) if( event->flags & k_ent_event_data_const_string ) { vg_info( "[event '%s'] %x -> %x ('%s') with '%s'\n", - af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id, - event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ), - af_str( &world->meta.af, event->data.const_pstr ) ); + af_str( world->meta.packed_strings, event->pstr_source_event ), event->source_entity_id, + event->recieve_entity_id, af_str( world->meta.packed_strings, event->pstr_recieve_event ), + af_str( world->meta.packed_strings, event->data.const_pstr ) ); } else if( event->flags & k_ent_event_data_const_i32 ) { vg_info( "[event '%s'] %x -> %x ('%s') with %d\n", - af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id, - event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ), + af_str( world->meta.packed_strings, event->pstr_source_event ), event->source_entity_id, + event->recieve_entity_id, af_str( world->meta.packed_strings, event->pstr_recieve_event ), event->data.const_i32 ); } else if( event->flags & k_ent_event_data_const_f32 ) { vg_info( "[event '%s'] %x -> %x ('%s') with %ff\n", - af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id, - event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ), + af_str( world->meta.packed_strings, event->pstr_source_event ), event->source_entity_id, + event->recieve_entity_id, af_str( world->meta.packed_strings, event->pstr_recieve_event ), event->data.const_f32 ); } else if( event->flags & k_ent_event_data_const_f32 ) { vg_info( "[event '%s'] %x -> %x ('%s') void\n", - af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id, - event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event )); + af_str( world->meta.packed_strings, event->pstr_source_event ), event->source_entity_id, + event->recieve_entity_id, af_str( world->meta.packed_strings, event->pstr_recieve_event )); } enum entity_event_result res = table[type]( event ); @@ -897,7 +870,7 @@ static void _event_trigger( ent_event *event ) if( res == k_entity_event_result_unhandled ) { vg_warn( "Call to entity %x#%x was unhandled (no event '%s').\n", type, index, - af_str( &world->meta.af, event->pstr_recieve_event ) ); + af_str( world->meta.packed_strings, event->pstr_recieve_event ) ); } else if( res == k_entity_event_result_invalid ) vg_warn( "Call to entity %x#%x invalid.\n", type, index ); diff --git a/src/world_entity.h b/src/world_entity.h index ea3e8b3..d03ee62 100644 --- a/src/world_entity.h +++ b/src/world_entity.h @@ -1,15 +1,13 @@ -#pragma once -#include "world.h" -#include "entity.h" -#include "vg/vg_bvh.h" -#include "vg/vg_msg.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/world_entity.c" +#else -void world_gen_entities_init( world_instance *world ); +void world_gen_entities_init( world_instance *world, vg_model_stream_context *ctx ); ent_spawn *world_find_spawn_by_name( world_instance *world, const char *name ); ent_spawn *world_find_closest_spawn( world_instance *world, v3f position ); void world_default_spawn_pos( world_instance *world, v3f pos ); -void world_entity_start( world_instance *world, vg_msg *sav ); -void world_entity_serialize( world_instance *world, vg_msg *sav ); +void world_entity_start( world_instance *world, vg_kvs *savedata ); +void world_entity_serialize( world_instance *world, vg_kvs *savedata ); //entity_call_result ent_volume_call( world_instance *world, ent_call *call ); //entity_call_result ent_audio_call( world_instance *world, ent_call *call ); @@ -26,3 +24,5 @@ void update_ach_models(void); extern bh_system bh_system_entity_list; void _world_raise_event( u32 caller, const char *event_alias ); void _ent_update(void); + +#endif diff --git a/src/world_gate.c b/src/world_gate.c index 493ea33..4759033 100644 --- a/src/world_gate.c +++ b/src/world_gate.c @@ -1,30 +1,9 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#ifndef WORLD_GATE_C -#define WORLD_GATE_C - -#include "world.h" -#include "world_gate.h" - -#include "skaterift.h" -#include "common.h" -#include "model.h" -#include "entity.h" -#include "render.h" - -#include "world_water.h" -#include "player_remote.h" -#include "shaders/model_gate_unlinked.h" -#include - -struct world_gates world_gates; +struct _world_gates _world_gates; /* * Update the transform matrices for gate */ -void gate_transform_update( ent_gate *gate ) +VG_TIER_0 void gate_transform_update( ent_gate *gate ) { if( gate->flags & k_ent_gate_flip ) { @@ -46,26 +25,21 @@ void gate_transform_update( ent_gate *gate ) m4x3_mul( recv_to_world, to_local, gate->transport ); } -void world_gates_init(void) +static void _world_gates_load_content_async( void *_, vg_async_info *async ) { - THREAD_1; - vg_info( "world_gates_init\n" ); - vg_stack_clear( &vg.scratch ); - - mdl_context mgate; - mdl_open( &mgate, "models/rs_gate.mdl", &vg.scratch ); - mdl_load_metadata_block( &mgate, &vg.scratch ); - - world_gates.sm_surface = mgate.submeshes[ mdl_get_submesh_index( &mgate, "rs_gate" ) ]; - - const char *names[] = { "rs_gate_marker", "rs_gate_marker.001", - "rs_gate_marker.002", "rs_gate_marker.003" }; - - for( int i=0; i<4; i++ ) - world_gates.sm_marker[i] = mgate.submeshes[ mdl_get_submesh_index( &mgate, names[i] ) ]; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + vg_model_load( &_world_gates.model, VG_MODEL_ENGINE_STANDARD, "models/rs_gate.mdl", VG_STACK_USE_HEAP ); + _world_gates.sm_surface = _world_gates.model.submeshes[ vg_model_get_submesh_index( &_world_gates.model, "rs_gate" ) ]; + const c8 *names[] = { "rs_gate_marker", "rs_gate_marker.001", + "rs_gate_marker.002", "rs_gate_marker.003" }; + for( u32 i=0; i<4; i++ ) + _world_gates.sm_marker[i] = _world_gates.model.submeshes[ vg_model_get_submesh_index( &_world_gates.model,names[i] ) ]; +} - mdl_async_load_glmesh( &mgate, &world_gates.mesh, NULL ); - mdl_close( &mgate ); +VG_API void _world_gates_init(void) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_world_gates_load_content_async ); } void ent_gate_get_mdl_mtx( ent_gate *gate, m4x3f mmdl ) @@ -82,17 +56,17 @@ static void render_gate_mesh( world_instance *world, ent_gate *gate ) { if( gate->flags & k_ent_gate_custom_mesh ) { - mesh_bind( &world->mesh_no_collide ); + scene_mesh_bind( &world->transparent_scene_mesh ); for( u32 i=0; isubmesh_count; i++ ) { mdl_submesh *sm = &world->meta.submeshes[ gate->submesh_start+i ]; - mdl_draw_submesh( sm ); + vg_model_draw_submesh( sm ); } } else { - mesh_bind( &world_gates.mesh ); - mdl_draw_submesh( &world_gates.sm_surface ); + vg_model_bind_mesh( &_world_gates.model ); + vg_model_draw_submesh( &_world_gates.sm_surface ); } } @@ -136,29 +110,29 @@ int render_gate( world_instance *world, world_instance *world_inside, ent_gate * } /* update gate camera */ - world_gates.cam.fov = cam->fov; - world_gates.cam.nearz = 0.1f; - world_gates.cam.farz = 2000.0f; + _world_gates.cam.fov = cam->fov; + _world_gates.cam.nearz = 0.1f; + _world_gates.cam.farz = 2000.0f; - m4x3_mul( gate->transport, cam->transform, world_gates.cam.transform ); - vg_camera_update_view( &world_gates.cam ); - vg_camera_update_projection( &world_gates.cam, vg.window_x, vg.window_y ); + m4x3_mul( gate->transport, cam->transform, _world_gates.cam.transform ); + vg_camera_update_view( &_world_gates.cam ); + vg_camera_update_projection( &_world_gates.cam, _vg_window.w, _vg_window.h ); /* Add special clipping plane to projection */ v4f surface; q_mulv( gate->q[1], (v3f){0.0f,0.0f,-1.0f}, surface ); surface[3] = v3_dot( surface, gate->co[1] ); - m4x3_mulp( world_gates.cam.transform_inverse, surface, surface ); + m4x3_mulp( _world_gates.cam.transform_inverse, surface, surface ); surface[3] = -fabsf(surface[3]); if( dist < -0.5f ) - m4x4_clip_projection( world_gates.cam.mtx.p, surface ); + m4x4_clip_projection( _world_gates.cam.mtx.p, surface ); /* Ready to draw with new camrea */ - vg_camera_finalize( &world_gates.cam ); + vg_camera_finalize( &_world_gates.cam ); - vg_line_point( world_gates.cam.transform[3], 0.3f, 0xff00ff00 ); + vg_line_point( _world_gates.cam.transform[3], 0.3f, 0xff00ff00 ); shader_model_gate_use(); shader_model_gate_uPv( cam->mtx.pv ); @@ -166,8 +140,8 @@ int render_gate( world_instance *world, world_instance *world_inside, ent_gate * shader_model_gate_uColour( (v4f){0.0f,1.0f,0.0f,0.0f} ); shader_model_gate_uTime( vg.time*0.25f ); shader_model_gate_uInvRes( (v2f){ - 1.0f / (float)vg.window_x, - 1.0f / (float)vg.window_y }); + 1.0f / (float)_vg_window.w, + 1.0f / (float)_vg_window.h }); glEnable( GL_STENCIL_TEST ); glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); @@ -181,7 +155,7 @@ int render_gate( world_instance *world, world_instance *world_inside, ent_gate * render_gate_mesh( world, gate ); if( world_inside ) - render_world( world_inside, &world_gates.cam, 1, !localplayer.gate_waiting, 1, 1, target_fb ); + render_world( world_inside, &_world_gates.cam, 1, !localplayer.gate_waiting, 1, 1, target_fb ); return 1; } @@ -299,7 +273,7 @@ entity_event_result ent_gate_event( ent_event *event ) { world_instance *world = &_world.main; ent_gate *gate = af_arritm( &world->ent_gate, mdl_entity_id_id( event->recieve_entity_id ) ); - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "lock" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "lock" ) ) { // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you) if( event->flags == k_ent_event_data_const_i32 ) @@ -333,7 +307,7 @@ void nonlocal_gate_cubemap_path( addon_id world_addon_id, const char *gate_key, */ void world_link_gates( world_instance *world ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); bool found_nonlocal_reciever = 0; @@ -349,7 +323,7 @@ void world_link_gates( world_instance *world ) { if( gate->target ) { - const char *dest_world = af_str( &world->meta.af, gate->target ); + const char *dest_world = af_str( world->meta.packed_strings, gate->target ); addon_alias q; if( addon_parse_uid( dest_world, &q ) ) @@ -367,7 +341,7 @@ void world_link_gates( world_instance *world ) if( _world.travelled_through_nonlocal_gate ) { - const char *key = af_str( &world->meta.af, gate->key ); + const char *key = af_str( world->meta.packed_strings, gate->key ); if( vg_str_eq( key, _world.nonlocal_destination_key ) ) { if( found_nonlocal_reciever ) @@ -424,5 +398,3 @@ void world_link_gates( world_instance *world ) _world.travelled_through_nonlocal_gate = 0; } } - -#endif /* WORLD_GATE_C */ diff --git a/src/world_gate.h b/src/world_gate.h index a11fb00..6939cef 100644 --- a/src/world_gate.h +++ b/src/world_gate.h @@ -1,26 +1,19 @@ -/* - * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ +#if defined( SR_IMPLEMENTATION ) +# include "src/world_gate.c" +#else -#pragma once - -#include "vg/vg_camera.h" -#include "world.h" -#include "shaders/model_gate.h" -#include "entity.h" - -struct world_gates +struct _world_gates { - glmesh mesh; + vg_model model; mdl_submesh sm_surface, sm_marker[4]; vg_camera cam; - v3f userportal_co; } -extern world_gates; +extern _world_gates; -void world_gates_init(void); -void gate_transform_update( ent_gate *gate ); +VG_API void _world_gates_init(void); + +VG_TIER_0 void gate_transform_update( ent_gate *gate ); int render_gate( world_instance *world, world_instance *world_inside, ent_gate *gate, vg_camera *cam, vg_framebuffer *target_fb ); @@ -34,3 +27,5 @@ void world_link_gates( world_instance *world ); void world_unlink_nonlocal( world_instance *world ); void render_gate_unlinked( world_instance *world, ent_gate *gate, vg_camera *cam ); void nonlocal_gate_cubemap_path( addon_id world_addon_id, const char *gate_key, char path[256] ); + +#endif diff --git a/src/world_gen.c b/src/world_gen.c index 314ef32..b20b7e1 100644 --- a/src/world_gen.c +++ b/src/world_gen.c @@ -1,27 +1,12 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - * - * World generation/population. Different to regular loading, since it needs to - * create geometry, apply procedural stuff and save that image to files etc. - */ -#include "world.h" -#include "world_gen.h" -#include "world_load.h" -#include "world_volumes.h" -#include "world_gate.h" -#include - /* * Add all triangles from the model, which match the material ID * applies affine transform to the model */ -static void world_add_all_if_material( m4x3f transform, scene_context *scene, - mdl_context *mdl, u32 id ) +static void world_add_all_if_material( m4x3f transform, scene_builder_context *builder, vg_model *mdl, u32 id ) { for( u32 i=0; imesh_count; i++ ) { mdl_mesh *mesh = &mdl->meshes[ i ]; - for( u32 j=0; jsubmesh_count; j++ ) { mdl_submesh *sm = &mdl->submeshes[ mesh->submesh_start+j ]; @@ -30,8 +15,7 @@ static void world_add_all_if_material( m4x3f transform, scene_context *scene, m4x3f transform2; mdl_transform_m4x3( &mesh->transform, transform2 ); m4x3_mul( transform, transform2, transform2 ); - - scene_add_mdl_submesh( scene, mdl, sm, transform2 ); + scene_builder_add_model_submesh( builder, mdl, sm, transform2 ); } } } @@ -46,8 +30,7 @@ static void world_add_all_if_material( m4x3f transform, scene_context *scene, * | | * |________| */ -static void world_gen_add_blob( vg_rand *rand, world_instance *world, - scene_context *scene, ray_hit *hit ) +static void world_gen_add_blob( vg_rand *rand, world_instance *world, scene_builder_context *builder, ray_hit *hit ) { m4x3f transform; v4f qsurface, qrandom; @@ -55,7 +38,7 @@ static void world_gen_add_blob( vg_rand *rand, world_instance *world, v3_cross( (v3f){0.0f,1.0f,0.0f}, hit->normal, axis ); - float angle = v3_dot(hit->normal,(v3f){0.0f,1.0f,0.0f}); + f32 angle = v3_dot(hit->normal,(v3f){0.0f,1.0f,0.0f}); q_axis_angle( qsurface, axis, angle ); q_axis_angle( qrandom, (v3f){0.0f,1.0f,0.0f}, vg_randf64(rand)*VG_TAUf ); q_mul( qsurface, qrandom, qsurface ); @@ -73,41 +56,30 @@ static void world_gen_add_blob( vg_rand *rand, world_instance *world, }; const u32 indices[] = { 0,1,3, 0,3,2, 2,3,5, 2,5,4 }; + scene_vert *dst_verts = vg_stack_allocate( &builder->vertex_stack, sizeof(scene_vert)*VG_ARRAY_LEN(verts), 1, "verts" ); + u32 *dst_indices = vg_stack_allocate( &builder->indice_stack, sizeof(u32)*VG_ARRAY_LEN(indices), 1, "indices" ); + scene_vert *ref = &world->scene_geometry.vertex_buffer[ hit->tri[0] ]; - if( scene->vertex_count + VG_ARRAY_LEN(verts) > scene->max_vertices ) - vg_fatal_error( "Scene vertex buffer overflow" ); - - if( scene->indice_count + VG_ARRAY_LEN(indices) > scene->max_indices ) - vg_fatal_error( "Scene index buffer overflow" ); - - scene_vert *dst_verts = &scene->arrvertices[ scene->vertex_count ]; - u32 *dst_indices = &scene->arrindices [ scene->indice_count ]; - - scene_vert *ref = &world->scene_geo.arrvertices[ hit->tri[0] ]; - - for( u32 i=0; ico, pvert->co ); scene_vert_pack_norm( pvert, transform[1], 0.0f ); - v2_copy( ref->uv, pvert->uv ); } for( u32 i=0; ivertex_count; + dst_indices[i] = indices[i] + builder->scene.vertex_count; - scene->vertex_count += VG_ARRAY_LEN(verts); - scene->indice_count += VG_ARRAY_LEN(indices); + builder->scene.vertex_count += VG_ARRAY_LEN(verts); + builder->scene.indice_count += VG_ARRAY_LEN(indices); } /* * Sprinkle foliage models over the map on terrain material */ -static void world_apply_procedural_foliage( world_instance *world, - scene_context *scene, - struct world_surface *mat ) +static void world_apply_procedural_foliage( world_instance *world, scene_builder_context *builder, struct world_surface *mat ) { if( (vg.quality_profile == k_quality_profile_low) || (vg.quality_profile == k_quality_profile_min) ) @@ -116,12 +88,12 @@ static void world_apply_procedural_foliage( world_instance *world, vg_info( "Applying foliage (%u)\n", mat->info.pstr_name ); v3f volume; - v3_sub( world->scene_geo.bbx[1], world->scene_geo.bbx[0], volume ); + v3_sub( world->scene_geometry.bbx[1], world->scene_geometry.bbx[0], volume ); volume[1] = 1.0f; int count = 0; - float area = volume[0]*volume[2]; + f32 area = volume[0]*volume[2]; u32 particles = 0.08f * area; vg_info( "Map area: %f. Max particles: %u\n", area, particles ); @@ -132,7 +104,7 @@ static void world_apply_procedural_foliage( world_instance *world, v3f pos; v3_mul( volume, (v3f){ vg_randf64(), 1000.0f, vg_randf64() }, pos ); pos[1] = 1000.0f; - v3_add( pos, world->scene_geo.bbx[0], pos ); + v3_add( pos, world->scene_geometry.bbx[0], pos ); ray_hit hit; hit.dist = INFINITY; @@ -153,26 +125,28 @@ static void world_apply_procedural_foliage( world_instance *world, const f32 tile_scale = 16.0f; v2i tiles = { volume[0]/tile_scale, volume[2]/tile_scale }; - u32 per_tile = particles/(tiles[0]*tiles[1]); - for( i32 x=0; xscene_geo.bbx[0], co ); + v3_add( co, world->scene_geometry.bbx[0], co ); ray_hit hit; hit.dist = INFINITY; - if( ray_world( world, co, (v3f){0.0f,-1.0f,0.0f}, &hit, - k_material_flag_ghosts )){ + if( ray_world( world, co, (v3f){0.0f,-1.0f,0.0f}, &hit, k_material_flag_ghosts )) + { struct world_surface *m1 = ray_hit_surface( world, &hit ); - if((hit.normal[1] > 0.8f) && (m1 == mat) && - (hit.pos[1] > 0.0f+10.0f)){ - world_gen_add_blob( &rand, world, scene, &hit ); + if((hit.normal[1] > 0.8f) && (m1 == mat) && (hit.pos[1] > 0.0f+10.0f)) + { + world_gen_add_blob( &rand, world, builder, &hit ); count ++; } } @@ -183,27 +157,22 @@ static void world_apply_procedural_foliage( world_instance *world, #endif - - u64 t1 = SDL_GetPerformanceCounter(), utime_blobs = t1-t0, ufreq = SDL_GetPerformanceFrequency(); f64 ftime_blobs = ((f64)utime_blobs / (f64)ufreq)*1000.0; - - vg_info( "%d foliage models added. %f%% (%fms)\n", count, - 100.0*((f64)count/(f64)particles), ftime_blobs); + vg_info( "%d foliage models added. %f%% (%fms)\n", count, 100.0*((f64)count/(f64)particles), ftime_blobs); } -static -void world_unpack_submesh_dynamic( world_instance *world, - scene_context *scene, mdl_submesh *sm ){ - if( sm->flags & k_submesh_flag_consumed ) return; +static void world_unpack_submesh_dynamic( world_instance *world, scene_builder_context *builder, mdl_submesh *sm ) +{ + if( sm->flags & k_submesh_flag_consumed ) + return; m4x3f identity; m4x3_identity( identity ); - scene_add_mdl_submesh( scene, &world->meta, sm, identity ); - - scene_copy_slice( scene, sm ); + scene_builder_add_model_submesh( builder, &world->meta, sm, identity ); + scene_builder_get_submesh( builder, sm ); sm->flags |= k_submesh_flag_consumed; } @@ -215,11 +184,9 @@ void world_gen_generate_meshes( world_instance *world ) /* * Compile meshes into the world scenes */ - u32 geo_max_verts = 320000, - geo_max_indices = 1200000; - scene_init( &world->scene_geo, geo_max_verts, geo_max_indices ); - u8 *buffer = vg_stack_allocate( world->stack, scene_mem_required( &world->scene_geo ), 8, "Geometry buffer" ); - scene_supply_buffer( &world->scene_geo, buffer ); + + scene_builder_context geo_ctx; + scene_builder_init( &geo_ctx, 320000, 1200000, world->stack ); m4x3f midentity; m4x3_identity( midentity ); @@ -234,73 +201,54 @@ void world_gen_generate_meshes( world_instance *world ) for( u32 i=0; isurface_count; i++ ) { struct world_surface *surf = &world->surfaces[ i ]; - if( surf->info.flags & k_material_flag_collision ) - world_add_all_if_material( midentity, &world->scene_geo, &world->meta, i ); + world_add_all_if_material( midentity, &geo_ctx, &world->meta, i ); - scene_copy_slice( &world->scene_geo, &surf->sm_geo ); - scene_set_vertex_flags( &world->scene_geo, - surf->sm_geo.vertex_start, - surf->sm_geo.vertex_count, - (u16)(surf->info.flags & 0xffff) ); + scene_builder_get_submesh( &geo_ctx, &surf->sm_geo ); + scene_builder_set_vertex_flags( &geo_ctx, + surf->sm_geo.vertex_start, + surf->sm_geo.vertex_count, + (u16)(surf->info.flags & 0xffff) ); } - /* reduce down to minimum size */ - u32 new_vert_max = world->scene_geo.vertex_count, - new_vert_size = vg_align8(new_vert_max*sizeof(scene_vert)), - new_indice_len = world->scene_geo.indice_count*sizeof(u32); - u32 *src_indices = world->scene_geo.arrindices, - *dst_indices = (u32 *)(buffer + new_vert_size); - memmove( dst_indices, src_indices, new_indice_len ); - - world->scene_geo.max_indices = world->scene_geo.indice_count; - world->scene_geo.max_vertices = world->scene_geo.vertex_count; - buffer = vg_stack_resize_last( world->stack, scene_mem_required( &world->scene_geo ) ); - - world->scene_geo.arrvertices = (scene_vert *)(buffer); - world->scene_geo.arrindices = (u32 *)(buffer + new_vert_size); - - /* create a copy for the GPU (bvh scrambles the data) */ - scene_context *gpu_scene = &world->scene_geo_gpu; - vg_async_task *task = scene_alloc_async( gpu_scene, &world->mesh_geo, geo_max_verts, geo_max_indices ); - memcpy( gpu_scene->arrvertices, world->scene_geo.arrvertices, world->scene_geo.vertex_count*sizeof(scene_vert) ); - memcpy( gpu_scene->arrindices, world->scene_geo.arrindices, world->scene_geo.indice_count*sizeof(u32) ); - gpu_scene->vertex_count = world->scene_geo.vertex_count; - gpu_scene->indice_count = world->scene_geo.indice_count; - box_copy( world->scene_geo.bbx, gpu_scene->bbx ); - vg_async_task_dispatch( task, async_scene_upload ); + scene_builder_compact_memory( &geo_ctx, world->stack ); + scene_builder_save_scene( &geo_ctx, &world->scene_geometry ); + scene_builder_upload_async( &geo_ctx, &world->main_scene_mesh ); if( !_world.loader_preview_mode ) { vg_info( "creating bvh\n" ); - world->geo_bh = scene_bh_create( world->stack, &world->scene_geo ); + // NOTE: destructive to geometry ordering (material/surface indices become garbage) + scene_bh_create( &world->scene_geometry, &world->geometry_bh, world->stack ); } /* * Generate scene: non-collidable geometry * ---------------------------------------------------------------- */ - vg_info( "Generating non-collidable geometry\n" ); - vg_async_task *task2 = scene_alloc_async( &world->scene_no_collide, &world->mesh_no_collide, 250000, 500000 ); + + u32 temp_frame = _vg_start_temp_frame(); + scene_builder_context trans_ctx; + scene_builder_init( &trans_ctx, 250000, 500000, _vg_temp_stack() ); for( u32 i=0; isurface_count; i++ ) { struct world_surface *surf = &world->surfaces[ i ]; - if( !(surf->info.flags & k_material_flag_collision) ) - world_add_all_if_material( midentity, &world->scene_no_collide, &world->meta, i ); + world_add_all_if_material( midentity, &trans_ctx, &world->meta, i ); if( !_world.loader_preview_mode ) - { if( surf->info.flags & k_material_flag_grow_grass ) - world_apply_procedural_foliage( world, &world->scene_no_collide, surf ); - } - - scene_copy_slice( &world->scene_no_collide, &surf->sm_no_collide ); + world_apply_procedural_foliage( world, &trans_ctx, surf ); + scene_builder_get_submesh( &trans_ctx, &surf->sm_no_collide ); } if( _world.loader_preview_mode ) - goto IL_UPLOAD; + { + scene_builder_upload_async( &trans_ctx, &world->transparent_scene_mesh ); + _vg_end_temp_frame( temp_frame ); + return; + } /* unpack traffic models.. TODO: should we just put all these submeshes in a * dynamic models list? and then the actual entitities point to the @@ -317,7 +265,7 @@ void world_gen_generate_meshes( world_instance *world ) for( u32 j=0; jsubmesh_count; j++ ) { mdl_submesh *sm = &world->meta.submeshes[ vehc->submesh_start+j ]; - world_unpack_submesh_dynamic( world, &world->scene_no_collide, sm ); + world_unpack_submesh_dynamic( world, &trans_ctx, sm ); world->surfaces[ sm->material_id ].flags |= WORLD_SURFACE_HAS_TRAFFIC; } } @@ -326,22 +274,21 @@ void world_gen_generate_meshes( world_instance *world ) for( u32 i=0; ient_objective ); i++ ) { ent_objective *objective = af_arritm( &world->ent_objective, i ); - for( u32 j=0; jsubmesh_count; j ++ ) { mdl_submesh *sm = &world->meta.submeshes[ objective->submesh_start+j ]; - world_unpack_submesh_dynamic( world, &world->scene_no_collide, sm ); + world_unpack_submesh_dynamic( world, &trans_ctx, sm ); } } /* unpack region models */ - for( u32 i=0; ient_region ); i++ ){ + for( u32 i=0; ient_region ); i++ ) + { ent_region *region = af_arritm( &world->ent_region, i ); - for( u32 j=0; jsubmesh_count; j ++ ) { mdl_submesh *sm = &world->meta.submeshes[ region->submesh_start+j ]; - world_unpack_submesh_dynamic( world, &world->scene_no_collide, sm ); + world_unpack_submesh_dynamic( world, &trans_ctx, sm ); } } @@ -349,12 +296,12 @@ void world_gen_generate_meshes( world_instance *world ) for( u32 i=0; ient_gate ); i++ ) { ent_gate *gate = af_arritm( &world->ent_gate, i ); - if( !(gate->flags & k_ent_gate_custom_mesh) ) continue; - + if( !(gate->flags & k_ent_gate_custom_mesh) ) + continue; for( u32 j=0; jsubmesh_count; j ++ ) { mdl_submesh *sm = &world->meta.submeshes[ gate->submesh_start+j ]; - world_unpack_submesh_dynamic( world, &world->scene_no_collide, sm ); + world_unpack_submesh_dynamic( world, &trans_ctx, sm ); } } @@ -362,30 +309,30 @@ void world_gen_generate_meshes( world_instance *world ) for( u32 i=0; ient_prop ); i++ ) { ent_prop *prop = af_arritm( &world->ent_prop, i ); - for( u32 j=0; jsubmesh_count; j ++ ) { mdl_submesh *sm = &world->meta.submeshes[ prop->submesh_start+j ]; world->surfaces[ sm->material_id ].flags |= WORLD_SURFACE_HAS_PROPS; - world_unpack_submesh_dynamic( world, &world->scene_no_collide, sm ); + world_unpack_submesh_dynamic( world, &trans_ctx, sm ); } } -IL_UPLOAD: - vg_async_task_dispatch( task2, async_scene_upload ); + scene_builder_upload_async( &trans_ctx, &world->transparent_scene_mesh ); + _vg_end_temp_frame( temp_frame ); + return; } /* signed distance function for cone */ static f32 fsd_cone_infinite( v3f p, v2f c ) { v2f q = { v2_length( (v2f){ p[0], p[2] } ), -p[1] }; - float s = vg_maxf( 0.0f, v2_dot( q, c ) ); + f32 s = vg_maxf( 0.0f, v2_dot( q, c ) ); v2f v0; v2_muls( c, s, v0 ); v2_sub( q, v0, v0 ); - float d = v2_length( v0 ); + f32 d = v2_length( v0 ); return d * ((q[0]*c[1]-q[1]*c[0]<0.0f)?-1.0f:1.0f); } @@ -395,15 +342,13 @@ struct light_indices_upload_info v3i count; u8 data[]; }; -static void async_upload_light_indices_task( vg_async_task *task ) +static void async_upload_light_indices_task( struct light_indices_upload_info *in_args, vg_async_info *async ) { - THREAD_0; - struct light_indices_upload_info *info = (void *)task->data; - - glGenTextures( 1, &info->world->tex_light_cubes ); - glBindTexture( GL_TEXTURE_3D, info->world->tex_light_cubes ); - glTexImage3D( GL_TEXTURE_3D, 0, GL_RG32UI, info->count[0], info->count[1], info->count[2], - 0, GL_RG_INTEGER, GL_UNSIGNED_INT, info->data ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + glGenTextures( 1, &in_args->world->tex_light_cubes ); + glBindTexture( GL_TEXTURE_3D, in_args->world->tex_light_cubes ); + glTexImage3D( GL_TEXTURE_3D, 0, GL_RG32UI, in_args->count[0], in_args->count[1], in_args->count[2], + 0, GL_RG_INTEGER, GL_UNSIGNED_INT, in_args->data ); glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); } @@ -415,8 +360,8 @@ void world_gen_compute_light_indices( world_instance *world ) { /* light cubes */ v3f cubes_min, cubes_max; - v3_muls( world->scene_geo.bbx[0], 1.0f/k_world_light_cube_size, cubes_min ); - v3_muls( world->scene_geo.bbx[1], 1.0f/k_world_light_cube_size, cubes_max ); + v3_muls( world->scene_geometry.bbx[0], 1.0f/k_world_light_cube_size, cubes_min ); + v3_muls( world->scene_geometry.bbx[1], 1.0f/k_world_light_cube_size, cubes_max ); v3_sub( cubes_min, (v3f){ 0.5f, 0.5f, 0.5f }, cubes_min ); v3_add( cubes_max, (v3f){ 0.5f, 0.5f, 0.5f }, cubes_max ); @@ -426,20 +371,21 @@ void world_gen_compute_light_indices( world_instance *world ) v3i icubes_min, icubes_max; - for( int i=0; i<3; i++ ){ + for( int i=0; i<3; i++ ) + { icubes_min[i] = cubes_min[i]; icubes_max[i] = cubes_max[i]; } v3f cube_size; - v3i icubes_count; v3i_sub( icubes_max, icubes_min, icubes_count ); - for( int i=0; i<3; i++ ){ + for( int i=0; i<3; i++ ) + { int clamped_count = VG_MIN( 128, icubes_count[i]+1 ); - float clamped_max = icubes_min[i] + clamped_count, - max = icubes_min[i] + icubes_count[i]+1; + f32 clamped_max = icubes_min[i] + clamped_count, + max = icubes_min[i] + icubes_count[i]+1; icubes_count[i] = clamped_count; cube_size[i] = (max / clamped_max) * k_world_light_cube_size; @@ -449,11 +395,11 @@ void world_gen_compute_light_indices( world_instance *world ) v3_mul( cubes_min, cube_size, cubes_min ); v3_mul( cubes_max, cube_size, cubes_max ); - for( int i=0; i<3; i++ ){ - float range = cubes_max[i]-cubes_min[i]; - world->ub_lighting.g_cube_inv_range[i] = 1.0f / range; - world->ub_lighting.g_cube_inv_range[i] *= (float)icubes_count[i]; - + for( int i=0; i<3; i++ ) + { + f32 range = cubes_max[i]-cubes_min[i]; + world_render.ub_lighting.g_cube_inv_range[i] = 1.0f / range; + world_render.ub_lighting.g_cube_inv_range[i] *= (f32)icubes_count[i]; vg_info( "cubes[%d]: %d\n", i, icubes_count[i] ); } @@ -461,21 +407,20 @@ void world_gen_compute_light_indices( world_instance *world ) u32 data_size = total_cubes*sizeof(u32)*2; - vg_async_task *task = - vg_allocate_async_task( &vg.main_tasks, sizeof(struct light_indices_upload_info) + data_size, 1 ); - struct light_indices_upload_info *info = (void *)task->data; - info->world = world; - u32 *cubes_index = (void *)info->data; + struct light_indices_upload_info *out_args = + _vg_async_alloc( VG_THREAD_MAIN_ID, sizeof(struct light_indices_upload_info) + data_size ); + out_args->world = world; + u32 *cubes_index = (void *)out_args->data; for( int i=0; i<3; i++ ) - info->count[i] = icubes_count[i]; + out_args->count[i] = icubes_count[i]; vg_info( "Computing light cubes (%d) [%f %f %f] -> [%f %f %f]\n", total_cubes, cubes_min[0], -cubes_min[2], cubes_min[1], cubes_max[0], -cubes_max[2], cubes_max[1] ); - v3_copy( cubes_min, world->ub_lighting.g_cube_min ); + v3_copy( cubes_min, world_render.ub_lighting.g_cube_min ); - float bound_radius = v3_length( cube_size ); + f32 bound_radius = v3_length( cube_size ); for( int iz = 0; izub_lighting.g_cube_inv_range, - bbx[0] ); - v3_div( (v3f){ ix+1, iy+1, iz+1 }, - world->ub_lighting.g_cube_inv_range, - bbx[1] ); + v3_div( (v3f){ ix, iy, iz }, world_render.ub_lighting.g_cube_inv_range, bbx[0] ); + v3_div( (v3f){ ix+1, iy+1, iz+1 }, world_render.ub_lighting.g_cube_inv_range, bbx[1] ); - v3_add( bbx[0], world->ub_lighting.g_cube_min, bbx[0] ); - v3_add( bbx[1], world->ub_lighting.g_cube_min, bbx[1] ); + v3_add( bbx[0], world_render.ub_lighting.g_cube_min, bbx[0] ); + v3_add( bbx[1], world_render.ub_lighting.g_cube_min, bbx[1] ); v3f center; v3_add( bbx[0], bbx[1], center ); @@ -500,7 +442,7 @@ void world_gen_compute_light_indices( world_instance *world ) u32 indices[6] = { 0, 0, 0, 0, 0, 0 }; u32 count = 0; - float influences[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + f32 influences[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; const int N = VG_ARRAY_LEN( influences ); for( u32 j=0; jent_light); j ++ ) @@ -522,8 +464,7 @@ void world_gen_compute_light_indices( world_instance *world ) v3f local; m4x3_mulv( light->inverse_world, center, local ); - float r = fsd_cone_infinite( local, light->angle_sin_cos ); - + f32 r = fsd_cone_infinite( local, light->angle_sin_cos ); if( r > bound_radius ) continue; } @@ -572,18 +513,17 @@ void world_gen_compute_light_indices( world_instance *world ) } } - vg_async_task_dispatch( task, async_upload_light_indices_task ); + _vg_async_send( out_args, (vg_async_fn)async_upload_light_indices_task ); } /* * Rendering pass needed to complete the world */ -void async_world_postprocess( void *userdata ) +void async_world_postprocess( void *_, vg_async_info *async ) { /* create scene lighting buffer */ - world_instance *world = userdata; - - u32 size = VG_MAX(af_arrcount(&world->ent_light),1) * sizeof(float)*12; + world_instance *world = _world.loader_instance; + u32 size = VG_MAX(af_arrcount(&world->ent_light),1) * sizeof(f32)*12; vg_info( "Upload %ubytes (lighting)\n", size ); glGenBuffers( 1, &world->tbo_light_entities ); @@ -610,8 +550,8 @@ void async_world_postprocess( void *userdata ) if( !light->daytime ) { u32 hash = (i * 29986577u) & 0xffu; - float switch_on = hash; - switch_on *= (1.0f/255.0f); + f32 switch_on = hash; + switch_on *= (1.0f/255.0f); light_dst[i*3+0][3] = 0.44f + switch_on * 0.015f; } @@ -633,16 +573,16 @@ void async_world_postprocess( void *userdata ) /* Upload lighting uniform buffer */ if( world->water.enabled ) - v4_copy( world->water.plane, world->ub_lighting.g_water_plane ); + v4_copy( world->water.plane, world_render.ub_lighting.g_water_plane ); v4f info_vec; - v3f *bounds = world->scene_geo.bbx; + v3f *bounds = world->scene_geometry.bbx; info_vec[0] = bounds[0][0]; info_vec[1] = bounds[0][2]; info_vec[2] = 1.0f/ (bounds[1][0]-bounds[0][0]); info_vec[3] = 1.0f/ (bounds[1][2]-bounds[0][2]); - v4_copy( info_vec, world->ub_lighting.g_depth_bounds ); + v4_copy( info_vec, world_render.ub_lighting.g_depth_bounds ); /* * Rendering the depth map @@ -650,14 +590,14 @@ void async_world_postprocess( void *userdata ) vg_camera ortho; v3f extent; - v3_sub( world->scene_geo.bbx[1], world->scene_geo.bbx[0], extent ); + v3_sub( world->scene_geometry.bbx[1], world->scene_geometry.bbx[0], extent ); - float fl = world->scene_geo.bbx[0][0], - fr = world->scene_geo.bbx[1][0], - fb = world->scene_geo.bbx[0][2], - ft = world->scene_geo.bbx[1][2], - rl = 1.0f / (fr-fl), - tb = 1.0f / (ft-fb); + f32 fl = world->scene_geometry.bbx[0][0], + fr = world->scene_geometry.bbx[1][0], + fb = world->scene_geometry.bbx[0][2], + ft = world->scene_geometry.bbx[1][2], + rl = 1.0f / (fr-fl), + tb = 1.0f / (ft-fb); m4x4_zero( ortho.mtx.p ); ortho.mtx.p[0][0] = 2.0f * rl; @@ -672,7 +612,7 @@ void async_world_postprocess( void *userdata ) glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); glDisable(GL_CULL_FACE); - vg_framebuffer_bind( world->heightmap, 1.0f ); + vg_framebuffer_bind( world_render.heightmap, 1.0f ); shader_blitcolour_use(); shader_blitcolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} ); render_fsquad(); @@ -687,8 +627,8 @@ void async_world_postprocess( void *userdata ) glBindFramebuffer( GL_FRAMEBUFFER, 0 ); /* upload full buffer */ - glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); - glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting), &world->ub_lighting ); + glBindBuffer( GL_UNIFORM_BUFFER, world_render.ubo_lighting ); + glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting), &world_render.ub_lighting ); /* * Allocate cubemaps @@ -731,38 +671,7 @@ void async_world_postprocess( void *userdata ) /* Loads textures from the pack file */ void world_gen_load_surfaces( world_instance *world ) { - THREAD_1; - if( _world.loader_preview_mode ) - { - world->texture_count = 0; - } - else - { - vg_info( "Loading textures\n" ); - world->texture_count = world->meta.texture_count+1; - world->textures = vg_stack_allocate( world->stack, sizeof(GLuint)*world->texture_count, 8, "Textures" ); - world->textures[0] = vg.tex_missing; - - for( u32 i=0; imeta.texture_count; i++ ) - { - mdl_texture *tex = &world->meta.textures[ i ]; - - if( !tex->file.pack_size ) - { - vg_fatal_error( "World models must have packed textures!" ); - } - - vg_stack_clear( &vg.scratch ); - void *src_data = vg_stack_allocate( &vg.scratch, tex->file.pack_size, 8, "Pack Data" ); - mdl_fread_pack_file( &world->meta, &tex->file, src_data ); - - vg_tex2d_load_qoi_async( src_data, tex->file.pack_size, - VG_TEX2D_NEAREST|VG_TEX2D_REPEAT, - &world->textures[i+1] ); - } - } - - vg_info( "Loading materials\n" ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); world->surface_count = world->meta.material_count+1; world->surfaces = vg_stack_allocate( world->stack, sizeof(struct world_surface)*world->surface_count, 8, "Surfaces" ); @@ -778,16 +687,10 @@ void world_gen_load_surfaces( world_instance *world ) surf->flags = 0; if( surf->info.shader == k_shader_water ) - { - struct shader_props_water *props = surf->info.props.compiled; - world->ub_lighting.g_water_fog = props->fog_scale; - } + world_render.ub_lighting.g_water_fog = world->meta.shader_props[i].water.fog_scale; if( surf->info.shader == k_shader_standard_cutout || surf->info.shader == k_shader_foliage ) - { - struct shader_props_standard *props = surf->info.props.compiled; - surf->alpha_tex = props->tex_diffuse; - } + surf->alpha_tex = world->meta.shader_props[i].standard.tex_diffuse; else surf->alpha_tex = 0; } diff --git a/src/world_gen.h b/src/world_gen.h index 8e65780..49e3283 100644 --- a/src/world_gen.h +++ b/src/world_gen.h @@ -1,15 +1,11 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - * - * World generation/population. Different to regular loading, since it needs to - * create geometry, apply procedural stuff and save that image to files etc. - */ - -#pragma once -#include "world.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/world_gen.c" +#else void world_init_blank( world_instance *world ); void world_gen_load_surfaces( world_instance *world ); void world_gen_generate_meshes( world_instance *world ); void world_gen_compute_light_indices( world_instance *world ); -void async_world_postprocess( void *userdata ); +void async_world_postprocess( void *_, vg_async_info *async ); + +#endif diff --git a/src/world_info.h b/src/world_info.h index 3b29b1f..ba0fecc 100644 --- a/src/world_info.h +++ b/src/world_info.h @@ -1,12 +1,5 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#ifndef WORLD_INFO_H -#define WORLD_INFO_H - -/* Purely an information header, shares common strings across client and - * server programs. */ +#if defined( SR_IMPLEMENTATION ) +#else struct track_info { diff --git a/src/world_load.c b/src/world_load.c index 01890c3..5abdace 100644 --- a/src/world_load.c +++ b/src/world_load.c @@ -1,56 +1,41 @@ -#include "world_load.h" -#include "world_routes.h" -#include "world_gate.h" -#include "ent_skateshop.h" -#include "addon.h" -#include "save.h" -#include "vg/vg_msg.h" -#include "network.h" -#include "player_remote.h" -#include "vg/vg_loader.h" -#include "vg/vg_io.h" -#include -#include "ent_atom.h" - /* * load the .mdl file located in path as a world instance */ static void world_instance_load_mdl( world_instance *world, const char *path, vg_stack_allocator *stack ) { - vg_loader_set_user_information( "Loading world data" ); + _vg_loader_set_user_information( "Loading world data" ); world_init_blank( world ); world->stack = stack; vg_info( "Loading world model: %s\n", path ); - mdl_context *meta = &world->meta; - array_file_context *af = &meta->af; - - mdl_open( meta, path, world->stack ); - mdl_load_metadata_block( meta, world->stack ); - mdl_load_mesh_block( meta, world->stack ); + vg_model_stream_context ctx; + vg_model_stream_open( &ctx, &world->meta, path ); + vg_model_stream_metadata( &ctx, stack ); + vg_model_stream_meshes_cpu( &ctx, stack ); // NOTE: Maybe this can go in temp storage now. + + if( !_world.loader_preview_mode ) + vg_model_stream_textures_gpu( &ctx ); bool load_all = !_world.loader_preview_mode; - if( load_all ) { - AF_LOAD_ARRAY_STRUCT( af, &world->ent_gate, ent_gate, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_camera, ent_camera, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_gate, ent_gate, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_camera, ent_camera, stack ); #if (MDL_VERSION_MIN <= 107) - if( meta->version <= 107 ) + if( world->meta.version <= 107 ) { + u32 temp_frame = _vg_start_temp_frame(); array_file_ptr legacy_cameras; - af_load_array( af, &legacy_cameras, "ent_camera", &vg.scratch, sizeof(struct ent_camera_v107) ); - + af_load_array( &ctx.af, &legacy_cameras, "ent_camera", _vg_temp_stack(), sizeof(struct ent_camera_v107) ); for( u32 i=0; ient_camera, i ) ); - } + _vg_end_temp_frame( temp_frame ); } #endif - AF_LOAD_ARRAY_STRUCT( af, &world->ent_spawn, ent_spawn, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_spawn, ent_spawn, stack ); if( af_arrcount( &world->ent_spawn ) == 0 ) { @@ -84,70 +69,68 @@ static void world_instance_load_mdl( world_instance *world, const char *path, vg } } - AF_LOAD_ARRAY_STRUCT( af, &world->ent_light, ent_light, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_route_node,ent_route_node, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_path_index,ent_path_index, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_checkpoint,ent_checkpoint, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_light, ent_light, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_route_node,ent_route_node, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_path_index,ent_path_index, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_checkpoint,ent_checkpoint, stack ); } - AF_LOAD_ARRAY_STRUCT( af, &world->ent_route, ent_route, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_region, ent_region, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_route, ent_route, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_region, ent_region, stack ); if( load_all ) { - AF_LOAD_ARRAY_STRUCT( af, &world->ent_water, ent_water, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_audio_clip,ent_audio_clip, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_audio, ent_audio, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_volume, ent_volume, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_traffic, ent_traffic, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_marker, ent_marker, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_skateshop, ent_skateshop, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_swspreview,ent_swspreview, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_ccmd, ent_ccmd, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_objective, ent_objective, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_challenge, ent_challenge, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_cubemap, ent_cubemap, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_prop, ent_prop, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_glider, ent_glider, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_list, ent_list, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->file_entity_ref, file_entity_ref, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_script, ent_script, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_event, ent_event, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_npc, ent_npc, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_atom, ent_atom, stack ); - AF_LOAD_ARRAY_STRUCT( af, &world->ent_cutscene, ent_cutscene, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_water, ent_water, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_audio_clip,ent_audio_clip, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_audio, ent_audio, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_volume, ent_volume, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_traffic, ent_traffic, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_marker, ent_marker, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_skateshop, ent_skateshop, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_swspreview,ent_swspreview, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_ccmd, ent_ccmd, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_objective, ent_objective, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_challenge, ent_challenge, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_cubemap, ent_cubemap, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_prop, ent_prop, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_glider, ent_glider, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_list, ent_list, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->file_entity_ref, file_entity_ref, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_script, ent_script, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_event, ent_event, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_npc, ent_npc, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_atom, ent_atom, stack ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world->ent_cutscene, ent_cutscene, stack ); } - array_file_ptr infos; - AF_LOAD_ARRAY_STRUCT( af, &infos, ent_worldinfo, &vg.scratch ); - - world->skybox = k_skybox_default; - if( af_arrcount(&infos) ) + u32 temp_frame = _vg_start_temp_frame(); { - world->info = *((ent_worldinfo *)af_arritm(&infos,0)); + array_file_ptr infos; + AF_LOAD_ARRAY_STRUCT( &ctx.af, &infos, ent_worldinfo, _vg_temp_stack() ); - if( world->meta.version >= 104 ) + world->skybox = k_skybox_default; + if( af_arrcount(&infos) ) { - if( AF_STR_EQ( &world->meta.af, world->info.pstr_skybox, "space" )) - { - world->skybox = k_skybox_space; - } - } + world->info = *((ent_worldinfo *)af_arritm(&infos,0)); + if( world->meta.version >= 104 ) + if( AF_STR_EQ( world->meta.packed_strings, world->info.pstr_skybox, "space" )) + world->skybox = k_skybox_space; - if( world->meta.version < 108 ) - world->info.wind_scale = 0.5f; - } - else - { - world->info.pstr_author = 0; - world->info.pstr_desc = 0; - world->info.pstr_name = 0; - world->info.timezone = 0.0f; - world->info.flags = 0; + if( world->meta.version < 108 ) + world->info.wind_scale = 0.5f; + } + else + { + world->info.pstr_author = 0; + world->info.pstr_desc = 0; + world->info.pstr_name = 0; + world->info.timezone = 0.0f; + world->info.flags = 0; + } } + _vg_end_temp_frame( temp_frame ); - vg_loader_set_user_information( "Compiling world details" ); - + _vg_loader_set_user_information( "Compiling world details" ); time_t seconds = time(NULL) % ((u32)vg_maxf(1.0f,k_day_length)*60); world->time = ((f64)(seconds)/(k_day_length*60.0)); world->time += (world->info.timezone/24.0); @@ -160,9 +143,11 @@ static void world_instance_load_mdl( world_instance *world, const char *path, vg if( load_all ) { world_gen_routes_ent_init( world ); - world_gen_entities_init( world ); + world_gen_entities_init( world, &ctx ); } + vg_model_stream_close( &ctx ); + u64 t6 = SDL_GetPerformanceCounter(); /* main bulk */ @@ -179,7 +164,6 @@ static void world_instance_load_mdl( world_instance *world, const char *path, vg world_gen_compute_light_indices( world ); u64 t3 = SDL_GetPerformanceCounter(); - mdl_close( meta ); u64 utime_mesh = t1-t0, utime_route = t2-t1, @@ -215,32 +199,24 @@ static void world_instance_load_mdl( world_instance *world, const char *path, vg world->routes_ui = vg_stack_allocate( stack, sizeof(struct route_ui)*af_arrcount(&world->ent_route), 8, "Route UI buffer" ); ent_script_alloc( world, stack ); - vg_loader_set_user_information( "Postprocessing world" ); - vg_async_call( &vg.main_tasks, async_world_postprocess, world ); + _vg_loader_set_user_information( "Postprocessing world" ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)async_world_postprocess ); } } static void async_world_loader_done( void *userdata ) { - THREAD_0; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); _world.loader_state = k_world_loader_init; _world.loader_instance->complete = 1; } - -struct world_load_info -{ - bool OK; - char path[4096]; -}; -void skaterift_world_load_t1( vg_async_task *task ) +void skaterift_world_load_t1( struct world_load_info *in_args, vg_async_info *async ) { - THREAD_1; - struct world_load_info *info = (void *)task->data; - - if( !info->OK ) + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + if( !in_args->OK ) return; - vg_loader_set_user_information( "Scanning world directory" ); + _vg_loader_set_user_information( "Scanning world directory" ); addon_reg *reg = addon_details( _world.load_addon ); _world.loader_instance->addon_id = _world.load_addon; @@ -252,7 +228,7 @@ void skaterift_world_load_t1( vg_async_task *task ) char path_buf[ 4096 ]; vg_str path; vg_strnull( &path, path_buf, sizeof( path_buf ) ); - vg_strcat( &path, info->path ); + vg_strcat( &path, in_args->path ); vg_str folder = path; if( !vg_strgood( &folder ) ) @@ -328,25 +304,27 @@ void skaterift_world_load_t1( vg_async_task *task ) } world_instance_load_mdl( _world.loader_instance, mdl_path, _world.loader_stack ); - vg_async_call( &vg.main_tasks, async_world_loader_done, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_MAIN_ID, 0 ), (vg_async_fn)async_world_loader_done ); } struct world_savedata_info { - savedata_file save; + //savedata_file save; world_instance *instance; }; -void async_worldsave_go( vg_async_task *task ) +void async_worldsave_go( struct world_savedata_info *in_args, vg_async_info *async ) { - THREAD_0; - struct world_savedata_info *info = (void *)task->data; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + VG_ASSERT( 0 ); - vg_msg sav; - vg_msg_init( &sav, info->save.buf, info->save.msg.max ); + // FIXME FIXME FIXME + +#if 0 + struct world_savedata_info *info = (void *)task->data; /* start entities in the world */ - world_entity_start( info->instance, &sav ); + world_entity_start( info->instance, &info->save.kvs ); /* start player in the world */ if( _world.travelled_through_nonlocal_gate ) @@ -358,12 +336,11 @@ void async_worldsave_go( vg_async_task *task ) else { bool restored_player_position = 0; - - vg_msg_init( &sav, info->save.buf, info->save.msg.max ); - vg_msg player_frame = sav; - if( vg_msg_seekframe( &player_frame, "player" ) ) + + u32 player_block = vg_kv_find( &info->save.kvs, 0, "player" ); + if( player_block ) { - if( vg_msg_getkvvecf( &player_frame, "co", k_vg_msg_v3f, localplayer.rb.co, NULL ) ) + if( vg_kv_read_vf32( &info->save.kvs, player_block, "co", NULL, localplayer.rb.co, 3 ) ) restored_player_position = 1; } @@ -376,18 +353,21 @@ void async_worldsave_go( vg_async_task *task ) network_send_item( k_netmsg_playeritem_world0 ); _world.loader_state = k_world_loader_done; _world.load_addon = 0; - _vg_tower_set_flag( skaterift.sig_world, 1 ); menu_on_world_change( _world.main.addon_id ); relink_all_remote_player_worlds(); vg_audio_lock(); vg_audio_oneshot( &audio_ui[2], 1.0f, 0.0f, 0, 0 ); vg_audio_unlock(); +#endif } -void load_world_savedata_t1( void *userdata ) +void load_world_savedata_t1( void *_, vg_async_info *async ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + VG_ASSERT( 0 ); + // FIXME FIXME +#if 0 vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct world_savedata_info), 1 ); struct world_savedata_info *info = (void *)task->data; @@ -396,6 +376,7 @@ void load_world_savedata_t1( void *userdata ) addon_make_savedata_path( _world.load_addon, info->save.path ); savedata_file_read( &info->save ); vg_async_task_dispatch( task, async_worldsave_go ); +#endif } void world_switcher_update(void) @@ -405,9 +386,11 @@ void world_switcher_update(void) if( _world.loader_state == k_world_loader_saving_current ) { - skaterift_write_all_savedata(1); + VG_ASSERT(0); + //FIXME FIXME FIMXE + //skaterift_write_all_savedata(1); _world.loader_state = k_world_loader_unloading_current; - vg_loader_set_user_information( "Unloading current world" ); + _vg_loader_set_user_information( "Unloading current world" ); } /* pre-load step aka waiting for audio to end. */ @@ -425,19 +408,19 @@ void world_switcher_update(void) world_instance_free_graphics_data( &_world.main ); _world.main.complete = 0; _world.loader_state = k_world_loader_ready; - vg_loader_set_user_information( "Waiting for loading thread" ); + _vg_loader_set_user_information( "Waiting for loading thread" ); } if( _world.loader_state == k_world_loader_ready ) { _world.loader_state = k_world_loader_loading; vg_stack_clear( _world.loader_stack ); - vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct world_load_info), 1 ); - struct world_load_info *info = (void *)task->data; + + struct world_load_info *out_args = _vg_async_alloc( VG_THREAD_ASYNC_ID, sizeof(struct world_load_info) ); vg_str folder_str; - vg_strnull( &folder_str, info->path, sizeof(info->path) ); - info->OK = addon_get_content_folder( _world.load_addon, &folder_str ); - vg_async_task_dispatch( task, skaterift_world_load_t1 ); + vg_strnull( &folder_str, out_args->path, sizeof(out_args->path) ); + out_args->OK = addon_get_content_folder( _world.load_addon, &folder_str ); + _vg_async_send( out_args, (vg_async_fn)skaterift_world_load_t1 ); } if( _world.loader_state == k_world_loader_init ) @@ -450,19 +433,13 @@ void world_switcher_update(void) else { _world.loader_state = k_world_loader_load_savedata; - vg_async_call( &vg.loader_tasks, load_world_savedata_t1, NULL ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)load_world_savedata_t1 ); } } } void skaterift_load_world_start( addon_id addon_id, bool preview ) { - if( !_vg_tower_clearence( skaterift.full_ready_mask ) ) - { - vg_error( "Cannot start changeworld while client is not ready?\n" ); - return; - } - if( _world.loader_state != k_world_loader_done ) { vg_error( "Cannot start changeworld while loader is not done?\n" ); @@ -487,14 +464,13 @@ void skaterift_load_world_start( addon_id addon_id, bool preview ) if( addon_id != world->addon_id ) _world.previous_world_addon = _world.main.addon_id; - _vg_tower_set_flag( skaterift.sig_world, 0 ); _replay2_clear_local_buffer(); _world.loader_state = k_world_loader_saving_current; _world.event = k_world_event_none; player__clear_world_dependent_variables(); relink_all_remote_player_worlds(); _ent_npc_reset(); - vg_loader_set_user_information( "Saving current world" ); + _vg_loader_set_user_information( "Saving current world" ); } else _world.loader_state = k_world_loader_ready; @@ -502,7 +478,6 @@ void skaterift_load_world_start( addon_id addon_id, bool preview ) char uid[ADDON_UID_MAX]; addon_make_uid( addon_id, uid ); vg_info( "loading world: %s %s\n", uid, preview? "(preview mode)": "" ); - vg_stack_clear( &vg.scratch ); /* ?? */ if( preview ) { @@ -524,7 +499,7 @@ void skaterift_load_world_start( addon_id addon_id, bool preview ) } _world.loader_instance = world; - _world.loader_stack = preview? _world.preview_stack: _world.stack; + _world.loader_stack = preview? &_world.preview_stack:& _world.stack; _world.loader_preview_mode = preview; _world_loader_set_addon( addon_id ); } @@ -572,7 +547,7 @@ int skaterift_load_world_command( int argc, const char *argv[] ) if( addon_id ) { bool allowed = 1; - if( g_client.demo_mode ) + if( _is_running_demo() ) { addon_reg *reg = addon_details( addon_id ); if( reg ) @@ -616,17 +591,16 @@ int skaterift_load_world_command( int argc, const char *argv[] ) void world_instance_free_graphics_data( world_instance *world ) { /* free meshes */ - mesh_free( &world->mesh_route_lines ); - mesh_free( &world->mesh_geo ); - mesh_free( &world->mesh_no_collide ); + scene_mesh_free( &world->main_scene_mesh ); + scene_mesh_free( &world->line_scene_mesh ); + scene_mesh_free( &world->transparent_scene_mesh ); glDeleteBuffers( 1, &world->tbo_light_entities ); glDeleteTextures( 1, &world->tex_light_entities ); glDeleteTextures( 1, &world->tex_light_cubes ); /* delete textures and meshes */ - if( world->texture_count ) - glDeleteTextures( world->texture_count-1, world->textures+1 ); + vg_model_unload_gpu( &world->meta ); for( u32 i=0; ient_cubemap); i++ ) { @@ -636,8 +610,8 @@ void world_instance_free_graphics_data( world_instance *world ) glDeleteRenderbuffers( 1, &cm->renderbuffer_id ); } - if( world->nonlocal_gate_count ) - glDeleteTextures( world->nonlocal_gate_count, world->nonlocal_gates_cubemaps ); + for( u32 i=0; inonlocal_gate_count; i ++ ) + vg_tex_delete( &world->nonlocal_gates_cubemaps[i] ); } /* @@ -646,15 +620,9 @@ void world_instance_free_graphics_data( world_instance *world ) */ void world_init_blank( world_instance *world ) { - memset( &world->meta, 0, sizeof(mdl_context) ); - - world->textures = NULL; - world->texture_count = 0; + vg_zero_mem( &world->meta, sizeof(vg_model) ); world->surfaces = NULL; world->surface_count = 0; - - world->geo_bh = NULL; - world->entity_bh = NULL; world->entity_list = NULL; world->rendering_gate = NULL; @@ -663,7 +631,7 @@ void world_init_blank( world_instance *world ) /* default lighting conditions * -------------------------------------------------------------*/ - struct ub_world_lighting *state = &world->ub_lighting; + struct ub_world_lighting *state = &world_render.ub_lighting; state->g_light_preview = 0; state->g_shadow_samples = 8; diff --git a/src/world_load.h b/src/world_load.h index 76f9813..6c5bacf 100644 --- a/src/world_load.h +++ b/src/world_load.h @@ -1,8 +1,6 @@ -#pragma once -#include - -#include "world.h" -#include "addon.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/world_load.c" +#else int skaterift_load_world_command( int argc, const char *argv[] ); void skaterift_load_world_start( addon_id addon, bool preview_mode ); @@ -10,4 +8,12 @@ void _world_loader_set_addon( addon_id addon ); void world_switcher_update(void); void world_instance_free_graphics_data( world_instance *world ); vg_async_task *world_load_go(void); -void skaterift_world_load_t1( vg_async_task *task ); + +struct world_load_info +{ + bool OK; + char path[4096]; +}; +void skaterift_world_load_t1( struct world_load_info *in_args, vg_async_info *async ); + +#endif diff --git a/src/world_map.c b/src/world_map.c index 7e9f5bc..fb32d78 100644 --- a/src/world_map.c +++ b/src/world_map.c @@ -1,12 +1,3 @@ -#include "skaterift.h" -#include "world_map.h" -#include "world.h" -#include "input.h" -#include "gui.h" -#include "menu.h" -#include "scene.h" -#include "shaders/model_superworld.h" - struct world_map world_map; static void world_map_get_dir( v3f dir ) @@ -63,7 +54,7 @@ static void respawn_map_draw_icon( vg_camera *cam, enum gui_icon icon, v3f pos, void world_map_initialize_view(void) { world_instance *world = &_world.main; - v3f *bbx = world->scene_geo.bbx; + v3f *bbx = world->scene_geometry.bbx; respawn_world_to_plane_pos( localplayer.rb.co, world_map.plane_pos ); world_map.boom_dist = 400.0f; @@ -98,7 +89,7 @@ static void world_map_update_final_camera( vg_camera *cam ) } vg_camera_update_transform( &world_map.final_cam ); vg_camera_update_view( &world_map.final_cam ); - vg_camera_update_projection( &world_map.final_cam, vg.window_x, vg.window_y ); + vg_camera_update_projection( &world_map.final_cam, _vg_window.w, _vg_window.h ); vg_camera_finalize( &world_map.final_cam ); vg_camera_finalize( &world_map.final_cam ); } @@ -194,11 +185,11 @@ void render_world_map(void) glDrawBuffers( 1, (GLenum[]){ GL_COLOR_ATTACHMENT0 } ); v3f bg; - v3_muls( world->ub_lighting.g_daysky_colour, - world->ub_lighting.g_day_phase - world->ub_lighting.g_sunset_phase*0.1f, bg ); + v3_muls( world_render.ub_lighting.g_daysky_colour, + world_render.ub_lighting.g_day_phase - world_render.ub_lighting.g_sunset_phase*0.1f, bg ); - v3_muladds( bg, world->ub_lighting.g_sunset_colour, (1.0f-0.5f)*world->ub_lighting.g_sunset_phase, bg ); - v3_muladds( bg, world->ub_lighting.g_nightsky_colour, (1.0f-world->ub_lighting.g_day_phase), bg ); + v3_muladds( bg, world_render.ub_lighting.g_sunset_colour, (1.0f-0.5f)*world_render.ub_lighting.g_sunset_phase, bg ); + v3_muladds( bg, world_render.ub_lighting.g_nightsky_colour, (1.0f-world_render.ub_lighting.g_day_phase), bg ); glClearColor( bg[0], bg[1], bg[2], 0.0f ); glClear( GL_COLOR_BUFFER_BIT ); @@ -349,7 +340,7 @@ void render_world_map(void) v3_normalize(dir); v3f centroid; - v3_add( world->scene_geo.bbx[0], world->scene_geo.bbx[1], centroid ); + v3_add( world->scene_geometry.bbx[0], world->scene_geometry.bbx[1], centroid ); v3_muls( centroid, 0.5f, centroid ); v3_muladds( centroid, dir, 900.0f, cam.pos ); @@ -367,7 +358,7 @@ void render_world_map(void) v3_angles( dir, cam.angles ); v3f v0, v1; v3_sub( centroid, cam.pos, v0 ); - v3_sub( world->scene_geo.bbx[1], cam.pos, v1 ); + v3_sub( world->scene_geometry.bbx[1], cam.pos, v1 ); v3_normalize( v0 ); v3_normalize( v1 ); @@ -418,12 +409,11 @@ void render_world_map(void) shader_model_superworld_uColour( (v4f){0.4f,0.8f,0.0f,0.0f} ); shader_model_superworld_uTime( vg.time*0.25f ); - mesh_bind( &world_map.superworld_mesh ); - mdl_context *model = &world_map.superworld_meta; + vg_model *model = &world_map.superworld_meta; + vg_model_bind_mesh( model ); for( u32 i=0; imesh_count; i ++ ) { mdl_mesh *mesh = &model->meshes[i]; - q_axis_angle( mesh->transform.q, (v3f){0,1,0}, vg.time_real*0.4f ); m4x3f mmdl; @@ -433,7 +423,7 @@ void render_world_map(void) for( u32 j=0; jsubmesh_count; j ++ ) { mdl_submesh *submesh = &model->submeshes[ mesh->submesh_start + j ]; - mdl_draw_submesh( submesh ); + vg_model_draw_submesh( submesh ); } } @@ -564,12 +554,12 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al if( selected_type == k_ent_challenge ) { ent_challenge *challenge = af_arritm( &world->ent_challenge, selected_index ); - name = af_str( &world->meta.af, challenge->pstr_alias ); + name = af_str( world->meta.packed_strings, challenge->pstr_alias ); } else if( selected_type == k_ent_route ) { ent_route *route = af_arritm( &world->ent_route, selected_index ); - name = af_str( &world->meta.af, route->pstr_name ); + name = af_str( world->meta.packed_strings, route->pstr_name ); ent_route_leaderboard_ui( ctx, spawn_box, selected_index ); } ui_text( ctx, name_box, name, 1, k_ui_align_middle_center, 0 ); @@ -591,7 +581,7 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al } else { - title_text = af_str( &world->meta.af, world->info.pstr_name ); + title_text = af_str( world->meta.packed_strings, world->info.pstr_name ); subtitle_text = "Current Location"; ctx->font = &vgf_default_title; upper_title[2] = ui_text_line_width(ctx,title_text) + 24; @@ -609,14 +599,14 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al m2x2_mulv( rm, steer, steer ); v2_muladds( world_map.plane_pos, steer, vg.time_frame_delta * 200.0f, world_map.plane_pos ); - v3f *bbx = world->scene_geo.bbx; + v3f *bbx = world->scene_geometry.bbx; v2_minv( (v2f){ bbx[1][0], bbx[1][2] }, world_map.plane_pos, world_map.plane_pos ); v2_maxv( (v2f){ bbx[0][0], bbx[0][2] }, world_map.plane_pos, world_map.plane_pos ); if( vg_input.display_input_method == k_input_method_kbm ) { - world_map.view_centroid[0] = ((f32)ctx->mouse[0] / (f32)vg.window_x)*2.0f - 1.0f; - world_map.view_centroid[1] = -(((f32)ctx->mouse[1] / (f32)vg.window_y)*2.0f - 1.0f); + world_map.view_centroid[0] = ((f32)ctx->mouse[0] / (f32)_vg_window.w)*2.0f - 1.0f; + world_map.view_centroid[1] = -(((f32)ctx->mouse[1] / (f32)_vg_window.h)*2.0f - 1.0f); } else { @@ -687,7 +677,7 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al continue; ent_list *list = af_arritm( &world->ent_list, mdl_entity_id_id( list_id ) ); - const char *title = af_str( &world->meta.af, region->pstr_title ); + const char *title = af_str( world->meta.packed_strings, region->pstr_title ); ctx->font = &vgf_default_large; ui_rect title_box; @@ -745,7 +735,7 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al vg_strnull( &str, buf, sizeof(buf) ); vg_strcat( &str, "(Race) " ); - vg_strcat( &str, af_str( &world->meta.af, route->pstr_name )); + vg_strcat( &str, af_str( world->meta.packed_strings, route->pstr_name )); if( route->flags & k_ent_route_flag_achieve_silver ) vg_strcat( &str, " \xb3"); @@ -762,7 +752,7 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al else { vg_strnull( &str, buf, sizeof(buf) ); - vg_strcat( &str, af_str( &world->meta.af,challenge->pstr_alias)); + vg_strcat( &str, af_str( world->meta.packed_strings,challenge->pstr_alias)); u32 flags = 0x00; if( challenge->status ) @@ -820,7 +810,7 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al #if 0 ctx->font = &vgf_default_large; - ui_rect title = { vg.window_x/2- 512/2, height+8, 512, 64 }; + ui_rect title = { _vg_window.w/2- 512/2, height+8, 512, 64 }; ui_px x = 8, y = height+8; @@ -832,7 +822,7 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al vg_strnull( &str, buf, sizeof(buf) ); world_instance *world = &_world.main; - const char *world_name = af_str( &world->meta.af, world->info.pstr_name ); + const char *world_name = af_str( world->meta.packed_strings, world->info.pstr_name ); vg_strnull( &str, buf, sizeof(buf) ); vg_strcat( &str, world_name ); @@ -852,7 +842,7 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al vs[3].co[1] = stat_panel[1]; ui_rect back_button = {0,0,300,32}; - ui_rect_center( (ui_rect){0,0,vg.window_x,vg.window_y}, back_button ); + ui_rect_center( (ui_rect){0,0,_vg_window.w,_vg_window.h}, back_button ); if( ui_button_text( ctx, back_button, "up", 1 ) == k_ui_button_click ) { world_map.activity = k_map_activity_ @@ -885,7 +875,7 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al planet_box[0] += 4; planet_box[2] = WORKSHOP_PREVIEW_WIDTH; planet_box[3] = WORKSHOP_PREVIEW_HEIGHT; - ui_image( ctx, planet_box, &g_render.fb_workshop_preview->attachments[0].id, 0 ); + ui_image( ctx, planet_box, &g_render.fb_workshop_preview->attachments[0].tex, 0 ); ui_rect planet_box_title; ui_split( planet_box, k_ui_axis_h, 28, 0, planet_box_title, planet_box ); @@ -1074,7 +1064,7 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al if( menu.clicked_world_id != _world.main.addon_id ) { - if( g_client.demo_mode ) + if( _is_running_demo() ) { addon_reg *reg = addon_details( menu.clicked_world_id ); if( reg ) @@ -1119,15 +1109,22 @@ void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *al } } -void world_map_init(void) +static void _world_map_load_content_async( void *_, vg_async_info *async ) +{ + vg_model_stream_context ctx; + VG_ASSERT( vg_model_stream_open( &ctx, &world_map.superworld_meta, "models/rs_superworlds.mdl" ) ); + vg_model_stream_metadata( &ctx, VG_STACK_USE_HEAP ); + vg_model_stream_meshes_gpu( &ctx, NULL ); + vg_model_stream_textures_gpu( &ctx ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world_map.ent_camera, ent_camera, NULL ); + AF_LOAD_ARRAY_STRUCT( &ctx.af, &world_map.ent_marker, ent_marker, NULL ); + vg_model_stream_close( &ctx ); +} + +VG_API void _world_map_init(void) { - mdl_context *model = &world_map.superworld_meta; - mdl_open( model, "models/rs_superworlds.mdl", &vg.rtmem ); - mdl_load_metadata_block( model, &vg.rtmem ); - mdl_async_load_glmesh( model, &world_map.superworld_mesh, NULL ); - AF_LOAD_ARRAY_STRUCT( &model->af, &world_map.ent_camera, ent_camera, &vg.rtmem ); - AF_LOAD_ARRAY_STRUCT( &model->af, &world_map.ent_marker, ent_marker, &vg.rtmem ); - mdl_close( model ); + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_world_map_load_content_async ); world_map.superworld_cam.nearz = 0.1f; world_map.superworld_cam.farz = 250.0f; diff --git a/src/world_map.h b/src/world_map.h index 41d7fd8..77a6a42 100644 --- a/src/world_map.h +++ b/src/world_map.h @@ -1,7 +1,7 @@ -#pragma once -#include "vg/vg_platform.h" -#include "vg/vg_camera.h" -#include "world_entity.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/world_map.c" +#else + enum superworld { k_superworld_venus_moon = 0, @@ -30,8 +30,7 @@ struct world_map } activity; - mdl_context superworld_meta; - glmesh superworld_mesh; + vg_model superworld_meta; array_file_ptr ent_camera, ent_marker, ent_challenge; @@ -46,7 +45,7 @@ struct world_map extern world_map; void world_map_gui( ui_context *ctx, ui_rect main_area, i32 mh, i32 mv, bool *allow_back_to_exit ); void render_world_map(void); -void world_map_init(void); +VG_API void _world_map_init(void); void world_map_initialize_view(void); bool world_map_get_transition_cam( vg_camera *cam ); @@ -57,3 +56,5 @@ const char *_superworld_names[] = [k_superworld_campaign] = "Earth", [k_superworld_steam_workshop] = "Steam Workshop Planet", }; + +#endif diff --git a/src/world_physics.c b/src/world_physics.c index 03be1fc..4971af6 100644 --- a/src/world_physics.c +++ b/src/world_physics.c @@ -1,20 +1,12 @@ -#ifndef WORLD_PHYSICS_C -#define WORLD_PHYSICS_C - -#include "world.h" -#include "world_physics.h" - void ray_world_get_tri( world_instance *world, ray_hit *hit, v3f tri[3] ) { for( int i=0; i<3; i++ ) - v3_copy( world->scene_geo.arrvertices[ hit->tri[i] ].co, tri[i] ); + v3_copy( world->scene_geometry.vertex_buffer[ hit->tri[i] ].co, tri[i] ); } -int ray_world( world_instance *world, - v3f pos, v3f dir, ray_hit *hit, u16 ignore ) +int ray_world( world_instance *world, v3f pos, v3f dir, ray_hit *hit, u16 ignore ) { - return scene_raycast( &world->scene_geo, world->geo_bh, pos, dir, hit, - ignore ); + return scene_raycast( &world->scene_geometry, &world->geometry_bh, pos, dir, hit, ignore ); } /* @@ -45,15 +37,17 @@ int spherecast_world( world_instance *world, bh_iter it; bh_iter_init_box( 0, &it, region ); i32 idx; - while( bh_next( world->geo_bh, &it, &idx ) ){ - u32 *ptri = &world->scene_geo.arrindices[ idx*3 ]; - if( world->scene_geo.arrvertices[ptri[0]].flags & ignore ) continue; + while( bh_next( &world->geometry_bh, &it, &idx ) ) + { + u32 *ptri = &world->scene_geometry.indice_buffer[ idx*3 ]; + if( world->scene_geometry.vertex_buffer[ptri[0]].flags & ignore ) continue; v3f tri[3]; boxf box; box_init_inf( box ); - for( int j=0; j<3; j++ ){ - v3_copy( world->scene_geo.arrvertices[ptri[j]].co, tri[j] ); + for( int j=0; j<3; j++ ) + { + v3_copy( world->scene_geometry.vertex_buffer[ptri[j]].co, tri[j] ); box_addpt( box, tri[j] ); } @@ -103,5 +97,3 @@ struct world_surface *ray_hit_surface( world_instance *world, ray_hit *hit ) { return world_tri_index_surface( world, hit->tri[0] ); } - -#endif /* WORLD_PHYSICS_C */ diff --git a/src/world_physics.h b/src/world_physics.h index 06143b9..cb238c0 100644 --- a/src/world_physics.h +++ b/src/world_physics.h @@ -1,24 +1,12 @@ -#pragma once -#include "world.h" -#include "vg/vg_rigidbody.h" -#include "vg/vg_rigidbody_collision.h" -#include "vg/vg_bvh.h" - -void ray_world_get_tri( world_instance *world, - ray_hit *hit, v3f tri[3] ); - -int ray_world( world_instance *world, - v3f pos, v3f dir, ray_hit *hit, u16 ignore ); - -int spherecast_world( world_instance *world, - v3f pa, v3f pb, float r, float *t, v3f n, - u16 ignore ); - -struct world_surface *world_tri_index_surface( world_instance *world, - u32 index ); - -struct world_surface *world_contact_surface( world_instance *world, - rb_ct *ct ); - -struct world_surface *ray_hit_surface( world_instance *world, - ray_hit *hit ); +#if defined( SR_IMPLEMENTATION ) +# include "src/world_physics.c" +#else + +void ray_world_get_tri( world_instance *world, ray_hit *hit, v3f tri[3] ); +int ray_world( world_instance *world, v3f pos, v3f dir, ray_hit *hit, u16 ignore ); +int spherecast_world( world_instance *world, v3f pa, v3f pb, float r, float *t, v3f n, u16 ignore ); +struct world_surface *world_tri_index_surface( world_instance *world, u32 index ); +struct world_surface *world_contact_surface( world_instance *world, rb_ct *ct ); +struct world_surface *ray_hit_surface( world_instance *world, ray_hit *hit ); + +#endif diff --git a/src/world_render.c b/src/world_render.c index 8023f0b..1ab6aed 100644 --- a/src/world_render.c +++ b/src/world_render.c @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#include "world.h" -#include "world_render.h" -#include "font.h" -#include "gui.h" -#include "world_map.h" -#include "player_remote.h" -#include "ent_skateshop.h" -#include "shaders/model_entity.h" -#include "shaders/model_sky_cubemap.h" -#include "shaders/scene_preview.h" -#include "shaders/scene_override.h" -#include "board_maker.h" - struct world_render world_render; static int ccmd_render_portals( int argc, const char *argv[] ); @@ -29,19 +12,7 @@ static int ccmd_set_time( int argc, const char *argv[] ) return 0; } -static void async_world_render_init( void *userdata ) -{ - vg_info( "Allocate uniform buffers\n" ); - - world_instance *world = &_world.main; - world->ubo_bind_point = 0; - glGenBuffers( 1, &world->ubo_lighting ); - glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); - glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting), NULL, GL_DYNAMIC_DRAW ); - glBindBufferBase( GL_UNIFORM_BUFFER, 0, world->ubo_lighting ); -} - -void world_render_register(void) +VG_API void _world_render_register(void) { VG_VAR_F32( k_day_length ); VG_VAR_I32( k_debug_light_indices ); @@ -52,33 +23,29 @@ void world_render_register(void) vg_console_reg_cmd( "render_portals", ccmd_render_portals, NULL ); } -void world_render_init(void) +static void _world_render_load_content_async( void *_, vg_async_info *async ) { - THREAD_1; - vg_info( "Loading world resources\n" ); - vg_stack_clear( &vg.scratch ); - - mdl_context msky; - mdl_open( &msky, "models/rs_skydome.mdl", &vg.scratch ); - mdl_load_metadata_block( &msky, &vg.scratch ); - mdl_async_load_glmesh( &msky, &world_render.skydome, NULL ); - world_render.skydome_complete_mesh = msky.submeshes[ mdl_get_submesh_index( &msky, "dome_complete" ) ]; - world_render.skydome_squanched_mesh = msky.submeshes[ mdl_get_submesh_index( &msky, "dome_squanched" ) ]; - mdl_close( &msky ); - - vg_info( "Loading default world textures\n" ); - vg_tex2d_load_qoi_async_file( "textures/garbage.qoi", - VG_TEX2D_NEAREST|VG_TEX2D_REPEAT, - &world_render.tex_terrain_noise ); - - vg_info( "Allocate frame buffers\n" ); - world_instance *world = &_world.main; - world->heightmap = vg_framebuffer_allocate( &vg.rtmem, 1, 0 ); - world->heightmap->display_name = NULL; - world->heightmap->fixed_w = 1024; - world->heightmap->fixed_h = 1024; - world->heightmap->resolution_div = 0; - world->heightmap->attachments[0] = (vg_framebuffer_attachment) + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + + vg_model_load( &world_render.skydome, VG_MODEL_ENGINE_STANDARD, "models/rs_skydome.mdl", VG_STACK_USE_HEAP ); + world_render.skydome_complete_mesh = vg_model_get_submesh_index( &world_render.skydome, "dome_complete" ); + world_render.skydome_squanched_mesh = vg_model_get_submesh_index( &world_render.skydome, "dome_squanched" ); + + u32 flags = VG_TEX_NEAREST|VG_TEX_REPEAT|VG_TEX_NOMIP; + _vg_tex_load( &world_render.tex_terrain_noise, "textures/garbage.qoi", flags ); +} + +VG_API void _world_render_init(void) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_world_render_load_content_async ); + + world_render.heightmap = _vg_framebuffer_alloc( VG_STACK_USE_HEAP, 1, 0 ); + world_render.heightmap->display_name = NULL; + world_render.heightmap->fixed_w = 1024; + world_render.heightmap->fixed_h = 1024; + world_render.heightmap->resolution_div = 0; + world_render.heightmap->attachments[0] = (vg_framebuffer_attachment) { NULL, k_framebuffer_attachment_type_texture, .internalformat = GL_RG16F, @@ -86,58 +53,54 @@ void world_render_init(void) .type = GL_FLOAT, .attachment = GL_COLOR_ATTACHMENT0 }; - vg_framebuffer_create( world->heightmap ); - vg_async_call( &vg.main_tasks, async_world_render_init, NULL ); + vg_framebuffer_init( world_render.heightmap ); + + world_render.ubo_bind_point = 0; + glGenBuffers( 1, &world_render.ubo_lighting ); + glBindBuffer( GL_UNIFORM_BUFFER, world_render.ubo_lighting ); + glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting), NULL, GL_DYNAMIC_DRAW ); + glBindBufferBase( GL_UNIFORM_BUFFER, 0, world_render.ubo_lighting ); } /* * standard uniform bindings * ---------------------------------------------------------------------------- */ -void world_link_lighting_ub( world_instance *world, GLuint shader ) +void world_link_lighting( world_instance *world, + enum e_shader_gl_name shader, + enum e_shader_gl_name uniform_block_index, + enum e_shader_gl_name uniform_position_tex, + enum e_shader_gl_name uniform_light_array, + enum e_shader_gl_name uniform_light_index ) { - GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" ); - glUniformBlockBinding( shader, idx, world->ubo_bind_point ); -} + glUniformBlockBinding( _vg_shader_names[ shader ], _vg_shader_names[ uniform_block_index ], + world_render.ubo_bind_point ); -void world_bind_position_texture( world_instance *world, - GLuint shader, GLuint location, - int slot ) -{ - vg_framebuffer_bind_texture( world->heightmap, 0, slot ); - glUniform1i( location, slot ); -} + vg_framebuffer_bind_texture( world_render.heightmap, 0, 2 ); + glUniform1i( _vg_shader_names[ uniform_position_tex ], 2 ); -void world_bind_light_array( world_instance *world, - GLuint shader, GLuint location, - int slot ) -{ - glActiveTexture( GL_TEXTURE0 + slot ); + glActiveTexture( GL_TEXTURE0 + 3 ); glBindTexture( GL_TEXTURE_BUFFER, world->tex_light_entities ); - glUniform1i( location, slot ); -} + glUniform1i( _vg_shader_names[ uniform_light_array ], 3 ); -void world_bind_light_index( world_instance *world, - GLuint shader, GLuint location, - int slot ) -{ - glActiveTexture( GL_TEXTURE0 + slot ); + glActiveTexture( GL_TEXTURE0 + 4 ); glBindTexture( GL_TEXTURE_3D, world->tex_light_cubes ); - glUniform1i( location, slot ); + glUniform1i( _vg_shader_names[ uniform_light_index ], 4 ); } -void bind_terrain_noise(void) +void world_link_terrain_noise( world_instance *world, enum e_shader_gl_name uniform_sampler ) { - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise ); + vg_tex_bind( GL_TEXTURE_2D, &world_render.tex_terrain_noise, 0 ); + glUniform1i( _vg_shader_names[ uniform_sampler ], 0 ); } /* * Get OpenGL texture name from texture ID. */ -static GLuint world_get_texture( world_instance *world, u32 id ){ +static vg_tex *world_get_texture( world_instance *world, u32 id ) +{ if( id & 0x80000000 ) return skaterift.rt_textures[id & ~0x80000000]; - else return world->textures[ id ]; + else return id? &world->meta.textures[ id-1 ].tex: NULL; } /* @@ -151,7 +114,7 @@ struct world_pass enum mdl_shader shader; enum world_geo_type geo_type; - void (*fn_bind)( world_instance *world, struct world_surface *mat ); + void (*fn_bind)( world_instance *world, u32 surface_id ); void (*fn_set_mdl)( m4x3f mdl ); void (*fn_set_uPvmPrev)( m4x4f pvm ); void (*fn_set_uNormalMtx)( m3x3f mnorm ); @@ -183,7 +146,7 @@ static void world_render_submeshes( world_instance *world, pass->fn_set_mdl( mmdl ); pass->fn_set_uPvmPrev( m4mdl ); - mdl_draw_submesh( sm ); + vg_model_draw_submesh( sm ); } } @@ -192,10 +155,12 @@ static void world_render_submeshes( world_instance *world, */ static void world_render_props( world_instance *world, u32 material_id, struct world_pass *pass ) { - struct world_surface *mat = &world->surfaces[ material_id ]; - if( !(mat->flags & WORLD_SURFACE_HAS_PROPS) ) return; + struct world_surface *surf = &world->surfaces[ material_id ]; + if( !(surf->flags & WORLD_SURFACE_HAS_PROPS) ) + return; - pass->fn_bind( world, mat ); + VG_ASSERT( material_id ); + pass->fn_bind( world, material_id ); for( u32 j=0; jent_prop ); j++ ) { @@ -212,11 +177,12 @@ static void world_render_props( world_instance *world, u32 material_id, struct w */ static void world_render_traffic( world_instance *world, u32 material_id,struct world_pass *pass ) { - struct world_surface *mat = &world->surfaces[ material_id ]; - if( !(mat->flags & WORLD_SURFACE_HAS_TRAFFIC) ) + struct world_surface *surf = &world->surfaces[ material_id ]; + if( !(surf->flags & WORLD_SURFACE_HAS_TRAFFIC) ) return; - pass->fn_bind( world, mat ); + VG_ASSERT( material_id ); + pass->fn_bind( world, material_id ); for( u32 j=0; jent_traffic ); j++ ){ ent_traffic *traffic = af_arritm( &world->ent_traffic, j ); @@ -233,23 +199,23 @@ static void world_render_traffic( world_instance *world, u32 material_id,struct */ static void world_render_pass( world_instance *world, struct world_pass *pass ) { - for( int i=0; isurface_count; i++ ) + for( int i=1; isurface_count; i++ ) { - struct world_surface *mat = &world->surfaces[i]; + struct world_surface *surf = &world->surfaces[i]; - if( mat->info.shader == pass->shader ) + if( surf->info.shader == pass->shader ) { mdl_submesh *sm; if( pass->geo_type == k_world_geo_type_solid ) { - sm = &mat->sm_geo; + sm = &surf->sm_geo; } else { world_render_traffic( world, i, pass ); world_render_props( world, i, pass ); - sm = &mat->sm_no_collide; + sm = &surf->sm_no_collide; } if( !sm->indice_count ) @@ -259,8 +225,8 @@ static void world_render_pass( world_instance *world, struct world_pass *pass ) m4x3_identity( mmdl ); pass->fn_set_mdl( mmdl ); pass->fn_set_uPvmPrev( pass->cam->mtx_prev.pv ); - pass->fn_bind( world, mat ); - mdl_draw_submesh( sm ); + pass->fn_bind( world, i ); + vg_model_draw_submesh( sm ); } } } @@ -273,24 +239,21 @@ static void world_render_pass( world_instance *world, struct world_pass *pass ) static void world_render_both_stages( world_instance *world, struct world_pass *pass ) { - mesh_bind( &world->mesh_geo ); + scene_mesh_bind( &world->main_scene_mesh ); pass->geo_type = k_world_geo_type_solid; world_render_pass( world, pass ); glDisable( GL_CULL_FACE ); - mesh_bind( &world->mesh_no_collide ); + scene_mesh_bind( &world->transparent_scene_mesh ); pass->geo_type = k_world_geo_type_nonsolid; world_render_pass( world, pass ); glEnable( GL_CULL_FACE ); } -static void bindpoint_world_vb( world_instance *world, - struct world_surface *mat ) +static void bindpoint_world_vb( world_instance *world, u32 surface_id ) { - struct shader_props_vertex_blend *props = mat->info.props.compiled; - - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, world_get_texture(world, props->tex_diffuse) ); + union shader_props *props = &world->meta.shader_props[ surface_id -1 ]; + vg_tex_bind( GL_TEXTURE_2D, world_get_texture(world, props->vertex_blend.tex_diffuse), 1 ); #if 0 shader_scene_vertex_blend_uOffset( props->blend_offset ); @@ -302,10 +265,8 @@ static void render_world_vb( world_instance *world, vg_camera *cam ) shader_scene_vertex_blend_use(); shader_scene_vertex_blend_uTexGarbage(0); shader_scene_vertex_blend_uTexGradients(1); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_vertex_blend ); - - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise ); + WORLD_LINK_LIGHTING( world, scene_vertex_blend ); + vg_tex_bind( GL_TEXTURE_2D, &world_render.tex_terrain_noise, 0 ); shader_scene_vertex_blend_uPv( cam->mtx.pv ); shader_scene_vertex_blend_uCamera( cam->transform[3] ); @@ -328,19 +289,15 @@ static void world_shader_standard_bind( world_instance *world, vg_camera *cam ) shader_scene_standard_uTexGarbage(0); shader_scene_standard_uTexMain(1); shader_scene_standard_uPv( cam->mtx.pv ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_standard ); - - bind_terrain_noise(); + WORLD_LINK_LIGHTING( world, scene_standard ); + world_link_terrain_noise( world, k_uniform_scene_standard_uTexGarbage ); shader_scene_standard_uCamera( cam->transform[3] ); } -static void bindpoint_standard( world_instance *world, - struct world_surface *mat ) +static void bindpoint_standard( world_instance *world, u32 surface_id ) { - struct shader_props_standard *props = mat->info.props.compiled; - - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, world_get_texture(world, props->tex_diffuse) ); + union shader_props *props = &world->meta.shader_props[ surface_id -1 ]; + vg_tex_bind( GL_TEXTURE_2D, world_get_texture(world, props->standard.tex_diffuse), 1 ); } static void render_world_standard( world_instance *world, vg_camera *cam ) @@ -358,15 +315,12 @@ static void render_world_standard( world_instance *world, vg_camera *cam ) world_render_both_stages( world, &pass ); } -static void bindpoint_world_cubemapped( world_instance *world, struct world_surface *mat ) +static void bindpoint_world_cubemapped( world_instance *world, u32 surface_id ) { - struct shader_props_cubemapped *props = mat->info.props.compiled; + union shader_props *props = &world->meta.shader_props[ surface_id -1 ]; + vg_tex_bind( GL_TEXTURE_2D, world_get_texture( world, props->cubemapped.tex_diffuse ), 1 ); - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, - world_get_texture( world,props->tex_diffuse ) ); - - u32 cubemap_id = props->cubemap_entity, + u32 cubemap_id = props->cubemapped.cubemap_entity, cubemap_index = 0; if( mdl_entity_id_type( cubemap_id ) == k_ent_cubemap ) @@ -378,17 +332,13 @@ static void bindpoint_world_cubemapped( world_instance *world, struct world_surf glActiveTexture( GL_TEXTURE10 ); glBindTexture( GL_TEXTURE_CUBE_MAP, cm->texture_id ); - shader_scene_cubemapped_uColour( props->tint ); + shader_scene_cubemapped_uColour( props->cubemapped.tint ); } -static void bindpoint_world_cubemapped_disabled( world_instance *world, - struct world_surface *mat ) +static void bindpoint_world_cubemapped_disabled( world_instance *world, u32 surface_id ) { - struct shader_props_cubemapped *props = mat->info.props.compiled; - - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, - world_get_texture( world, props->tex_diffuse ) ); + union shader_props *props = &world->meta.shader_props[ surface_id -1 ]; + vg_tex_bind( GL_TEXTURE_2D, world_get_texture( world, props->cubemapped.tex_diffuse ), 1 ); } static void render_world_cubemapped( world_instance *world, vg_camera *cam, int enabled ) @@ -419,9 +369,9 @@ static void render_world_cubemapped( world_instance *world, vg_camera *cam, int shader_scene_cubemapped_uTexCubemap(10); shader_scene_cubemapped_uPv( cam->mtx.pv ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_cubemapped ); + WORLD_LINK_LIGHTING( world, scene_cubemapped ); - bind_terrain_noise(); + world_link_terrain_noise( world, k_uniform_scene_cubemapped_uTexGarbage ); shader_scene_cubemapped_uCamera( cam->transform[3] ); struct world_pass pass = @@ -440,13 +390,12 @@ static void render_world_cubemapped( world_instance *world, vg_camera *cam, int static void render_world_alphatest( world_instance *world, vg_camera *cam ) { shader_scene_standard_alphatest_use(); - shader_scene_standard_alphatest_uTexGarbage(0); shader_scene_standard_alphatest_uTexMain(1); shader_scene_standard_alphatest_uPv( cam->mtx.pv ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_standard_alphatest ); + WORLD_LINK_LIGHTING( world, scene_standard_alphatest ); - bind_terrain_noise(); + world_link_terrain_noise( world, k_uniform_scene_standard_uTexGarbage ); shader_scene_standard_alphatest_uCamera( cam->transform[3] ); glDisable(GL_CULL_FACE); @@ -466,14 +415,13 @@ static void render_world_alphatest( world_instance *world, vg_camera *cam ) static void render_world_foliage( world_instance *world, vg_camera *cam ) { shader_scene_foliage_use(); - shader_scene_foliage_uTexGarbage(0); shader_scene_foliage_uTexMain(1); shader_scene_foliage_uPv( cam->mtx.pv ); shader_scene_foliage_uTime( vg.time ); shader_scene_foliage_uAmt( world->info.wind_scale ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_foliage ); - bind_terrain_noise(); + WORLD_LINK_LIGHTING( world, scene_foliage ); + world_link_terrain_noise( world, k_uniform_scene_foliage_uTexGarbage ); shader_scene_foliage_uCamera( cam->transform[3] ); glDisable(GL_CULL_FACE); @@ -535,7 +483,7 @@ static void world_render_challenges( world_instance *world, struct world_pass *p bh_iter it; bh_iter_init_range( 0, &it, pos, radius+10.0f ); i32 idx; - while( bh_next( world->entity_bh, &it, &idx ) ) + while( bh_next( &world->entity_bh, &it, &idx ) ) { u32 id = world->entity_list[ idx ], type = mdl_entity_id_type( id ), @@ -556,7 +504,7 @@ static void world_render_challenges( world_instance *world, struct world_pass *p /* render objectives */ glDisable( GL_CULL_FACE ); - mesh_bind( &world->mesh_no_collide ); + scene_mesh_bind( &world->transparent_scene_mesh ); u32 last_material = 0; for( u32 i=0; imaterial_id != last_material ) { last_material = sm->material_id; - pass->fn_bind( world, &world->surfaces[sm->material_id] ); + VG_ASSERT( sm->material_id ); + pass->fn_bind( world, sm->material_id ); } - mdl_draw_submesh( sm ); + vg_model_draw_submesh( sm ); } } /* render texts */ - font3d_bind( &gui.font, k_font_shader_world, 0, world, &g_render.cam ); + font3d_bind( &gui.font, k_font_shader_world, 0, &g_render.cam ); u32 count = 0, total = 0; for( u32 i=0; ient_challenge); i++ ) @@ -624,9 +573,9 @@ static void world_render_challenges( world_instance *world, struct world_pass *p char buf[32]; vg_str str; vg_strnull( &str, buf, sizeof(buf) ); - vg_strcati32( &str, count ); + vg_strcati64( &str, count, 10 ); vg_strcatch( &str, '/' ); - vg_strcati32( &str, total ); + vg_strcati64( &str, total, 10 ); f32 w = font3d_string_width( 1, buf ); m4x3f mlocal; @@ -662,12 +611,10 @@ static void world_render_challenges( world_instance *world, struct world_pass *p } } -static void bindpoint_fxglow( world_instance *world, struct world_surface *mat ) +static void bindpoint_fxglow( world_instance *world, u32 surface_id ) { - struct shader_props_standard *props = mat->info.props.compiled; - - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, world_get_texture(world, props->tex_diffuse) ); + union shader_props *props = &world->meta.shader_props[ surface_id -1 ]; + vg_tex_bind( GL_TEXTURE_2D, world_get_texture(world, props->standard.tex_diffuse), 1 ); } static void render_world_fxglow( world_instance *host_world, @@ -679,7 +626,7 @@ static void render_world_fxglow( world_instance *host_world, shader_scene_fxglow_uUvOffset( (v2f){ 0.0f, 0.0f } ); shader_scene_fxglow_uTexMain(1); shader_scene_fxglow_uPv( cam->mtx.pv ); - //WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_fxglow ); + //WORLD_LINK_LIGHTING( world, scene_fxglow ); shader_scene_fxglow_uCamera( cam->transform[3] ); glDisable(GL_CULL_FACE); @@ -697,7 +644,7 @@ static void render_world_fxglow( world_instance *host_world, if( regions ) { - mesh_bind( &world->mesh_no_collide ); + scene_mesh_bind( &world->transparent_scene_mesh ); u32 last_material = 0; for( u32 i=0; ient_region); i ++ ) @@ -725,9 +672,10 @@ static void render_world_fxglow( world_instance *host_world, if( sm->material_id != last_material ) { last_material = sm->material_id; - pass.fn_bind( world, &world->surfaces[sm->material_id] ); + VG_ASSERT( sm->material_id ); + pass.fn_bind( world, sm->material_id ); } - mdl_draw_submesh( sm ); + vg_model_draw_submesh( sm ); } } } @@ -738,40 +686,41 @@ static void render_world_fxglow( world_instance *host_world, glEnable(GL_CULL_FACE); } -static void bindpoint_terrain( world_instance *world, - struct world_surface *mat ) +static void bindpoint_terrain( world_instance *world, u32 surface_id ) { - struct shader_props_terrain *props = mat->info.props.compiled; + union shader_props *props = &world->meta.shader_props[ surface_id -1 ]; - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, world_get_texture(world, props->tex_diffuse) ); - shader_scene_terrain_uBlendOffset( props->blend_offset ); - shader_scene_terrain_uSandColour( props->sand_colour ); + vg_tex_bind( GL_TEXTURE_2D, world_get_texture(world, props->terrain.tex_diffuse), 1 ); + shader_scene_terrain_uBlendOffset( props->terrain.blend_offset ); + shader_scene_terrain_uSandColour( props->terrain.sand_colour ); } -static void bindpoint_override( world_instance *world, struct world_surface *mat ) +static void bindpoint_override( world_instance *world, u32 surface_id ) { - f32 skate_surface = mat->info.flags & k_material_flag_skate_target? 1.0f: 0.0f; + struct world_surface *surf = &world->surfaces[ surface_id ]; + f32 skate_surface = surf->info.flags & k_material_flag_skate_target? 1.0f: 0.0f; shader_scene_override_uSurfaceInfo( (v4f){ skate_surface, 0,0,0 } ); - if( mat->info.flags & k_material_flag_collision ) + if( surf->info.flags & k_material_flag_collision ) { shader_scene_override_uAlphatest(0); } else { - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, world_get_texture(world, mat->alpha_tex) ); + vg_tex_bind( GL_TEXTURE_2D, world_get_texture(world, surf->alpha_tex), 1 ); shader_scene_override_uAlphatest(1); } } -static void bindpoint_world_preview( world_instance *world, struct world_surface *mat ) +static void bindpoint_world_preview( world_instance *world, u32 surface_id ) { - f32 skate_surface = mat->info.flags & k_material_flag_skate_target? 1.0f: 0.0f; + union shader_props *props = &world->meta.shader_props[ surface_id -1 ]; + struct world_surface *surf = &world->surfaces[ surface_id ]; + + f32 skate_surface = surf->info.flags & k_material_flag_skate_target? 1.0f: 0.0f; shader_scene_preview_uSurfaceInfo( (v4f){ skate_surface, 0,0,0 } ); - if( mat->info.flags & k_material_flag_collision ) + if( surf->info.flags & k_material_flag_collision ) { } else @@ -786,9 +735,8 @@ static void render_terrain( world_instance *world, vg_camera *cam ) shader_scene_terrain_uTexGarbage(0); shader_scene_terrain_uTexGradients(1); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_terrain ); - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise ); + WORLD_LINK_LIGHTING( world, scene_terrain ); + vg_tex_bind( GL_TEXTURE_2D, &world_render.tex_terrain_noise, 0 ); shader_scene_terrain_uPv( cam->mtx.pv ); shader_scene_terrain_uCamera( cam->transform[3] ); @@ -846,36 +794,37 @@ static void render_sky( world_instance *world, vg_camera *cam ) shader_model_sky_uPv( pv ); shader_model_sky_uPvmPrev( pv_prev ); shader_model_sky_uTexGarbage(0); - world_link_lighting_ub( world, _shader_model_sky.id ); + glUniformBlockBinding( _vg_shader_names[ k_shader_model_sky ], + _vg_shader_names[ k_uniform_block_model_sky_ub_world_lighting ], + world_render.ubo_bind_point ); - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise ); + vg_tex_bind( GL_TEXTURE_2D, &world_render.tex_terrain_noise, 0 ); } - else if( world->skybox == k_skybox_space ){ + else if( world->skybox == k_skybox_space ) + { shader_model_sky_space_use(); - shader_model_sky_space_uMdl( identity_matrix ); shader_model_sky_space_uPv( pv ); shader_model_sky_space_uPvmPrev( pv_prev ); shader_model_sky_space_uTexGarbage(0); - world_link_lighting_ub( world, _shader_model_sky_space.id ); + glUniformBlockBinding( _vg_shader_names[ k_shader_model_sky_space ], + _vg_shader_names[ k_uniform_block_model_sky_space_ub_world_lighting ], + world_render.ubo_bind_point ); - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise ); + vg_tex_bind( GL_TEXTURE_2D, &world_render.tex_terrain_noise, 0 ); } else if( world->skybox == k_skybox_cubemap ) { /* TODO */ } - else { + else vg_fatal_error( "Programming error\n" ); - } glDepthMask( GL_FALSE ); glDisable( GL_DEPTH_TEST ); - mesh_bind( &world_render.skydome ); - mdl_draw_submesh( &world_render.skydome_complete_mesh ); + vg_model_bind_mesh( &world_render.skydome ); + vg_model_draw_submesh( &world_render.skydome.submeshes[ world_render.skydome_complete_mesh ]); glEnable( GL_DEPTH_TEST ); glDepthMask( GL_TRUE ); @@ -946,9 +895,7 @@ void render_world_gates( world_instance *world, vg_camera *cam, vg_framebuffer * shader_model_sky_cubemap_uPv( cam->mtx.pv ); shader_model_sky_cubemap_uPvmPrev( pvm ); shader_model_sky_cubemap_uTexCubemap(10); - - glActiveTexture( GL_TEXTURE10 ); - glBindTexture( GL_TEXTURE_CUBE_MAP, world->nonlocal_gates_cubemaps[ gate->cubemap_id ] ); + vg_tex_bind( GL_TEXTURE_CUBE_MAP, &world->nonlocal_gates_cubemaps[ gate->cubemap_id ], 10 ); glClear( GL_DEPTH_BUFFER_BIT ); glStencilFunc( GL_EQUAL, 1, 0xFF ); @@ -956,8 +903,8 @@ void render_world_gates( world_instance *world, vg_camera *cam, vg_framebuffer * glEnable( GL_CULL_FACE ); glEnable( GL_STENCIL_TEST ); - mesh_bind( &world_render.skydome ); - mdl_draw_submesh( &world_render.skydome_squanched_mesh ); + vg_model_bind_mesh( &world_render.skydome ); + vg_model_draw_submesh( &world_render.skydome.submeshes[ world_render.skydome_squanched_mesh ]); glStencilMask( 0xFF ); glStencilFunc( GL_ALWAYS, 1, 0xFF ); @@ -987,7 +934,7 @@ void world_prerender( world_instance *world ) world->time = world->info.timezone; } - struct ub_world_lighting *state = &world->ub_lighting; + struct ub_world_lighting *state = &world_render.ub_lighting; state->g_time = world->time; state->g_realtime = vg.time_real; @@ -1023,9 +970,8 @@ void world_prerender( world_instance *world ) world->probabilities[ k_probability_curve_wildlife_night ] = 1.0f-powf(fabsf((state->g_time_of_day-0.5f)*5.0f),5.0f); - glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); - glBufferSubData( GL_UNIFORM_BUFFER, 0, - sizeof(struct ub_world_lighting), &world->ub_lighting ); + glBindBuffer( GL_UNIFORM_BUFFER, world_render.ubo_lighting ); + glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting), &world_render.ub_lighting ); } static void render_other_entities( world_instance *world, vg_camera *cam ) @@ -1038,7 +984,8 @@ static void render_other_entities( world_instance *world, vg_camera *cam ) glider_count = 0; i32 idx; - while( bh_next( world->entity_bh, &it, &idx ) ){ + while( bh_next( &world->entity_bh, &it, &idx ) ) + { u32 id = world->entity_list[ idx ], type = mdl_entity_id_type( id ), index = mdl_entity_id_id( id ); @@ -1054,7 +1001,7 @@ static void render_other_entities( world_instance *world, vg_camera *cam ) shader_model_entity_uTexMain( 0 ); shader_model_entity_uCamera( cam->transform[3] ); shader_model_entity_uPv( cam->mtx.pv ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_entity ); + WORLD_LINK_LIGHTING( world, model_entity ); for( u32 j=0; jsurface_count; i++ ) + for( int i=1; isurface_count; i++ ) { struct world_surface *mat = &world->surfaces[i]; if( mat->info.flags & k_material_flag_ghosts ) continue; @@ -1225,8 +1172,8 @@ static void render_world_override_pass( world_instance *world, pass->fn_set_mdl( mmdl ); pass->fn_set_uNormalMtx( mnormal ); pass->fn_set_uPvmPrev( mpvm_prev ); - pass->fn_bind( world, mat ); - mdl_draw_submesh( sm ); + pass->fn_bind( world, i ); + vg_model_draw_submesh( sm ); } } @@ -1247,13 +1194,12 @@ void render_world_override( world_instance *world, }; shader_scene_override_use(); - shader_scene_override_uTexGarbage(0); shader_scene_override_uTexMain(1); shader_scene_override_uPv( pass.cam->mtx.pv ); shader_scene_override_uMapInfo( map_info ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( lighting_source, scene_override ); - bind_terrain_noise(); + WORLD_LINK_LIGHTING( lighting_source, scene_override ); + world_link_terrain_noise( world, k_uniform_scene_override_uTexGarbage ); shader_scene_override_uCamera( pass.cam->transform[3] ); @@ -1286,10 +1232,10 @@ void render_world_override( world_instance *world, glDisable( GL_CULL_FACE ); - mesh_bind( &world->mesh_geo ); + scene_mesh_bind( &world->main_scene_mesh ); pass.geo_type = k_world_geo_type_solid; render_world_override_pass( world, &pass, mmdl, mnormal, mpvm_prev ); - mesh_bind( &world->mesh_no_collide ); + scene_mesh_bind( &world->transparent_scene_mesh ); pass.geo_type = k_world_geo_type_nonsolid; render_world_override_pass( world, &pass, mmdl, mnormal, mpvm_prev ); glEnable( GL_CULL_FACE ); @@ -1332,12 +1278,12 @@ void render_world_preview( vg_camera *cam ) v3_normalize( mnormal[2] ); glEnable( GL_CULL_FACE ); - mesh_bind( &world->mesh_geo ); + scene_mesh_bind( &world->main_scene_mesh ); pass.geo_type = k_world_geo_type_solid; render_world_override_pass( world, &pass, mmdl, mnormal, mpvm_prev ); glDisable( GL_CULL_FACE ); - mesh_bind( &world->mesh_no_collide ); + scene_mesh_bind( &world->transparent_scene_mesh ); pass.geo_type = k_world_geo_type_nonsolid; render_world_override_pass( world, &pass, mmdl, mnormal, mpvm_prev ); @@ -1424,7 +1370,6 @@ void render_world_cubemaps( world_instance *world ) .fixed_h = WORLD_CUBEMAP_RES, .id = cm->framebuffer_id, .attachment_count = 0, - .attachments = NULL }; render_cubemap_side( world, cm->co, identity, world->cubemap_side, &temp_vg_framebuffer ); } @@ -1442,8 +1387,8 @@ void render_world_portal_cubemaps(void) .colorspace = 0 }; - u8 *src_image = malloc( 512*512*3*6 ); - u8 *compressed_image = malloc( vg_query_qoi_storage_size( &desc ) ); + u32 temp_frame = _vg_start_temp_frame(); + u8 *src_image = vg_stack_allocate( _vg_temp_stack(), 512*512*3*6, 8, "RGBA Image data" ); GLuint temp_tex, temp_fb, temp_rb; glGenFramebuffers( 1, &temp_fb ); @@ -1474,7 +1419,6 @@ void render_world_portal_cubemaps(void) .fixed_h = 512, .id = temp_fb, .attachment_count = 0, - .attachments = NULL }; world_instance *world = &_world.main; @@ -1501,19 +1445,21 @@ void render_world_portal_cubemaps(void) } char path[256]; - nonlocal_gate_cubemap_path( world->addon_id, af_str( &world->meta.af, gate->key ), path ); + nonlocal_gate_cubemap_path( world->addon_id, af_str( world->meta.packed_strings, gate->key ), path ); - int file_size; - if( vg_encode_qoi2( src_image, &desc, compressed_image, &file_size ) ) - vg_asset_write( path, compressed_image, file_size ); + vg_stream file; + if( vg_file_stream_open( &file, path, VG_STREAM_WRITE ) ) + { + vg_qoi_stream_encode( &desc, src_image, &file, 0 ); + vg_file_stream_close( &file ); + } } } e0:glDeleteTextures( 1, &temp_tex ); glDeleteFramebuffers( 1, &temp_fb ); glDeleteRenderbuffers( 1, &temp_rb ); - free( src_image ); - free( compressed_image ); + _vg_end_temp_frame( temp_frame ); } static int ccmd_render_portals( int argc, const char *argv[] ) @@ -1537,16 +1483,18 @@ void render_world_depth( world_instance *world, vg_camera *cam ) shader_scene_depth_uPv( cam->mtx.pv ); shader_scene_depth_uPvmPrev( cam->mtx_prev.pv ); shader_scene_depth_uMdl( identity_matrix ); - world_link_lighting_ub( world, _shader_scene_depth.id ); + glUniformBlockBinding( _vg_shader_names[ k_shader_scene_depth ], + _vg_shader_names[ k_uniform_block_scene_depth_ub_world_lighting ], + world_render.ubo_bind_point ); - mesh_bind( &world->mesh_geo ); + scene_mesh_bind( &world->main_scene_mesh ); for( int i=0; isurface_count; i++ ) { struct world_surface *mat = &world->surfaces[i]; if( mat->info.flags & k_material_flag_ghosts ) continue; mdl_submesh *sm = &mat->sm_geo; - mdl_draw_submesh( sm ); + vg_model_draw_submesh( sm ); } } @@ -1560,16 +1508,18 @@ void render_world_position( world_instance *world, vg_camera *cam ) shader_scene_position_uPv( cam->mtx.pv ); shader_scene_position_uPvmPrev( cam->mtx_prev.pv ); shader_scene_position_uMdl( identity_matrix ); - world_link_lighting_ub( world, _shader_scene_position.id ); + glUniformBlockBinding( _vg_shader_names[ k_shader_scene_position ], + _vg_shader_names[ k_uniform_block_scene_position_ub_world_lighting ], + world_render.ubo_bind_point ); - mesh_bind( &world->mesh_geo ); + scene_mesh_bind( &world->main_scene_mesh ); for( int i=0; isurface_count; i++ ) { struct world_surface *mat = &world->surfaces[i]; if( mat->info.flags & k_material_flag_ghosts ) continue; mdl_submesh *sm = &mat->sm_geo; - mdl_draw_submesh( sm ); + vg_model_draw_submesh( sm ); } } @@ -1583,18 +1533,18 @@ struct ui_enum_opt skybox_setting_options[] = { static f32 *skybox_prop_location( world_instance *world, i32 index ){ switch( index ){ - case 0: return world->ub_lighting.g_daysky_colour; break; - case 1: return world->ub_lighting.g_nightsky_colour; break; - case 2: return world->ub_lighting.g_sunset_colour; break; - case 3: return world->ub_lighting.g_ambient_colour; break; - case 4: return world->ub_lighting.g_sun_colour; break; + case 0: return world_render.ub_lighting.g_daysky_colour; break; + case 1: return world_render.ub_lighting.g_nightsky_colour; break; + case 2: return world_render.ub_lighting.g_sunset_colour; break; + case 3: return world_render.ub_lighting.g_ambient_colour; break; + case 4: return world_render.ub_lighting.g_sun_colour; break; default: return NULL; } } void imgui_world_light_edit( ui_context *ctx, world_instance *world ) { - ui_rect panel = { vg.window_x-400, 0, 400, vg.window_y }; + ui_rect panel = { _vg_window.w-400, 0, 400, _vg_window.h }; ui_fill( ctx, panel, ui_colour( ctx, k_ui_bg+1 ) ); ui_outline( ctx, panel, 1, ui_colour( ctx, k_ui_bg+7 ), 0 ); ui_rect_pad( panel, (ui_px[2]){ 8, 8 } ); diff --git a/src/world_render.h b/src/world_render.h index 4f329d5..331ac63 100644 --- a/src/world_render.h +++ b/src/world_render.h @@ -1,37 +1,19 @@ -/* - * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#pragma once +#if defined( SR_IMPLEMENTATION ) +# include "src/world_render.c" +#else #define WORLD_CUBEMAP_RES 32 -#include "vg/vg_camera.h" -#include "world.h" -#include "shaders/scene_standard.h" -#include "shaders/scene_standard_alphatest.h" -#include "shaders/scene_foliage.h" -#include "shaders/scene_override.h" -#include "shaders/scene_cubemapped.h" -#include "shaders/scene_vertex_blend.h" -#include "shaders/scene_terrain.h" -#include "shaders/scene_fxglow.h" -#include "shaders/scene_depth.h" -#include "shaders/scene_position.h" -#include "shaders/scene_font.h" -#include "shaders/model_sky.h" -#include "shaders/model_sky_space.h" - static const float k_world_light_cube_size = 8.0f; struct world_render { - GLuint tex_terrain_noise; + vg_tex tex_terrain_noise; /* rendering */ - glmesh skydome; - mdl_submesh skydome_complete_mesh, - skydome_squanched_mesh; + vg_model skydome; + i32 skydome_complete_mesh, + skydome_squanched_mesh; v3f render_gate_pos; struct timer_text{ @@ -53,23 +35,72 @@ struct world_render } text_particles[6*4]; u32 text_particle_count; + + /* STD140 */ + struct ub_world_lighting{ + v4f g_cube_min, + g_cube_inv_range; + + v4f g_water_plane, + g_depth_bounds; + + v4f g_daysky_colour; + v4f g_nightsky_colour; + v4f g_sunset_colour; + v4f g_ambient_colour; + v4f g_sunset_ambient; + v4f g_sun_colour; + v4f g_sun_dir; + v4f g_board_0; + v4f g_board_1; + + float g_water_fog; + float g_time; + float g_realtime; + float g_shadow_length; + float g_shadow_spread; + + float g_time_of_day; + float g_day_phase; + float g_sunset_phase; + + int g_light_preview; + int g_shadow_samples; + + int g_debug_indices; + int g_debug_complexity; + } + ub_lighting; + GLuint ubo_lighting; + int ubo_bind_point; + vg_framebuffer *heightmap; } extern world_render; -void world_render_register(void); -void world_render_init(void); +VG_API void _world_render_register(void); +VG_API void _world_render_init(void); void world_prerender( world_instance *world ); -void world_link_lighting_ub( world_instance *world, GLuint shader ); -void world_bind_position_texture( world_instance *world, - GLuint shader, GLuint location, - int slot ); -void world_bind_light_array( world_instance *world, - GLuint shader, GLuint location, - int slot ); -void world_bind_light_index( world_instance *world, - GLuint shader, GLuint location, - int slot ); +void world_link_lighting( world_instance *world, + enum e_shader_gl_name shader, + enum e_shader_gl_name uniform_block_index, + enum e_shader_gl_name uniform_position_tex, + enum e_shader_gl_name uniform_light_array, + enum e_shader_gl_name uniform_light_index ); + +void world_link_terrain_noise( world_instance *world, enum e_shader_gl_name uniform_sampler ); + +#define WORLD_LINK_LIGHTING( WORLD, SHADER_NAME ) \ + world_link_lighting( WORLD, \ + k_shader_##SHADER_NAME, \ + k_uniform_block_##SHADER_NAME##_ub_world_lighting, \ + k_uniform_##SHADER_NAME##_g_world_depth, \ + k_uniform_##SHADER_NAME##_uLightsArray, \ + k_uniform_##SHADER_NAME##_uLightsIndex ) + +#define WORLD_LINK_TERRAIN_NOISE( WORLD, SHADER_NAME ) \ + world_link_terrain_noise( WORLD, k_uniform_##SHADER_NAME##_uTexGarbage ) + void render_world_position( world_instance *world, vg_camera *cam ); void render_world_depth( world_instance *world, vg_camera *cam ); void render_world( world_instance *world, vg_camera *cam, @@ -86,12 +117,4 @@ void render_world_preview( vg_camera *cam ); void render_world_gates( world_instance *world, vg_camera *cam, vg_framebuffer *target_fb ); void imgui_world_light_edit( ui_context *ctx, world_instance *world ); -#define WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( WORLD, SHADER ) \ - world_link_lighting_ub( WORLD, _shader_##SHADER.id ); \ - world_bind_position_texture( WORLD, _shader_##SHADER.id, \ - _uniform_##SHADER##_g_world_depth, 2 ); \ - world_bind_light_array( WORLD, _shader_##SHADER.id, \ - _uniform_##SHADER##_uLightsArray, 3 ); \ - world_bind_light_index( WORLD, _shader_##SHADER.id, \ - _uniform_##SHADER##_uLightsIndex, 4 ); - +#endif diff --git a/src/world_routes.c b/src/world_routes.c index fe85807..79972f8 100644 --- a/src/world_routes.c +++ b/src/world_routes.c @@ -1,28 +1,3 @@ -#pragma once - -/* - * Copyright (C) 2021-2024 Mt.ZERO Software - All Rights Reserved - * - * World routes - */ - -#include -#include "entity.h" -#include "world_routes.h" -#include "world_gate.h" -#include "world_load.h" -#include "network.h" - -#include "font.h" -#include "gui.h" -#include "network_msg.h" -#include "network_common.h" - -#include "shaders/scene_route.h" -#include "shaders/routeui.h" -#include "ent_region.h" -#include "scene_rigidbody.h" - void world_routes_clear( world_instance *world ) { for( u32 i=0; ient_route ); i++ ) @@ -50,7 +25,7 @@ static void world_routes_time_lap( u32 route_index ) world_instance *world = &_world.main; ent_route *route = af_arritm( &world->ent_route, route_index ); - const char *route_name = af_str( &world->meta.af, route->pstr_name); + const char *route_name = af_str( world->meta.packed_strings, route->pstr_name); vg_info( "------- time lap %s -------\n", route_name ); double start_time = 0.0; @@ -125,11 +100,11 @@ static void world_routes_time_lap( u32 route_index ) if( (route->flags & k_ent_route_flag_achieve_gold) && !(original_flags & k_ent_route_flag_achieve_gold) ) { - gui_notify( "\xb3 Route completed in gold!", 5.0f, k_ui_yellow ); + _gui_notify( "\xb3 Route completed in gold!", 5.0f, k_ui_yellow ); } else if( (route->flags & k_ent_route_flag_achieve_silver) && !(original_flags & k_ent_route_flag_achieve_silver) ) { - gui_notify( "\xb3 Route completed in silver!", 5.0f, k_ui_fg ); + _gui_notify( "\xb3 Route completed in silver!", 5.0f, k_ui_fg ); } struct ent_script_event event; @@ -151,7 +126,7 @@ static void world_routes_time_lap( u32 route_index ) char mod_uid[ ADDON_UID_MAX ]; addon_make_uid( _world.main.addon_id, mod_uid ); - network_publish_laptime( mod_uid, af_str( &world->meta.af, route->pstr_name ), lap_time ); + network_publish_laptime( mod_uid, af_str( world->meta.packed_strings, route->pstr_name ), lap_time ); } route->valid_checkpoints = valid_sections+1; @@ -270,42 +245,43 @@ static void world_routes_debug( world_instance *world ) } -static -void world_routes_place_curve( world_instance *world, ent_route *route, - v4f h[3], v3f n0, v3f n2, scene_context *scene ) +static void world_routes_place_curve( world_instance *world, ent_route *route, + v4f h[3], v3f n0, v3f n2, scene_builder_context *builder ) { - float t; + f32 t; v3f p, pd; int last_valid=0; - float total_length = 0.0f, - travel_length = 0.0; + f32 total_length = 0.0f, + travel_length = 0.0; v3f last; v3_copy( h[0], last ); - for( int it=0; it<128; it ++ ){ - t = (float)(it+1) * (1.0f/128.0f); + for( int it=0; it<128; it ++ ) + { + t = (f32)(it+1) * (1.0f/128.0f); eval_bezier3( h[0], h[1], h[2], t, p ); total_length += v3_dist( p, last ); v3_copy( p, last ); } - float patch_size = 4.0f, - patch_count = ceilf( total_length / patch_size ); + f32 patch_size = 4.0f, + patch_count = ceilf( total_length / patch_size ); t = 0.0f; v3_copy( h[0], last ); - for( int it=0; it<128; it ++ ){ - float const k_sample_dist = 0.0025f, - k_line_width = 1.5f; + for( int it=0; it<128; it ++ ) + { + f32 const k_sample_dist = 0.0025f, + k_line_width = 1.5f; eval_bezier3( h[0], h[1], h[2], t, p ); eval_bezier3( h[0], h[1], h[2], t+k_sample_dist, pd ); travel_length += v3_dist( p, last ); - float mod = k_sample_dist / v3_dist( p, pd ); + f32 mod = k_sample_dist / v3_dist( p, pd ); v3f v0,up, right; @@ -317,7 +293,7 @@ void world_routes_place_curve( world_instance *world, ent_route *route, v3_cross( up, v0, right ); v3_normalize( right ); - float cur_x = (1.0f-t)*h[0][3] + t*h[2][3]; + f32 cur_x = (1.0f-t)*h[0][3] + t*h[2][3]; v3f sc, sa, sb, down; v3_muladds( p, right, cur_x * k_line_width, sc ); @@ -333,7 +309,8 @@ void world_routes_place_curve( world_instance *world, ent_route *route, int resa = ray_world( world, sa, down, &ha, k_material_flag_ghosts ), resb = ray_world( world, sb, down, &hb, k_material_flag_ghosts ); - if( resa && resb ){ + if( resa && resb ) + { struct world_surface *surfa = ray_hit_surface( world, &ha ), *surfb = ray_hit_surface( world, &hb ); @@ -342,7 +319,7 @@ void world_routes_place_curve( world_instance *world, ent_route *route, { scene_vert va, vb; - float gap = vg_fractf(cur_x*0.5f)*0.02f; + f32 gap = vg_fractf(cur_x*0.5f)*0.02f; v3_muladds( ha.pos, up, 0.06f+gap, va.co ); v3_muladds( hb.pos, up, 0.06f+gap, vb.co ); @@ -350,24 +327,23 @@ void world_routes_place_curve( world_instance *world, ent_route *route, scene_vert_pack_norm( &va, up, 0.0f ); scene_vert_pack_norm( &vb, up, 0.0f ); - float t1 = (travel_length / total_length) * patch_count; + f32 t1 = (travel_length / total_length) * patch_count; va.uv[0] = t1; va.uv[1] = 0.0f; vb.uv[0] = t1; vb.uv[1] = 1.0f; - scene_push_vert( scene, &va ); - scene_push_vert( scene, &vb ); + scene_builder_push_vert( builder, &va ); + scene_builder_push_vert( builder, &vb ); - if( last_valid ){ + if( last_valid ) + { /* Connect them with triangles */ - scene_push_tri( scene, (u32[3]){ - last_valid+0-2, last_valid+1-2, last_valid+2-2} ); - scene_push_tri( scene, (u32[3]){ - last_valid+1-2, last_valid+3-2, last_valid+2-2} ); + scene_builder_push_tri( builder, (u32[3]){ last_valid+0-2, last_valid+1-2, last_valid+2-2} ); + scene_builder_push_tri( builder, (u32[3]){ last_valid+1-2, last_valid+3-2, last_valid+2-2} ); } - last_valid = scene->vertex_count; + last_valid = builder->scene.vertex_count; } else last_valid = 0; @@ -386,7 +362,7 @@ void world_routes_place_curve( world_instance *world, ent_route *route, } } -static void world_routes_gen_meshes( world_instance *world, u32 route_id, scene_context *sc ) +static void world_routes_gen_meshes( world_instance *world, u32 route_id, scene_builder_context *builder ) { ent_route *route = af_arritm( &world->ent_route, route_id ); u8 colour[4]; @@ -394,7 +370,6 @@ static void world_routes_gen_meshes( world_instance *world, u32 route_id, scene_ colour[1] = route->colour[1] * 255.0f; colour[2] = route->colour[2] * 255.0f; colour[3] = route->colour[3] * 255.0f; - u32 last_valid = 0; for( int i=0; icheckpoints_count; i++ ) @@ -421,7 +396,7 @@ static void world_routes_gen_meshes( world_instance *world, u32 route_id, scene_ v3_add( (v3f){0.0f,0.1f,0.0f}, start_gate->co[0], p[0] ); p[0][3] = start_gate->ref_count; - p[0][3] -= (float)start_gate->route_count * 0.5f; + p[0][3] -= (f32)start_gate->route_count * 0.5f; start_gate->ref_count ++; if( !c0->path_count ) @@ -440,10 +415,9 @@ static void world_routes_gen_meshes( world_instance *world, u32 route_id, scene_ index->index ); v3f v0; v3_sub( rn->co, both[j]->co[0], v0 ); - float d = v3_dot( v0, both[j]->to_world[2] ); + f32 d = v3_dot( v0, both[j]->to_world[2] ); - v3_muladds( both[j]->co[0], both[j]->to_world[2], d, - temp_alignments[j] ); + v3_muladds( both[j]->co[0], both[j]->to_world[2], d, temp_alignments[j] ); v3_add( (v3f){0.0f,0.1f,0.0f}, temp_alignments[j], temp_alignments[j]); } @@ -462,7 +436,7 @@ static void world_routes_gen_meshes( world_instance *world, u32 route_id, scene_ v3_copy( rn->co, p[1] ); p[1][3] = rn->ref_count; - p[1][3] -= (float)rn->ref_total * 0.5f; + p[1][3] -= (f32)rn->ref_total * 0.5f; rn->ref_count ++; if( j+1 < c0->path_count ) @@ -476,7 +450,7 @@ static void world_routes_gen_meshes( world_instance *world, u32 route_id, scene_ v3_lerp( p[1], rn->co, 0.5f, p[2] ); p[2][3] = rn->ref_count; - p[2][3] -= (float)rn->ref_total * 0.5f; + p[2][3] -= (f32)rn->ref_total * 0.5f; } else { @@ -487,7 +461,7 @@ static void world_routes_gen_meshes( world_instance *world, u32 route_id, scene_ if( i == route->checkpoints_count-1) p[2][3] -= 1.0f; - p[2][3] -= (float)collector->route_count * 0.5f; + p[2][3] -= (f32)collector->route_count * 0.5f; //collector->ref_count ++; } @@ -495,10 +469,10 @@ static void world_routes_gen_meshes( world_instance *world, u32 route_id, scene_ * --------------------------------------*/ v3f surf0, surf2, n0, n2; - if( bh_closest_point( world->geo_bh, p[0], surf0, 5.0f ) == -1 ) + if( bh_closest_point( &world->geometry_bh, p[0], surf0, 5.0f ) == -1 ) v3_add( (v3f){0.0f,-0.1f,0.0f}, p[0], surf0 ); - if( bh_closest_point( world->geo_bh, p[2], surf2, 5.0f ) == -1 ) + if( bh_closest_point( &world->geometry_bh, p[2], surf2, 5.0f ) == -1 ) v3_add( (v3f){0.0f,-0.1f,0.0f}, p[2], surf2 ); v3_sub( surf0, p[0], n0 ); @@ -506,14 +480,14 @@ static void world_routes_gen_meshes( world_instance *world, u32 route_id, scene_ v3_normalize( n0 ); v3_normalize( n2 ); - world_routes_place_curve( world, route, p, n0, n2, sc ); + world_routes_place_curve( world, route, p, n0, n2, builder ); /* --- */ v4_copy( p[2], p[0] ); } } - scene_copy_slice( sc, &route->sm ); + scene_builder_get_submesh( builder, &route->sm ); } struct world_surface *world_tri_index_surface( world_instance *world, @@ -524,9 +498,8 @@ struct world_surface *world_tri_index_surface( world_instance *world, */ void world_gen_routes_generate( world_instance *world ) { - THREAD_1; + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); vg_info( "Generating route meshes\n" ); - vg_async_task *task = scene_alloc_async( &world->scene_lines, &world->mesh_route_lines, 200000, 300000 ); for( u32 i=0; ient_gate); i++ ) { @@ -546,10 +519,11 @@ void world_gen_routes_generate( world_instance *world ) rn->ref_total = 0; } - for( u32 k=0; kent_route); k++ ){ + for( u32 k=0; kent_route); k++ ) + { ent_route *route = af_arritm( &world->ent_route, k ); - - for( int i=0; icheckpoints_count; i++ ){ + for( int i=0; icheckpoints_count; i++ ) + { int i0 = route->checkpoints_start+i, i1 = route->checkpoints_start+((i+1)%route->checkpoints_count); @@ -563,20 +537,23 @@ void world_gen_routes_generate( world_instance *world ) if( !c0->path_count ) continue; - for( int j=0; jpath_count; j ++ ){ - ent_path_index *index = af_arritm( &world->ent_path_index, - c0->path_start+j ); - ent_route_node *rn = af_arritm( &world->ent_route_node, - index->index ); + for( int j=0; jpath_count; j ++ ) + { + ent_path_index *index = af_arritm( &world->ent_path_index, c0->path_start+j ); + ent_route_node *rn = af_arritm( &world->ent_route_node, index->index ); rn->ref_total ++; } } } + u32 temp_frame = _vg_start_temp_frame(); + scene_builder_context builder; + scene_builder_init( &builder, 200000, 300000, _vg_temp_stack() ); for( u32 i=0; ient_route); i++ ) - world_routes_gen_meshes( world, i, &world->scene_lines ); + world_routes_gen_meshes( world, i, &builder ); + scene_builder_upload_async( &builder, &world->line_scene_mesh ); + _vg_end_temp_frame( temp_frame ); - vg_async_task_dispatch( task, async_scene_upload ); world_routes_clear( world ); } @@ -608,7 +585,7 @@ void world_gen_routes_ent_init( world_instance *world ) route->flags |= k_ent_route_flag_out_of_zone; route->anon.official_track_id = 0xffffffff; - const char *route_name = af_str( &world->meta.af, route->pstr_name ); + const char *route_name = af_str( world->meta.packed_strings, route->pstr_name ); for( u32 j=0; j= af_arrcount( &world->ent_route ) ) { vg_error( "Scoreboard route_id out of range (%u)\n", route_id ); @@ -691,6 +670,7 @@ void world_routes_recv_scoreboard( world_instance *world, vg_msg *body, u32 rout memcpy( board->data, body->buf, body->max ); board->data_len = body->max; +#endif } /* @@ -699,7 +679,7 @@ void world_routes_recv_scoreboard( world_instance *world, vg_msg *body, u32 rout * ----------------------------------------------------------------------------- */ -void world_routes_init(void) +VG_API void _world_routes_init(void) { _world.current_run_version = 200; _world.time = 300.0; @@ -731,56 +711,44 @@ void world_routes_fixedupdate( world_instance *world ) _null.inv_mass = 0.0f; m3x3_zero( _null.iI ); - for( u32 i=0; irb.to_world, - particle->radius, - NULL, world->geo_bh, buf, + i32 l = rb_sphere__scene( particle->rb.to_world, particle->radius, NULL, &world->geometry_bh, buf, k_material_flag_ghosts ); - - for( int j=0; jrb; buf[j].rbb = &_null; } - rb_contact_count += l; } } - rb_presolve_contacts( rb_contact_buffer, - vg.time_fixed_delta, rb_contact_count ); + rb_presolve_contacts( rb_contact_buffer, vg.time_fixed_delta, rb_contact_count ); - for( int i=0; irb ); } - for( u32 i=0; irb ); } } -void bind_terrain_noise(void); -void world_bind_light_array( world_instance *world, - GLuint shader, GLuint location, - int slot ); -void world_bind_light_index( world_instance *world, - GLuint shader, GLuint location, - int slot ); - void world_routes_update_timer_texts( world_instance *world ) { world_render.timer_text_count = 0; @@ -813,10 +781,10 @@ void world_routes_update_timer_texts( world_instance *world ) } } - float h0 = 0.8f, - h1 = 1.2f, - depth = 0.4f, - size = 0.4f; + f32 h0 = 0.8f, + h1 = 1.2f, + depth = 0.4f, + size = 0.4f; struct timer_text *text = &world_render.timer_texts[ world_render.timer_text_count ++ ]; text->gate = gate; @@ -830,7 +798,7 @@ void world_routes_update_timer_texts( world_instance *world ) double lap_time = _world.time - route->timing_base, time_centiseconds = lap_time * 100.0; - if( time_centiseconds > (float)0xfffe ) time_centiseconds = 0.0; + if( time_centiseconds > (f32)0xfffe ) time_centiseconds = 0.0; u16 centiseconds = time_centiseconds, seconds = centiseconds / 100, @@ -845,32 +813,32 @@ void world_routes_update_timer_texts( world_instance *world ) if( minutes ) { - vg_strcati32r( &str, minutes, 1, ' ' ); + vg_strcati64r( &str, minutes, 10, 1, ' ' ); vg_strcatch( &str, ':' ); } if( seconds >= 10 || minutes ) { - vg_strcati32r( &str, seconds, 2, '0' ); + vg_strcati64r( &str, seconds, 10, 2, '0' ); } else { - vg_strcati32r( &str, seconds, 1, '0' ); + vg_strcati64r( &str, seconds, 10, 1, '0' ); } vg_strcatch( &str, '.' ); - vg_strcati32r( &str, centiseconds, 1, '0' ); + vg_strcati64r( &str, centiseconds, 10, 1, '0' ); } else { - vg_strcati32r( &str, route->valid_checkpoints, 1, ' ' ); + vg_strcati64r( &str, route->valid_checkpoints, 10, 1, ' ' ); vg_strcatch( &str, '/' ); - vg_strcati32r( &str, route->checkpoints_count + 1, 1, ' ' ); + vg_strcati64r( &str, route->checkpoints_count + 1, 10, 1, ' ' ); } gui_font3d.font = &gui.font; - float align_r = font3d_string_width( 0, text->text ); - align_r *= size; + f32 align_r = font3d_string_width( 0, text->text ); + align_r *= size; v3f positions[] = { { -0.92f, h0, depth }, @@ -889,7 +857,7 @@ void world_routes_update_timer_texts( world_instance *world ) ent_gate_get_mdl_mtx( gate, mmdl ); m3x3_copy( mmdl, text->transform ); - float ratio = v3_length(text->transform[0]) / v3_length(text->transform[1]); + f32 ratio = v3_length(text->transform[0]) / v3_length(text->transform[1]); m3x3_scale( text->transform, (v3f){ size, size*ratio, 0.1f } ); m4x3_mulv( mmdl, positions[j], text->transform[3] ); @@ -924,7 +892,7 @@ void world_routes_fracture( world_instance *world, ent_gate *gate, v3f imp_co, v v3_zero( offset ); v4f colour; - float brightness = 0.3f + world->ub_lighting.g_day_phase; + f32 brightness = 0.3f + world_render.ub_lighting.g_day_phase; v3_muls( text->route->colour, brightness, colour ); colour[3] = 1.0f-text->route->factive; @@ -990,7 +958,7 @@ static void render_gate_markers( m4x3f world_mmdl, int run_id, ent_gate *gate ) m4x3_mul( world_mmdl, mmdl, mmdl ); shader_model_gate_uMdl( mmdl ); - mdl_draw_submesh( &world_gates.sm_marker[j] ); + vg_model_draw_submesh( &_world_gates.sm_marker[j] ); break; } } @@ -1002,15 +970,8 @@ void render_world_routes( world_instance *world, int viewing_from_gate, int viewing_from_hub ) { shader_scene_route_use(); - shader_scene_route_uTexGarbage(0); - world_link_lighting_ub( host_world, _shader_scene_route.id ); - world_bind_position_texture( host_world, _shader_scene_route.id, - _uniform_scene_route_g_world_depth, 2 ); - world_bind_light_array( host_world, _shader_scene_route.id, - _uniform_scene_route_uLightsArray, 3 ); - world_bind_light_index( host_world, _shader_scene_route.id, - _uniform_scene_route_uLightsIndex, 4 ); - bind_terrain_noise(); + world_link_terrain_noise( host_world, k_uniform_scene_route_uTexGarbage ); + WORLD_LINK_LIGHTING( host_world, scene_route ); shader_scene_route_uPv( cam->mtx.pv ); @@ -1041,12 +1002,10 @@ void render_world_routes( world_instance *world, shader_scene_route_uCamera( cam->transform[3] ); - mesh_bind( &world->mesh_route_lines ); - + scene_mesh_bind( &world->line_scene_mesh ); for( u32 i=0; ient_route); i++ ) { ent_route *route = af_arritm( &world->ent_route, i ); - f32 t = viewing_from_hub? 1.0f: route->factive; v4f colour; @@ -1054,21 +1013,21 @@ void render_world_routes( world_instance *world, colour[3] = t*0.2f; shader_scene_route_uColour( colour ); - mdl_draw_submesh( &route->sm ); + vg_model_draw_submesh( &route->sm ); } /* timers * ---------------------------------------------------- */ if( !viewing_from_gate && !viewing_from_hub ) { - font3d_bind( &gui.font, k_font_shader_default, 0, world, cam ); + font3d_bind( &gui.font, k_font_shader_default, 0, cam ); for( u32 i=0; iub_lighting.g_day_phase; + f32 brightness = 0.3f + world_render.ub_lighting.g_day_phase; v3_muls( text->route->colour, brightness, colour ); colour[3] = 1.0f-text->route->factive; @@ -1097,8 +1056,7 @@ void render_world_routes( world_instance *world, m4x3_mul( model, particle->mlocal, particle->mdl ); shader_model_font_uMdl( particle->mdl ); shader_model_font_uColour( particle->colour ); - - mesh_drawn( particle->glyph->indice_start, particle->glyph->indice_count ); + vg_model_draw_elements( particle->glyph->indice_start, particle->glyph->indice_count ); } } @@ -1109,11 +1067,8 @@ void render_world_routes( world_instance *world, shader_model_gate_uPv( cam->mtx.pv ); shader_model_gate_uCam( cam->pos ); shader_model_gate_uTime( vg.time*0.25f ); - shader_model_gate_uInvRes( (v2f){ - 1.0f / (float)vg.window_x, - 1.0f / (float)vg.window_y }); - - mesh_bind( &world_gates.mesh ); + shader_model_gate_uInvRes( (v2f){ 1.0f/(f32)_vg_window.w, 1.0f/(f32)_vg_window.h }); + vg_model_bind_mesh( &_world_gates.model ); /* skip writing into the motion vectors for this */ glDrawBuffers( 1, (GLenum[]){ GL_COLOR_ATTACHMENT0 } ); @@ -1139,13 +1094,15 @@ void render_world_routes( world_instance *world, } } } - else{ - for( u32 i=0; ient_route); i++ ){ + else + { + for( u32 i=0; ient_route); i++ ) + { ent_route *route = af_arritm( &world->ent_route, i ); - - if( route->active_checkpoint != 0xffff ){ + if( route->active_checkpoint != 0xffff ) + { v4f colour; - float brightness = 0.3f + world->ub_lighting.g_day_phase; + f32 brightness = 0.3f + world_render.ub_lighting.g_day_phase; v3_muls( route->colour, brightness, colour ); colour[3] = 1.0f-route->factive; diff --git a/src/world_routes.h b/src/world_routes.h index 09e183b..74ad39a 100644 --- a/src/world_routes.h +++ b/src/world_routes.h @@ -1,14 +1,9 @@ -/* - * Copyright (C) 2021-2025 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ +#if defined( SR_IMPLEMENTATION ) +# include "src/world_routes.c" +#else -#pragma once -#include "vg/vg_camera.h" -#include "vg/vg_msg.h" -#include "world.h" -#include "network_msg.h" +VG_API void _world_routes_init(void); -void world_routes_init(void); void world_routes_fracture( world_instance *world, ent_gate *gate, v3f imp_co, v3f imp_v ); void world_routes_activate_entry_gate( world_instance *world, ent_gate *rg ); void render_world_routes( world_instance *world, @@ -22,6 +17,6 @@ void world_routes_update_timer_texts( world_instance *world ); void world_routes_update( world_instance *world ); void world_routes_fixedupdate( world_instance *world ); void world_routes_clear( world_instance *world ); -void world_routes_recv_scoreboard( world_instance *world, - vg_msg *body, u32 route_id, - enum request_status status ); +void world_routes_recv_scoreboard( world_instance *world, vg_kvs *kvs, u32 route_id, enum request_status status ); + +#endif diff --git a/src/world_routes_ui.c b/src/world_routes_ui.c index ec6c115..4d350d0 100644 --- a/src/world_routes_ui.c +++ b/src/world_routes_ui.c @@ -1,8 +1,3 @@ -#include "skaterift.h" -#include "world_routes_ui.h" -#include "world_routes.h" -#include "player.h" - static u32 v4_rgba( v4f colour ) { u32 r = vg_minf(1.0f,colour[0])*255.0f, @@ -117,9 +112,9 @@ static void ent_route_imgui( ui_context *ctx, world_instance *world, ent_route * else vg_strcatch( &str, '-' ); - vg_strcati32( &str, s ); + vg_strcati64( &str, s, 10 ); vg_strcatch( &str, '.' ); - vg_strcati32( &str, ds ); + vg_strcati64( &str, ds, 10 ); ui_text( ctx, rect, buf, 1, k_ui_align_middle_center, 0 ); } diff --git a/src/world_routes_ui.h b/src/world_routes_ui.h index 70c0fcd..016186f 100644 --- a/src/world_routes_ui.h +++ b/src/world_routes_ui.h @@ -1,5 +1,8 @@ -#pragma once -#include "world_routes.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/world_routes_ui.c" +#else struct route_ui{}; void world_routes_imgui( ui_context *ctx, world_instance *world ); + +#endif diff --git a/src/world_sfd.c b/src/world_sfd.c index 04a0585..4f1b01e 100644 --- a/src/world_sfd.c +++ b/src/world_sfd.c @@ -1,14 +1,3 @@ -#ifndef SFD_C -#define SFD_C - -#include "world_sfd.h" -#include "shaders/scene_scoretext.h" -#include "shaders/scene_vertex_blend.h" -#include "network.h" -#include "entity.h" -#include "network_common.h" -#include "world_routes.h" - struct world_sfd world_sfd; static f32 sfd_encode_glyph( char c ){ @@ -94,7 +83,7 @@ void world_sfd_compile_active_scores(void) { board = &world->leaderboard_cache[ world_sfd.active_route_board ]; ent_route *route = af_arritm( &world->ent_route, world_sfd.active_route_board ); - title = af_str( &world->meta.af, route->pstr_name ); + title = af_str( world->meta.packed_strings, route->pstr_name ); } for( u32 i=0; i<13; i++ ) @@ -126,11 +115,14 @@ void world_sfd_compile_active_scores(void) vg_str s; vg_strnull( &s, buf, 32 ); vg_strcat( &s, "Error: " ); - vg_strcati32( &s, board->status ); + vg_strcati64( &s, board->status, 10 ); sfd_encode( (v2i){-1,4}, buf, k_world_sfd_center ); return; } + // FIXME FIXME + sfd_encode( (v2i){-1,0}, "FIX ME!!!!!", k_world_sfd_right ); +#if 0 vg_msg body; vg_msg_init( &body, board->data, board->data_len ); @@ -157,7 +149,7 @@ void world_sfd_compile_active_scores(void) char buf[100]; vg_str str; vg_strnull( &str, buf, 100 ); - vg_strcati32( &str, l ); + vg_strcati64( &str, l, 10 ); vg_strcat( &str, " " ); if( username ) @@ -180,11 +172,11 @@ void world_sfd_compile_active_scores(void) seconds %= 60; minutes %= 60; if( minutes > 9 ) vg_strcat( &str, "?" ); - else vg_strcati32( &str, minutes ); + else vg_strcati64( &str, minutes, 10 ); vg_strcat( &str, ":" ); - vg_strcati32r( &str, seconds, 2, '0' ); + vg_strcati64r( &str, seconds, 10, 2, '0' ); vg_strcat( &str, "." ); - vg_strcati32r( &str, centiseconds, 2, '0' ); + vg_strcati64r( &str, centiseconds, 10, 2, '0' ); sfd_encode( (v2i){-1,l}, str.buffer, k_world_sfd_right ); l ++; @@ -195,6 +187,7 @@ void world_sfd_compile_active_scores(void) { sfd_encode( (v2i){-1,4}, "No records", k_world_sfd_center ); } +#endif } void world_sfd_update( world_instance *world, v3f pos ) @@ -229,7 +222,7 @@ void world_sfd_update( world_instance *world, v3f pos ) char mod_uid[ ADDON_UID_MAX ]; addon_make_uid( _world.main.addon_id, mod_uid ); - network_request_scoreboard( mod_uid, af_str( &world->meta.af, route->pstr_name ), + network_request_scoreboard( mod_uid, af_str( world->meta.packed_strings, route->pstr_name ), NETWORK_LEADERBOARD_ALLTIME_AND_CURRENT_WEEK, closest ); } } @@ -263,10 +256,11 @@ void world_sfd_update( world_instance *world, v3f pos ) void bind_terrain_noise(void); void sfd_render( world_instance *world, vg_camera *cam, m4x3f transform ) { +#if 0 mesh_bind( &world_sfd.mesh_display ); shader_scene_scoretext_use(); shader_scene_scoretext_uTexMain(1); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_scoretext ); + WORLD_LINK_LIGHTING( world, scene_scoretext ); bind_terrain_noise(); @@ -293,11 +287,14 @@ void sfd_render( world_instance *world, vg_camera *cam, m4x3f transform ) shader_scene_vertex_blend_use(); shader_scene_vertex_blend_uTexGarbage(0); shader_scene_vertex_blend_uTexGradients(1); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_vertex_blend ); + WORLD_LINK_LIGHTING( world, scene_vertex_blend ); bind_terrain_noise(); - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, world_sfd.tex_scoretex ); + + VG_ASSERT(0); + // FIXME FIXME FIXME + // glActiveTexture( GL_TEXTURE1 ); + // glBindTexture( GL_TEXTURE_2D, world_sfd.tex_scoretex ); shader_scene_vertex_blend_uPv( cam->mtx.pv ); shader_scene_vertex_blend_uPvmPrev( pvm_prev ); @@ -305,20 +302,30 @@ void sfd_render( world_instance *world, vg_camera *cam, m4x3f transform ) shader_scene_vertex_blend_uCamera( cam->transform[3] ); mesh_bind( &world_sfd.mesh_base ); - mdl_draw_submesh( &world_sfd.sm_base ); + vg_model_draw_submesh( &world_sfd.sm_base ); +#endif } -void world_sfd_init(void) +static void _world_sfd_load_content( void *_, vg_async_info *async ) { - THREAD_1; - vg_info( "world_sfd_init\n" ); - vg_stack_clear( &vg.scratch ); + // FIXME FIXME FIXME + VG_ASSERT( 0 ); +#if 0 + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_BACKGROUND ) ); + + u32 temp_frame = _vg_start_temp_frame(); + vg_model scoreboard_mdl; + VG_ASSERT( vg_model_load( &scoreboard_mdl, VG_MODEL_ENGINE_PROCEDURAL_SOURCE, "models/rs_scoretext.mdl", + _vg_temp_stack() )); + + + _vg_end_temp_frame( temp_frame ); + mdl_context mscoreboard; - mdl_open( &mscoreboard, "models/rs_scoretext.mdl", &vg.scratch ); + mdl_open( &mscoreboard, , &vg.scratch ); mdl_load_metadata_block( &mscoreboard, &vg.scratch ); mdl_async_load_glmesh( &mscoreboard, &world_sfd.mesh_base, NULL ); - mdl_load_mesh_block( &mscoreboard, &vg.scratch ); scene_context *scene = &world_sfd.scene; @@ -339,25 +346,28 @@ void world_sfd_init(void) { scene_vert *vert = &scene->arrvertices[ vert_start+j ]; - float const k_glyph_uvw = 1.0f/64.0f; + f32 const k_glyph_uvw = 1.0f/64.0f; vert->uv[0] -= k_glyph_uvw * (float)(i-1); vert->norm[3] = i*42; } } - vg_async_task_dispatch( task, async_scene_upload ); - vg_tex2d_load_qoi_async_file( "textures/scoretext.qoi", VG_TEX2D_CLAMP|VG_TEX2D_NEAREST, &world_sfd.tex_scoretex ); mdl_close( &mscoreboard ); +#endif +} - int w = 27, +VG_API void _world_sfd_init(void) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_world_sfd_load_content ); + + i32 w = 27, h = 13; world_sfd.w = w; world_sfd.h = h; - world_sfd.buffer = vg_stack_allocate( &vg.rtmem, 2*w*h*sizeof(f32), 8, "SFD Buffer" ); + world_sfd.buffer = vg_stack_allocate( VG_STACK_USE_HEAP, 2*w*h*sizeof(f32), 8, "SFD Buffer" ); - for( int i=0; ientity_bh, &it, &idx ) ) + while( bh_next( &world->entity_bh, &it, &idx ) ) { u32 id = world->entity_list[ idx ], type = mdl_entity_id_type( id ), @@ -126,10 +124,10 @@ void world_volumes_update( world_instance *world, v3f pos ) { if( world_set_event( k_world_event_interact ) ) { - gui_helper_reset( k_gui_helper_mode_black_bars ); + _gui_helper_reset( k_gui_helper_mode_black_bars ); vg_str text; - if( gui_new_helper( input_button_list[k_srbind_maccept], &text )) - vg_strcat( &text, af_str( &world->meta.af, volume->interact.pstr_text ) ); + if( _gui_new_helper( input_button_list[k_srbind_maccept], &text )) + vg_strcat( &text, af_str( world->meta.packed_strings, volume->interact.pstr_text ) ); _world_volumes.active_volume_interact = id; } } @@ -159,7 +157,7 @@ next_volume:; if( world_clear_event( k_world_event_interact ) ) { _world_volumes.active_volume_interact = 0; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); } } else if( button_down( k_srbind_maccept ) && (_cutscene.state == k_cutscene_state_none) @@ -171,7 +169,7 @@ next_volume:; if( world_clear_event( k_world_event_interact ) ) { _world_volumes.active_volume_interact = 0; - gui_helper_reset( k_gui_helper_mode_clear ); + _gui_helper_reset( k_gui_helper_mode_clear ); } } diff --git a/src/world_volumes.h b/src/world_volumes.h index 06ccf5f..b766540 100644 --- a/src/world_volumes.h +++ b/src/world_volumes.h @@ -1,6 +1,6 @@ -#pragma once -#include "world.h" -#include "vg/vg_bvh.h" +#if defined( SR_IMPLEMENTATION ) +# include "src/world_volumes.c" +#else struct _world_volumes { @@ -10,3 +10,5 @@ extern _world_volumes; void world_volumes_update( world_instance *world, v3f pos ); void world_volumes_start( world_instance *world ); + +#endif diff --git a/src/world_water.c b/src/world_water.c index e9e74ef..7436b34 100644 --- a/src/world_water.c +++ b/src/world_water.c @@ -1,28 +1,14 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#include "world_water.h" -#include "world_render.h" -#include "render.h" -#include "shaders/scene_water.h" -#include "shaders/scene_water_fast.h" -#include "scene.h" -#include "player.h" -#include "player_walk.h" -#include "player_dead.h" - struct world_water world_water; -void world_water_init(void) +static void _world_water_load_content( void *_, vg_async_info *async ) { - vg_info( "world_water_init\n" ); - - vg_tex2d_load_qoi_async_file( "textures/water_surf.qoi", - VG_TEX2D_LINEAR|VG_TEX2D_REPEAT, - &world_water.tex_water_surf ); + _vg_tex_load( &world_water.tex_water_surf, "textures/water_surf.qoi", VG_TEX_LINEAR|VG_TEX_REPEAT ); +} - vg_success( "done\n" ); +VG_API void _world_water_init(void) +{ + VG_ASSERT( _vg_thread_has_flags( VG_THREAD_MAIN ) ); + _vg_async_send( _vg_async_alloc( VG_THREAD_ASYNC_ID, 0 ), (vg_async_fn)_world_water_load_content ); } void water_set_surface( world_instance *world, float height ) @@ -31,17 +17,6 @@ void water_set_surface( world_instance *world, float height ) v4_copy( (v4f){ 0.0f, 1.0f, 0.0f, height }, world->water.plane ); } -void world_link_lighting_ub( world_instance *world, GLuint shader ); -void world_bind_position_texture( world_instance *world, - GLuint shader, GLuint location, - int slot ); -void world_bind_light_array( world_instance *world, - GLuint shader, GLuint location, - int slot ); -void world_bind_light_index( world_instance *world, - GLuint shader, GLuint location, - int slot ); - /* * Does not write motion vectors */ @@ -132,15 +107,11 @@ void render_water_surface( world_instance *world, vg_camera *cam ) vg_framebuffer_bind_texture( _vg_render.fb_water_reflection, 0, 0 ); shader_scene_water_uTexMain( 0 ); - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, world_water.tex_water_surf ); + vg_tex_bind( GL_TEXTURE_2D, &world_water.tex_water_surf, 1 ); shader_scene_water_uTexDudv( 1 ); - shader_scene_water_uInvRes( (v2f){ - 1.0f / (float)vg.window_x, - 1.0f / (float)vg.window_y }); - - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_water ); + shader_scene_water_uInvRes( (v2f){ 1.0f / (f32)_vg_window.w, 1.0f / (f32)_vg_window.h }); + WORLD_LINK_LIGHTING( world, scene_water ); vg_framebuffer_bind_texture( _vg_render.fb_water_beneath, 0, 5 ); shader_scene_water_uTexBack( 5 ); @@ -159,22 +130,21 @@ void render_water_surface( world_instance *world, vg_camera *cam ) glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); - mesh_bind( &world->mesh_no_collide ); - + scene_mesh_bind( &world->transparent_scene_mesh ); for( int i=0; isurface_count; i++ ) { struct world_surface *mat = &world->surfaces[i]; - struct shader_props_water *props = mat->info.props.compiled; if( mat->info.shader == k_shader_water ) { - shader_scene_water_uShoreColour( props->shore_colour ); - shader_scene_water_uOceanColour( props->deep_colour ); - shader_scene_water_uFresnel( props->fresnel ); - shader_scene_water_uWaterScale( props->water_sale ); - shader_scene_water_uWaveSpeed( props->wave_speed ); - - mdl_draw_submesh( &mat->sm_no_collide ); + VG_ASSERT(i); + union shader_props *props = &world->meta.shader_props[i-1]; + shader_scene_water_uShoreColour( props->water.shore_colour ); + shader_scene_water_uOceanColour( props->water.deep_colour ); + shader_scene_water_uFresnel( props->water.fresnel ); + shader_scene_water_uWaterScale( props->water.water_sale ); + shader_scene_water_uWaveSpeed( props->water.wave_speed ); + vg_model_draw_submesh( &mat->sm_no_collide ); } } @@ -185,15 +155,13 @@ void render_water_surface( world_instance *world, vg_camera *cam ) { shader_scene_water_fast_use(); - glActiveTexture( GL_TEXTURE1 ); - glBindTexture( GL_TEXTURE_2D, world_water.tex_water_surf ); + vg_tex_bind( GL_TEXTURE_2D, &world_water.tex_water_surf, 1 ); shader_scene_water_fast_uTexDudv( 1 ); shader_scene_water_fast_uTime( _world.time ); shader_scene_water_fast_uCamera( cam->transform[3] ); shader_scene_water_fast_uSurfaceY( world->water.height ); - - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_water_fast ); + WORLD_LINK_LIGHTING( world, scene_water_fast ); m4x3f full; m4x3_identity( full ); @@ -205,19 +173,19 @@ void render_water_surface( world_instance *world, vg_camera *cam ) glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); - mesh_bind( &world->mesh_no_collide ); - + scene_mesh_bind( &world->transparent_scene_mesh ); for( int i=0; isurface_count; i++ ) { struct world_surface *mat = &world->surfaces[i]; - struct shader_props_water *props = mat->info.props.compiled; if( mat->info.shader == k_shader_water ) { - shader_scene_water_fast_uShoreColour( props->shore_colour ); - shader_scene_water_fast_uOceanColour( props->deep_colour ); + VG_ASSERT(i); + union shader_props *props = &world->meta.shader_props[i-1]; + shader_scene_water_fast_uShoreColour( props->water.shore_colour ); + shader_scene_water_fast_uOceanColour( props->water.deep_colour ); - mdl_draw_submesh( &mat->sm_no_collide ); + vg_model_draw_submesh( &mat->sm_no_collide ); } } @@ -242,7 +210,7 @@ static void world_water_drown(void) { vg_str str; struct gui_helper *helper; - if( (helper = gui_new_helper(input_button_list[k_srbind_reset], &str)) ) + if( (helper = _gui_new_helper(input_button_list[k_srbind_reset], &str)) ) { vg_strcat( &str, "Respawn" ); } @@ -268,7 +236,7 @@ bool world_water_player_safe( world_instance *world, f32 allowance ) entity_event_result ent_water_event( ent_event *event ) { world_instance *world = &_world.main; - if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "drown" ) ) + if( AF_STR_EQ( world->meta.packed_strings, event->pstr_recieve_event, "drown" ) ) { world_water_drown(); return k_entity_event_result_OK; diff --git a/src/world_water.h b/src/world_water.h index b2d753d..672f743 100644 --- a/src/world_water.h +++ b/src/world_water.h @@ -1,18 +1,19 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ +#if defined( SR_IMPLEMENTATION ) +# include "src/world_water.c" +#else -#pragma once -#include "world.h" - -struct world_water{ - GLuint tex_water_surf; +struct world_water +{ + vg_tex tex_water_surf; } extern world_water; -void world_water_init(void); + +VG_API void _world_water_init(void); void water_set_surface( world_instance *world, f32 height ); void render_water_texture( world_instance *world, vg_camera *cam ); void render_water_surface( world_instance *world, vg_camera *cam ); entity_event_result ent_water_event( ent_event *event ); bool world_water_player_safe( world_instance *world, f32 allowance ); + +#endif