From 5a6199fecf8afcff4b4ef2d341a0dfd0e220420d Mon Sep 17 00:00:00 2001 From: hgn Date: Fri, 3 Feb 2023 11:16:26 +0000 Subject: [PATCH] cam rework --- models_src/ch_jordan.mdl | Bin 612864 -> 627984 bytes models_src/ch_new.mdl | Bin 664352 -> 679456 bytes models_src/ch_outlaw.mdl | Bin 607664 -> 622784 bytes player.c | 54 +------------ player.h | 14 ++++ player_common.c | 106 ++++++++++++++++++++++++- player_common.h | 4 +- player_skate.c | 85 ++++++++------------ player_skate.h | 8 +- player_walk.c | 165 ++++++++++++++++++++++++++++++++------- player_walk.h | 8 +- skeleton.h | 13 ++- 12 files changed, 316 insertions(+), 141 deletions(-) diff --git a/models_src/ch_jordan.mdl b/models_src/ch_jordan.mdl index 0d147d1765460c17371fd29bcdf13a9a4bd195f1..dbf1e54cf2f039897d1e655af0266d2cb4febb45 100644 GIT binary patch delta 13852 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 delta 1115 zcmYk3ZEO@}5XWcsZrj=RFo#|(zLX;L1r?;mU~3H5^EOQ(rnY>jas;&|R1h^@vDZSi zQc);aLFxlHVp1Si+AF0+$W_)zxaAC~m`E%Jv{7rg4}_ZVQeq5*)W$ib=ALAJJOAhT z?>;lLyZVdTh6=L)&K^dPwX!p-sMIYR5EK`=SN5IlzIwHJfm8LBPt;rRk~*4MYT*gu676~)H%)6Zh^Yj;YUyb zhl!-Rgl?4-&QgU=6X&Scg!9#)utePumZ`;PtsWv152$)FodeRcIyzROej~T)qg>@M7D|aKhe@6?{ zLBrz&>0f*c)VSe6SL|;iAMv!x%dS=rW|L~np0h~?k($9XF?lVO-*ZQQs{_oJ{Qf)o zS|&h=lDScF?y;QR4^Rk%$tI{;dhu4ap_K$kxj{t1?f1~a``DJN_ z@jQTSX&(sA1=yXYeNyd#H0>?|7!WOW$&vz#0fr=-E=YSAV76$dgw*!$aziZQ`iWv6 z=8zWKm3zzlAQ)~BhEYP3a7Z{MbSoIn7=5F?#*t~&IOt=);j-72@0}co4_lWis9eW@ zRroBeDbmA<@RFO{*+7r#S-#1W5l%GFb?o3{>uC{Q<>Y$m(3fp~y1a!O-lpq%D$#_2(hNxX%J#e@E6(0-H3F9*}!`>MU*ta>UuY8llr|AB zaICVo@SbL}(P`Cgpi0CE?%GIe(9e2{cuTGN7HUSLXX;wqcf8Kd=S%OC|5iY?Fc7fg9* zabAyHvzV9nPzUDoSdVn@DR=eKBI8$Rw6|7nkFVqly)wm|Z|wL>tVihuy=}^2SMe)R z*FX##`>E&d~pjk5xk>kog)y`M9 diff --git a/models_src/ch_new.mdl b/models_src/ch_new.mdl index 53b5900c5916ef3dd9124e9cb646f81a5b34fbae..a5f34470df6b506d45981e82d197acb0ce8d39c1 100644 GIT binary patch delta 13386 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 Bksts7 diff --git a/models_src/ch_outlaw.mdl b/models_src/ch_outlaw.mdl index 29609e767f25a00932614718282ec5ff70bb017b..545312327134de39c9c3b98f25b516d325c0893f 100644 GIT binary patch delta 13587 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 B@0|bu diff --git a/player.c b/player.c index 08741d3..72d4810 100644 --- a/player.c +++ b/player.c @@ -180,42 +180,6 @@ void player__pass_gate( player_instance *player, teleport_gate *gate ) /* TODO: Add back other logic thats normally here */ } -VG_STATIC void player_camera_portal_correction( player_instance *player ) -{ - if( player->gate_waiting ) - { - /* construct plane equation for reciever gate */ - v4f plane; - v3_copy( player->gate_waiting->recv_to_world[2], plane ); - plane[3] = v3_dot( plane, player->gate_waiting->recv_to_world[3] ); - - /* check camera polarity */ - if( v3_dot( player->cam.pos, plane ) < plane[3] ) - { - vg_success( "Plane cleared\n" ); - player_apply_transport_to_cam( player->gate_waiting->transport ); - player->gate_waiting = NULL; - } - else - { - /* de-transform camera and player back */ - m4x3f inverse; - m4x3_invert_affine( player->gate_waiting->transport, inverse ); - m4x3_mulv( inverse, player->cam.pos, player->cam.pos ); - - /* TODO: Find robust method for this */ - v3f fwd_dir = { cosf(player->cam.angles[0]), - 0.0f, - sinf(player->cam.angles[0])}; - m3x3_mulv( inverse, fwd_dir, fwd_dir ); - player->cam.angles[0] = atan2f( fwd_dir[2], fwd_dir[0] ); - - struct skeleton *sk = &player->playeravatar->sk; - skeleton_apply_transform( sk, inverse ); - } - } -} - VG_STATIC void player__pre_render( player_instance *player ) { if( _player_animate[ player->subsystem ] ) @@ -242,23 +206,7 @@ VG_STATIC void player__pre_render( player_instance *player ) if( _player_post_animate[ player->subsystem ] ) _player_post_animate[ player->subsystem ]( player ); - /* TODO: eventually, blending code goes here */ - - float camera_blend_target = 1.0f; - if( player->camera_mode == k_cam_firstperson ) - camera_blend_target = 0.0f; - - player->camera_type_blend = vg_lerpf( player->camera_type_blend, - camera_blend_target, - 5.0f * vg.frame_delta ); - - float t = player->camera_type_blend; - camera_lerp_angles( player->cam1.angles, player->cam3.angles, - t, player->cam.angles ); - v3_lerp( player->cam1.co, player->cam3.co, t, player->cam.pos ); - player->cam.fov = vg_lerpf( 118.0f, 90.0f, t ); - - player_camera_portal_correction( player ); + player__cam_iterate( player ); } PLAYER_API void player__render( camera *cam, player_instance *player ) diff --git a/player.h b/player.h index c9f13f7..85bca0a 100644 --- a/player.h +++ b/player.h @@ -28,11 +28,25 @@ struct player_instance camera_mode; float camera_type_blend; +#if 0 struct { v3f co, angles; } cam1, cam3; +#endif + + v3f follow_pos, + follow_angles, + follow_pos_target, + follow_angles_target, + override_pos, + override_angles, + fpv_pos, + fpv_angles; + + float cam_position_override_strength, + cam_angles_override_strength; teleport_gate *gate_waiting; diff --git a/player_common.c b/player_common.c index 69d35ab..3f8e7b1 100644 --- a/player_common.c +++ b/player_common.c @@ -3,7 +3,111 @@ #include "player.h" -void player_look( player_instance *player, v3f angles ) +VG_STATIC void player_vector_angles( v3f angles, v3f v, float C, float k ) +{ + float yaw = atan2f( v[0], -v[2] ), + pitch = atan2f + ( + -v[1], + sqrtf + ( + v[0]*v[0] + v[2]*v[2] + ) + ) * C + k; + + angles[0] = yaw; + angles[1] = pitch; +} + +VG_STATIC void player_camera_portal_correction( player_instance *player ) +{ + if( player->gate_waiting ) + { + /* construct plane equation for reciever gate */ + v4f plane; + v3_copy( player->gate_waiting->recv_to_world[2], plane ); + plane[3] = v3_dot( plane, player->gate_waiting->recv_to_world[3] ); + + /* check camera polarity */ + if( v3_dot( player->cam.pos, plane ) < plane[3] ) + { + vg_success( "Plane cleared\n" ); + player_apply_transport_to_cam( player->gate_waiting->transport ); + player->gate_waiting = NULL; + } + else + { + /* de-transform camera and player back */ + m4x3f inverse; + m4x3_invert_affine( player->gate_waiting->transport, inverse ); + m4x3_mulv( inverse, player->cam.pos, player->cam.pos ); + + /* TODO: Find robust method for this */ + v3f fwd_dir = { cosf(player->cam.angles[0]), + 0.0f, + sinf(player->cam.angles[0])}; + m3x3_mulv( inverse, fwd_dir, fwd_dir ); + player->cam.angles[0] = atan2f( fwd_dir[2], fwd_dir[0] ); + + struct skeleton *sk = &player->playeravatar->sk; + skeleton_apply_transform( sk, inverse ); + } + } +} + +VG_STATIC void player__cam_iterate( player_instance *player ) +{ + struct player_avatar *av = player->playeravatar; + + v3_lerp( player->follow_pos, player->follow_pos_target, + vg.frame_delta * 15.0f, player->follow_pos ); + camera_lerp_angles( player->follow_angles, player->follow_angles_target, + vg.frame_delta * 18.0f, player->follow_angles ); + + /* Blending */ + player->camera_type_blend = + vg_lerpf( player->camera_type_blend, + (player->camera_mode == k_cam_firstperson)? 1.0f: 0.0f, + 5.0f * vg.frame_delta ); + float t = player->camera_type_blend; + + v3f p0, p1, a0, a1; + v3_lerp( player->follow_pos, player->override_pos, + player->cam_position_override_strength, p1 ); + camera_lerp_angles( player->follow_angles, player->override_angles, + player->cam_angles_override_strength, a1 ); + + v3_copy( player->fpv_pos, p0 ); + v3_copy( player->fpv_angles, a0 ); + + v3_lerp( p0, p1, player->camera_type_blend, player->cam.pos ); + camera_lerp_angles( a0, a1, player->camera_type_blend, player->cam.angles ); + + /* FIXME: cl_fov */ + player->cam.fov = vg_lerpf( 118.0f, 90.0f, player->camera_type_blend ); + + /* portal transitions */ + player_camera_portal_correction( player ); +} + +VG_STATIC void player_set_follower_subject( player_instance *player, + v3f subj ) +{ + v3f dir; + v3_sub( subj, player->follow_pos, dir ); + + if( v3_length2( dir ) < 0.1f*0.1f ) + v3_copy( (v3f){ 0.0f, 0.0f, 1.0f }, dir ); /* FIXME */ + else + v3_normalize( dir ); + + dir[1] *= 0.0f; + + v3_muladds( subj, dir, -2.0f, player->follow_pos_target ); + player_vector_angles( player->follow_angles_target, dir, 1.0f, 0.2f ); +} + +VG_STATIC void player_look( player_instance *player, v3f angles ) { angles[2] = 0.0f; v2_muladds( angles, vg.mouse_delta, 0.0025f, angles ); diff --git a/player_common.h b/player_common.h index 91298fc..6c825d8 100644 --- a/player_common.h +++ b/player_common.h @@ -3,6 +3,8 @@ #include "player_api.h" -void player_look( player_instance *player, v3f angles ); +VG_STATIC void player_look( player_instance *player, v3f angles ); +VG_STATIC void player__cam_iterate( player_instance *player ); +VG_STATIC void player_vector_angles( v3f angles, v3f v, float C, float k ); #endif /* PLAYER_COMMON_H */ diff --git a/player_skate.c b/player_skate.c index fedeee8..32a3670 100644 --- a/player_skate.c +++ b/player_skate.c @@ -1179,9 +1179,7 @@ VG_STATIC void player__skate_update( player_instance *player ) m3x3_mulv( gate->transport, s->state.throw_v, s->state.throw_v ); /*camera */ - m4x3_mulv( gate->transport, s->state.posl, s->state.posl ); m3x3_mulv( gate->transport, s->state.vl, s->state.vl ); - m3x3_mulv( gate->transport, s->state.dirl, s->state.dirl ); #if 0 mixedcam_transport( &s->state.cam, gate ); @@ -1419,7 +1417,6 @@ VG_STATIC void player__skate_animate( player_instance *player, /* transform */ rb_extrapolate( &player->rb, dest->root_co, dest->root_q ); - v3_muladds( dest->root_co, player->rb.to_world[1], -0.28f, dest->root_co ); v4f qresy, qresx, qresidual; @@ -1460,22 +1457,6 @@ VG_STATIC void player__skate_animate( player_instance *player, } } -VG_STATIC void skate_camera_vector_look( v3f angles, v3f v, float C, float k ) -{ - float yaw = atan2f( v[0], -v[2] ), - pitch = atan2f - ( - -v[1], - sqrtf - ( - v[0]*v[0] + v[2]*v[2] - ) - ) * C + k; - - angles[0] = yaw; - angles[1] = pitch; -} - VG_STATIC void skate_camera_firstperson( player_instance *player ) { struct player_skate *s = &player->_skate; @@ -1483,8 +1464,8 @@ VG_STATIC void skate_camera_firstperson( player_instance *player ) /* FIXME: viewpoint entity */ v3f vp = {-0.1f,1.8f,0.0f}; - m4x3_mulv( av->sk.final_mtx[ av->id_head-1 ], vp, player->cam1.co ); - v3_zero( player->cam1.angles ); + m4x3_mulv( av->sk.final_mtx[ av->id_head-1 ], vp, player->fpv_pos ); + v3_zero( player->fpv_angles ); v3f flat_dir, vel_dir, @@ -1508,8 +1489,7 @@ VG_STATIC void skate_camera_firstperson( player_instance *player ) v3_lerp( flat_dir, vel_dir, vg_clampf( tti / 2.0f, 0.4f, 1.0f ), look_dir ); v3_lerp( s->state.vl, look_dir, 4.0f*vg.time_delta, s->state.vl ); - - skate_camera_vector_look( player->cam1.angles, s->state.vl, 1.0f, 0.25f ); + player_vector_angles( player->fpv_angles, s->state.vl, 1.0f, 0.25f ); } VG_STATIC void skate_camera_thirdperson( player_instance *player ) @@ -1520,24 +1500,7 @@ VG_STATIC void skate_camera_thirdperson( player_instance *player ) v3f origin, dir, target; v3_copy( player->rb.co, origin ); v3_add( origin, (v3f){0.0f,1.35f,0.0f}, origin ); - v3_sub( origin, s->state.posl, dir ); - - if( v3_length2( dir ) < 0.1f*0.1f ) - v3_copy( (v3f){ 0.0f, 0.0f, 1.0f }, dir ); /* FIXME */ - else - v3_normalize( dir ); - - if( s->state.activity == k_skate_activity_air ) - dir[1] *= vg_maxf( 0.0f, 1.0f - (s->land_dist/2.0f) ); - dir[1] *= 0.0f; - - v3_muladds( origin, dir, -2.0f, target ); - - v3_lerp( s->state.posl, target, vg.frame_delta * 15.0f, s->state.posl ); - v3_lerp( s->state.dirl, dir, 18.0f*vg.time_delta, s->state.dirl ); - - v3_copy( s->state.posl, player->cam3.co ); - skate_camera_vector_look( player->cam3.angles, s->state.dirl, 1.0f, 0.2f ); + player_set_follower_subject( player, origin ); } VG_STATIC void player__skate_post_animate( player_instance *player ) @@ -1545,11 +1508,13 @@ VG_STATIC void player__skate_post_animate( player_instance *player ) struct player_skate *s = &player->_skate; struct player_avatar *av = player->playeravatar; - v3_zero( player->cam1.co ); - v3_zero( player->cam1.angles ); - skate_camera_thirdperson( player ); skate_camera_firstperson( player ); + player->cam_angles_override_strength = 0.0f; + player->cam_position_override_strength = 0.0f; + + + /* FIXME: Organize this. Its int wrong fucking place */ v3f vp0 = {0.0f,0.1f, 0.6f}, @@ -1571,30 +1536,46 @@ VG_STATIC void player__skate_reset( player_instance *player, } VG_STATIC void player__skate_transition( player_instance *player, - v3f init_velocity ) + v3f init_velocity, + enum skate_activity init_acitivity ) { struct player_skate *s = &player->_skate; s->state.activity_prev = k_skate_activity_ground; - s->state.activity = k_skate_activity_air; + s->state.activity = init_acitivity; v3f dir; v3_copy( init_velocity, dir ); v3_normalize( dir ); + + vg_info( "init velocity: %f %f %f\n", init_velocity[0], + init_velocity[1], + init_velocity[2] ); q_axis_angle( player->rb.q, (v3f){0.0f,1.0f,0.0f}, atan2f( dir[0], dir[2] ) ); - v3_copy( player->cam.pos, s->state.posl ); - - m3x3f temp; - euler_m3x3( player->cam.angles, temp ); - v3_muls( temp[2], -1.0f, s->state.dirl ); v3_muladds( player->rb.co, player->rb.to_world[1], 1.0f, s->state.cog ); v3_copy( init_velocity, s->state.cog_v ); + v3_copy( init_velocity, s->state.vl ); v3_copy( init_velocity, player->rb.v ); rb_update_transform( &player->rb ); -} + if( init_acitivity == k_skate_activity_air ) + { + player_approximate_best_trajectory( player ); + s->blend_fly = 1.0f; + } + else + s->blend_fly = 0.0f; + + s->blend_slide = 0.0f; + s->blend_z = 0.0f; + s->blend_x = 0.0f; + s->blend_stand = 0.0f; + s->blend_push = 0.0f; + s->blend_jump = 0.0f; + s->blend_airdir = 0.0f; +} #endif /* PLAYER_SKATE_C */ diff --git a/player_skate.h b/player_skate.h index 57922a6..e17e983 100644 --- a/player_skate.h +++ b/player_skate.h @@ -49,8 +49,12 @@ struct player_skate v3f prev_pos; /* FIXME: Sensible names */ + + v3f vl; +#if 0 v3f vl, /* 1st */ posl, dirl; /* 3rd */ +#endif } state, state_gate_storage; @@ -116,6 +120,8 @@ VG_STATIC void player__skate_reset ( player_instance *player, struct respawn_point *rp ); VG_STATIC void player__skate_transition ( player_instance *player, - v3f init_velocity ); + v3f init_velocity, + enum skate_activity init_acitivity + ); #endif /* PLAYER_SKATE_H */ diff --git a/player_walk.c b/player_walk.c index 77386fa..fe74981 100644 --- a/player_walk.c +++ b/player_walk.c @@ -3,29 +3,63 @@ #include "player.h" +VG_STATIC void player_walk_transfer_to_skate( player_instance *player, + enum skate_activity init ) +{ + struct player_walk *w = &player->_walk; + + v3f xy_speed, v; + + v3_copy( player->rb.v, xy_speed ); + xy_speed[1] = 0.0f; + + if( v3_length2( xy_speed ) < 0.1f * 0.1f ) + { + v[0] = -sinf( -w->state.angles[0] ); + v[1] = 0.0f; + v[2] = -cosf( -w->state.angles[0] ); + v3_muls( v, 1.6f, v ); + } + else + v3_copy( player->rb.v, v ); + + player->subsystem = k_player_subsystem_skate; + player__skate_transition( player, v, init ); + return; +} + VG_STATIC void player__walk_pre_update( player_instance *player ) { struct player_walk *w = &player->_walk; player_look( player, w->state.angles ); - if( vg_input_button_down( player->input_use ) ) + if( w->state.outro_anim ) { - v3f xy_speed, v; - v3_copy( player->rb.v, v ); - v3_copy( v, xy_speed ); - xy_speed[1] = 0.0f; + float outro_length = (float)w->state.outro_anim->length / + w->state.outro_anim->rate, + outro_time = vg.time - w->state.outro_start_time; - if( v3_length2( xy_speed ) < 0.1f * 0.1f ) + if( outro_time >= outro_length ) { - v[0] = -sinf( -w->state.angles[0] ); - v[1] = 0.0f; - v[2] = -cosf( -w->state.angles[0] ); - v3_muls( v, 1.6f, v ); + w->state.outro_anim = NULL; + player_walk_transfer_to_skate( player, k_skate_activity_air ); + return; + } + } + else if( vg_input_button_down( player->input_use ) ) + { + if( w->state.activity == k_walk_activity_ground ) + { + player_walk_transfer_to_skate( player, k_skate_activity_ground ); + } + else + { + w->state.outro_anim = w->anim_jump_to_air; + w->state.outro_start_time = vg.time; + v3_copy( player->cam.pos, player->follow_pos ); + v3_copy( player->cam.angles, player->follow_angles ); + return; } - - player->subsystem = k_player_subsystem_skate; - player__skate_transition( player, v ); - return; } } @@ -121,7 +155,6 @@ VG_STATIC void player__walk_update( player_instance *player ) rb_prepare_contact( ct ); } - /* * Move & Friction @@ -320,6 +353,16 @@ VG_STATIC void player__walk_post_update( player_instance *player ) float substep = vg_clampf( vg.accumulator / k_rb_delta, 0.0f, 1.0f ); v3_muladds( mtx[3], player->rb.v, k_rb_delta*substep, mtx[3] ); debug_capsule( mtx, w->collider.radius, w->collider.height, VG__YELOW ); + + + /* Calculate header */ + v3f xy_speed, v; + + v3_copy( player->rb.v, xy_speed ); + xy_speed[1] = 0.0f; + + if( v3_length2( xy_speed ) > 0.1f * 0.1f ) + w->state.heading_angle = atan2f( player->rb.v[0], player->rb.v[2] ); } VG_STATIC void player__walk_animate( player_instance *player, @@ -378,12 +421,36 @@ VG_STATIC void player__walk_animate( player_instance *player, /* air */ skeleton_sample_anim( sk, w->anim_jump, vg.time*0.6f, bpose ); - skeleton_lerp_pose( sk, apose, bpose, w->blend_fly, dest->pose ); + skeleton_lerp_pose( sk, apose, bpose, w->blend_fly, apose ); /* Create transform */ rb_extrapolate( &player->rb, dest->root_co, dest->root_q ); - q_axis_angle( dest->root_q, (v3f){0.0f,1.0f,0.0f}, - -w->state.angles[0]-VG_PIf*0.5f ); + + float walk_yaw = w->state.heading_angle + VG_PIf*0.5f; + + if( w->state.outro_anim ) + { + float outro_length = (float)w->state.outro_anim->length / + w->state.outro_anim->rate, + outro_time = vg.time - w->state.outro_start_time, + outro_t = outro_time / outro_length; + + walk_yaw += -VG_PIf*0.5f*outro_t; + + /* TODO: Compression */ + v3_muladds( dest->root_co, player->rb.to_world[1], + -0.28f * outro_t, dest->root_co ); + + skeleton_sample_anim_clamped( sk, w->state.outro_anim, + outro_time, bpose ); + skeleton_lerp_pose( sk, apose, bpose, outro_t * 10.0f, dest->pose ); + } + else + { + skeleton_copy_pose( sk, apose, dest->pose ); + } + + q_axis_angle( dest->root_q, (v3f){0.0f,1.0f,0.0f}, walk_yaw ); } VG_STATIC void player__walk_post_animate( player_instance *player ) @@ -402,25 +469,50 @@ VG_STATIC void player__walk_post_animate( player_instance *player ) v3_add( player->rb.co, (v3f){0.0f,2.0f,0.0f}, origin ); - v3_muladds( origin, angles[2], 2.0f, player->cam3.co ); - v3_muladds( player->cam3.co, angles[0], 0.5f, player->cam3.co ); + v3_muladds( origin, angles[2], 2.0f, player->override_pos ); + v3_muladds( player->override_pos, angles[0], 0.5f, player->override_pos ); float t; v3f n; - if( spherecast_world( origin, player->cam3.co, 0.1f, &t, n ) != -1 ) - v3_lerp( origin, player->cam3.co, t, player->cam3.co ); - v3_copy( w->state.angles, player->cam3.angles ); + if( spherecast_world( origin, player->override_pos, 0.1f, &t, n ) != -1 ) + v3_lerp( origin, player->override_pos, t, player->override_pos ); + v3_copy( w->state.angles, player->override_angles ); /* 1ST */ /* FIXME: viewpoint entity */ v3f vp = {-0.1f,1.8f,0.0f}; - m4x3_mulv( av->sk.final_mtx[ av->id_head-1 ], vp, player->cam1.co ); - v3_copy( w->state.angles, player->cam1.angles ); + m4x3_mulv( av->sk.final_mtx[ av->id_head-1 ], vp, player->fpv_pos ); + v3_copy( w->state.angles, player->fpv_angles ); /* FIXME: Organize this. Its int wrong fucking place */ v3f vp0 = {0.0f,0.1f, 0.6f}, vp1 = {0.0f,0.1f,-0.6f}; + if( w->state.outro_anim ) + { + float outro_length = (float)w->state.outro_anim->length / + w->state.outro_anim->rate, + outro_time = vg.time - w->state.outro_start_time, + outro_t = outro_time / outro_length; + + /* FIXME: Compression */ + v3_add( player->rb.co, (v3f){0.0f,1.35f,0.0f}, origin ); + player_set_follower_subject( player, origin ); + + player->cam_angles_override_strength = 1.0f-outro_t; + player->cam_position_override_strength = 1.0f-outro_t; + + + v3f fpv_angles; + player_vector_angles( fpv_angles, player->rb.v, 1.0f, 0.25f ); + v3_lerp( player->fpv_angles,fpv_angles, outro_t, player->fpv_angles ); + } + else + { + player->cam_angles_override_strength = 1.0f; + player->cam_position_override_strength = 1.0f; + } + m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp0, TEMP_BOARD_0 ); m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp1, TEMP_BOARD_1 ); } @@ -428,12 +520,26 @@ VG_STATIC void player__walk_post_animate( player_instance *player ) VG_STATIC void player__walk_im_gui( player_instance *player ) { + struct player_walk *w = &player->_walk; player__debugtext( 1, "V: %5.2f %5.2f %5.2f",player->rb.v[0], player->rb.v[1], player->rb.v[2] ); player__debugtext( 1, "CO: %5.2f %5.2f %5.2f",player->rb.co[0], player->rb.co[1], player->rb.co[2] ); + player__debugtext( 1, "activity: %s\n", + (const char *[]){ "k_walk_activity_air", + "k_walk_activity_ground", + "k_walk_activity_sleep" } + [w->state.activity] ); + + if( w->state.outro_anim ) + { + float outro_length = (float)w->state.outro_anim->length / + w->state.outro_anim->rate, + outro_time = vg.time - w->state.outro_start_time; + player__debugtext( 1, "outro time: %f / %f", outro_time, outro_length ); + } } VG_STATIC void player__walk_bind( player_instance *player ) @@ -442,10 +548,11 @@ VG_STATIC void player__walk_bind( player_instance *player ) struct player_avatar *av = player->playeravatar; struct skeleton *sk = &av->sk; - w->anim_idle = skeleton_get_anim( sk, "idle_cycle" ); - w->anim_walk = skeleton_get_anim( sk, "walk" ); - w->anim_run = skeleton_get_anim( sk, "run" ); - w->anim_jump = skeleton_get_anim( sk, "jump" ); + w->anim_idle = skeleton_get_anim( sk, "idle_cycle" ); + w->anim_walk = skeleton_get_anim( sk, "walk" ); + w->anim_run = skeleton_get_anim( sk, "run" ); + w->anim_jump = skeleton_get_anim( sk, "jump" ); + w->anim_jump_to_air = skeleton_get_anim( sk, "jump_to_air" ); } VG_STATIC void player__walk_transition( player_instance *player, v3f angles ) diff --git a/player_walk.h b/player_walk.h index 7a597c3..f1efabc 100644 --- a/player_walk.h +++ b/player_walk.h @@ -10,6 +10,8 @@ struct player_walk struct { v3f angles; + float heading_angle; + v3f prev_pos; enum walk_activity @@ -19,12 +21,16 @@ struct player_walk k_walk_activity_sleep } activity; + + struct skeleton_anim *outro_anim; + double outro_start_time; } state, state_gate_storage; enum mdl_surface_prop surface; - struct skeleton_anim *anim_walk, *anim_run, *anim_idle, *anim_jump; + struct skeleton_anim *anim_walk, *anim_run, *anim_idle, *anim_jump, + *anim_jump_to_air; float blend_fly, blend_run, diff --git a/skeleton.h b/skeleton.h index ad87fd9..c5f59da 100644 --- a/skeleton.h +++ b/skeleton.h @@ -67,7 +67,8 @@ VG_STATIC u32 skeleton_bone_id( struct skeleton *skele, const char *name ) return 0; } -VG_STATIC void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, int num ) +VG_STATIC void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, + int num ) { for( int i=0; ibone_count-1 ); } +VG_STATIC void skeleton_copy_pose( struct skeleton *skele, + mdl_keyframe *kfa, mdl_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 -- 2.25.1