3 #include "player_replay.h"
8 #include "player_walk.h"
9 #include "player_skate.h"
10 #include "player_dead.h"
11 #include "player_glide.h"
13 struct replay_globals player_replay
=
18 void replay_clear( replay_buffer
*replay
)
22 replay
->cursor_frame
= NULL
;
23 replay
->statehead
= NULL
;
24 replay
->cursor
= -99999.9;
27 void *replay_frame_data( replay_frame
*frame
, enum replay_framedata type
)
29 if( frame
->data_table
[type
][1] == 0 )
32 void *baseptr
= frame
;
33 return baseptr
+ frame
->data_table
[type
][0];
36 static u16
replay_frame_calculate_data_offsets(
37 u16 data_table
[k_replay_framedata_rows
][2] ){
39 u32 total
= vg_align8( sizeof(replay_frame
) );
40 for( u32 i
=0; i
<k_replay_framedata_rows
; i
++ ){
41 data_table
[i
][0] = total
;
42 total
+= vg_align8(data_table
[i
][1]);
45 vg_fatal_error( "Exceeded frame storage capacity\n" );
50 static void replay_tailpop( replay_buffer
*replay
){
51 if( replay
->cursor_frame
== replay
->tail
)
52 replay
->cursor_frame
= NULL
;
53 if( replay
->statehead
== replay
->tail
)
54 replay
->statehead
= NULL
;
56 replay
->tail
= replay
->tail
->r
;
59 replay
->tail
->l
= NULL
;
64 static replay_frame
*replay_newframe( replay_buffer
*replay
,
69 u16 data_table
[ k_replay_framedata_rows
][2];
70 data_table
[ k_replay_framedata_animator
][1] = animator_size
;
71 data_table
[ k_replay_framedata_gamestate
][1] = gamestate_size
;
72 data_table
[ k_replay_framedata_sfx
][1] = sfx_count
*sizeof(struct net_sfx
);
73 data_table
[ k_replay_framedata_internal_gamestate
][1] = 0;
76 data_table
[ k_replay_framedata_internal_gamestate
][1] =
77 sizeof( replay_gamestate
);
80 data_table
[ k_replay_framedata_glider
][1] = 0;
83 data_table
[ k_replay_framedata_glider
][1] =
84 sizeof(struct replay_glider_data
);
87 u32 nextsize
= replay_frame_calculate_data_offsets( data_table
);
89 replay_frame
*frame
= NULL
;
92 u32 headsize
= replay
->head
->total_size
,
93 nextpos
= ((void *)replay
->head
- replay
->data
) + headsize
;
95 if( nextpos
+ nextsize
> replay
->size
)
99 /* maintain contiguity */
100 while( replay
->tail
)
102 if( (void *)replay
->tail
- replay
->data
)
103 replay_tailpop( replay
);
109 u32 tailpos
= (void *)replay
->tail
- replay
->data
;
111 if( tailpos
>= nextpos
)
113 if( nextpos
+ nextsize
> tailpos
)
115 replay_tailpop( replay
);
122 frame
= replay
->data
+ nextpos
;
125 replay
->head
->r
= frame
;
128 frame
= replay
->data
;
130 for( u32 i
=0; i
<k_replay_framedata_rows
; i
++ )
132 frame
->data_table
[i
][0] = data_table
[i
][0];
133 frame
->data_table
[i
][1] = data_table
[i
][1];
136 frame
->total_size
= nextsize
;
137 frame
->l
= replay
->head
;
139 replay
->head
= frame
;
140 if( !replay
->tail
) replay
->tail
= frame
;
141 if( gamestate_size
) replay
->statehead
= frame
;
146 static void replay_emit_frame_sounds( replay_frame
*frame
){
147 void *baseptr
= frame
;
148 u16
*inf
= frame
->data_table
[k_replay_framedata_sfx
];
149 struct net_sfx
*buffer
= baseptr
+ inf
[0];
150 u32 count
= inf
[1] / sizeof(struct net_sfx
);
152 for( u32 i
=0; i
<count
; i
++ ){
153 net_sfx_play( buffer
+ i
);
157 int replay_seek( replay_buffer
*replay
, f64 t
)
159 if( !replay
->head
) return 0;
161 if( t
< replay
->tail
->time
) t
= replay
->tail
->time
;
162 if( t
> replay
->head
->time
) t
= replay
->head
->time
;
164 if( !replay
->cursor_frame
) {
165 replay
->cursor
= replay
->head
->time
;
166 replay
->cursor_frame
= replay
->head
;
168 if( fabs(replay
->head
->time
-t
) > fabs(replay
->tail
->time
-t
) ){
169 replay
->cursor
= replay
->tail
->time
;
170 replay
->cursor_frame
= replay
->tail
;
174 f64 dir
= t
- replay
->cursor
;
175 if( dir
== 0.0 ) return 0;
176 dir
= vg_signf( dir
);
182 if( t
> replay
->cursor_frame
->time
) {
189 if( dir
> 0.0 ) next
= replay
->cursor_frame
->r
;
190 else next
= replay
->cursor_frame
->l
;
195 if( t
< next
->time
){
201 replay_emit_frame_sounds( next
);
203 replay
->cursor_frame
= next
;
204 replay
->cursor
= next
->time
;
213 replay_frame
*replay_find_recent_stateframe( replay_buffer
*replay
)
215 replay_frame
*frame
= replay
->cursor_frame
;
218 if( !frame
) return frame
;
219 if( frame
->data_table
[ k_replay_framedata_gamestate
][1] ) return frame
;
226 f32
replay_subframe_time( replay_buffer
*replay
)
228 replay_frame
*frame
= replay
->cursor_frame
;
229 if( !frame
) return 0.0f
;
230 replay_frame
*next
= frame
->r
;
233 f64 l
= next
->time
- frame
->time
,
234 t
= (l
<= (1.0/128.0))? 0.0: (replay
->cursor
- frame
->time
) / l
;
235 return vg_clampf( t
, 0.0f
, 1.0f
);
241 void replay_get_frame_camera( replay_frame
*frame
, vg_camera
*cam
)
243 cam
->fov
= frame
->cam
.fov
;
244 v3_copy( frame
->cam
.pos
, cam
->pos
);
245 v3_copy( frame
->cam
.angles
, cam
->angles
);
248 void replay_get_camera( replay_buffer
*replay
, vg_camera
*cam
)
252 if( replay
->cursor_frame
)
254 replay_frame
*next
= replay
->cursor_frame
->r
;
260 replay_get_frame_camera( replay
->cursor_frame
, cam
);
261 replay_get_frame_camera( next
, &temp
);
262 vg_camera_lerp( cam
, &temp
, replay_subframe_time( replay
), cam
);
266 replay_get_frame_camera( replay
->cursor_frame
, cam
);
272 v3_zero( cam
->angles
);
277 void skaterift_get_replay_cam( vg_camera
*cam
)
279 replay_buffer
*replay
= &player_replay
.local
;
281 if( player_replay
.active_keyframe
!= -1 )
283 replay_keyframe
*kf
=
284 &player_replay
.keyframes
[player_replay
.active_keyframe
];
286 v3_copy( kf
->cam
.pos
, cam
->pos
);
287 v3_copy( kf
->cam
.angles
, cam
->angles
);
288 cam
->fov
= kf
->cam
.fov
;
292 if( player_replay
.keyframe_count
>= 2 )
294 for( u32 i
=0; i
<player_replay
.keyframe_count
-1; i
++ )
296 replay_keyframe
*kf
= &player_replay
.keyframes
[i
];
298 if( (kf
[0].time
<=replay
->cursor
) && (kf
[1].time
>replay
->cursor
) )
300 f64 l
= kf
[1].time
- kf
[0].time
,
301 t
= (l
<= (1.0/128.0))? 0.0: (replay
->cursor
-kf
[0].time
) / l
;
303 if( player_replay
.keyframe_count
>= 3 )
305 f32 m_start
= 0.5f
, m_end
= 0.5f
;
309 if( (t
< 0.5f
) || (i
==player_replay
.keyframe_count
-2) )
315 u32 last
= player_replay
.keyframe_count
-1;
316 if( kf
+0 == player_replay
.keyframes
) m_start
= 1.0f
;
317 if( kf
+2 == player_replay
.keyframes
+last
) m_end
= 1.0f
;
319 f32 ts
= vg_lerpf( kf
[0].time
, kf
[1].time
, 1.0f
-m_start
),
320 te
= vg_lerpf( kf
[1].time
, kf
[2].time
, m_end
);
323 t
= (replay
->cursor
-ts
)/l
;
325 f32 t0
= t
*m_start
+(1.0f
-m_start
),
332 v3_lerp( kf
[0].cam
.pos
, kf
[1].cam
.pos
, t0
, ps
);
333 vg_camera_lerp_angles( kf
[0].cam
.angles
, kf
[1].cam
.angles
,
335 fs
= vg_lerpf( kf
[0].cam
.fov
, kf
[1].cam
.fov
, t0
);
337 v3_lerp( kf
[1].cam
.pos
, kf
[2].cam
.pos
, t1
, pe
);
338 vg_camera_lerp_angles( kf
[1].cam
.angles
, kf
[2].cam
.angles
,
340 fe
= vg_lerpf( kf
[1].cam
.fov
, kf
[2].cam
.fov
, t1
);
343 v3_lerp( ps
, pe
, t
, cam
->pos
);
344 vg_camera_lerp_angles( as
, ae
, t
, cam
->angles
);
345 cam
->fov
= vg_lerpf( fs
, fe
, t
);
349 v3_lerp( kf
[0].cam
.pos
, kf
[1].cam
.pos
, t
, cam
->pos
);
350 vg_camera_lerp_angles( kf
[0].cam
.angles
, kf
[1].cam
.angles
,
352 cam
->fov
= vg_lerpf( kf
[0].cam
.fov
, kf
[1].cam
.fov
, t
);
359 replay_get_camera( replay
, cam
);
368 void skaterift_record_frame( replay_buffer
*replay
, int force_gamestate
)
370 f64 delta
= 9999999.9,
371 statedelta
= 9999999.9;
374 delta
= vg
.time
- replay
->head
->time
;
376 if( replay
->statehead
)
377 statedelta
= vg
.time
- replay
->statehead
->time
;
379 const f64 k_replay_rate
= 1.0/30.0,
380 k_gamestate_rate
= 0.5;
386 if( force_gamestate
) save_state
= 1;
387 if( statedelta
> k_gamestate_rate
) save_state
= 1;
388 if( delta
> k_replay_rate
) save_frame
= 1;
389 if( save_state
) save_frame
= 1;
391 if( localplayer
.have_glider
|| localplayer
.glider_orphan
||
392 localplayer
.subsystem
== k_player_subsystem_glide
){
396 if( !save_frame
) return;
398 u16 gamestate_size
= 0;
400 /* TODO: have as part of system struct */
401 gamestate_size
= (u32
[]){
402 [k_player_subsystem_walk
] = sizeof(struct player_walk_state
),
403 [k_player_subsystem_drive
] = 0,
404 [k_player_subsystem_skate
] = sizeof(struct player_skate_state
),
405 [k_player_subsystem_dead
] = localplayer
.ragdoll
.part_count
*
406 sizeof(struct replay_rb
),
407 [k_player_subsystem_glide
] = sizeof(struct replay_rb
),
408 }[ localplayer
.subsystem
];
411 u16 animator_size
= player_subsystems
[localplayer
.subsystem
]->animator_size
;
413 replay_frame
*frame
= replay_newframe( replay
,
414 animator_size
, gamestate_size
,
415 localplayer
.local_sfx_buffer_count
,
417 frame
->system
= localplayer
.subsystem
;
420 replay_gamestate
*gs
=
421 replay_frame_data( frame
, k_replay_framedata_internal_gamestate
);
423 gs
->current_run_version
= world_static
.current_run_version
;
425 /* permanent block */
426 memcpy( &gs
->rb
, &localplayer
.rb
, sizeof(rigidbody
) );
427 memcpy( &gs
->glider_rb
, &player_glide
.rb
, sizeof(rigidbody
) );
428 memcpy( &gs
->cam_control
, &localplayer
.cam_control
,
429 sizeof(struct player_cam_controller
) );
430 v3_copy( localplayer
.angles
, gs
->angles
);
432 void *dst
= replay_frame_data( frame
, k_replay_framedata_gamestate
);
434 /* subsytem/dynamic block */
435 if( localplayer
.subsystem
== k_player_subsystem_walk
)
436 memcpy( dst
, &player_walk
.state
, gamestate_size
);
437 else if( localplayer
.subsystem
== k_player_subsystem_skate
)
438 memcpy( dst
, &player_skate
.state
, gamestate_size
);
439 else if( localplayer
.subsystem
== k_player_subsystem_dead
){
440 struct replay_rb
*arr
= dst
;
441 for( u32 i
=0; i
<localplayer
.ragdoll
.part_count
; i
++ ){
442 rigidbody
*rb
= &localplayer
.ragdoll
.parts
[i
].rb
;
443 v3_copy( rb
->co
, arr
[i
].co
);
444 v3_copy( rb
->w
, arr
[i
].w
);
445 v3_copy( rb
->v
, arr
[i
].v
);
446 v4_copy( rb
->q
, arr
[i
].q
);
449 else if( localplayer
.subsystem
== k_player_subsystem_glide
){
450 struct replay_rb
*arr
= dst
;
451 rigidbody
*rb
= &player_glide
.rb
;
452 v3_copy( rb
->co
, arr
[0].co
);
453 v3_copy( rb
->w
, arr
[0].w
);
454 v3_copy( rb
->v
, arr
[0].v
);
455 v4_copy( rb
->q
, arr
[0].q
);
460 struct replay_glider_data
*inf
=
461 replay_frame_data( frame
, k_replay_framedata_glider
);
463 inf
->have_glider
= localplayer
.have_glider
;
464 inf
->glider_orphan
= localplayer
.glider_orphan
;
465 inf
->t
= player_glide
.t
;
466 v3_copy( player_glide
.rb
.co
, inf
->co
);
467 v4_copy( player_glide
.rb
.q
, inf
->q
);
470 replay
->cursor
= vg
.time
;
471 replay
->cursor_frame
= frame
;
472 frame
->time
= vg
.time
;
475 v3_copy( localplayer
.cam
.pos
, frame
->cam
.pos
);
476 if( localplayer
.gate_waiting
){
477 m4x3_mulv( localplayer
.gate_waiting
->transport
,
478 frame
->cam
.pos
, frame
->cam
.pos
);
481 v3_angles_vector( localplayer
.cam
.angles
, v0
);
482 m3x3_mulv( localplayer
.gate_waiting
->transport
, v0
, v0
);
483 v3_angles( v0
, frame
->cam
.angles
);
486 v3_copy( localplayer
.cam
.angles
, frame
->cam
.angles
);
488 frame
->cam
.fov
= localplayer
.cam
.fov
;
491 void *dst
= replay_frame_data( frame
, k_replay_framedata_animator
),
492 *src
= player_subsystems
[localplayer
.subsystem
]->animator_data
;
493 memcpy( dst
, src
, animator_size
);
496 memcpy( replay_frame_data( frame
, k_replay_framedata_sfx
),
497 localplayer
.local_sfx_buffer
,
498 sizeof(struct net_sfx
)*localplayer
.local_sfx_buffer_count
);
500 localplayer
.local_sfx_buffer_count
= 0;
504 void skaterift_restore_frame( replay_frame
*frame
){
505 replay_gamestate
*gs
=
506 replay_frame_data( frame
, k_replay_framedata_internal_gamestate
);
507 void *src
= replay_frame_data( frame
, k_replay_framedata_gamestate
);
508 u16 src_size
= frame
->data_table
[ k_replay_framedata_gamestate
][1];
509 world_static
.current_run_version
= gs
->current_run_version
;
511 if(frame
->system
== k_player_subsystem_walk
){
512 memcpy( &player_walk
.state
, src
, src_size
);
514 else if( frame
->system
== k_player_subsystem_skate
){
515 memcpy( &player_skate
.state
, src
, src_size
);
517 else if( frame
->system
== k_player_subsystem_dead
){
518 player__dead_transition(0);
519 struct replay_rb
*arr
= src
;
521 for( u32 i
=0; i
<localplayer
.ragdoll
.part_count
; i
++ ){
522 struct ragdoll_part
*part
= &localplayer
.ragdoll
.parts
[i
];
523 rigidbody
*rb
= &part
->rb
;
525 v3_copy( arr
[i
].co
, rb
->co
);
526 v3_copy( arr
[i
].w
, rb
->w
);
527 v3_copy( arr
[i
].v
, rb
->v
);
528 v4_copy( arr
[i
].q
, rb
->q
);
530 v3_copy( arr
[i
].co
, part
->prev_co
);
531 v4_copy( arr
[i
].q
, part
->prev_q
);
532 rb_update_matrices( rb
);
535 else if( frame
->system
== k_player_subsystem_glide
){
536 struct replay_rb
*arr
= src
;
537 rigidbody
*rb
= &player_glide
.rb
;
538 v3_copy( arr
[0].co
, rb
->co
);
539 v3_copy( arr
[0].w
, rb
->w
);
540 v3_copy( arr
[0].v
, rb
->v
);
541 v4_copy( arr
[0].q
, rb
->q
);
542 rb_update_matrices( rb
);
545 localplayer
.subsystem
= frame
->system
;
547 /* restore the seperated glider data if we have it */
548 if( frame
->data_table
[ k_replay_framedata_glider
][1] ){
549 struct replay_glider_data
*inf
=
550 replay_frame_data( frame
, k_replay_framedata_glider
);
552 localplayer
.have_glider
= inf
->have_glider
;
553 localplayer
.glider_orphan
= inf
->glider_orphan
;
554 player_glide
.t
= inf
->t
;
557 localplayer
.have_glider
= 0;
558 localplayer
.glider_orphan
= 0;
559 player_glide
.t
= 0.0f
;
562 memcpy( &localplayer
.rb
, &gs
->rb
, sizeof(rigidbody
) );
563 memcpy( &player_glide
.rb
, &gs
->glider_rb
, sizeof(rigidbody
) );
564 v3_copy( gs
->angles
, localplayer
.angles
);
566 v3_copy( frame
->cam
.pos
, localplayer
.cam
.pos
);
567 v3_copy( frame
->cam
.angles
, localplayer
.cam
.angles
);
568 localplayer
.cam
.fov
= frame
->cam
.fov
;
570 memcpy( &localplayer
.cam_control
, &gs
->cam_control
,
571 sizeof(struct player_cam_controller
) );
573 /* chop end off replay */
575 player_replay
.local
.statehead
= frame
;
576 player_replay
.local
.head
= frame
;
577 player_replay
.local
.cursor_frame
= frame
;
578 player_replay
.local
.cursor
= frame
->time
;
579 player_replay
.replay_control
= k_replay_control_scrub
;
580 skaterift
.activity
= k_skaterift_default
;
581 vg
.time
= frame
->time
;
584 static void skaterift_replay_resume(void){
585 replay_frame
*prev
= replay_find_recent_stateframe(&player_replay
.local
);
588 player_replay
.replay_control
= k_replay_control_resume
;
589 player_replay
.resume_target
= prev
;
590 player_replay
.resume_begin
= player_replay
.local
.cursor
;
591 player_replay
.resume_transition
= 0.0f
;
597 static void skaterift_replay_update_helpers(void);
599 void skaterift_replay_pre_update(void)
601 if( skaterift
.activity
!= k_skaterift_replay
) return;
603 if( player_replay
.replay_control
== k_replay_control_resume
)
605 if( player_replay
.local
.cursor_frame
== player_replay
.resume_target
||
606 player_replay
.local
.cursor_frame
== NULL
)
608 skaterift_restore_frame( player_replay
.resume_target
);
612 vg_slewf( &player_replay
.resume_transition
, 1.0f
,
613 vg
.time_frame_delta
* (1.0f
/1.0f
) );
615 if( player_replay
.resume_transition
>= 1.0f
)
616 skaterift_restore_frame( player_replay
.resume_target
);
618 f64 target
= vg_lerp( player_replay
.resume_begin
,
619 player_replay
.resume_target
->time
,
620 vg_smoothstepf( player_replay
.resume_transition
) );
621 if( replay_seek( &player_replay
.local
, target
) )
622 player_replay
.track_velocity
= 1.0f
;
624 player_replay
.track_velocity
= 0.0f
;
629 if( button_down( k_srbind_replay_play
) )
630 player_replay
.replay_control
= k_replay_control_play
;
631 if( button_down( k_srbind_replay_freecam
) )
633 player_replay
.use_freecam
^= 0x1;
635 if( player_replay
.use_freecam
)
637 replay_get_camera( &player_replay
.local
,
638 &player_replay
.replay_freecam
);
640 skaterift_replay_update_helpers();
643 f32 target_speed
= axis_state( k_sraxis_replay_h
) * 5.0;
644 if( button_press( k_srbind_reset
) )
645 target_speed
+= -2.0;
647 if( fabsf(target_speed
) > 0.01f
)
648 player_replay
.replay_control
= k_replay_control_scrub
;
650 if( player_replay
.replay_control
== k_replay_control_play
)
653 vg_slewf( &player_replay
.track_velocity
, target_speed
,
654 18.0f
*vg
.time_frame_delta
);
656 if( fabsf( player_replay
.track_velocity
) > 0.0001f
)
658 f64 target
= player_replay
.local
.cursor
;
659 target
+= player_replay
.track_velocity
* vg
.time_frame_delta
;
661 if( !replay_seek( &player_replay
.local
, target
) )
662 player_replay
.track_velocity
= 0.0f
;
665 if( button_down( k_srbind_mback
) )
667 if( player_replay
.local
.statehead
)
668 skaterift_restore_frame( player_replay
.local
.statehead
);
670 skaterift
.activity
= k_skaterift_default
;
671 srinput
.state
= k_input_state_resume
;
675 if( player_replay
.use_freecam
)
681 if( button_down( k_srbind_replay_resume
) )
683 skaterift_replay_resume();
689 static void skaterift_replay_update_helpers(void)
691 player_replay
.helper_resume
->greyed
= player_replay
.use_freecam
;
694 vg_strnull( &freecam_text
, player_replay
.helper_freecam
->text
,
695 GUI_HELPER_TEXT_LENGTH
);
696 vg_strcat( &freecam_text
,
697 player_replay
.use_freecam
? "exit freecam": "freecam" );
700 void skaterift_replay_post_render(void)
702 #ifndef SR_ALLOW_REWIND_HUB
703 if( world_static
.active_instance
!= k_world_purpose_client
)
707 /* capture the current resume frame at the very last point */
708 if( button_down( k_srbind_reset
) )
710 if( skaterift
.activity
== k_skaterift_default
)
712 localplayer
.rewinded_since_last_gate
= 1;
713 skaterift
.activity
= k_skaterift_replay
;
714 skaterift_record_frame( &player_replay
.local
, 1 );
715 if( player_replay
.local
.head
)
717 player_replay
.local
.cursor
= player_replay
.local
.head
->time
;
718 player_replay
.local
.cursor_frame
= player_replay
.local
.head
;
720 player_replay
.replay_control
= k_replay_control_scrub
;
725 if( gui_new_helper( input_axis_list
[k_sraxis_replay_h
], &text
) )
726 vg_strcat( &text
, "scrub" );
728 if( (player_replay
.helper_resume
= gui_new_helper(
729 input_button_list
[k_srbind_replay_resume
], &text
)) )
730 vg_strcat( &text
, "resume" );
732 if( gui_new_helper( input_button_list
[k_srbind_replay_play
], &text
))
733 vg_strcat( &text
, "playback" );
735 player_replay
.helper_freecam
= gui_new_helper(
736 input_button_list
[k_srbind_replay_freecam
], &text
);
738 skaterift_replay_update_helpers();
743 void skaterift_replay_init(void)
745 u32 bytes
= 1024*1024*10;
746 player_replay
.local
.data
= vg_linear_alloc( vg_mem
.rtmemory
, bytes
);
747 player_replay
.local
.size
= bytes
;
748 replay_clear( &player_replay
.local
);
750 vg_console_reg_var( "replay_editor", &player_replay
.editor_mode
,
751 k_var_dtype_i32
, VG_VAR_PERSISTENT
);
754 void skaterift_replay_debug_info(void)
756 player__debugtext( 2, "replay info" );
757 replay_buffer
*replay
= &player_replay
.local
;
761 if( replay
->tail
) tail
= (void *)replay
->tail
- replay
->data
;
762 if( replay
->head
) head
= (void *)replay
->head
- replay
->data
;
764 player__debugtext( 1, "head @%u | tail @%u\n", head
, tail
);
766 if( replay
->statehead
){
767 for( u32 i
=0; i
<k_replay_framedata_rows
; i
++ ){
768 player__debugtext( 1, "[%u]: [%hu, %hu]\n", i
,
769 replay
->statehead
->data_table
[i
][0],
770 replay
->statehead
->data_table
[i
][1] );
772 u32 state
= (void *)replay
->statehead
- replay
->data
;
773 player__debugtext( 1, "gs @%u\n", state
);
774 player__debugtext( 1, "gamestate_size: %hu\n",
775 replay
->statehead
->data_table
[k_replay_framedata_gamestate
][1] );
778 player__debugtext( 1, "gs @NULL\n" );
780 f64 start
= replay
->cursor
,
781 end
= replay
->cursor
;
782 if( replay
->tail
) start
= replay
->tail
->time
;
783 if( replay
->head
) end
= replay
->head
->time
;
785 f64 cur
= replay
->cursor
- start
,
788 player__debugtext( 1, "cursor: %.2fs / %.2fs\n", cur
, len
);
791 static int _keyframe_cmp( const void *p1
, const void *p2
)
793 const replay_keyframe
*kf1
= p1
, *kf2
= p2
;
794 return kf1
->time
> kf2
->time
;
797 static void replay_keyframe_sort(void)
799 qsort( player_replay
.keyframes
, player_replay
.keyframe_count
,
800 sizeof(replay_keyframe
), _keyframe_cmp
);
803 static void replay_editor_imgui(void)
808 void skaterift_replay_imgui(void)
810 if( skaterift
.activity
!= k_skaterift_replay
) return;
812 replay_buffer
*replay
= &player_replay
.local
;
813 f64 start
= replay
->cursor
,
814 end
= replay
->cursor
;
815 if( replay
->tail
) start
= replay
->tail
->time
;
816 if( replay
->head
) end
= replay
->head
->time
;
817 f64 len
= end
- start
,
818 cur
= (replay
->cursor
- start
) / len
;
825 ui_rect timeline
= { 0, 0, vg
.window_x
, height
};
826 ui_fill( timeline
, ui_colour( k_ui_bg
) );
828 /* cursor frame block */
829 if( replay
->cursor_frame
)
831 if( replay
->cursor_frame
->r
)
833 f64 l
= (replay
->cursor_frame
->r
->time
-replay
->cursor_frame
->time
)/len
,
834 s
= (replay
->cursor_frame
->time
- start
) / len
;
835 ui_rect box
= { s
*(f64
)vg
.window_x
, 0,
836 VG_MAX(4,(ui_px
)(l
*vg
.window_x
)), timeline
[3]+2 };
837 ui_fill( box
, ui_colour( k_ui_bg
+4 ) );
842 ui_rect cusor
= { cur
* (f64
)vg
.window_x
- (cwidth
/2), 0,
843 cwidth
, (player_replay
.editor_mode
? 0: 16) + timeline
[3] };
844 ui_fill( cusor
, ui_colour( k_ui_bg
+7 ) );
846 /* latest state marker */
847 if( replay
->statehead
)
849 f64 t
= (replay
->statehead
->time
- start
) / len
;
850 ui_rect tag
= { t
*(f64
)vg
.window_x
, 0, 2, timeline
[3]+8 };
851 ui_fill( tag
, ui_colour( k_ui_green
+k_ui_brighter
) );
854 /* previous state marker */
855 replay_frame
*prev
= replay_find_recent_stateframe( replay
);
858 f64 t
= (prev
->time
- start
) / len
;
859 ui_rect tag
= { t
*(f64
)vg
.window_x
, 0, 2, timeline
[3]+8 };
860 ui_fill( tag
, ui_colour( k_ui_yellow
+k_ui_brighter
) );
865 snprintf( buffer
, 128, "-%.2fs\n", (end
-replay
->cursor
) );
866 ui_text( cusor
, buffer
, 1, k_ui_align_middle_left
, 0 );
868 snprintf( buffer
, 128, "-%.2fs\n", len
);
869 ui_text( timeline
, buffer
, 1, k_ui_align_middle_left
, 0 );
870 ui_text( timeline
, "0s", 1, k_ui_align_middle_right
, 0 );
872 if( player_replay
.editor_mode
)
875 vg_ui
.wants_mouse
= 1;
877 ui_rect panel
= { 0, timeline
[3] + 20, 200, 400 };
878 ui_fill( panel
, ui_opacity( ui_colour(k_ui_bg
), 0.5f
) );
879 ui_rect_pad( panel
, (ui_px
[2]){4,4} );
881 if( ui_button( panel
,
882 (player_replay
.replay_control
== k_replay_control_play
)?
883 "Pause": "Play" ) == k_ui_button_click
)
885 player_replay
.replay_control
^= k_replay_control_play
;
892 ui_rect script
= { 0, height
+ 2, vg
.window_x
, 16 };
893 ui_fill( script
, ui_colour( k_ui_bg
) );
895 f64 mouse_t
= start
+ ((f64
)vg_ui
.mouse
[0] / (f64
)vg
.window_x
)*len
;
897 /* keyframe draw and select */
898 bool absorb_by_keyframe
= 0;
900 for( u32 i
=0; i
<player_replay
.keyframe_count
; i
++ )
902 replay_keyframe
*kf
= &player_replay
.keyframes
[i
];
903 f64 t
= (kf
->time
-start
)/len
;
905 ui_px x
= t
*(f64
)vg
.window_x
-8;
909 ui_rect con
= { lx
, script
[1]+7, x
-lx
, 1 };
910 ui_fill( con
, ui_colour(k_ui_blue
) );
912 vg_line( kf
->cam
.pos
,
913 player_replay
.keyframes
[i
-1].cam
.pos
, VG__BLUE
);
916 ui_rect tag
= { x
, script
[1], 16, 16 };
918 if( ui_inside_rect( tag
, vg_ui
.mouse
) )
920 absorb_by_keyframe
= 1;
922 if( ui_click_down( UI_MOUSE_LEFT
) )
924 if( player_replay
.active_keyframe
!= i
)
926 player_replay
.drag_wait
= 1;
927 player_replay
.active_keyframe
= i
;
928 replay_seek( &player_replay
.local
, kf
->time
);
933 ui_outline( tag
, 1, ui_colour(k_ui_fg
), 0 );
937 if( i
== player_replay
.active_keyframe
)
939 ui_outline( tag
, 2, ui_colour(k_ui_fg
), 0 );
941 if( ui_inside_rect( tag
, vg_ui
.mouse_click
)
942 && !player_replay
.drag_wait
)
944 if( ui_clicking( UI_MOUSE_LEFT
) )
946 absorb_by_keyframe
= 1;
947 tag
[0] = vg_ui
.mouse
[0]-8;
948 replay_seek( &player_replay
.local
, mouse_t
);
950 else if( ui_click_up( UI_MOUSE_LEFT
) )
953 replay_keyframe_sort();
958 ui_fill( tag
, ui_colour(k_ui_blue
) );
962 if( player_replay
.drag_wait
&& !ui_clicking(UI_MOUSE_LEFT
) )
963 player_replay
.drag_wait
= 0;
965 /* adding keyframes */
966 if( ui_inside_rect( script
, vg_ui
.mouse
) )
968 vg_ui
.cursor
= k_ui_cursor_hand
;
970 ui_rect cursor
= { vg_ui
.mouse
[0], script
[1], 4, 16 };
971 ui_fill( cursor
, ui_colour( k_ui_fg
) );
973 if( !absorb_by_keyframe
&& ui_click_down( UI_MOUSE_LEFT
) )
975 u32 max
= vg_list_size( player_replay
.keyframes
);
976 if( player_replay
.keyframe_count
== max
)
978 ui_start_modal( "Maximum keyframes reached", UI_MODAL_BAD
);
982 replay_keyframe
*kf
=
983 &player_replay
.keyframes
[player_replay
.keyframe_count
++];
986 v3_copy( skaterift
.cam
.pos
, kf
->cam
.pos
);
987 v3_copy( skaterift
.cam
.angles
, kf
->cam
.angles
);
988 kf
->cam
.fov
= skaterift
.cam
.fov
;
990 replay_keyframe_sort();
997 bool start_in_timeline
=
998 ui_clicking(UI_MOUSE_LEFT
) &&
999 ui_inside_rect(timeline
, vg_ui
.mouse_click
);
1000 if( (ui_inside_rect( timeline
, vg_ui
.mouse
)) || start_in_timeline
)
1002 ui_rect cursor
= { vg_ui
.mouse
[0], timeline
[1], 4, timeline
[3] };
1003 ui_fill( cursor
, ui_colour( k_ui_fg
) );
1004 vg_ui
.cursor
= k_ui_cursor_ibeam
;
1006 if( ui_clicking( UI_MOUSE_LEFT
) && start_in_timeline
)
1008 replay_seek( &player_replay
.local
, mouse_t
);
1009 player_replay
.active_keyframe
= -1;
1013 if( player_replay
.active_keyframe
!= -1 )
1015 replay_keyframe
*kf
=
1016 &player_replay
.keyframes
[ player_replay
.active_keyframe
];
1018 enum ui_button_state mask_using
=
1019 k_ui_button_holding_inside
|
1020 k_ui_button_holding_outside
|
1023 if( ui_button( panel
, "Edit cam" ) & mask_using
)
1025 if( ui_click_down( UI_MOUSE_LEFT
) )
1028 v3_copy( kf
->cam
.pos
, player_replay
.replay_freecam
.pos
);
1029 v3_copy( kf
->cam
.angles
, player_replay
.replay_freecam
.angles
);
1030 player_replay
.replay_freecam
.fov
= kf
->cam
.fov
;
1034 vg_ui
.wants_mouse
= 0;
1035 freecam_preupdate();
1037 v3_copy( player_replay
.replay_freecam
.pos
, skaterift
.cam
.pos
);
1038 v3_copy( player_replay
.replay_freecam
.angles
, skaterift
.cam
.angles
);
1039 skaterift
.cam
.fov
= player_replay
.replay_freecam
.fov
;
1041 v3_copy( skaterift
.cam
.pos
, kf
->cam
.pos
);
1042 v3_copy( skaterift
.cam
.angles
, kf
->cam
.angles
);
1043 kf
->cam
.fov
= skaterift
.cam
.fov
;