38c21921aa387af1f9dfe04cde497ad0b8abd38b
[carveJwlIkooP6JGAAIwe30JlM.git] / player_replay.c
1 #ifndef PLAYER_REPLAY_C
2 #define PLAYER_REPLAY_C
3
4 #include "player_replay.h"
5
6 VG_STATIC void replay_clear( replay_buffer *replay ){
7 replay->head = NULL;
8 replay->tail = NULL;
9 replay->cursor_frame = NULL;
10 replay->statehead = NULL;
11 replay->cursor = -99999.9;
12 replay->control = k_replay_control_none;
13 }
14
15 replay_gamestate *replay_frame_gamestate( replay_frame *frame, u16 index ){
16 void *baseptr = frame;
17
18 replay_gamestate *array = (baseptr + vg_align8( sizeof(replay_frame)));
19 return &array[ index ];
20 }
21
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);
25
26 replay_sfx *array = (gsarr + vg_align8(gssize));
27 return &array[index];
28 }
29
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) );
34 }
35
36 u32 replay_frame_size( replay_frame *frame ){
37 return _replay_frame_size( frame->gamestate_count, frame->sfx_count );
38 }
39
40 VG_STATIC replay_frame *replay_newframe( replay_buffer *replay,
41 u16 gamestate_count, u16 sfx_count ){
42 replay_frame *frame = NULL;
43 if( replay->head ){
44 assert( replay->head );
45
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 );
49
50 if( nextsize > replay->size ){
51 vg_error( "Keyframe too big\n" );
52 return NULL;
53 }
54
55 if( nextpos + nextsize > replay->size )
56 nextpos = 0;
57
58 check_again:;
59
60 u32 tailpos = (void *)replay->tail - replay->data;
61
62 if( tailpos >= nextpos ){
63 if( nextpos + nextsize > tailpos ){
64 /* remove links */
65 if( replay->cursor_frame == replay->tail )
66 replay->cursor_frame = NULL;
67 if( replay->statehead == replay->tail )
68 replay->statehead = NULL;
69
70 /* pop node */
71 replay->tail = replay->tail->r;
72
73 if( replay->tail ) {
74 replay->tail->l = NULL;
75 goto check_again;
76 }
77 else
78 replay->head = NULL;
79 }
80 }
81
82 frame = replay->data + nextpos;
83
84 if( replay->head )
85 replay->head->r = frame;
86 }
87 else
88 frame = replay->data;
89
90 frame->gamestate_count = gamestate_count;
91 frame->sfx_count = sfx_count;
92 frame->l = replay->head;
93 frame->r = NULL;
94 replay->head = frame;
95 if( !replay->tail ) replay->tail = frame;
96 if( gamestate_count ) replay->statehead = frame;
97
98 return frame;
99 }
100
101 VG_STATIC void replay_seek( replay_buffer *replay, f64 t ){
102 if( !replay->head ) return;
103 assert( replay->tail );
104
105 if( t < replay->tail->time ) t = replay->tail->time;
106 if( t > replay->head->time ) t = replay->head->time;
107
108 if( !replay->cursor_frame ) {
109 replay->cursor = replay->head->time;
110 replay->cursor_frame = replay->head;
111
112 if( fabs(replay->head->time-t) > fabs(replay->tail->time-t) ){
113 replay->cursor = replay->tail->time;
114 replay->cursor_frame = replay->tail;
115 }
116 }
117
118 f64 dir = t - replay->cursor;
119 if( dir == 0.0 ) return;
120 dir = vg_signf( dir );
121
122 u32 i=4096;
123 while( i --> 0 ){
124 if( dir < 0.0 )
125 if( t > replay->cursor_frame->time ) break;
126
127 replay_frame *next;
128 if( dir > 0.0 ) next = replay->cursor_frame->r;
129 else next = replay->cursor_frame->l;
130
131 if( !next ) break;
132
133 if( dir > 0.0 )
134 if( t < next->time ) break;
135
136 replay->cursor_frame = next;
137 replay->cursor = next->time;
138
139 if( !i ) return;
140 }
141
142 replay->cursor = t;
143 }
144
145 VG_STATIC replay_frame *replay_find_recent_stateframe( replay_buffer *replay ){
146 replay_frame *frame = replay->cursor_frame;
147
148 u32 i=4096;
149 while( i --> 0 ){
150 if( !frame ) return frame;
151 if( frame->gamestate_count ) return frame;
152 frame = frame->l;
153 }
154
155 return NULL;
156 }
157
158 VG_STATIC void player_replay_control_update( player_instance *player ){
159 #if 0
160 f64 speed = 1.0;
161 f64 target = player->replay.cursor;
162
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 );
167 }
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 );
172 }
173
174 if( vg_getkey( SDLK_7 ) )
175 player->replay.control = k_replay_control_play;
176
177 if( player->replay.control == k_replay_control_play ){
178 target += vg.time_frame_delta;
179 replay_seek( &player->replay, target );
180 }
181
182 if( vg_getkey( SDLK_8 ) ){
183 replay_frame *prev = replay_find_recent_stateframe( &player->replay );
184
185 if( prev ){
186 /* TODO: Make gamestate_apply function / swap ... */
187 replay_gamestate *gs = replay_frame_gamestate( prev, 0 );
188
189 if( gs->system == k_player_subsystem_walk ){
190 memcpy( &player->_walk.state, &gs->walk,
191 sizeof(struct player_walk_state) );
192 }
193 else if( gs->system == k_player_subsystem_skate ){
194 memcpy( &player->_skate.state, &gs->skate,
195 sizeof(struct player_skate_state) );
196 }
197 player->subsystem = gs->system;
198
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) );
206
207 /* chop end off replay */
208 prev->r = NULL;
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;
215 return;
216 }
217 }
218 #endif
219 }
220
221 VG_STATIC void replay_debug_info( player_instance *player ){
222 #if 0
223 player__debugtext( 2, "replay info" );
224
225 replay_buffer *replay = &player->replay;
226
227 u32 head = 0,
228 tail = 0;
229 if( replay->tail ) tail = (void *)replay->tail - replay->data;
230 if( replay->head ) head = (void *)replay->head - replay->data;
231
232 player__debugtext( 1, "head @%u | tail @%u\n", head, tail );
233
234 if( replay->statehead ){
235 u32 state = (void *)replay->statehead - replay->data;
236 player__debugtext( 1, "gs @%u\n", state );
237 }
238 else
239 player__debugtext( 1, "gs @NULL\n" );
240
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;
245
246 f64 cur = replay->cursor - start,
247 len = end - start;
248
249 player__debugtext( 1, "cursor: %.2fs / %.2fs\n", cur, len );
250 #endif
251 }
252
253 VG_STATIC void replay_imgui( player_instance *player ){
254 #if 0
255 if( player->replay.control == k_replay_control_none ) return;
256
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;
264
265 char buffer[ 128 ];
266
267 /* mainbar */
268 ui_px height = 20,
269 cwidth = 2;
270 ui_rect bar = { 0, vg.window_y - height, vg.window_x, height };
271 ui_fill( bar, ui_colour( k_ui_bg ) );
272
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 ) );
281 }
282 }
283
284 /* cursor */
285 ui_rect cusor = { cur * (f64)vg.window_x - (cwidth/2), bar[1],
286 cwidth, bar[3] };
287 ui_fill( cusor, ui_colour( k_ui_bg+7 ) );
288
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 ) );
294 }
295
296 /* previous state marker */
297 replay_frame *prev = replay_find_recent_stateframe( replay );
298 if( prev ){
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 ) );
302 }
303
304 cusor[1] -= height;
305 cusor[2] = 200;
306 snprintf( buffer, 128, "-%.2fs\n", (end-replay->cursor) );
307 ui_text( cusor, buffer, 1, k_ui_align_middle_left, 0 );
308
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 );
312 #endif
313 }
314
315 #endif /* PLAYER_REPLAY_C */