+ player->cam_velocity_constant = 0.25f;
+ player->cam_velocity_coefficient = 0.7f;
+
+ /* lerping */
+
+ player->cam_velocity_influence_smooth = vg_lerpf(
+ player->cam_velocity_influence_smooth,
+ player->cam_velocity_influence,
+ vg.time_frame_delta * 8.0f );
+
+ player->cam_velocity_coefficient_smooth = vg_lerpf(
+ player->cam_velocity_coefficient_smooth,
+ player->cam_velocity_coefficient,
+ vg.time_frame_delta * 8.0f );
+
+ player->cam_velocity_constant_smooth = vg_lerpf(
+ player->cam_velocity_constant_smooth,
+ player->cam_velocity_constant,
+ vg.time_frame_delta * 8.0f );
+
+ enum camera_mode target_mode = player->camera_mode;
+
+ if( player->subsystem == k_player_subsystem_dead )
+ target_mode = k_cam_thirdperson;
+
+ player->camera_type_blend =
+ vg_lerpf( player->camera_type_blend,
+ (target_mode == k_cam_firstperson)? 1.0f: 0.0f,
+ 5.0f * vg.time_frame_delta );
+
+ v3_lerp( player->fpv_viewpoint_smooth, player->fpv_viewpoint,
+ vg.time_frame_delta * 8.0f, player->fpv_viewpoint_smooth );
+
+ v3_lerp( player->fpv_offset_smooth, player->fpv_offset,
+ vg.time_frame_delta * 8.0f, player->fpv_offset_smooth );
+
+ v3_lerp( player->tpv_offset_smooth, player->tpv_offset,
+ vg.time_frame_delta * 8.0f, player->tpv_offset_smooth );
+
+ /* fov -- simple blend */
+ float fov_skate = vg_lerpf( 97.0f, 135.0f, cl_fov ),
+ fov_walk = vg_lerpf( 90.0f, 110.0f, cl_fov );
+
+ player->cam.fov = vg_lerpf( fov_walk, fov_skate, player->camera_type_blend );
+
+ /*
+ * first person camera
+ */
+
+ /* position */
+ v3f fpv_pos, fpv_offset;
+ m4x3_mulv( av->sk.final_mtx[ av->id_head-1 ],
+ player->fpv_viewpoint_smooth, fpv_pos );
+ m3x3_mulv( player->rb.to_world, player->fpv_offset_smooth, fpv_offset );
+ v3_add( fpv_offset, fpv_pos, fpv_pos );
+
+ /* angles */
+ v3f velocity_angles;
+ v3_lerp( player->cam_velocity_smooth, player->rb.v, 4.0f*vg.time_frame_delta,
+ player->cam_velocity_smooth );
+
+ v3f velocity_local;
+ m3x3_mulv( player->invbasis, player->cam_velocity_smooth, velocity_local );
+ player_vector_angles( velocity_angles, velocity_local,
+ player->cam_velocity_coefficient_smooth,
+ player->cam_velocity_constant_smooth );
+
+ float inf_fpv = player->cam_velocity_influence_smooth *
+ player->camera_type_blend,
+ inf_tpv = player->cam_velocity_influence_smooth *
+ (1.0f-player->camera_type_blend);
+
+ camera_lerp_angles( player->angles, velocity_angles,
+ inf_fpv,
+ player->angles );
+
+ /*
+ * Third person camera
+ */
+
+ /* no idea what this technique is called, it acts like clamped position based
+ * on some derivative of where the final camera would end up ....
+ *
+ * it is done in the local basis then transformed back */
+
+ v3f future;
+ v3_muls( player->rb.v, 0.4f*vg.time_frame_delta, future );
+ m3x3_mulv( player->invbasis, future, future );
+
+ v3f camera_follow_dir =
+ { -sinf( player->angles[0] ) * cosf( player->angles[1] ),
+ sinf( player->angles[1] ),
+ cosf( player->angles[0] ) * cosf( player->angles[1] ) };
+
+ v3f v0;
+ v3_sub( camera_follow_dir, future, v0 );
+
+ v3f follow_angles;
+ v3_copy( player->angles, follow_angles );
+ follow_angles[0] = atan2f( -v0[0], v0[2] );
+ follow_angles[1] = 0.3f + velocity_angles[1] * 0.2f;
+
+ float ya = atan2f( -velocity_local[1], 30.0f );
+
+ follow_angles[1] = 0.3f + ya;
+ camera_lerp_angles( player->angles, follow_angles,
+ inf_tpv,
+ player->angles );
+
+ v3f pco;
+ v4f pq;
+ rb_extrapolate( &player->rb, pco, pq );
+ v3_lerp( player->tpv_lpf, pco, 20.0f*vg.time_frame_delta, player->tpv_lpf );
+
+ /* now move into world */
+
+ m3x3_mulv( player->basis, camera_follow_dir, camera_follow_dir );
+ v3f tpv_pos, tpv_offset;
+
+ v3_muladds( player->tpv_lpf, camera_follow_dir, 1.8f, tpv_pos );
+ q_mulv( pq, player->tpv_offset_smooth, tpv_offset );
+ v3_add( tpv_offset, tpv_pos, tpv_pos );
+ v3_muladds( tpv_pos, player->cam_velocity_smooth, -0.025f, tpv_pos );
+
+ /*
+ * Blend cameras
+ */
+ v3_lerp( tpv_pos, fpv_pos, player->camera_type_blend, player->cam.pos );
+ v3_copy( player->angles, player->cam.angles );
+
+ /* Camera shake */
+ f32 speed = v3_length(player->rb.v),
+ strength = k_cam_shake_strength * speed;
+ player->cam_trackshake += speed*k_cam_shake_trackspeed*vg.time_frame_delta;
+
+ v2f rnd = {perlin1d( player->cam_trackshake, 1.0f, 4, 20 ),
+ perlin1d( player->cam_trackshake, 1.0f, 4, 63 ) };
+ v2_muladds( player->cam.angles, rnd, strength, player->cam.angles );
+
+ v3f Fd, Fs, F;
+ v3_muls( player->cam_land_punch_v, -k_cam_damp, Fd );
+ v3_muls( player->cam_land_punch, -k_cam_spring, Fs );
+ v3_muladds( player->cam_land_punch, player->cam_land_punch_v,
+ vg.time_frame_delta, player->cam_land_punch );
+ v3_add( Fd, Fs, F );
+ v3_muladds( player->cam_land_punch_v, F, vg.time_frame_delta,
+ player->cam_land_punch_v );
+ v3_add( player->cam_land_punch, player->cam.pos, player->cam.pos );
+
+ /* override camera */
+ player->cam.angles[0] =
+ vg_alerpf( player->cam.angles[0], player->cam_override_angles[0],
+ player->cam_override_strength );
+ player->cam.angles[1] =
+ vg_lerpf ( player->cam.angles[1], player->cam_override_angles[1],
+ player->cam_override_strength );
+ v3_lerp( player->cam.pos, player->cam_override_pos,
+ player->cam_override_strength, player->cam.pos );
+ player->cam.fov = vg_lerpf( player->cam.fov, player->cam_override_fov,
+ player->cam_override_strength );
+
+ /* portal transitions */
+ player_camera_portal_correction( player );
+}
+
+VG_STATIC void player_look( player_instance *player, v3f angles )
+{
+ if( vg_ui.wants_mouse ) return;
+
+ float sensitivity = 1.0f-menu.factive;
+
+ angles[2] = 0.0f;
+
+ v2f mouse_input;
+ v2_copy( vg.mouse_delta, mouse_input );
+ if( cl_invert_y ) mouse_input[1] *= -1.0f;
+ v2_muladds( angles, mouse_input, 0.0025f * sensitivity, angles );
+
+ v2f jlook;
+ joystick_state( k_srjoystick_look, jlook );
+
+ angles[0] += jlook[0] * vg.time_delta * 4.0f * sensitivity;
+ float input_y = jlook[1] * vg.time_delta * 4.0f;
+ if( cl_invert_y ) input_y *= -1.0f;
+
+ angles[1] += input_y * sensitivity;