@@ -47,6 +47,9 @@ Variable sar_cam_path_interp("sar_cam_path_interp", "2", 0, 2,
4747
4848Variable sar_cam_path_draw (" sar_cam_path_draw" , " 0" , 0 , 1 , " Draws a representation of the camera path in the world. Disabled in cinematic mode.\n " );
4949
50+ Variable sar_cam_path_sync_to_demo (" sar_cam_path_sync_to_demo" , " 1" , 0 , 1 ,
51+ " If enabled, path will be synchronized to demo in cinematic mode.\n " );
52+
5053Variable cl_skip_player_render_in_main_view;
5154Variable ss_force_primary_fullscreen;
5255
@@ -74,6 +77,16 @@ ON_EVENT(SAR_UNLOAD) {
7477 ResetCameraRelatedCvars ();
7578}
7679
80+ ON_EVENT (DEMO_START) {
81+ if (sar_cam_path_sync_to_demo.GetBool ()) {
82+ camera->ActivatePath ();
83+ }
84+ }
85+
86+ float Camera::GetCurrentPathTime () {
87+ return pathActive ? engine->GetClientTime () - timeOffset : 0 .0f ;
88+ }
89+
7790// if in drive mode, checks if player wants to control the camera
7891// for now it requires LMB input (as in demo drive mode)
7992bool Camera::IsDriving () {
@@ -279,7 +292,7 @@ void Camera::DrawInWorld() const {
279292
280293 if (camera->states .size () < 2 ) return ;
281294
282- if (!(sv_cheats. GetBool () || engine-> demoplayer -> IsPlaying () ) || !sar_cam_path_draw.GetBool () || sar_cam_control.GetInt () == 2 ) return ;
295+ if (!camera-> CanUseNonDefaultMode ( ) || !sar_cam_path_draw.GetBool () || sar_cam_control.GetInt () == 2 ) return ;
283296
284297 MeshId mesh_path = OverlayRender::createMesh (RenderCallback::none, RenderCallback::constant ({ 255 , 255 , 255 }, true ));
285298 MeshId mesh_cams = OverlayRender::createMesh (RenderCallback::none, RenderCallback::constant ({ 255 , 0 , 0 }, true ));
@@ -312,9 +325,7 @@ void Camera::DrawInWorld() const {
312325
313326 // draw fov things at each keyframe and the current one
314327 // the way this is done is rather sacrilegious
315-
316- float currentTime = engine->GetClientTime () - timeOffset;
317- CameraState currentCameraState = camera->InterpolateStates (currentTime);
328+ CameraState currentCameraState = camera->InterpolateStates (camera->GetCurrentPathTime ());
318329
319330 std::vector<int > keyframeTicks (camera->states .size ());
320331 int i = 0 ;
@@ -388,40 +399,18 @@ void Camera::OverrideView(ViewSetup *m_View) {
388399 }
389400
390401 if (timeOffsetRefreshRequested) {
391- timeOffset = engine->GetClientTime () - engine->demoplayer ->GetTick () * engine->GetIPT ();
402+ timeOffset = engine->GetClientTime ();
403+ if (IsSyncingPathToDemo ()) {
404+ timeOffset -= engine->demoplayer ->GetTick () * engine->GetIPT ();
405+ }
392406 timeOffsetRefreshRequested = false ;
393407 }
394408
395409 auto newControlType = static_cast <CameraControlType>(sar_cam_control.GetInt ());
396410
397- // don't allow cinematic mode outside of demo player
398- if (!engine->demoplayer ->IsPlaying () && newControlType == Cinematic) {
399- if (controlType != Cinematic) {
400- console->Print (" Cinematic mode cannot be used outside of demo player.\n " );
401- } else {
402- controlType = Default;
403- ResetCameraRelatedCvars ();
404- }
405- newControlType = controlType;
406- sar_cam_control.SetValue (controlType);
407- }
408-
409- // don't allow drive mode when not using sv_cheats
410- if (newControlType == Drive && !sv_cheats.GetBool () && !engine->demoplayer ->IsPlaying ()) {
411- if (controlType != Drive) {
412- console->Print (" Drive mode requires sv_cheats 1 or demo player.\n " );
413- } else {
414- controlType = Default;
415- ResetCameraRelatedCvars ();
416- }
417- newControlType = controlType;
418- sar_cam_control.SetValue (controlType);
419- }
420-
421- // don't allow follow mode when not using sv_cheats
422- if (newControlType == Follow && !sv_cheats.GetBool () && !engine->demoplayer ->IsPlaying ()) {
423- if (controlType != Follow) {
424- console->Print (" Follow mode requires sv_cheats 1 or demo player.\n " );
411+ if (newControlType != Default && !camera->CanUseNonDefaultMode ()) {
412+ if (controlType == Default) {
413+ console->Print (" Different camera modes require sv_cheats 1 or demo player.\n " );
425414 } else {
426415 controlType = Default;
427416 ResetCameraRelatedCvars ();
@@ -441,6 +430,9 @@ void Camera::OverrideView(ViewSetup *m_View) {
441430
442431 // handling camera control type switching
443432 if (newControlType != controlType) {
433+ if (newControlType == Cinematic && IsSyncingPathToDemo ()) {
434+ this ->ActivatePath ();
435+ }
444436 if (controlType == Default && newControlType != Default) {
445437 // enabling
446438 if (newControlType == Follow)
@@ -454,6 +446,11 @@ void Camera::OverrideView(ViewSetup *m_View) {
454446 controlType = newControlType;
455447 }
456448
449+ // reset path active state if outside of cinematic mode
450+ if (pathActive && controlType != Cinematic) {
451+ pathActive = false ;
452+ }
453+
457454 // don't do anything if not in game or demo player
458455 if (engine->hoststate ->m_activeGame || engine->demoplayer ->IsPlaying ()) {
459456 if (controlType == Default || cameraRefreshRequested) {
@@ -545,8 +542,7 @@ void Camera::OverrideView(ViewSetup *m_View) {
545542 if (controlType == Cinematic) {
546543 // don't do interpolation when there are no points
547544 if (states.size () > 0 ) {
548- float currentTime = engine->GetClientTime () - timeOffset;
549- currentState = InterpolateStates (currentTime);
545+ currentState = InterpolateStates (GetCurrentPathTime ());
550546 }
551547 }
552548 // applying custom view
@@ -579,8 +575,9 @@ void Camera::OverrideView(ViewSetup *m_View) {
579575 }
580576}
581577
582- void Camera::RequestTimeOffsetRefresh () {
578+ void Camera::ActivatePath () {
583579 timeOffsetRefreshRequested = true ;
580+ pathActive = true ;
584581}
585582
586583void Camera::RequestCameraRefresh () {
@@ -652,8 +649,11 @@ CON_COMMAND_F_COMPLETION(
652649 " sar_cam_path_setkf [frame] [x] [y] [z] [pitch] [yaw] [roll] [fov] - sets the camera path keyframe\n " ,
653650 0 ,
654651 AUTOCOMPLETION_FUNCTION (sar_cam_path_setkf)) {
655- if (!engine->demoplayer ->IsPlaying ())
656- return console->Print (" Cinematic mode cannot be used outside of demo player.\n " );
652+
653+ if (args.ArgC () == 1 && !engine->demoplayer ->IsPlaying ()) {
654+ console->Print (" Frame has to be explicitly defined outside of demo player.\n " );
655+ return ;
656+ }
657657
658658 if (args.ArgC () >= 1 && args.ArgC () <= 9 ) {
659659 CameraState campos = camera->currentState ;
@@ -713,8 +713,6 @@ CON_COMMAND_F_COMPLETION(
713713 " sar_cam_path_showkf <frame> - display information about camera path keyframe at specified frame\n " ,
714714 0 ,
715715 AUTOCOMPLETION_FUNCTION (sar_cam_path_showkf)) {
716- if (!engine->demoplayer ->IsPlaying ())
717- return console->Print (" Cinematic mode cannot be used outside of demo player.\n " );
718716
719717 if (args.ArgC () == 2 ) {
720718 int i = std::atoi (args[1 ]);
@@ -730,9 +728,6 @@ CON_COMMAND_F_COMPLETION(
730728}
731729
732730CON_COMMAND (sar_cam_path_getkfs, " sar_cam_path_getkfs - exports commands for recreating currently made camera path\n " ) {
733- if (!engine->demoplayer ->IsPlaying ())
734- return console->Print (" Cinematic mode cannot be used outside of demo player.\n " );
735-
736731 if (args.ArgC () == 1 ) {
737732 for (auto const &state : camera->states ) {
738733 CameraState cam = state.second ;
@@ -774,8 +769,6 @@ CON_COMMAND_F_COMPLETION(
774769 " sar_cam_path_remkf <frame> - removes camera path keyframe at specified frame\n " ,
775770 0 ,
776771 AUTOCOMPLETION_FUNCTION (sar_cam_path_remkf)) {
777- if (!engine->demoplayer ->IsPlaying ())
778- return console->Print (" Cinematic mode cannot be used outside of demo player.\n " );
779772
780773 if (args.ArgC () == 2 ) {
781774 int i = std::atoi (args[1 ]);
@@ -791,9 +784,6 @@ CON_COMMAND_F_COMPLETION(
791784}
792785
793786CON_COMMAND (sar_cam_path_remkfs, " sar_cam_path_remkfs - removes all camera path keyframes\n " ) {
794- if (!engine->demoplayer ->IsPlaying ())
795- return console->Print (" Cinematic mode cannot be used outside of demo player.\n " );
796-
797787 if (args.ArgC () == 1 ) {
798788 camera->states .clear ();
799789 console->Print (" All camera path keyframes have been removed.\n " );
@@ -987,3 +977,28 @@ CON_COMMAND(sar_cam_reset, "sar_cam_reset - resets camera to its default positio
987977 return console->Print (sar_cam_reset.ThisPtr ()->m_pszHelpString );
988978 }
989979}
980+
981+ CON_COMMAND (sar_cam_path_start, " sar_cam_path_start - starts playback of predefined camera path. (requires camera Cinematic Mode)" ) {
982+ if (args.ArgC () != 1 ) {
983+ return console->Print (sar_cam_path_start.ThisPtr ()->m_pszHelpString );
984+ }
985+
986+ if (camera->states .size () == 0 ) {
987+ return console->Print (" No camera path has been defined.\n " );
988+ }
989+
990+ if (engine->demoplayer ->IsPlaying () && sar_cam_path_sync_to_demo.GetBool ()) {
991+ return console->Print (" Cannot restart the path. Camera path is synchronized to demo time. Turn off sar_cam_path_sync_to_demo.\n " );
992+ }
993+
994+ if (camera->controlType != Cinematic) {
995+ if (!camera->CanUseNonDefaultMode ()) {
996+ return console->Print (" Camera path cannot be started - switching to cinematic mode is not possible.\n " );
997+ }
998+
999+ console->Print (" Camera has been switched to cinematic mode. You can switch it back with 'sar_cam_control' cvar.\n " );
1000+ sar_cam_control.SetValue (CameraControlType::Cinematic);
1001+ }
1002+
1003+ camera->ActivatePath ();
1004+ }
0 commit comments