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;
12 replay
->control
= k_replay_control_none
;
15 VG_STATIC
void local_replay_init( u32 bytes
){
16 localplayer
.replay
.data
= vg_linear_alloc( vg_mem
.rtmemory
, bytes
);
17 localplayer
.replay
.size
= bytes
;
18 replay_clear( &localplayer
.replay
);
21 replay_gamestate
*replay_frame_gamestate( replay_frame
*frame
, u16 index
){
22 void *baseptr
= frame
;
24 replay_gamestate
*array
= (baseptr
+ vg_align8( sizeof(replay_frame
)));
25 return &array
[ index
];
28 replay_sfx
*replay_frame_sfx( replay_frame
*frame
, u16 index
){
29 void *gsarr
= replay_frame_gamestate( frame
, 0 );
30 u32 gssize
= frame
->gamestate_count
* sizeof(replay_gamestate
);
32 replay_sfx
*array
= (gsarr
+ vg_align8(gssize
));
36 u32
_replay_frame_size( u16 gamestate_count
, u16 sfx_count
){
37 return vg_align8( sizeof( replay_frame
) ) +
38 vg_align8( gamestate_count
* sizeof(replay_gamestate
) ) +
39 vg_align8( sfx_count
* sizeof(replay_sfx
) );
42 u32
replay_frame_size( replay_frame
*frame
){
43 return _replay_frame_size( frame
->gamestate_count
, frame
->sfx_count
);
46 VG_STATIC replay_frame
*replay_newframe( replay_buffer
*replay
,
47 u16 gamestate_count
, u16 sfx_count
){
48 replay_frame
*frame
= NULL
;
50 assert( replay
->head
);
52 u32 headsize
= replay_frame_size( replay
->head
),
53 nextpos
= ((void *)replay
->head
- replay
->data
) + headsize
,
54 nextsize
= _replay_frame_size( gamestate_count
, sfx_count
);
56 if( nextsize
> replay
->size
){
57 vg_error( "Keyframe too big\n" );
61 if( nextpos
+ nextsize
> replay
->size
)
66 u32 tailpos
= (void *)replay
->tail
- replay
->data
;
68 if( tailpos
>= nextpos
){
69 if( nextpos
+ nextsize
> tailpos
){
71 if( replay
->cursor_frame
== replay
->tail
)
72 replay
->cursor_frame
= NULL
;
73 if( replay
->statehead
== replay
->tail
)
74 replay
->statehead
= NULL
;
77 replay
->tail
= replay
->tail
->r
;
80 replay
->tail
->l
= NULL
;
88 frame
= replay
->data
+ nextpos
;
91 replay
->head
->r
= frame
;
96 frame
->gamestate_count
= gamestate_count
;
97 frame
->sfx_count
= sfx_count
;
98 frame
->l
= replay
->head
;
100 replay
->head
= frame
;
101 if( !replay
->tail
) replay
->tail
= frame
;
102 if( gamestate_count
) replay
->statehead
= frame
;
107 VG_STATIC
void replay_seek( replay_buffer
*replay
, f64 t
){
108 if( !replay
->head
) return;
109 assert( replay
->tail
);
111 if( t
< replay
->tail
->time
) t
= replay
->tail
->time
;
112 if( t
> replay
->head
->time
) t
= replay
->head
->time
;
114 if( !replay
->cursor_frame
) {
115 replay
->cursor
= replay
->head
->time
;
116 replay
->cursor_frame
= replay
->head
;
118 if( fabs(replay
->head
->time
-t
) > fabs(replay
->tail
->time
-t
) ){
119 replay
->cursor
= replay
->tail
->time
;
120 replay
->cursor_frame
= replay
->tail
;
124 f64 dir
= t
- replay
->cursor
;
125 if( dir
== 0.0 ) return;
126 dir
= vg_signf( dir
);
131 if( t
> replay
->cursor_frame
->time
) break;
134 if( dir
> 0.0 ) next
= replay
->cursor_frame
->r
;
135 else next
= replay
->cursor_frame
->l
;
140 if( t
< next
->time
) break;
142 replay
->cursor_frame
= next
;
143 replay
->cursor
= next
->time
;
151 VG_STATIC replay_frame
*replay_find_recent_stateframe( replay_buffer
*replay
){
152 replay_frame
*frame
= replay
->cursor_frame
;
156 if( !frame
) return frame
;
157 if( frame
->gamestate_count
) return frame
;
164 VG_STATIC
void player_replay_control_update( player_instance
*player
){
166 f64 target
= player
->replay
.cursor
;
168 if( vg_getkey( SDLK_9
) ){
169 target
-= vg
.time_frame_delta
* speed
;
170 player
->replay
.control
= k_replay_control_scrub
;
171 replay_seek( &player
->replay
, target
);
173 if( vg_getkey( SDLK_0
) ){
174 target
+= vg
.time_frame_delta
* speed
;
175 player
->replay
.control
= k_replay_control_scrub
;
176 replay_seek( &player
->replay
, target
);
179 if( vg_getkey( SDLK_7
) )
180 player
->replay
.control
= k_replay_control_play
;
182 if( player
->replay
.control
== k_replay_control_play
){
183 target
+= vg
.time_frame_delta
;
184 replay_seek( &player
->replay
, target
);
187 if( vg_getkey( SDLK_8
) ){
188 replay_frame
*prev
= replay_find_recent_stateframe( &player
->replay
);
191 /* TODO: Make gamestate_apply function / swap ... */
192 replay_gamestate
*gs
= replay_frame_gamestate( prev
, 0 );
194 if( gs
->system
== k_player_subsystem_walk
){
195 memcpy( &player
->_walk
.state
, &gs
->walk
,
196 sizeof(struct player_walk_state
) );
198 else if( gs
->system
== k_player_subsystem_skate
){
199 memcpy( &player
->_skate
.state
, &gs
->skate
,
200 sizeof(struct player_skate_state
) );
202 player
->subsystem
= gs
->system
;
204 memcpy( &player
->rb
, &gs
->rb
, sizeof(rigidbody
) );
205 v3_copy( gs
->angles
, player
->angles
);
206 v3_copy( prev
->cam_pos
, player
->cam
.pos
);
207 v3_copy( prev
->cam_angles
, player
->cam_override_angles
);
208 player
->cam
.fov
= prev
->cam_fov
;
209 memcpy( &player
->cam_control
, &gs
->cam_control
,
210 sizeof(struct player_cam_controller
) );
212 /* chop end off replay */
214 player
->replay
.statehead
= prev
;
215 player
->replay
.head
= prev
;
216 player
->replay
.cursor_frame
= prev
;
217 player
->replay
.cursor
= prev
->time
;
218 player
->replay
.control
= k_replay_control_none
;
219 vg
.time
= prev
->time
;
225 VG_STATIC
void replay_debug_info( player_instance
*player
){
226 player__debugtext( 2, "replay info" );
228 replay_buffer
*replay
= &player
->replay
;
232 if( replay
->tail
) tail
= (void *)replay
->tail
- replay
->data
;
233 if( replay
->head
) head
= (void *)replay
->head
- replay
->data
;
235 player__debugtext( 1, "head @%u | tail @%u\n", head
, tail
);
237 if( replay
->statehead
){
238 u32 state
= (void *)replay
->statehead
- replay
->data
;
239 player__debugtext( 1, "gs @%u\n", state
);
242 player__debugtext( 1, "gs @NULL\n" );
244 f64 start
= replay
->cursor
,
245 end
= replay
->cursor
;
246 if( replay
->tail
) start
= replay
->tail
->time
;
247 if( replay
->head
) end
= replay
->head
->time
;
249 f64 cur
= replay
->cursor
- start
,
252 player__debugtext( 1, "cursor: %.2fs / %.2fs\n", cur
, len
);
255 VG_STATIC
void replay_imgui( player_instance
*player
){
256 if( player
->replay
.control
== k_replay_control_none
) return;
258 replay_buffer
*replay
= &player
->replay
;
259 f64 start
= replay
->cursor
,
260 end
= replay
->cursor
;
261 if( replay
->tail
) start
= replay
->tail
->time
;
262 if( replay
->head
) end
= replay
->head
->time
;
263 f64 len
= end
- start
,
264 cur
= (replay
->cursor
- start
) / len
;
271 ui_rect bar
= { 0, vg
.window_y
- height
, vg
.window_x
, height
};
272 ui_fill( bar
, ui_colour( k_ui_bg
) );
274 /* cursor frame block */
275 if( replay
->cursor_frame
){
276 if( replay
->cursor_frame
->r
){
277 f64 l
= (replay
->cursor_frame
->r
->time
-replay
->cursor_frame
->time
)/len
,
278 s
= (replay
->cursor_frame
->time
- start
) / len
;
279 ui_rect box
= { s
*(f64
)vg
.window_x
, bar
[1]-2,
280 VG_MAX(4,(ui_px
)l
), bar
[3]+2 };
281 ui_fill( box
, ui_colour( k_ui_bg
+4 ) );
286 ui_rect cusor
= { cur
* (f64
)vg
.window_x
- (cwidth
/2), bar
[1],
288 ui_fill( cusor
, ui_colour( k_ui_bg
+7 ) );
290 /* latest state marker */
291 if( replay
->statehead
){
292 f64 t
= (replay
->statehead
->time
- start
) / len
;
293 ui_rect tag
= { t
*(f64
)vg
.window_x
, bar
[1]-8, 2, bar
[3]+8 };
294 ui_fill( tag
, ui_colour( k_ui_green
+k_ui_brighter
) );
297 /* previous state marker */
298 replay_frame
*prev
= replay_find_recent_stateframe( replay
);
300 f64 t
= (prev
->time
- start
) / len
;
301 ui_rect tag
= { t
*(f64
)vg
.window_x
, bar
[1]-8, 2, bar
[3]+8 };
302 ui_fill( tag
, ui_colour( k_ui_yellow
+k_ui_brighter
) );
307 snprintf( buffer
, 128, "-%.2fs\n", (end
-replay
->cursor
) );
308 ui_text( cusor
, buffer
, 1, k_ui_align_middle_left
, 0 );
310 snprintf( buffer
, 128, "-%.2fs\n", len
);
311 ui_text( bar
, buffer
, 1, k_ui_align_middle_left
, 0 );
312 ui_text( bar
, "0s", 1, k_ui_align_middle_right
, 0 );
315 #endif /* PLAYER_REPLAY_C */