+
+ float walk_yaw = player_get_heading_yaw( player );
+
+ if( w->state.outro_anim )
+ {
+ struct player_avatar *av = player->playeravatar;
+ 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;
+
+ /* TODO: Compression */
+ skeleton_sample_anim_clamped( sk, w->state.outro_anim,
+ outro_time, bpose );
+ skeleton_lerp_pose( sk, apose, bpose, outro_t * 10.0f, dest->pose );
+
+ if( w->state.outro_type == k_walk_outro_drop_in )
+ {
+ float inv_rate = 1.0f / w->state.outro_anim->rate,
+ anim_frames = w->state.outro_anim->length * inv_rate,
+ step_frames = 12.0f * inv_rate,
+ commit_frames = 6.0f * inv_rate,
+ drop_frames = anim_frames - step_frames,
+ step_t = vg_minf( 1.0f, outro_time / step_frames ),
+ remaind_time = vg_maxf( 0.0f, outro_time - step_frames ),
+ dop_t = vg_minf( 1.0f, remaind_time / drop_frames ),
+ commit_t = vg_minf( 1.0f, remaind_time / commit_frames );
+
+ walk_yaw = vg_alerpf( w->state.drop_in_start_angle,
+ w->state.drop_in_angle, step_t );
+
+ v3_lerp( w->state.drop_in_start, w->state.drop_in_target,
+ step_t, player->rb.co );
+ q_axis_angle( dest->root_q, (v3f){0.0f,1.0f,0.0f}, walk_yaw + VG_PIf );
+
+ m4x3f transform, inverse;
+ q_m3x3( dest->root_q, transform );
+ v3_copy( dest->root_co, transform[3] );
+ m4x3_invert_affine( transform, inverse );
+
+ v3f anchored_pos;
+ m4x3_mulv( inverse, w->state.drop_in_foot_anchor, anchored_pos );
+
+ v3_lerp( dest->pose[ av->id_ik_foot_r-1 ].co, anchored_pos,
+ 1.0f-commit_t,
+ dest->pose[ av->id_ik_foot_r-1 ].co );
+
+
+ /* the drop in bit */
+ if( step_t >= 1.0f )
+ {
+ v4f final_q;
+ v3f axis;
+ v3_cross( (v3f){0.0f,1.0f,0.0f}, w->state.drop_in_normal, axis );
+ v3_normalize( axis );
+
+ float a = acosf( w->state.drop_in_normal[1] ) * dop_t;
+
+ q_axis_angle( final_q, axis, a );
+ q_mul( final_q, dest->root_q, dest->root_q );
+
+ float l = dop_t * 0.5f,
+ heading_angle = w->state.drop_in_angle;
+
+ v3f overhang;
+ overhang[0] = sinf( heading_angle ) * l;
+ overhang[1] = 0.28f * l;
+ overhang[2] = cosf( heading_angle ) * l;
+
+ q_mulv( final_q, overhang, overhang );
+
+ v3f overhang_pos;
+ v3_add( w->state.drop_in_target, overhang, player->rb.co );
+ v4_copy( dest->root_q, player->rb.q );
+ v3_muladds( dest->root_co, player->rb.to_world[1],
+ -0.28f * dop_t, dest->root_co );
+
+ skeleton_copy_pose( sk, dest->pose, player->holdout_pose );
+ player->holdout_time = 1.0f;
+ }
+ return;
+ }
+ else
+ {
+ v3_muladds( dest->root_co, player->rb.to_world[1],
+ -0.28f * outro_t, dest->root_co );
+
+ skeleton_copy_pose( sk, dest->pose, player->holdout_pose );
+ player->holdout_time = 1.0f;
+ }
+ }
+ else
+ {
+ skeleton_copy_pose( sk, apose, dest->pose );
+ }
+
+ q_axis_angle( dest->root_q, (v3f){0.0f,1.0f,0.0f}, walk_yaw + VG_PIf );