From 6c84fa207dec2cf8e92b3882492bdd2f92ee7afe Mon Sep 17 00:00:00 2001 From: hgn Date: Sun, 9 Jul 2023 22:11:25 +0100 Subject: [PATCH] switch to dynamic sizes --- player_dead.h | 3 +- player_render.c | 65 +++++++++++++++------- player_replay.c | 141 ++++++++++++++++++++++++++++++++++-------------- player_replay.h | 16 ++++-- skaterift.c | 15 +++--- 5 files changed, 167 insertions(+), 73 deletions(-) diff --git a/player_dead.h b/player_dead.h index 4a10e98..fbdb47f 100644 --- a/player_dead.h +++ b/player_dead.h @@ -3,8 +3,7 @@ #include "player_api.h" -struct player_dead -{ +struct player_dead{ v3f co_lpf, v_lpf, w_lpf; }; diff --git a/player_render.c b/player_render.c index b6cbf63..aaefb07 100644 --- a/player_render.c +++ b/player_render.c @@ -183,12 +183,28 @@ VG_STATIC void player__animate_from_replay( player_instance *player, /* TODO: holdout blending (from when the game has to slow down) */ player_animation res; - replay_frame *frame = replay->cursor_frame; + replay_frame *frame = replay->cursor_frame, + *next = NULL; if( frame ){ - memcpy( &res, &frame->anim, sizeof(frame->anim) ); - memcpy( &frame->board_pose, &player->board_pose, - sizeof(player->board_pose) ); + next = frame->r; + + if( next ){ + f32 t = replay_subframe_time( replay ); + + struct skeleton *sk = &player->playeravatar->sk; + skeleton_lerp_pose(sk, frame->anim.pose, next->anim.pose, t, res.pose); + v3_lerp( frame->anim.root_co, next->anim.root_co, t, res.root_co ); + q_nlerp( frame->anim.root_q, next->anim.root_q, t, res.root_q ); + res.type = k_player_animation_type_absolute; + player->board_pose.lean = vg_lerpf( frame->board_pose.lean, + next->board_pose.lean, t ); + } + else { + memcpy( &res, &frame->anim, sizeof(frame->anim) ); + memcpy( &frame->board_pose, &player->board_pose, + sizeof(player->board_pose) ); + } } else return; @@ -211,13 +227,26 @@ void player_record_replay_frame( player_instance *player, const f64 k_replay_rate = 1.0/30.0, k_gamestate_rate = 0.5; - u16 gamestates = 0; - if( statedelta > k_gamestate_rate || force_gamestate /* or switching */ ){ - gamestates = 1; + u32 gamestate_size = 0; + void *gamestate_src = NULL; + if( (statedelta > k_gamestate_rate) || force_gamestate ){ + if( player->subsystem == k_player_subsystem_walk ){ + gamestate_size = sizeof(struct player_walk_state); + gamestate_src = &player->_walk.state; + } + else if( player->subsystem == k_player_subsystem_skate ){ + gamestate_size = sizeof(struct player_skate_state); + gamestate_src = &player->_skate.state; + } + else if( player->subsystem == k_player_subsystem_dead ){ + gamestate_size = sizeof(struct player_ragdoll); + gamestate_src = &player->ragdoll; + } } + assert( gamestate_size < 0xffff ); - if( (delta > k_replay_rate) || gamestates ){ - replay_frame *frame = replay_newframe( replay, gamestates, 0 ); + if( (delta > k_replay_rate) || gamestate_size ){ + replay_frame *frame = replay_newframe( replay, gamestate_size, 0 ); replay->cursor = vg.time; replay->cursor_frame = frame; @@ -236,23 +265,19 @@ void player_record_replay_frame( player_instance *player, v3_copy( player->cam.angles, frame->cam_angles ); frame->cam_fov = player->cam.fov; - if( gamestates ){ - replay_gamestate *gs = replay_frame_gamestate( frame, 0 ); + if( gamestate_size ){ + replay_gamestate *gs = replay_frame_gamestate( frame ); gs->system = player->subsystem; - if( player->subsystem == k_player_subsystem_walk ){ - memcpy( &gs->walk, &player->_walk.state, - sizeof(struct player_walk_state) ); - } - else if( player->subsystem == k_player_subsystem_skate ){ - memcpy( &gs->skate, &player->_skate.state, - sizeof(struct player_skate_state) ); - } - + /* permanent block */ memcpy( &gs->rb, &player->rb, sizeof(rigidbody) ); memcpy( &gs->cam_control, &player->cam_control, sizeof(struct player_cam_controller) ); v3_copy( player->angles, gs->angles ); + + /* subsytem/dynamic block */ + void *dst = replay_gamestate_subsystem_data( gs ); + memcpy( dst, gamestate_src, gamestate_size ); } } } diff --git a/player_replay.c b/player_replay.c index 09cc136..1215f62 100644 --- a/player_replay.c +++ b/player_replay.c @@ -11,48 +11,85 @@ VG_STATIC void replay_clear( replay_buffer *replay ){ replay->cursor = -99999.9; } -replay_gamestate *replay_frame_gamestate( replay_frame *frame, u16 index ){ +replay_gamestate *replay_frame_gamestate( replay_frame *frame ){ void *baseptr = frame; - - replay_gamestate *array = (baseptr + vg_align8( sizeof(replay_frame))); - return &array[ index ]; + return baseptr + vg_align8(sizeof(replay_frame)); +} + +void *replay_gamestate_subsystem_data( replay_gamestate *gs ){ + void *baseptr = gs; + return baseptr + vg_align8(sizeof(replay_gamestate)); +} + +u32 replay_frame_gamestate_total_size( u32 subsystem_gamestate_size ){ + if( subsystem_gamestate_size ){ + return vg_align8( sizeof(replay_gamestate) ) + + vg_align8( subsystem_gamestate_size ); + } + else + return 0; } -replay_sfx *replay_frame_sfx( replay_frame *frame, u16 index ){ - void *gsarr = replay_frame_gamestate( frame, 0 ); - u32 gssize = frame->gamestate_count * sizeof(replay_gamestate); +replay_sfx *replay_frame_sfx( replay_frame *frame, u32 index ){ + void *gs = replay_frame_gamestate( frame ); + u32 total_size = + replay_frame_gamestate_total_size( frame->subsystem_gamestate_size ); - replay_sfx *array = (gsarr + vg_align8(gssize)); + replay_sfx *array = (gs + total_size); return &array[index]; } -u32 _replay_frame_size( u16 gamestate_count, u16 sfx_count ){ +u32 _replay_frame_size( u32 subsystem_gamestate_size, u32 sfx_count ){ return vg_align8( sizeof( replay_frame ) ) + - vg_align8( gamestate_count * sizeof(replay_gamestate) ) + + replay_frame_gamestate_total_size( subsystem_gamestate_size ) + vg_align8( sfx_count * sizeof(replay_sfx) ); } u32 replay_frame_size( replay_frame *frame ){ - return _replay_frame_size( frame->gamestate_count, frame->sfx_count ); + return _replay_frame_size( frame->subsystem_gamestate_size, + frame->sfx_count ); +} + +VG_STATIC void replay_tailpop( replay_buffer *replay ){ + if( replay->cursor_frame == replay->tail ) + replay->cursor_frame = NULL; + if( replay->statehead == replay->tail ) + replay->statehead = NULL; + + replay->tail = replay->tail->r; + + if( replay->tail ) + replay->tail->l = NULL; + else + replay->head = NULL; } VG_STATIC replay_frame *replay_newframe( replay_buffer *replay, - u16 gamestate_count, u16 sfx_count ){ + u32 subsystem_gamestate_size, + u32 sfx_count ){ replay_frame *frame = NULL; if( replay->head ){ assert( replay->head ); u32 headsize = replay_frame_size( replay->head ), nextpos = ((void *)replay->head - replay->data) + headsize, - nextsize = _replay_frame_size( gamestate_count, sfx_count ); + nextsize = _replay_frame_size( subsystem_gamestate_size, sfx_count ); if( nextsize > replay->size ){ vg_error( "Keyframe too big\n" ); return NULL; } - if( nextpos + nextsize > replay->size ) + if( nextpos + nextsize > replay->size ){ nextpos = 0; + + /* maintain contiguity */ + while( replay->tail ){ + if( (void *)replay->tail - replay->data ) + replay_tailpop( replay ); + else break; + } + } check_again:; @@ -60,21 +97,10 @@ check_again:; if( tailpos >= nextpos ){ if( nextpos + nextsize > tailpos ){ - /* remove links */ - if( replay->cursor_frame == replay->tail ) - replay->cursor_frame = NULL; - if( replay->statehead == replay->tail ) - replay->statehead = NULL; - - /* pop node */ - replay->tail = replay->tail->r; + replay_tailpop( replay ); - if( replay->tail ) { - replay->tail->l = NULL; + if( replay->tail ) goto check_again; - } - else - replay->head = NULL; } } @@ -86,13 +112,13 @@ check_again:; else frame = replay->data; - frame->gamestate_count = gamestate_count; + frame->subsystem_gamestate_size = subsystem_gamestate_size; frame->sfx_count = sfx_count; frame->l = replay->head; frame->r = NULL; replay->head = frame; if( !replay->tail ) replay->tail = frame; - if( gamestate_count ) replay->statehead = frame; + if( subsystem_gamestate_size ) replay->statehead = frame; return frame; } @@ -143,25 +169,51 @@ VG_STATIC void replay_seek( replay_buffer *replay, f64 t ){ VG_STATIC replay_frame *replay_find_recent_stateframe( replay_buffer *replay ){ replay_frame *frame = replay->cursor_frame; - u32 i=4096; while( i --> 0 ){ if( !frame ) return frame; - if( frame->gamestate_count ) return frame; + if( frame->subsystem_gamestate_size ) return frame; frame = frame->l; } return NULL; } +VG_STATIC f32 replay_subframe_time( replay_buffer *replay ){ + replay_frame *frame = replay->cursor_frame; + if( !frame ) return 0.0f; + replay_frame *next = frame->r; + if( next ){ + f64 l = next->time - frame->time, + t = (replay->cursor - frame->time) / l; + return vg_clampf( t, 0.0f, 1.0f ); + } + else + return 0.0f; +} + +VG_STATIC void replay_get_frame_camera( replay_frame *frame, camera *cam ){ + cam->fov = frame->cam_fov; + v3_copy( frame->cam_pos, cam->pos ); + v3_copy( frame->cam_angles, cam->angles ); +} + VG_STATIC void replay_get_camera( replay_buffer *replay, camera *cam ){ cam->nearz = 0.1f; cam->farz = 100.0f; if( replay->cursor_frame ){ - /* TODO: frame lerp */ - cam->fov = replay->cursor_frame->cam_fov; - v3_copy( replay->cursor_frame->cam_pos, cam->pos ); - v3_copy( replay->cursor_frame->cam_angles, cam->angles ); + replay_frame *next = replay->cursor_frame->r; + + if( next ){ + camera temp; + + replay_get_frame_camera( replay->cursor_frame, cam ); + replay_get_frame_camera( next, &temp ); + camera_lerp( cam, &temp, replay_subframe_time( replay ), cam ); + } + else { + replay_get_frame_camera( replay->cursor_frame, cam ); + } } else { v3_zero( cam->pos ); @@ -200,16 +252,23 @@ VG_STATIC void skaterift_replay_pre_update(void){ if( prev ){ /* TODO: Make gamestate_apply function / swap ... */ - replay_gamestate *gs = replay_frame_gamestate( prev, 0 ); + replay_gamestate *gs = replay_frame_gamestate( prev ); + void *src = replay_gamestate_subsystem_data( gs ); if( gs->system == k_player_subsystem_walk ){ - memcpy( &localplayer._walk.state, &gs->walk, - sizeof(struct player_walk_state) ); + memcpy( &localplayer._walk.state, src, + prev->subsystem_gamestate_size ); } else if( gs->system == k_player_subsystem_skate ){ - memcpy( &localplayer._skate.state, &gs->skate, - sizeof(struct player_skate_state) ); + memcpy( &localplayer._skate.state, src, + prev->subsystem_gamestate_size ); + } + else if( gs->system == k_player_subsystem_dead ){ + player__dead_transition( &localplayer ); + memcpy( &localplayer.ragdoll, src, + prev->subsystem_gamestate_size ); } + localplayer.subsystem = gs->system; memcpy( &localplayer.rb, &gs->rb, sizeof(rigidbody) ); @@ -251,6 +310,8 @@ VG_STATIC void skaterift_replay_debug_info(void){ if( replay->statehead ){ u32 state = (void *)replay->statehead - replay->data; player__debugtext( 1, "gs @%u\n", state ); + player__debugtext( 1, "gamestate_size: %u\n", + replay->statehead->subsystem_gamestate_size ); } else player__debugtext( 1, "gs @NULL\n" ); diff --git a/player_replay.h b/player_replay.h index 52a0772..91b9f72 100644 --- a/player_replay.h +++ b/player_replay.h @@ -29,7 +29,8 @@ struct replay_frame { f64 time; replay_frame *l, *r; - u16 gamestate_count, sfx_count; + u32 subsystem_gamestate_size, + sfx_count; }; struct replay_gamestate { @@ -39,10 +40,13 @@ struct replay_gamestate { struct player_cam_controller cam_control; +#if 0 union { struct player_skate_state skate; struct player_walk_state walk; + struct player_ragdoll ragdoll; }; +#endif }; struct replay_sfx { @@ -50,12 +54,16 @@ struct replay_sfx { }; VG_STATIC replay_frame *replay_newframe( replay_buffer *replay, - u16 gamestate_count, u16 sfx_count ); + u32 gamestate_count, u32 sfx_count ); VG_STATIC void replay_seek( replay_buffer *replay, f64 t ); -replay_gamestate *replay_frame_gamestate( replay_frame *frame, u16 index ); -replay_sfx *replay_frame_sfx( replay_frame *frame, u16 index ); +replay_gamestate *replay_frame_gamestate( replay_frame *frame ); +void *replay_gamestate_subsystem_data( replay_gamestate *gs ); +replay_sfx *replay_frame_sfx( replay_frame *frame, u32 index ); VG_STATIC replay_frame *replay_find_recent_stateframe( replay_buffer *replay ); +VG_STATIC void replay_get_camera( replay_buffer *replay, camera *cam ); +VG_STATIC void replay_get_frame_camera( replay_frame *frame, camera *cam ); +VG_STATIC f32 replay_subframe_time( replay_buffer *replay ); VG_STATIC void skaterift_replay_pre_update(void); VG_STATIC void skaterift_replay_imgui(void); diff --git a/skaterift.c b/skaterift.c index 64fb65a..b06db68 100644 --- a/skaterift.c +++ b/skaterift.c @@ -284,13 +284,6 @@ VG_STATIC void vg_pre_update(void){ vg_slewf( &skaterift.time_rate, target, vg.time_frame_delta * 6.0f ); vg.time_rate = vg_smoothstepf( skaterift.time_rate ); - - if( button_down( k_srbind_reset ) ){ - if( skaterift.activity == k_skaterift_default ){ - skaterift.activity = k_skaterift_replay; - player_record_replay_frame( &localplayer, &skaterift.replay, 1 ); - } - } player__pre_update( &localplayer ); global_skateshop_preupdate(); @@ -493,6 +486,14 @@ VG_STATIC void render_main_game(void){ render_scene_gate_subview(); present_view_with_post_processing(); + + /* capture the current resume frame at the very last point */ + if( button_down( k_srbind_reset ) ){ + if( skaterift.activity == k_skaterift_default ){ + skaterift.activity = k_skaterift_replay; + player_record_replay_frame( &localplayer, &skaterift.replay, 1 ); + } + } } VG_STATIC void vg_render(void){ -- 2.25.1