+ mdl_keyframe air_pose[32];
+ {
+ float target = -vg_get_axis("horizontal");
+ player.fairdir = vg_lerpf( player.fairdir, target, 0.04f );
+
+ float air_frame = (player.fairdir*0.5f+0.5f) * (15.0f/30.0f);
+
+ skeleton_sample_anim( sk, player.mdl.anim_air, air_frame, apose );
+
+ static v2f grab_choice;
+ v2_lerp( grab_choice, (v2f){ vg_get_axis("h1"), vg_get_axis("v1") },
+ 0.04f, grab_choice );
+
+ float ang = atan2f( grab_choice[0], grab_choice[1] ),
+ ang_unit = (ang+VG_PIf) * (1.0f/VG_TAUf),
+ grab_frame = ang_unit * (15.0f/30.0f);
+
+ skeleton_sample_anim( sk, player.mdl.anim_grabs, grab_frame, bpose );
+ skeleton_lerp_pose( sk, apose, bpose, player.grab, air_pose );
+ }
+
+ skeleton_lerp_pose( sk, ground_pose, air_pose, player.ffly, apose );
+
+ float add_grab_mod = player.ffly * player.grab;
+
+ /* additive effects */
+ apose[player.mdl.id_hip-1].co[0] += offset[0]*add_grab_mod;
+ apose[player.mdl.id_hip-1].co[2] += offset[2]*add_grab_mod;
+ apose[player.mdl.id_ik_hand_l-1].co[0] += offset[0]*add_grab_mod;
+ apose[player.mdl.id_ik_hand_l-1].co[2] += offset[2]*add_grab_mod;
+ apose[player.mdl.id_ik_hand_r-1].co[0] += offset[0]*add_grab_mod;
+ apose[player.mdl.id_ik_hand_r-1].co[2] += offset[2]*add_grab_mod;
+ apose[player.mdl.id_ik_elbow_l-1].co[0] += offset[0]*add_grab_mod;
+ apose[player.mdl.id_ik_elbow_l-1].co[2] += offset[2]*add_grab_mod;
+ apose[player.mdl.id_ik_elbow_r-1].co[0] += offset[0]*add_grab_mod;
+ apose[player.mdl.id_ik_elbow_r-1].co[2] += offset[2]*add_grab_mod;
+
+ skeleton_apply_pose( &player.mdl.sk, apose, k_anim_apply_defer_ik );
+ skeleton_apply_ik_pass( &player.mdl.sk );
+ skeleton_apply_pose( &player.mdl.sk, apose, k_anim_apply_deffered_only );
+
+ v3_copy( player.mdl.sk.final_mtx[player.mdl.id_head-1][3],
+ player.mdl.cam_pos );
+ skeleton_apply_inverses( &player.mdl.sk );
+ skeleton_apply_transform( &player.mdl.sk, player.rb.to_world );
+
+ skeleton_debug( &player.mdl.sk );
+}
+
+static void player_camera_update(void)
+{
+ /* Update camera matrices */
+ m4x3_identity( player.camera );
+ m4x3_rotate_y( player.camera, -player.angles[0] );
+ m4x3_rotate_x( player.camera, -player.angles[1] );
+ v3_copy( player.camera_pos, player.camera[3] );
+ m4x3_invert_affine( player.camera, player.camera_inverse );
+}
+
+static void player_animate_death_cam(void)
+{
+ v3f delta;
+ v3f head_pos;
+ v3_copy( player.mdl.ragdoll[0].rb.co, head_pos );
+
+ v3_sub( head_pos, player.camera_pos, delta );
+ v3_normalize( delta );
+
+ v3f follow_pos;
+ v3_muladds( head_pos, delta, -2.5f, follow_pos );
+ v3_lerp( player.camera_pos, follow_pos, 0.1f, player.camera_pos );
+
+ /*
+ * Make sure the camera stays above the ground
+ */
+ v3f min_height = {0.0f,1.0f,0.0f};
+
+ v3f sample;
+ v3_add( player.camera_pos, min_height, sample );
+ ray_hit hit;
+ hit.dist = min_height[1]*2.0f;