#include "player_dead.h"
#include "player_glide.h"
-struct replay_globals player_replay;
+struct replay_globals player_replay =
+{
+ .active_keyframe = -1
+};
void replay_clear( replay_buffer *replay )
{
data_table[ k_replay_framedata_gamestate ][1] = gamestate_size;
data_table[ k_replay_framedata_sfx ][1] = sfx_count*sizeof(struct net_sfx);
data_table[ k_replay_framedata_internal_gamestate ][1] = 0;
- if( gamestate_size ){
+ if( gamestate_size )
+ {
data_table[ k_replay_framedata_internal_gamestate ][1] =
sizeof( replay_gamestate );
}
data_table[ k_replay_framedata_glider ][1] = 0;
- if( save_glider ){
+ if( save_glider )
+ {
data_table[ k_replay_framedata_glider ][1] =
sizeof(struct replay_glider_data);
}
u32 nextsize = replay_frame_calculate_data_offsets( data_table );
replay_frame *frame = NULL;
- if( replay->head ){
+ if( replay->head )
+ {
u32 headsize = replay->head->total_size,
nextpos = ((void *)replay->head - replay->data) + headsize;
- if( nextpos + nextsize > replay->size ){
+ if( nextpos + nextsize > replay->size )
+ {
nextpos = 0;
/* maintain contiguity */
- while( replay->tail ){
+ while( replay->tail )
+ {
if( (void *)replay->tail - replay->data )
replay_tailpop( replay );
else break;
check_again:;
u32 tailpos = (void *)replay->tail - replay->data;
- if( tailpos >= nextpos ){
- if( nextpos + nextsize > tailpos ){
+ if( tailpos >= nextpos )
+ {
+ if( nextpos + nextsize > tailpos )
+ {
replay_tailpop( replay );
if( replay->tail )
else
frame = replay->data;
- for( u32 i=0; i<k_replay_framedata_rows; i++ ){
+ for( u32 i=0; i<k_replay_framedata_rows; i++ )
+ {
frame->data_table[i][0] = data_table[i][0];
frame->data_table[i][1] = data_table[i][1];
}
replay_frame *frame = replay->cursor_frame;
if( !frame ) return 0.0f;
replay_frame *next = frame->r;
- if( next ){
+ if( next )
+ {
f64 l = next->time - frame->time,
t = (l <= (1.0/128.0))? 0.0: (replay->cursor - frame->time) / l;
return vg_clampf( t, 0.0f, 1.0f );
void replay_get_frame_camera( replay_frame *frame, vg_camera *cam )
{
- cam->fov = frame->cam_fov;
- v3_copy( frame->cam_pos, cam->pos );
- v3_copy( frame->cam_angles, cam->angles );
+ cam->fov = frame->cam.fov;
+ v3_copy( frame->cam.pos, cam->pos );
+ v3_copy( frame->cam.angles, cam->angles );
}
void replay_get_camera( replay_buffer *replay, vg_camera *cam )
{
cam->nearz = 0.1f;
cam->farz = 100.0f;
- if( replay->cursor_frame ){
+ if( replay->cursor_frame )
+ {
replay_frame *next = replay->cursor_frame->r;
- if( next ){
+ if( next )
+ {
vg_camera temp;
replay_get_frame_camera( replay->cursor_frame, cam );
replay_get_frame_camera( next, &temp );
vg_camera_lerp( cam, &temp, replay_subframe_time( replay ), cam );
}
- else {
+ else
+ {
replay_get_frame_camera( replay->cursor_frame, cam );
}
}
- else {
+ else
+ {
v3_zero( cam->pos );
v3_zero( cam->angles );
cam->fov = 90.0f;
}
}
-struct replay_rb{
+void skaterift_get_replay_cam( vg_camera *cam )
+{
+ replay_buffer *replay = &player_replay.local;
+
+ if( player_replay.active_keyframe != -1 )
+ {
+ replay_keyframe *kf =
+ &player_replay.keyframes[player_replay.active_keyframe];
+
+ v3_copy( kf->cam.pos, cam->pos );
+ v3_copy( kf->cam.angles, cam->angles );
+ cam->fov = kf->cam.fov;
+ return;
+ }
+
+ if( player_replay.keyframe_count >= 2 )
+ {
+ for( u32 i=0; i<player_replay.keyframe_count-1; i ++ )
+ {
+ replay_keyframe *kf = &player_replay.keyframes[i];
+
+ if( (kf[0].time<=replay->cursor) && (kf[1].time>replay->cursor) )
+ {
+ f64 l = kf[1].time - kf[0].time,
+ t = (l <= (1.0/128.0))? 0.0: (replay->cursor-kf[0].time) / l;
+
+ if( player_replay.keyframe_count >= 3 )
+ {
+ f32 m_start = 0.5f, m_end = 0.5f;
+
+ if( i > 0 )
+ {
+ if( (t < 0.5f) || (i==player_replay.keyframe_count-2) )
+ {
+ kf --;
+ }
+ }
+
+ u32 last = player_replay.keyframe_count-1;
+ if( kf+0 == player_replay.keyframes ) m_start = 1.0f;
+ if( kf+2 == player_replay.keyframes+last ) m_end = 1.0f;
+
+ f32 ts = vg_lerpf( kf[0].time, kf[1].time, 1.0f-m_start ),
+ te = vg_lerpf( kf[1].time, kf[2].time, m_end );
+
+ l = te-ts;
+ t = (replay->cursor-ts)/l;
+
+ f32 t0 = t*m_start+(1.0f-m_start),
+ t1 = t*m_end;
+
+ v3f ps, pe, as, ae;
+ f32 fs, fe;
+
+ /* first order */
+ v3_lerp( kf[0].cam.pos, kf[1].cam.pos, t0, ps );
+ vg_camera_lerp_angles( kf[0].cam.angles, kf[1].cam.angles,
+ t0, as );
+ fs = vg_lerpf( kf[0].cam.fov, kf[1].cam.fov, t0 );
+
+ v3_lerp( kf[1].cam.pos, kf[2].cam.pos, t1, pe );
+ vg_camera_lerp_angles( kf[1].cam.angles, kf[2].cam.angles,
+ t1, ae );
+ fe = vg_lerpf( kf[1].cam.fov, kf[2].cam.fov, t1 );
+
+ /* second order */
+ v3_lerp( ps, pe, t, cam->pos );
+ vg_camera_lerp_angles( as, ae, t, cam->angles );
+ cam->fov = vg_lerpf( fs, fe, t );
+ }
+ else
+ {
+ v3_lerp( kf[0].cam.pos, kf[1].cam.pos, t, cam->pos );
+ vg_camera_lerp_angles( kf[0].cam.angles, kf[1].cam.angles,
+ t, cam->angles );
+ cam->fov = vg_lerpf( kf[0].cam.fov, kf[1].cam.fov, t );
+ }
+ return;
+ }
+ }
+ }
+
+ replay_get_camera( replay, cam );
+}
+
+struct replay_rb
+{
v3f co, v, w;
v4f q;
};
frame->time = vg.time;
/* camera */
- v3_copy( localplayer.cam.pos, frame->cam_pos );
+ v3_copy( localplayer.cam.pos, frame->cam.pos );
if( localplayer.gate_waiting ){
m4x3_mulv( localplayer.gate_waiting->transport,
- frame->cam_pos, frame->cam_pos );
+ frame->cam.pos, frame->cam.pos );
v3f v0;
v3_angles_vector( localplayer.cam.angles, v0 );
m3x3_mulv( localplayer.gate_waiting->transport, v0, v0 );
- v3_angles( v0, frame->cam_angles );
+ v3_angles( v0, frame->cam.angles );
}
else
- v3_copy( localplayer.cam.angles, frame->cam_angles );
+ v3_copy( localplayer.cam.angles, frame->cam.angles );
- frame->cam_fov = localplayer.cam.fov;
+ frame->cam.fov = localplayer.cam.fov;
/* animator */
void *dst = replay_frame_data( frame, k_replay_framedata_animator ),
memcpy( &player_glide.rb, &gs->glider_rb, sizeof(rigidbody) );
v3_copy( gs->angles, localplayer.angles );
- v3_copy( frame->cam_pos, localplayer.cam.pos );
- v3_copy( frame->cam_angles, localplayer.cam.angles );
- localplayer.cam.fov = frame->cam_fov;
+ v3_copy( frame->cam.pos, localplayer.cam.pos );
+ v3_copy( frame->cam.angles, localplayer.cam.angles );
+ localplayer.cam.fov = frame->cam.fov;
memcpy( &localplayer.cam_control, &gs->cam_control,
sizeof(struct player_cam_controller) );
else {
if( button_down( k_srbind_replay_play ) )
player_replay.replay_control = k_replay_control_play;
- if( button_down( k_srbind_replay_freecam ) ){
- player_replay.freecam = player_replay.freecam ^ 0x1;
+ if( button_down( k_srbind_replay_freecam ) )
+ {
+ player_replay.use_freecam ^= 0x1;
- if( player_replay.freecam )
+ if( player_replay.use_freecam )
+ {
replay_get_camera( &player_replay.local,
&player_replay.replay_freecam );
+ }
skaterift_replay_update_helpers();
}
gui_helper_clear();
}
- if( player_replay.freecam ){
- //freecam_preupdate();
+ if( player_replay.use_freecam )
+ {
+ freecam_preupdate();
}
- else {
- if( button_down( k_srbind_replay_resume ) ){
+ else
+ {
+ if( button_down( k_srbind_replay_resume ) )
+ {
skaterift_replay_resume();
}
}
}
}
-static void skaterift_replay_update_helpers(void){
- player_replay.helper_resume->greyed = player_replay.freecam;
+static void skaterift_replay_update_helpers(void)
+{
+ player_replay.helper_resume->greyed = player_replay.use_freecam;
vg_str freecam_text;
vg_strnull( &freecam_text, player_replay.helper_freecam->text,
GUI_HELPER_TEXT_LENGTH );
- vg_strcat( &freecam_text, player_replay.freecam? "exit freecam": "freecam" );
+ vg_strcat( &freecam_text,
+ player_replay.use_freecam? "exit freecam": "freecam" );
}
void skaterift_replay_post_render(void)
}
}
+void skaterift_replay_init(void)
+{
+ u32 bytes = 1024*1024*10;
+ player_replay.local.data = vg_linear_alloc( vg_mem.rtmemory, bytes );
+ player_replay.local.size = bytes;
+ replay_clear( &player_replay.local );
+
+ vg_console_reg_var( "replay_editor", &player_replay.editor_mode,
+ k_var_dtype_i32, VG_VAR_PERSISTENT );
+}
+
void skaterift_replay_debug_info(void)
{
player__debugtext( 2, "replay info" );
player__debugtext( 1, "cursor: %.2fs / %.2fs\n", cur, len );
}
+static int _keyframe_cmp( const void *p1, const void *p2 )
+{
+ const replay_keyframe *kf1 = p1, *kf2 = p2;
+ return kf1->time > kf2->time;
+}
+
+static void replay_keyframe_sort(void)
+{
+ qsort( player_replay.keyframes, player_replay.keyframe_count,
+ sizeof(replay_keyframe), _keyframe_cmp );
+}
+
+static void replay_editor_imgui(void)
+{
+
+}
+
void skaterift_replay_imgui(void)
{
if( skaterift.activity != k_skaterift_replay ) return;
/* mainbar */
ui_px height = 32,
cwidth = 2;
- ui_rect bar = { 0, 0, vg.window_x, height };
- ui_fill( bar, ui_colour( k_ui_bg ) );
+ ui_rect timeline = { 0, 0, vg.window_x, height };
+ ui_fill( timeline, ui_colour( k_ui_bg ) );
/* cursor frame block */
- if( replay->cursor_frame ){
- if( replay->cursor_frame->r ){
+ if( replay->cursor_frame )
+ {
+ if( replay->cursor_frame->r )
+ {
f64 l = (replay->cursor_frame->r->time-replay->cursor_frame->time)/len,
s = (replay->cursor_frame->time - start) / len;
ui_rect box = { s*(f64)vg.window_x, 0,
- VG_MAX(4,(ui_px)(l*vg.window_x)), bar[3]+2 };
+ VG_MAX(4,(ui_px)(l*vg.window_x)), timeline[3]+2 };
ui_fill( box, ui_colour( k_ui_bg+4 ) );
}
}
/* cursor */
ui_rect cusor = { cur * (f64)vg.window_x - (cwidth/2), 0,
- cwidth, bar[3] };
+ cwidth, (player_replay.editor_mode? 0: 16) + timeline[3] };
ui_fill( cusor, ui_colour( k_ui_bg+7 ) );
/* latest state marker */
- if( replay->statehead ){
+ if( replay->statehead )
+ {
f64 t = (replay->statehead->time - start) / len;
- ui_rect tag = { t*(f64)vg.window_x, 0, 2, bar[3]+8 };
+ ui_rect tag = { t*(f64)vg.window_x, 0, 2, timeline[3]+8 };
ui_fill( tag, ui_colour( k_ui_green+k_ui_brighter ) );
}
/* previous state marker */
replay_frame *prev = replay_find_recent_stateframe( replay );
- if( prev ){
+ if( prev )
+ {
f64 t = (prev->time - start) / len;
- ui_rect tag = { t*(f64)vg.window_x, 0, 2, bar[3]+8 };
+ ui_rect tag = { t*(f64)vg.window_x, 0, 2, timeline[3]+8 };
ui_fill( tag, ui_colour( k_ui_yellow+k_ui_brighter ) );
}
ui_text( cusor, buffer, 1, k_ui_align_middle_left, 0 );
snprintf( buffer, 128, "-%.2fs\n", len );
- ui_text( bar, buffer, 1, k_ui_align_middle_left, 0 );
- ui_text( bar, "0s", 1, k_ui_align_middle_right, 0 );
+ ui_text( timeline, buffer, 1, k_ui_align_middle_left, 0 );
+ ui_text( timeline, "0s", 1, k_ui_align_middle_right, 0 );
+
+ if( player_replay.editor_mode )
+ {
+ gui_helper_clear();
+ vg_ui.wants_mouse = 1;
+
+ ui_rect panel = { 0, timeline[3] + 20, 200, 400 };
+ ui_fill( panel, ui_opacity( ui_colour(k_ui_bg), 0.5f ) );
+ ui_rect_pad( panel, (ui_px[2]){4,4} );
+
+ if( ui_button( panel,
+ (player_replay.replay_control == k_replay_control_play)?
+ "Pause": "Play" ) == k_ui_button_click )
+ {
+ player_replay.replay_control ^= k_replay_control_play;
+ }
+
+
+
+
+ /* script bar */
+ ui_rect script = { 0, height + 2, vg.window_x, 16 };
+ ui_fill( script, ui_colour( k_ui_bg ) );
+
+ f64 mouse_t = start + ((f64)vg_ui.mouse[0] / (f64)vg.window_x)*len;
+
+ /* keyframe draw and select */
+ bool absorb_by_keyframe = 0;
+ ui_px lx = 0;
+ for( u32 i=0; i<player_replay.keyframe_count; i ++ )
+ {
+ replay_keyframe *kf = &player_replay.keyframes[i];
+ f64 t = (kf->time-start)/len;
+
+ ui_px x = t*(f64)vg.window_x-8;
+
+ if( i )
+ {
+ ui_rect con = { lx, script[1]+7, x-lx, 1 };
+ ui_fill( con, ui_colour(k_ui_blue) );
+
+ vg_line( kf->cam.pos,
+ player_replay.keyframes[i-1].cam.pos, VG__BLUE );
+ }
+
+ ui_rect tag = { x, script[1], 16, 16 };
+
+ if( ui_inside_rect( tag, vg_ui.mouse ) )
+ {
+ absorb_by_keyframe = 1;
+
+ if( ui_click_down( UI_MOUSE_LEFT ) )
+ {
+ if( player_replay.active_keyframe != i )
+ {
+ player_replay.drag_wait = 1;
+ player_replay.active_keyframe = i;
+ replay_seek( &player_replay.local, kf->time );
+ }
+ }
+ else
+ {
+ ui_outline( tag, 1, ui_colour(k_ui_fg), 0 );
+ }
+ }
+
+ if( i == player_replay.active_keyframe )
+ {
+ ui_outline( tag, 2, ui_colour(k_ui_fg), 0 );
+
+ if( ui_inside_rect( tag, vg_ui.mouse_click )
+ && !player_replay.drag_wait )
+ {
+ if( ui_clicking( UI_MOUSE_LEFT ) )
+ {
+ absorb_by_keyframe = 1;
+ tag[0] = vg_ui.mouse[0]-8;
+ replay_seek( &player_replay.local, mouse_t );
+ }
+ else if( ui_click_up( UI_MOUSE_LEFT ) )
+ {
+ kf->time = mouse_t;
+ replay_keyframe_sort();
+ }
+ }
+ }
+
+ ui_fill( tag, ui_colour(k_ui_blue) );
+ lx = x;
+ }
+
+ if( player_replay.drag_wait && !ui_clicking(UI_MOUSE_LEFT) )
+ player_replay.drag_wait = 0;
+
+ /* adding keyframes */
+ if( ui_inside_rect( script, vg_ui.mouse ) )
+ {
+ vg_ui.cursor = k_ui_cursor_hand;
+
+ ui_rect cursor = { vg_ui.mouse[0], script[1], 4, 16 };
+ ui_fill( cursor, ui_colour( k_ui_fg ) );
+
+ if( !absorb_by_keyframe && ui_click_down( UI_MOUSE_LEFT ) )
+ {
+ u32 max = vg_list_size( player_replay.keyframes );
+ if( player_replay.keyframe_count == max )
+ {
+ ui_start_modal( "Maximum keyframes reached", UI_MODAL_BAD );
+ }
+ else
+ {
+ replay_keyframe *kf =
+ &player_replay.keyframes[player_replay.keyframe_count++];
+
+ kf->time = mouse_t;
+ v3_copy( skaterift.cam.pos, kf->cam.pos );
+ v3_copy( skaterift.cam.angles, kf->cam.angles );
+ kf->cam.fov = skaterift.cam.fov;
+
+ replay_keyframe_sort();
+ }
+ }
+ }
+
+
+ /* timeline scrub */
+ bool start_in_timeline =
+ ui_clicking(UI_MOUSE_LEFT) &&
+ ui_inside_rect(timeline, vg_ui.mouse_click);
+ if( (ui_inside_rect( timeline, vg_ui.mouse )) || start_in_timeline )
+ {
+ ui_rect cursor = { vg_ui.mouse[0], timeline[1], 4, timeline[3] };
+ ui_fill( cursor, ui_colour( k_ui_fg ) );
+ vg_ui.cursor = k_ui_cursor_ibeam;
+
+ if( ui_clicking( UI_MOUSE_LEFT ) && start_in_timeline )
+ {
+ replay_seek( &player_replay.local, mouse_t );
+ player_replay.active_keyframe = -1;
+ }
+ }
+
+ if( player_replay.active_keyframe != -1 )
+ {
+ replay_keyframe *kf =
+ &player_replay.keyframes[ player_replay.active_keyframe ];
+
+ enum ui_button_state mask_using =
+ k_ui_button_holding_inside |
+ k_ui_button_holding_outside |
+ k_ui_button_click;
+
+ if( ui_button( panel, "Edit cam" ) & mask_using )
+ {
+ if( ui_click_down( UI_MOUSE_LEFT ) )
+ {
+ /* init freecam */
+ v3_copy( kf->cam.pos, player_replay.replay_freecam.pos );
+ v3_copy( kf->cam.angles, player_replay.replay_freecam.angles );
+ player_replay.replay_freecam.fov = kf->cam.fov;
+ }
+
+ /* move freecam */
+ vg_ui.wants_mouse = 0;
+ freecam_preupdate();
+
+ v3_copy( player_replay.replay_freecam.pos, skaterift.cam.pos );
+ v3_copy( player_replay.replay_freecam.angles, skaterift.cam.angles);
+ skaterift.cam.fov = player_replay.replay_freecam.fov;
+
+ v3_copy( skaterift.cam.pos, kf->cam.pos );
+ v3_copy( skaterift.cam.angles, kf->cam.angles );
+ kf->cam.fov = skaterift.cam.fov;
+ }
+ }
+ }
}