+ 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;
+
+ if( ray_world( sample, (v3f){0.0f,-1.0f,0.0f}, &hit ))
+ v3_add( hit.pos, min_height, player.camera_pos );
+
+ player.camera_pos[1] =
+ vg_maxf( wrender.height + 2.0f, player.camera_pos[1] );
+
+ player.angles[0] = atan2f( delta[0], -delta[2] );
+ player.angles[1] = -asinf( delta[1] );
+}
+
+static void player_animate_camera(void)
+{
+ static v3f lerp_cam = {0.0f,0.0f,0.0f};
+ v3f cam_pos;
+
+ player.fonboard = vg_lerpf(player.fonboard, player.on_board, ktimestep*1.0f);
+
+ if( player.on_board )
+ {
+ v3f offs = { -0.4f, 0.15f, 0.0f };
+ v3_lerp( lerp_cam, player.mdl.cam_pos, 0.8f, lerp_cam );
+ v3_add( lerp_cam, offs, cam_pos );
+
+ /* Look angles */
+ v3_lerp( player.vl, player.rb.v, 0.05f, player.vl );
+
+ float yaw = atan2f( player.vl[0], -player.vl[2] ),
+ pitch = atan2f( -player.vl[1],
+ sqrtf(
+ player.vl[0]*player.vl[0] + player.vl[2]*player.vl[2]
+ )) * 0.7f;
+
+ player.angles[0] = yaw;
+ player.angles[1] = vg_lerpf( player.angles[1], pitch + 0.30f,
+ player.fonboard );
+
+ /* Camera shake */
+ static v2f shake_damp = {0.0f,0.0f};
+ v2f shake = { vg_randf()-0.5f, vg_randf()-0.5f };
+ v2_muls( shake, v3_length(player.rb.v)*0.3f
+ * (1.0f+fabsf(player.slip)), shake);
+
+ v2_lerp( shake_damp, shake, 0.01f, shake_damp );
+ shake_damp[0] *= 0.2f;
+
+ v2_muladds( player.angles, shake_damp, 0.1f, player.angles );
+ m4x3_mulv( player.rb.to_world, cam_pos, player.camera_pos );
+ }
+ else