From 9fc370833bf3c43127fa250bb86413853123b715 Mon Sep 17 00:00:00 2001 From: Lwmte <3331699+Lwmte@users.noreply.github.com> Date: Fri, 28 Mar 2025 21:36:37 +0100 Subject: [PATCH] Implement flyby spline looping in lua API --- CHANGELOG.md | 1 + Documentation/doc/1 modules/View.html | 18 ++++++-- TombEngine/Game/spotcam.cpp | 44 +++++++++++++++---- TombEngine/Game/spotcam.h | 2 +- .../Internal/TEN/View/ViewHandler.cpp | 10 +++-- 5 files changed, 58 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f1ceec64..3d47c249b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ TombEngine releases are located in this repository (alongside with Tomb Editor): ### Lua API changes * Added missing constructor for `Collision.Probe` without room number. +* Added optional looping argument for `View.GetFlybyPosition` and `View.GetFlybyRotation` functions. ## [Version 1.8](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.8) - 2025-03-16 diff --git a/Documentation/doc/1 modules/View.html b/Documentation/doc/1 modules/View.html index f1725ceb1..40f491a7b 100644 --- a/Documentation/doc/1 modules/View.html +++ b/Documentation/doc/1 modules/View.html @@ -176,11 +176,11 @@ Play a flyby sequence. - GetFlybyPosition(seqID, progress) + GetFlybyPosition(seqID, progress[, loop]) Get a flyby sequence's position at a specified progress point in percent. - GetFlybyRotation(seqID, progress) + GetFlybyRotation(seqID, progress[, loop]) Get a flyby sequence's rotation at a specified progress point in percent. @@ -499,7 +499,7 @@
- GetFlybyPosition(seqID, progress) + GetFlybyPosition(seqID, progress[, loop])
Get a flyby sequence's position at a specified progress point in percent. @@ -516,6 +516,11 @@ float Progress point in percent. Clamped to [0, 100]. +
  • loop + bool + Smooth the position near start and end points, as if the sequence is looped. + (optional) +
  • Returns:

    @@ -531,7 +536,7 @@
    - GetFlybyRotation(seqID, progress) + GetFlybyRotation(seqID, progress[, loop])
    Get a flyby sequence's rotation at a specified progress point in percent. @@ -548,6 +553,11 @@ float Progress point in percent. Clamped to [0, 100]. +
  • loop + bool + Smooth the position near start and end points, as if the sequence is looped. + (optional) +
  • Returns:

    diff --git a/TombEngine/Game/spotcam.cpp b/TombEngine/Game/spotcam.cpp index ffa8be942..2b6ea8d10 100644 --- a/TombEngine/Game/spotcam.cpp +++ b/TombEngine/Game/spotcam.cpp @@ -839,7 +839,7 @@ int Spline(int x, int* knots, int nk) return ((__int64)x * (((__int64)x * (((__int64)x * c1 >> 16) + c2) >> 16) + (k[2] >> 1) + ((-k[0] - 1) >> 1)) >> 16) + k[1]; } -Pose GetCameraTransform(int sequence, float alpha) +Pose GetCameraTransform(int sequence, float alpha, bool loop) { alpha = std::clamp(alpha, 0.0f, 1.0f); @@ -873,15 +873,43 @@ Pose GetCameraTransform(int sequence, float alpha) } // Compute spline interpolation of main flyby camera parameters. - auto origin = Vector3(Spline(splineAlpha, xOrigins.data(), splinePoints), - Spline(splineAlpha, yOrigins.data(), splinePoints), - Spline(splineAlpha, zOrigins.data(), splinePoints)); + auto getInterpolatedPoint = [&](float t, std::vector& x, std::vector& y, std::vector& z) + { + int tAlpha = int(t * (float)USHRT_MAX); + return Vector3(Spline(tAlpha, x.data(), splinePoints), + Spline(tAlpha, y.data(), splinePoints), + Spline(tAlpha, z.data(), splinePoints)); + }; - auto target = Vector3(Spline(splineAlpha, xTargets.data(), splinePoints), - Spline(splineAlpha, yTargets.data(), splinePoints), - Spline(splineAlpha, zTargets.data(), splinePoints)); + auto getInterpolatedRoll = [&](float t) + { + int tAlpha = int(t * (float)USHRT_MAX); + return Spline(tAlpha, rolls.data(), splinePoints); + }; - short orientZ = Spline(splineAlpha, rolls.data(), splinePoints); + Vector3 origin = {}; + Vector3 target = {}; + short orientZ = 0; + + constexpr float BLEND_RANGE = 0.1f; + constexpr float BLEND_START = BLEND_RANGE; + constexpr float BLEND_END = 1.0f - BLEND_RANGE; + + // If loop is enabled and we are at the start or end of the sequence, blend between the last and first cameras. + if (loop && (alpha < BLEND_START || alpha >= BLEND_END)) + { + float blendFactor = (alpha < BLEND_START) ? 0.5f + (alpha / BLEND_RANGE) * 0.5f : (alpha - BLEND_END) / BLEND_START * 0.5f; + + origin = Vector3::Lerp(getInterpolatedPoint(BLEND_END, xOrigins, yOrigins, zOrigins), getInterpolatedPoint(BLEND_START, xOrigins, yOrigins, zOrigins), blendFactor); + target = Vector3::Lerp(getInterpolatedPoint(BLEND_END, xTargets, yTargets, zTargets), getInterpolatedPoint(BLEND_START, xTargets, yTargets, zTargets), blendFactor); + orientZ = Lerp(getInterpolatedRoll(BLEND_END), getInterpolatedRoll(BLEND_START), blendFactor); + } + else + { + origin = getInterpolatedPoint(alpha, xOrigins, yOrigins, zOrigins); + target = getInterpolatedPoint(alpha, xTargets, yTargets, zTargets); + orientZ = getInterpolatedRoll(alpha); + } auto pose = Pose(origin, EulerAngles(target - origin)); pose.Orientation.z = orientZ; diff --git a/TombEngine/Game/spotcam.h b/TombEngine/Game/spotcam.h index 035929e93..07917c26d 100644 --- a/TombEngine/Game/spotcam.h +++ b/TombEngine/Game/spotcam.h @@ -64,4 +64,4 @@ void InitializeSpotCam(short sequence); void CalculateSpotCameras(); int Spline(int x, int* knots, int nk); -Pose GetCameraTransform(int sequence, float alpha); +Pose GetCameraTransform(int sequence, float alpha, bool loop); diff --git a/TombEngine/Scripting/Internal/TEN/View/ViewHandler.cpp b/TombEngine/Scripting/Internal/TEN/View/ViewHandler.cpp index 501784af1..8076215b2 100644 --- a/TombEngine/Scripting/Internal/TEN/View/ViewHandler.cpp +++ b/TombEngine/Scripting/Internal/TEN/View/ViewHandler.cpp @@ -111,18 +111,18 @@ namespace TEN::Scripting::View InitializeSpotCam(seqID); } - static Vec3 GetFlybyPosition(int seqID, float progress) + static Vec3 GetFlybyPosition(int seqID, float progress, TypeOrNil loop) { constexpr auto PROGRESS_MAX = 100.0f; - return Vec3(GetCameraTransform(seqID, progress / PROGRESS_MAX).Position); + return Vec3(GetCameraTransform(seqID, progress / PROGRESS_MAX, ValueOr(loop, false)).Position); } - static Rotation GetFlybyRotation(int seqID, float progress) + static Rotation GetFlybyRotation(int seqID, float progress, TypeOrNil loop) { constexpr auto PROGRESS_MAX = 100.0f; - return Rotation(GetCameraTransform(seqID, progress / PROGRESS_MAX).Orientation); + return Rotation(GetCameraTransform(seqID, progress / PROGRESS_MAX, ValueOr(loop, false)).Orientation); } static void FlashScreen(TypeOrNil col, TypeOrNil speed) @@ -244,6 +244,7 @@ namespace TEN::Scripting::View // @function GetFlybyPosition // @tparam int seqID Flyby sequence ID. // @tparam float progress Progress point in percent. Clamped to [0, 100]. + // @tparam[opt] bool loop Smooth the position near start and end points, as if the sequence is looped. // @treturn Vec3 Position at the given progress point. tableView.set_function(ScriptReserved_GetFlybyPosition, &GetFlybyPosition); @@ -251,6 +252,7 @@ namespace TEN::Scripting::View // @function GetFlybyRotation // @tparam int seqID Flyby sequence ID. // @tparam float progress Progress point in percent. Clamped to [0, 100]. + // @tparam[opt] bool loop Smooth the position near start and end points, as if the sequence is looped. // @treturn Rotation Rotation at the given progress point. tableView.set_function(ScriptReserved_GetFlybyRotation, &GetFlybyRotation);