#ifndef PLAYER_H
#define PLAYER_H
+#define PLAYER_REWIND_FRAMES 60*4
+
#include "audio.h"
#include "common.h"
#include "world.h"
m4x3f visual_transform,
inv_visual_transform;
- int is_dead, death_tick_allowance;
+ int is_dead, death_tick_allowance, rewinding;
v3f land_target;
v3f land_target_log[22];
v3f camera_pos, smooth_localcam;
v2f angles;
+ struct rewind_frame
+ {
+ v3f pos;
+ v2f ang;
+ }
+ *rewind_buffer;
+ u32 rewind_incrementer,
+ rewind_length;
+
+ float rewind_time;
+
/* animation */
double jump_time;
float fslide,
static float *player_cam_pos(void);
static void player_save_frame(void);
static void player_restore_frame(void);
+static void player_save_rewind_frame(void);
/*
* Submodules
.function = reset_player
});
+ player.rewind_length = 0;
+ player.rewind_buffer = vg_alloc( sizeof(struct rewind_frame)
+ * PLAYER_REWIND_FRAMES );
+
/* other systems */
vg_loader_highwater( player_model_init, player_model_free, NULL );
}
+static void player_save_rewind_frame(void)
+{
+ if( player.rewind_length < PLAYER_REWIND_FRAMES )
+ {
+ struct rewind_frame *fr =
+ &player.rewind_buffer[ player.rewind_length ++ ];
+
+ v2_copy( player.angles, fr->ang );
+ v3_copy( player.camera_pos, fr->pos );
+
+ player.rewind_incrementer = 0;
+ }
+}
+
/* Deal with input etc */
static void player_update_pre(void)
{
struct player_phys *phys = &player.phys;
+ if( player.rewinding )
+ {
+ return;
+ }
+
if( vg_get_button_down( "reset" ) )
{
+ player.rewinding = 1;
+ player.rewind_time = (float)player.rewind_length - 0.0001f;
+ player_save_rewind_frame();
+
player.is_dead = 0;
player.death_tick_allowance = 30;
player_restore_frame();
player.mdl.shoes[1] = 1;
world_routes_notify_reset();
+
+ /* apply 1 frame of movement */
+ player_do_motion();
}
if( vg_get_button_down( "switchmode" ) )
static void player_update_fixed(void) /* 2 */
{
+ if( player.rewinding )
+ return;
+
if( player.death_tick_allowance )
player.death_tick_allowance --;
}
else
{
+ player.rewind_incrementer ++;
+
+ if( player.rewind_incrementer > (u32)(0.25/VG_TIMESTEP_FIXED) )
+ {
+ player_save_rewind_frame();
+ }
+
player_do_motion();
}
}
if( freecam )
player_freecam();
+
/* CAMERA POSITIONING: LAYER 0 */
v2_copy( player.angles, camera_angles );
v3_copy( player.camera_pos, camera_pos );
- camera_update();
+ if( player.rewinding )
+ {
+ if( player.rewind_time <= 0.0f )
+ {
+ player.rewinding = 0;
+ player.rewind_length = 1;
+ }
+ else
+ {
+ assert( player.rewind_length > 0 );
+
+ v2f override_angles;
+ v3f override_pos;
+
+ float budget = vg.time_delta,
+ overall_length = player.rewind_length*0.25f;
+
+ for( int i=0; (i<10)&&(player.rewind_time>0.0f)&&(budget>0.0f); i ++ )
+ {
+ /* Interpolate frames */
+ int i0 = floorf( player.rewind_time ),
+ i1 = VG_MIN( i0+1, player.rewind_length-1 );
+
+ struct rewind_frame *fr = &player.rewind_buffer[i0],
+ *fr1 = &player.rewind_buffer[i1];
+
+ float dist = vg_maxf( v3_dist( fr->pos, fr1->pos ), 0.001f ),
+ subl = vg_fractf( player.rewind_time ) + 0.001f,
+
+#if 0
+ speed=sqrtf(player.rewind_time*player.rewind_time+11.0f)*3.0f,
+#else
+ speed = (3.0f-(1.0f/(0.4f+0.4f*player.rewind_time)))*28.0f,
+#endif
+ mod = speed * (budget / dist),
+
+ advl = vg_minf( mod, subl ),
+ advt = (advl / mod) * budget;
+
+ player.rewind_time -= advl;
+ budget -= advt;
+ }
+
+ player.rewind_time = vg_maxf( 0.0f, player.rewind_time );
+
+ int i0 = floorf( player.rewind_time ),
+ i1 = VG_MIN( i0+1, player.rewind_length-1 );
+
+ struct rewind_frame *fr = &player.rewind_buffer[i0],
+ *fr1 = &player.rewind_buffer[i1];
+
+ float sub = vg_fractf(player.rewind_time);
+
+ v3_lerp( fr->pos, fr1->pos, sub, override_pos );
+ override_angles[0] = vg_alerpf( fr->ang[0], fr1->ang[0], sub );
+ override_angles[1] = vg_lerpf ( fr->ang[1], fr1->ang[1], sub );
+
+ /* CAMERA POSITIONING: LAYER 1 */
+ float blend = (4.0f-player.rewind_time) * 0.25f,
+ c = vg_clampf( blend, 0.0f, 1.0f );
+
+ camera_angles[0] = vg_alerpf(override_angles[0], player.angles[0], c);
+ camera_angles[1] = vg_lerpf (override_angles[1], player.angles[1], c);
+ v3_lerp( override_pos, player.camera_pos, c, camera_pos );
+ }
+ }
+
+ camera_update();
player_audio();
}