1 #ifndef PLAYER_REPLAY_C
2 #define PLAYER_REPLAY_C
4 #include "player_replay.h"
6 VG_STATIC
void local_replay_init( u32 bytes
){
7 localplayer
.replay
.data
= vg_linear_alloc( vg_mem
.rtmemory
, bytes
);
8 localplayer
.replay
.size
= bytes
;
9 localplayer
.replay
.cursor
= -9999.9;
10 vg_console_reg_var( "k_replay_test", &k_replay_test
, k_var_dtype_i32
, 0 );
13 replay_gamestate
*replay_frame_gamestate( replay_frame
*frame
, u16 index
){
14 void *baseptr
= frame
;
16 replay_gamestate
*array
= (baseptr
+ vg_align8( sizeof(replay_frame
)));
17 return &array
[ index
];
20 replay_sfx
*replay_frame_sfx( replay_frame
*frame
, u16 index
){
21 void *gsarr
= replay_frame_gamestate( frame
, 0 );
22 u32 gssize
= frame
->gamestate_count
* sizeof(replay_gamestate
);
24 replay_sfx
*array
= (gsarr
+ vg_align8(gssize
));
28 u32
_replay_frame_size( u16 gamestate_count
, u16 sfx_count
){
29 return vg_align8( sizeof( replay_frame
) ) +
30 vg_align8( gamestate_count
* sizeof(replay_gamestate
) ) +
31 vg_align8( sfx_count
* sizeof(replay_sfx
) );
34 u32
replay_frame_size( replay_frame
*frame
){
35 return _replay_frame_size( frame
->gamestate_count
, frame
->sfx_count
);
38 VG_STATIC replay_frame
*replay_newframe( replay_buffer
*replay
,
39 u16 gamestate_count
, u16 sfx_count
){
40 replay_frame
*frame
= NULL
;
42 assert( replay
->head
);
44 u32 headsize
= replay_frame_size( replay
->head
),
45 nextpos
= ((void *)replay
->head
- replay
->data
) + headsize
,
46 nextsize
= _replay_frame_size( gamestate_count
, sfx_count
);
48 if( nextsize
> replay
->size
){
49 vg_error( "Keyframe too big\n" );
53 if( nextpos
+ nextsize
> replay
->size
)
58 u32 tailpos
= (void *)replay
->tail
- replay
->data
;
60 if( tailpos
>= nextpos
){
61 if( nextpos
+ nextsize
> tailpos
){
63 if( replay
->cursor_frame
== replay
->tail
)
64 replay
->cursor_frame
= NULL
;
65 if( replay
->statehead
== replay
->tail
)
66 replay
->statehead
= NULL
;
69 replay
->tail
= replay
->tail
->r
;
72 replay
->tail
->l
= NULL
;
80 frame
= replay
->data
+ nextpos
;
83 replay
->head
->r
= frame
;
88 frame
->gamestate_count
= gamestate_count
;
89 frame
->sfx_count
= sfx_count
;
90 frame
->l
= replay
->head
;
93 if( !replay
->tail
) replay
->tail
= frame
;
94 if( gamestate_count
) replay
->statehead
= frame
;
99 VG_STATIC
void replay_seek( replay_buffer
*replay
, f64 t
){
100 if( !replay
->head
) return;
101 assert( replay
->tail
);
103 if( t
< replay
->tail
->time
) t
= replay
->tail
->time
;
104 if( t
> replay
->head
->time
) t
= replay
->head
->time
;
106 if( !replay
->cursor_frame
) {
107 replay
->cursor
= replay
->head
->time
;
108 replay
->cursor_frame
= replay
->head
;
110 if( fabs(replay
->head
->time
-t
) > fabs(replay
->tail
->time
-t
) ){
111 replay
->cursor
= replay
->tail
->time
;
112 replay
->cursor_frame
= replay
->tail
;
116 f64 dir
= t
- replay
->cursor
;
117 if( dir
== 0.0 ) return;
118 dir
= vg_signf( dir
);
121 for( ; i
<1024; i
++ ){
123 if( t
> replay
->cursor_frame
->time
) break;
126 if( dir
> 0.0 ) next
= replay
->cursor_frame
->r
;
127 else next
= replay
->cursor_frame
->l
;
132 if( t
< next
->time
) break;
134 replay
->cursor_frame
= next
;
135 replay
->cursor
= next
->time
;
137 if( i
== 1023 ) return;
143 VG_STATIC replay_frame
*replay_find_recent_stateframe( replay_buffer
*replay
){
144 replay_frame
*frame
= replay
->cursor_frame
;
147 for( ; i
<4096; i
++ ){
148 if( !frame
) return frame
;
149 if( frame
->gamestate_count
) return frame
;
156 VG_STATIC
void replay_debug_info( player_instance
*player
){
157 player__debugtext( 2, "replay info" );
159 replay_buffer
*replay
= &player
->replay
;
163 if( replay
->tail
) tail
= (void *)replay
->tail
- replay
->data
;
164 if( replay
->head
) head
= (void *)replay
->head
- replay
->data
;
166 player__debugtext( 1, "head @%u | tail @%u\n", head
, tail
);
168 if( replay
->statehead
){
169 u32 state
= (void *)replay
->statehead
- replay
->data
;
170 player__debugtext( 1, "gs @%u\n", state
);
173 player__debugtext( 1, "gs @NULL\n" );
175 f64 start
= replay
->cursor
,
176 end
= replay
->cursor
;
177 if( replay
->tail
) start
= replay
->tail
->time
;
178 if( replay
->head
) end
= replay
->head
->time
;
180 f64 cur
= replay
->cursor
- start
,
183 player__debugtext( 1, "cursor: %.2fs / %.2fs\n", cur
, len
);
186 VG_STATIC
void replay_imgui( player_instance
*player
){
187 if( !k_replay_test
) return;
189 replay_buffer
*replay
= &player
->replay
;
190 f64 start
= replay
->cursor
,
191 end
= replay
->cursor
;
192 if( replay
->tail
) start
= replay
->tail
->time
;
193 if( replay
->head
) end
= replay
->head
->time
;
194 f64 len
= end
- start
,
195 cur
= (replay
->cursor
- start
) / len
;
202 ui_rect bar
= { 0, vg
.window_y
- height
, vg
.window_x
, height
};
203 ui_fill( bar
, ui_colour( k_ui_bg
) );
205 /* cursor frame block */
206 if( replay
->cursor_frame
){
207 if( replay
->cursor_frame
->r
){
208 f64 l
= (replay
->cursor_frame
->r
->time
-replay
->cursor_frame
->time
)/len
,
209 s
= (replay
->cursor_frame
->time
- start
) / len
;
210 ui_rect box
= { s
*(f64
)vg
.window_x
, bar
[1]-2,
211 VG_MAX(4,(ui_px
)l
), bar
[3]+2 };
212 ui_fill( box
, ui_colour( k_ui_bg
+4 ) );
217 ui_rect cusor
= { cur
* (f64
)vg
.window_x
- (cwidth
/2), bar
[1],
219 ui_fill( cusor
, ui_colour( k_ui_bg
+7 ) );
221 /* latest state marker */
222 if( replay
->statehead
){
223 f64 t
= (replay
->statehead
->time
- start
) / len
;
224 ui_rect tag
= { t
*(f64
)vg
.window_x
, bar
[1]-8, 2, bar
[3]+8 };
225 ui_fill( tag
, ui_colour( k_ui_green
+k_ui_brighter
) );
228 /* previous state marker */
229 replay_frame
*prev
= replay_find_recent_stateframe( replay
);
231 f64 t
= (prev
->time
- start
) / len
;
232 ui_rect tag
= { t
*(f64
)vg
.window_x
, bar
[1]-8, 2, bar
[3]+8 };
233 ui_fill( tag
, ui_colour( k_ui_yellow
+k_ui_brighter
) );
238 snprintf( buffer
, 128, "-%.2fs\n", (end
-replay
->cursor
) );
239 ui_text( cusor
, buffer
, 1, k_ui_align_middle_left
, 0 );
241 snprintf( buffer
, 128, "-%.2fs\n", len
);
242 ui_text( bar
, buffer
, 1, k_ui_align_middle_left
, 0 );
243 ui_text( bar
, "0s", 1, k_ui_align_middle_right
, 0 );
246 #endif /* PLAYER_REPLAY_C */