1 #ifndef PLAYER_REPLAY_C
2 #define PLAYER_REPLAY_C
4 #include "player_replay.h"
6 VG_STATIC
void replay_clear( replay_buffer
*replay
){
9 replay
->cursor_frame
= NULL
;
10 replay
->statehead
= NULL
;
11 replay
->cursor
= -99999.9;
14 replay_gamestate
*replay_frame_gamestate( replay_frame
*frame
){
15 void *baseptr
= frame
;
16 return baseptr
+ vg_align8(sizeof(replay_frame
));
19 void *replay_gamestate_subsystem_data( replay_gamestate
*gs
){
21 return baseptr
+ vg_align8(sizeof(replay_gamestate
));
24 u32
replay_frame_gamestate_total_size( u32 subsystem_gamestate_size
){
25 if( subsystem_gamestate_size
){
26 return vg_align8( sizeof(replay_gamestate
) ) +
27 vg_align8( subsystem_gamestate_size
);
33 replay_sfx
*replay_frame_sfx( replay_frame
*frame
, u32 index
){
34 void *gs
= replay_frame_gamestate( frame
);
36 replay_frame_gamestate_total_size( frame
->subsystem_gamestate_size
);
38 replay_sfx
*array
= (gs
+ total_size
);
42 u32
_replay_frame_size( u32 subsystem_gamestate_size
, u32 sfx_count
){
43 return vg_align8( sizeof( replay_frame
) ) +
44 replay_frame_gamestate_total_size( subsystem_gamestate_size
) +
45 vg_align8( sfx_count
* sizeof(replay_sfx
) );
48 u32
replay_frame_size( replay_frame
*frame
){
49 return _replay_frame_size( frame
->subsystem_gamestate_size
,
53 VG_STATIC
void replay_tailpop( replay_buffer
*replay
){
54 if( replay
->cursor_frame
== replay
->tail
)
55 replay
->cursor_frame
= NULL
;
56 if( replay
->statehead
== replay
->tail
)
57 replay
->statehead
= NULL
;
59 replay
->tail
= replay
->tail
->r
;
62 replay
->tail
->l
= NULL
;
67 VG_STATIC replay_frame
*replay_newframe( replay_buffer
*replay
,
68 u32 subsystem_gamestate_size
,
70 replay_frame
*frame
= NULL
;
72 assert( replay
->head
);
74 u32 headsize
= replay_frame_size( replay
->head
),
75 nextpos
= ((void *)replay
->head
- replay
->data
) + headsize
,
76 nextsize
= _replay_frame_size( subsystem_gamestate_size
, sfx_count
);
78 if( nextsize
> replay
->size
){
79 vg_error( "Keyframe too big\n" );
83 if( nextpos
+ nextsize
> replay
->size
){
86 /* maintain contiguity */
87 while( replay
->tail
){
88 if( (void *)replay
->tail
- replay
->data
)
89 replay_tailpop( replay
);
96 u32 tailpos
= (void *)replay
->tail
- replay
->data
;
98 if( tailpos
>= nextpos
){
99 if( nextpos
+ nextsize
> tailpos
){
100 replay_tailpop( replay
);
107 frame
= replay
->data
+ nextpos
;
110 replay
->head
->r
= frame
;
113 frame
= replay
->data
;
115 frame
->subsystem_gamestate_size
= subsystem_gamestate_size
;
116 frame
->sfx_count
= sfx_count
;
117 frame
->l
= replay
->head
;
119 replay
->head
= frame
;
120 if( !replay
->tail
) replay
->tail
= frame
;
121 if( subsystem_gamestate_size
) replay
->statehead
= frame
;
126 VG_STATIC
void replay_seek( replay_buffer
*replay
, f64 t
){
127 if( !replay
->head
) return;
128 assert( replay
->tail
);
130 if( t
< replay
->tail
->time
) t
= replay
->tail
->time
;
131 if( t
> replay
->head
->time
) t
= replay
->head
->time
;
133 if( !replay
->cursor_frame
) {
134 replay
->cursor
= replay
->head
->time
;
135 replay
->cursor_frame
= replay
->head
;
137 if( fabs(replay
->head
->time
-t
) > fabs(replay
->tail
->time
-t
) ){
138 replay
->cursor
= replay
->tail
->time
;
139 replay
->cursor_frame
= replay
->tail
;
143 f64 dir
= t
- replay
->cursor
;
144 if( dir
== 0.0 ) return;
145 dir
= vg_signf( dir
);
150 if( t
> replay
->cursor_frame
->time
) break;
153 if( dir
> 0.0 ) next
= replay
->cursor_frame
->r
;
154 else next
= replay
->cursor_frame
->l
;
159 if( t
< next
->time
) break;
161 replay
->cursor_frame
= next
;
162 replay
->cursor
= next
->time
;
170 VG_STATIC replay_frame
*replay_find_recent_stateframe( replay_buffer
*replay
){
171 replay_frame
*frame
= replay
->cursor_frame
;
174 if( !frame
) return frame
;
175 if( frame
->subsystem_gamestate_size
) return frame
;
182 VG_STATIC f32
replay_subframe_time( replay_buffer
*replay
){
183 replay_frame
*frame
= replay
->cursor_frame
;
184 if( !frame
) return 0.0f
;
185 replay_frame
*next
= frame
->r
;
187 f64 l
= next
->time
- frame
->time
,
188 t
= (replay
->cursor
- frame
->time
) / l
;
189 return vg_clampf( t
, 0.0f
, 1.0f
);
195 VG_STATIC
void replay_get_frame_camera( replay_frame
*frame
, camera
*cam
){
196 cam
->fov
= frame
->cam_fov
;
197 v3_copy( frame
->cam_pos
, cam
->pos
);
198 v3_copy( frame
->cam_angles
, cam
->angles
);
201 VG_STATIC
void replay_get_camera( replay_buffer
*replay
, camera
*cam
){
204 if( replay
->cursor_frame
){
205 replay_frame
*next
= replay
->cursor_frame
->r
;
210 replay_get_frame_camera( replay
->cursor_frame
, cam
);
211 replay_get_frame_camera( next
, &temp
);
212 camera_lerp( cam
, &temp
, replay_subframe_time( replay
), cam
);
215 replay_get_frame_camera( replay
->cursor_frame
, cam
);
220 v3_zero( cam
->angles
);
225 VG_STATIC
void skaterift_replay_pre_update(void){
226 if( skaterift
.activity
!= k_skaterift_replay
) return;
229 f64 target
= skaterift
.replay
.cursor
;
231 if( vg_getkey( SDLK_9
) ){
232 target
-= vg
.time_frame_delta
* speed
;
233 skaterift
.replay_control
= k_replay_control_scrub
;
234 replay_seek( &skaterift
.replay
, target
);
236 if( vg_getkey( SDLK_0
) ){
237 target
+= vg
.time_frame_delta
* speed
;
238 skaterift
.replay_control
= k_replay_control_scrub
;
239 replay_seek( &skaterift
.replay
, target
);
242 if( vg_getkey( SDLK_7
) )
243 skaterift
.replay_control
= k_replay_control_play
;
245 if( skaterift
.replay_control
== k_replay_control_play
){
246 target
+= vg
.time_frame_delta
;
247 replay_seek( &skaterift
.replay
, target
);
250 if( vg_getkey( SDLK_8
) ){
251 replay_frame
*prev
= replay_find_recent_stateframe( &skaterift
.replay
);
254 /* TODO: Make gamestate_apply function / swap ... */
255 replay_gamestate
*gs
= replay_frame_gamestate( prev
);
256 void *src
= replay_gamestate_subsystem_data( gs
);
258 if( gs
->system
== k_player_subsystem_walk
){
259 memcpy( &localplayer
._walk
.state
, src
,
260 prev
->subsystem_gamestate_size
);
262 else if( gs
->system
== k_player_subsystem_skate
){
263 memcpy( &localplayer
._skate
.state
, src
,
264 prev
->subsystem_gamestate_size
);
266 else if( gs
->system
== k_player_subsystem_dead
){
267 player__dead_transition( &localplayer
);
268 memcpy( &localplayer
.ragdoll
, src
,
269 prev
->subsystem_gamestate_size
);
272 localplayer
.subsystem
= gs
->system
;
274 memcpy( &localplayer
.rb
, &gs
->rb
, sizeof(rigidbody
) );
275 v3_copy( gs
->angles
, localplayer
.angles
);
277 v3_copy( prev
->cam_pos
, localplayer
.cam
.pos
);
278 v3_copy( prev
->cam_angles
, localplayer
.cam
.angles
);
279 localplayer
.cam
.fov
= prev
->cam_fov
;
281 memcpy( &localplayer
.cam_control
, &gs
->cam_control
,
282 sizeof(struct player_cam_controller
) );
284 /* chop end off replay */
286 skaterift
.replay
.statehead
= prev
;
287 skaterift
.replay
.head
= prev
;
288 skaterift
.replay
.cursor_frame
= prev
;
289 skaterift
.replay
.cursor
= prev
->time
;
290 skaterift
.replay_control
= k_replay_control_scrub
;
291 skaterift
.activity
= k_skaterift_default
;
292 vg
.time
= prev
->time
;
298 VG_STATIC
void skaterift_replay_debug_info(void){
299 player__debugtext( 2, "replay info" );
301 replay_buffer
*replay
= &skaterift
.replay
;
305 if( replay
->tail
) tail
= (void *)replay
->tail
- replay
->data
;
306 if( replay
->head
) head
= (void *)replay
->head
- replay
->data
;
308 player__debugtext( 1, "head @%u | tail @%u\n", head
, tail
);
310 if( replay
->statehead
){
311 u32 state
= (void *)replay
->statehead
- replay
->data
;
312 player__debugtext( 1, "gs @%u\n", state
);
313 player__debugtext( 1, "gamestate_size: %u\n",
314 replay
->statehead
->subsystem_gamestate_size
);
317 player__debugtext( 1, "gs @NULL\n" );
319 f64 start
= replay
->cursor
,
320 end
= replay
->cursor
;
321 if( replay
->tail
) start
= replay
->tail
->time
;
322 if( replay
->head
) end
= replay
->head
->time
;
324 f64 cur
= replay
->cursor
- start
,
327 player__debugtext( 1, "cursor: %.2fs / %.2fs\n", cur
, len
);
330 VG_STATIC
void skaterift_replay_imgui(void){
331 if( skaterift
.activity
!= k_skaterift_replay
) return;
333 replay_buffer
*replay
= &skaterift
.replay
;
334 f64 start
= replay
->cursor
,
335 end
= replay
->cursor
;
336 if( replay
->tail
) start
= replay
->tail
->time
;
337 if( replay
->head
) end
= replay
->head
->time
;
338 f64 len
= end
- start
,
339 cur
= (replay
->cursor
- start
) / len
;
346 ui_rect bar
= { 0, vg
.window_y
- height
, vg
.window_x
, height
};
347 ui_fill( bar
, ui_colour( k_ui_bg
) );
349 /* cursor frame block */
350 if( replay
->cursor_frame
){
351 if( replay
->cursor_frame
->r
){
352 f64 l
= (replay
->cursor_frame
->r
->time
-replay
->cursor_frame
->time
)/len
,
353 s
= (replay
->cursor_frame
->time
- start
) / len
;
354 ui_rect box
= { s
*(f64
)vg
.window_x
, bar
[1]-2,
355 VG_MAX(4,(ui_px
)(l
*vg
.window_x
)), bar
[3]+2 };
356 ui_fill( box
, ui_colour( k_ui_bg
+4 ) );
361 ui_rect cusor
= { cur
* (f64
)vg
.window_x
- (cwidth
/2), bar
[1],
363 ui_fill( cusor
, ui_colour( k_ui_bg
+7 ) );
365 /* latest state marker */
366 if( replay
->statehead
){
367 f64 t
= (replay
->statehead
->time
- start
) / len
;
368 ui_rect tag
= { t
*(f64
)vg
.window_x
, bar
[1]-8, 2, bar
[3]+8 };
369 ui_fill( tag
, ui_colour( k_ui_green
+k_ui_brighter
) );
372 /* previous state marker */
373 replay_frame
*prev
= replay_find_recent_stateframe( replay
);
375 f64 t
= (prev
->time
- start
) / len
;
376 ui_rect tag
= { t
*(f64
)vg
.window_x
, bar
[1]-8, 2, bar
[3]+8 };
377 ui_fill( tag
, ui_colour( k_ui_yellow
+k_ui_brighter
) );
382 snprintf( buffer
, 128, "-%.2fs\n", (end
-replay
->cursor
) );
383 ui_text( cusor
, buffer
, 1, k_ui_align_middle_left
, 0 );
385 snprintf( buffer
, 128, "-%.2fs\n", len
);
386 ui_text( bar
, buffer
, 1, k_ui_align_middle_left
, 0 );
387 ui_text( bar
, "0s", 1, k_ui_align_middle_right
, 0 );
390 #endif /* PLAYER_REPLAY_C */