38c21921aa387af1f9dfe04cde497ad0b8abd38b
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 replay_gamestate
*replay_frame_gamestate( replay_frame
*frame
, u16 index
){
16 void *baseptr
= frame
;
18 replay_gamestate
*array
= (baseptr
+ vg_align8( sizeof(replay_frame
)));
19 return &array
[ index
];
22 replay_sfx
*replay_frame_sfx( replay_frame
*frame
, u16 index
){
23 void *gsarr
= replay_frame_gamestate( frame
, 0 );
24 u32 gssize
= frame
->gamestate_count
* sizeof(replay_gamestate
);
26 replay_sfx
*array
= (gsarr
+ vg_align8(gssize
));
30 u32
_replay_frame_size( u16 gamestate_count
, u16 sfx_count
){
31 return vg_align8( sizeof( replay_frame
) ) +
32 vg_align8( gamestate_count
* sizeof(replay_gamestate
) ) +
33 vg_align8( sfx_count
* sizeof(replay_sfx
) );
36 u32
replay_frame_size( replay_frame
*frame
){
37 return _replay_frame_size( frame
->gamestate_count
, frame
->sfx_count
);
40 VG_STATIC replay_frame
*replay_newframe( replay_buffer
*replay
,
41 u16 gamestate_count
, u16 sfx_count
){
42 replay_frame
*frame
= NULL
;
44 assert( replay
->head
);
46 u32 headsize
= replay_frame_size( replay
->head
),
47 nextpos
= ((void *)replay
->head
- replay
->data
) + headsize
,
48 nextsize
= _replay_frame_size( gamestate_count
, sfx_count
);
50 if( nextsize
> replay
->size
){
51 vg_error( "Keyframe too big\n" );
55 if( nextpos
+ nextsize
> replay
->size
)
60 u32 tailpos
= (void *)replay
->tail
- replay
->data
;
62 if( tailpos
>= nextpos
){
63 if( nextpos
+ nextsize
> tailpos
){
65 if( replay
->cursor_frame
== replay
->tail
)
66 replay
->cursor_frame
= NULL
;
67 if( replay
->statehead
== replay
->tail
)
68 replay
->statehead
= NULL
;
71 replay
->tail
= replay
->tail
->r
;
74 replay
->tail
->l
= NULL
;
82 frame
= replay
->data
+ nextpos
;
85 replay
->head
->r
= frame
;
90 frame
->gamestate_count
= gamestate_count
;
91 frame
->sfx_count
= sfx_count
;
92 frame
->l
= replay
->head
;
95 if( !replay
->tail
) replay
->tail
= frame
;
96 if( gamestate_count
) replay
->statehead
= frame
;
101 VG_STATIC
void replay_seek( replay_buffer
*replay
, f64 t
){
102 if( !replay
->head
) return;
103 assert( replay
->tail
);
105 if( t
< replay
->tail
->time
) t
= replay
->tail
->time
;
106 if( t
> replay
->head
->time
) t
= replay
->head
->time
;
108 if( !replay
->cursor_frame
) {
109 replay
->cursor
= replay
->head
->time
;
110 replay
->cursor_frame
= replay
->head
;
112 if( fabs(replay
->head
->time
-t
) > fabs(replay
->tail
->time
-t
) ){
113 replay
->cursor
= replay
->tail
->time
;
114 replay
->cursor_frame
= replay
->tail
;
118 f64 dir
= t
- replay
->cursor
;
119 if( dir
== 0.0 ) return;
120 dir
= vg_signf( dir
);
125 if( t
> replay
->cursor_frame
->time
) break;
128 if( dir
> 0.0 ) next
= replay
->cursor_frame
->r
;
129 else next
= replay
->cursor_frame
->l
;
134 if( t
< next
->time
) break;
136 replay
->cursor_frame
= next
;
137 replay
->cursor
= next
->time
;
145 VG_STATIC replay_frame
*replay_find_recent_stateframe( replay_buffer
*replay
){
146 replay_frame
*frame
= replay
->cursor_frame
;
150 if( !frame
) return frame
;
151 if( frame
->gamestate_count
) return frame
;
158 VG_STATIC
void player_replay_control_update( player_instance
*player
){
161 f64 target
= player
->replay
.cursor
;
163 if( vg_getkey( SDLK_9
) ){
164 target
-= vg
.time_frame_delta
* speed
;
165 player
->replay
.control
= k_replay_control_scrub
;
166 replay_seek( &player
->replay
, target
);
168 if( vg_getkey( SDLK_0
) ){
169 target
+= vg
.time_frame_delta
* speed
;
170 player
->replay
.control
= k_replay_control_scrub
;
171 replay_seek( &player
->replay
, target
);
174 if( vg_getkey( SDLK_7
) )
175 player
->replay
.control
= k_replay_control_play
;
177 if( player
->replay
.control
== k_replay_control_play
){
178 target
+= vg
.time_frame_delta
;
179 replay_seek( &player
->replay
, target
);
182 if( vg_getkey( SDLK_8
) ){
183 replay_frame
*prev
= replay_find_recent_stateframe( &player
->replay
);
186 /* TODO: Make gamestate_apply function / swap ... */
187 replay_gamestate
*gs
= replay_frame_gamestate( prev
, 0 );
189 if( gs
->system
== k_player_subsystem_walk
){
190 memcpy( &player
->_walk
.state
, &gs
->walk
,
191 sizeof(struct player_walk_state
) );
193 else if( gs
->system
== k_player_subsystem_skate
){
194 memcpy( &player
->_skate
.state
, &gs
->skate
,
195 sizeof(struct player_skate_state
) );
197 player
->subsystem
= gs
->system
;
199 memcpy( &player
->rb
, &gs
->rb
, sizeof(rigidbody
) );
200 v3_copy( gs
->angles
, player
->angles
);
201 v3_copy( prev
->cam_pos
, player
->cam
.pos
);
202 v3_copy( prev
->cam_angles
, player
->cam_override_angles
);
203 player
->cam
.fov
= prev
->cam_fov
;
204 memcpy( &player
->cam_control
, &gs
->cam_control
,
205 sizeof(struct player_cam_controller
) );
207 /* chop end off replay */
209 player
->replay
.statehead
= prev
;
210 player
->replay
.head
= prev
;
211 player
->replay
.cursor_frame
= prev
;
212 player
->replay
.cursor
= prev
->time
;
213 player
->replay
.control
= k_replay_control_none
;
214 vg
.time
= prev
->time
;
221 VG_STATIC
void replay_debug_info( player_instance
*player
){
223 player__debugtext( 2, "replay info" );
225 replay_buffer
*replay
= &player
->replay
;
229 if( replay
->tail
) tail
= (void *)replay
->tail
- replay
->data
;
230 if( replay
->head
) head
= (void *)replay
->head
- replay
->data
;
232 player__debugtext( 1, "head @%u | tail @%u\n", head
, tail
);
234 if( replay
->statehead
){
235 u32 state
= (void *)replay
->statehead
- replay
->data
;
236 player__debugtext( 1, "gs @%u\n", state
);
239 player__debugtext( 1, "gs @NULL\n" );
241 f64 start
= replay
->cursor
,
242 end
= replay
->cursor
;
243 if( replay
->tail
) start
= replay
->tail
->time
;
244 if( replay
->head
) end
= replay
->head
->time
;
246 f64 cur
= replay
->cursor
- start
,
249 player__debugtext( 1, "cursor: %.2fs / %.2fs\n", cur
, len
);
253 VG_STATIC
void replay_imgui( player_instance
*player
){
255 if( player
->replay
.control
== k_replay_control_none
) return;
257 replay_buffer
*replay
= &player
->replay
;
258 f64 start
= replay
->cursor
,
259 end
= replay
->cursor
;
260 if( replay
->tail
) start
= replay
->tail
->time
;
261 if( replay
->head
) end
= replay
->head
->time
;
262 f64 len
= end
- start
,
263 cur
= (replay
->cursor
- start
) / len
;
270 ui_rect bar
= { 0, vg
.window_y
- height
, vg
.window_x
, height
};
271 ui_fill( bar
, ui_colour( k_ui_bg
) );
273 /* cursor frame block */
274 if( replay
->cursor_frame
){
275 if( replay
->cursor_frame
->r
){
276 f64 l
= (replay
->cursor_frame
->r
->time
-replay
->cursor_frame
->time
)/len
,
277 s
= (replay
->cursor_frame
->time
- start
) / len
;
278 ui_rect box
= { s
*(f64
)vg
.window_x
, bar
[1]-2,
279 VG_MAX(4,(ui_px
)l
), bar
[3]+2 };
280 ui_fill( box
, ui_colour( k_ui_bg
+4 ) );
285 ui_rect cusor
= { cur
* (f64
)vg
.window_x
- (cwidth
/2), bar
[1],
287 ui_fill( cusor
, ui_colour( k_ui_bg
+7 ) );
289 /* latest state marker */
290 if( replay
->statehead
){
291 f64 t
= (replay
->statehead
->time
- start
) / len
;
292 ui_rect tag
= { t
*(f64
)vg
.window_x
, bar
[1]-8, 2, bar
[3]+8 };
293 ui_fill( tag
, ui_colour( k_ui_green
+k_ui_brighter
) );
296 /* previous state marker */
297 replay_frame
*prev
= replay_find_recent_stateframe( replay
);
299 f64 t
= (prev
->time
- start
) / len
;
300 ui_rect tag
= { t
*(f64
)vg
.window_x
, bar
[1]-8, 2, bar
[3]+8 };
301 ui_fill( tag
, ui_colour( k_ui_yellow
+k_ui_brighter
) );
306 snprintf( buffer
, 128, "-%.2fs\n", (end
-replay
->cursor
) );
307 ui_text( cusor
, buffer
, 1, k_ui_align_middle_left
, 0 );
309 snprintf( buffer
, 128, "-%.2fs\n", len
);
310 ui_text( bar
, buffer
, 1, k_ui_align_middle_left
, 0 );
311 ui_text( bar
, "0s", 1, k_ui_align_middle_right
, 0 );
315 #endif /* PLAYER_REPLAY_C */