+ 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.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.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 );
+
+
+ float Fd = -player->cam_land_punch_v * k_cam_damp,
+ Fs = -player->cam_land_punch * k_cam_spring;
+ player->cam_land_punch += player->cam_land_punch_v * vg.frame_delta;
+ player->cam_land_punch_v += ( Fd + Fs ) * vg.frame_delta;
+ player->cam.angles[1] += player->cam_land_punch;
+
+ /* portal transitions */
+ player_camera_portal_correction( player );