+ /*
+ * Commit player movement into the grid
+ */
+
+ if( v3_length2(delta) <= 0.00001f )
+ return;
+
+ int i=0;
+ for(; i<8 && wg.move > 0.001f; i++ )
+ player_walkgrid_iter( &wg, i );
+
+ player_walkgrid_stand_cell( &wg );
+}
+
+static void player_walkgrid(void)
+{
+ player_walkgrid_getsurface();
+
+ m4x3_mulv( player.rb.to_world, (v3f){0.0f,1.8f,0.0f}, player.camera_pos );
+ player_mouseview();
+ rb_update_transform( &player.rb );
+}
+
+/*
+ * Animation
+ */
+
+static void player_animate(void)
+{
+ /* Camera position */
+ v3_sub( player.rb.v, player.v_last, player.a );
+ v3_copy( player.rb.v, player.v_last );
+
+ v3_add( player.m, player.a, player.m );
+ v3_lerp( player.m, (v3f){0.0f,0.0f,0.0f}, 0.1f, player.m );
+
+ player.m[0] = vg_clampf( player.m[0], -2.0f, 2.0f );
+ player.m[1] = vg_clampf( player.m[1], -2.0f, 2.0f );
+ player.m[2] = vg_clampf( player.m[2], -2.0f, 2.0f );
+ v3_lerp( player.bob, player.m, 0.2f, player.bob );
+
+ /* Head */
+ float lslip = fabsf(player.slip);
+
+ float kheight = 2.0f,
+ kleg = 0.6f;
+
+ v3f offset;
+ v3_zero( offset );
+ m3x3_mulv( player.rb.to_local, player.bob, offset );
+
+ static float speed_wobble = 0.0f, speed_wobble_2 = 0.0f;
+
+ float kickspeed = vg_clampf(v3_length(player.rb.v)*(1.0f/40.0f), 0.0f, 1.0f);
+ float kicks = (vg_randf()-0.5f)*2.0f*kickspeed;
+ float sign = vg_signf( kicks );
+ speed_wobble = vg_lerpf( speed_wobble, kicks*kicks*sign, 0.1f );
+ speed_wobble_2 = vg_lerpf( speed_wobble_2, speed_wobble, 0.04f );
+
+ offset[0] *= 0.26f;
+ offset[0] += speed_wobble_2*3.0f;
+
+ offset[1] *= -0.3f;
+ offset[2] *= 0.01f;
+
+ offset[0] = vg_clampf( offset[0], -0.8f, 0.8f );
+ offset[1] = vg_clampf( offset[1], -0.5f, 0.0f );
+ offset[1] = 0.0f;
+
+ /*
+ * Animation blending
+ * ===========================================
+ */
+
+ /* scalar blending information */
+ float speed = v3_length( player.rb.v );
+
+ /* sliding */
+ {
+ float desired = vg_clampf( lslip, 0.0f, 1.0f );
+ player.fslide = vg_lerpf( player.fslide, desired, 0.04f );
+ }
+
+ /* movement information */
+ {
+ float dirz = player.reverse > 0.0f? 0.0f: 1.0f,
+ dirx = player.slip < 0.0f? 0.0f: 1.0f,
+ fly = player.in_air? 1.0f: 0.0f;
+
+ player.fdirz = vg_lerpf( player.fdirz, dirz, 0.04f );
+ player.fdirx = vg_lerpf( player.fdirx, dirx, 0.01f );
+ player.ffly = vg_lerpf( player.ffly, fly, 0.04f );
+ }
+
+ struct skeleton *sk = &player.mdl.sk;
+
+ mdl_keyframe apose[32], bpose[32];
+ mdl_keyframe ground_pose[32];
+ {
+ /* when the player is moving fast he will crouch down a little bit */
+ float stand = 1.0f - vg_clampf( speed * 0.03f, 0.0f, 1.0f );
+ player.fstand = vg_lerpf( player.fstand, stand, 0.1f );
+
+ /* stand/crouch */
+ float dir_frame = player.fdirz * (15.0f/30.0f),
+ stand_blend = offset[1]*-2.0f;
+
+ skeleton_sample_anim( sk, player.mdl.anim_stand, dir_frame, apose );
+ skeleton_sample_anim( sk, player.mdl.anim_highg, dir_frame, bpose );
+ skeleton_lerp_pose( sk, apose, bpose, stand_blend, apose );
+
+ /* sliding */
+ float slide_frame = player.fdirx * (15.0f/30.0f);
+ skeleton_sample_anim( sk, player.mdl.anim_slide, slide_frame, bpose );
+ skeleton_lerp_pose( sk, apose, bpose, player.fslide, apose );
+
+ /* pushing */
+ player.fpush = vg_lerpf( player.fpush, player.pushing, 0.1f );
+
+ float pt = player.push_time;
+ if( player.reverse > 0.0f )
+ skeleton_sample_anim( sk, player.mdl.anim_push, pt, bpose );
+ else
+ skeleton_sample_anim( sk, player.mdl.anim_push_reverse, pt, bpose );
+
+ skeleton_lerp_pose( sk, apose, bpose, player.fpush, apose );
+
+ /* trick setup */
+ float setup_frame = player.jump * (12.0f/30.0f),
+ setup_blend = vg_minf( player.jump*5.0f, 1.0f );
+
+ float jump_frame = (vg_time - player.jump_time) + (12.0f/30.0f);
+ if( jump_frame >= (12.0f/30.0f) && jump_frame <= (40.0f/30.0f) )
+ setup_frame = jump_frame;
+
+ skeleton_sample_anim_clamped( sk, player.mdl.anim_ollie,
+ setup_frame, bpose );
+ skeleton_lerp_pose( sk, apose, bpose, setup_blend, ground_pose );
+ }
+
+ 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, air_pose );
+ }
+
+ skeleton_lerp_pose( sk, ground_pose, air_pose, player.ffly, apose );
+
+ /* additive effects */
+ apose[player.mdl.id_hip-1].co[0] += offset[0];
+ apose[player.mdl.id_hip-1].co[2] += offset[2];
+ apose[player.mdl.id_ik_hand_l-1].co[0] += offset[0];
+ apose[player.mdl.id_ik_hand_l-1].co[2] += offset[2];
+ apose[player.mdl.id_ik_hand_r-1].co[0] += offset[0];
+ apose[player.mdl.id_ik_hand_r-1].co[2] += offset[2];
+ apose[player.mdl.id_ik_elbow_l-1].co[0] += offset[0];
+ apose[player.mdl.id_ik_elbow_l-1].co[2] += offset[2];
+ apose[player.mdl.id_ik_elbow_r-1].co[0] += offset[0];
+ apose[player.mdl.id_ik_elbow_r-1].co[2] += offset[2];
+
+ 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)
+{