From 835d023b980ab18e406efb26252494d15b44471d Mon Sep 17 00:00:00 2001 From: Efraim2704 Date: Wed, 13 May 2026 13:26:49 +0200 Subject: [PATCH 1/2] Kyoto/Animation: add CAnimMathUtils --- include/Kyoto/Animation/CAnimMathUtils.hpp | 12 +++ src/Kyoto/Animation/CAnimMathUtils.cpp | 87 ++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 include/Kyoto/Animation/CAnimMathUtils.hpp create mode 100644 src/Kyoto/Animation/CAnimMathUtils.cpp diff --git a/include/Kyoto/Animation/CAnimMathUtils.hpp b/include/Kyoto/Animation/CAnimMathUtils.hpp new file mode 100644 index 00000000..b31fba99 --- /dev/null +++ b/include/Kyoto/Animation/CAnimMathUtils.hpp @@ -0,0 +1,12 @@ +#ifndef _CANIMMATHUTILS +#define _CANIMMATHUTILS + +#include "Kyoto/Math/CQuaternion.hpp" + +class CAnimMathUtils { +public: + static CQuaternion Slerp(const CQuaternion& a, const CQuaternion& b, float t); + static CQuaternion SlerpLocal(const CQuaternion& from, const CQuaternion& to, float t); +}; + +#endif // _CANIMMATHUTILS \ No newline at end of file diff --git a/src/Kyoto/Animation/CAnimMathUtils.cpp b/src/Kyoto/Animation/CAnimMathUtils.cpp new file mode 100644 index 00000000..3ef1fe3e --- /dev/null +++ b/src/Kyoto/Animation/CAnimMathUtils.cpp @@ -0,0 +1,87 @@ +#include "Kyoto/Animation/CAnimMathUtils.hpp" +#include "Kyoto/Math/CQuaternion.hpp" +#include "Kyoto/Math/CMath.hpp" +#include "rstl/vector.hpp" + +CQuaternion CAnimMathUtils::Slerp(const CQuaternion& a, const CQuaternion& b, float t) { + if (t <= 0.00001f) { + return a; + } + if (t >= 0.99999f) { + return b; + } + float dot = a.GetY() * b.GetY(); + dot = a.GetX() * b.GetX() + dot; + dot = a.GetZ() * b.GetZ() + dot; + dot = a.GetW() * b.GetW() + dot; + if (dot >= 1.0f) { + return a; + } + if (dot > 0.95f) { + float dx = b.GetX() - a.GetX(); + float dy = b.GetY() - a.GetY(); + float dz = b.GetZ() - a.GetZ(); + float lx = t * dx; + float lz = t * dz; + float ly = t * dy; + float rx = a.GetX() + lx; + float dw = b.GetW() - a.GetW(); + float ry = a.GetY() + ly; + float rz = a.GetZ() + lz; + float lw = t * dw; + float rw = a.GetW() + lw; + float lenSq = rx * rx + ry * ry + rz * rz + rw * rw; + float inv = CMath::InvSqrtF(lenSq); + return CQuaternion(inv * rw, inv * rx, inv * ry, inv * rz); + } + float angle = CMath::FastArcCosR(dot); + float sinA = CMath::FastSinR(angle * (1.0f - t)); + float sinB = CMath::FastSinR(angle * t); + #pragma fp_contract off + float r4 = sinA * a.GetX(); + float r3 = sinB * b.GetX(); + float r2 = sinA * a.GetY(); + float r0 = sinB * b.GetY(); + float r6 = sinA * a.GetZ(); + float r5 = sinB * b.GetZ(); + float r7 = sinA * a.GetW(); + float r1 = sinB * b.GetW(); + #pragma fp_contract on + float r29 = r2 + r0; + float r28 = r4 + r3; + float r31 = r6 + r5; + float r30 = r7 + r1; + float lenSq2 = r29 * r29 + r28 * r28 + r31 * r31 + r30 * r30; + float inv2 = CMath::InvSqrtF(lenSq2); + return CQuaternion(inv2 * r30, inv2 * r29, inv2 * r28, inv2 * r31); +} + +CQuaternion CAnimMathUtils::SlerpLocal(const CQuaternion& from, const CQuaternion& to, float t) { + float dot = from.GetY() * to.GetY(); + dot = from.GetX() * to.GetX() + dot; + dot = from.GetZ() * to.GetZ() + dot; + dot = from.GetW() * to.GetW() + dot; + if (dot >= 0.0f) { + return CAnimMathUtils::Slerp(from, to, t); + } + CQuaternion toEq = to.BuildEquivalent(); + return CAnimMathUtils::Slerp(from, toEq, t); +} + +template <> +rstl::vector< CQuaternion, rstl::rmemory_allocator >::vector(CInputStream& in, + const rstl::rmemory_allocator& alloc) +: x0_allocator(alloc), x4_count(0), x8_capacity(0), xc_items(nullptr) { + int count = in.ReadLong(); + reserve(count); + for (int i = 0; i < count; ++i) { + CQuaternion q(in); + if (x4_count >= x8_capacity) { + reserve(x8_capacity == 0 ? 4 : x8_capacity * 2); + } + if (xc_items != nullptr) { + xc_items[x4_count] = q; + } + ++x4_count; + } +} \ No newline at end of file From ca70a522e6510cfb194eefc51b4802b5cb4654cd Mon Sep 17 00:00:00 2001 From: Efraim2704 Date: Wed, 13 May 2026 14:29:22 +0200 Subject: [PATCH 2/2] Kyoto/Animation: add CMetaAnimBlend, CAnimTreeBlend --- include/Kyoto/Animation/CAnimTreeBlend.hpp | 20 ++++++++++++++++++ include/Kyoto/Animation/IMetaAnim.hpp | 17 +-------------- src/Kyoto/Animation/CMetaAnimBlend.cpp | 24 ++++++++++++++++++++-- 3 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 include/Kyoto/Animation/CAnimTreeBlend.hpp diff --git a/include/Kyoto/Animation/CAnimTreeBlend.hpp b/include/Kyoto/Animation/CAnimTreeBlend.hpp new file mode 100644 index 00000000..ae165a60 --- /dev/null +++ b/include/Kyoto/Animation/CAnimTreeBlend.hpp @@ -0,0 +1,20 @@ +#ifndef _CANIMTREEBLEND +#define _CANIMTREEBLEND + +#include "Kyoto/Animation/CAnimTreeTweenBase.hpp" + +class CAnimTreeBlend : public CAnimTreeTweenBase { + float x24_blendWeight; +public: + CAnimTreeBlend(bool b, const rstl::ncrc_ptr< CAnimTreeNode >& a, + const rstl::ncrc_ptr< CAnimTreeNode >& b2, int flags, + const rstl::string& name); + void SetBlendingWeight(float w) override { x24_blendWeight = w; } + float VGetBlendingWeight() const override { return x24_blendWeight; } + float VGetRightChildWeight() const override { return x24_blendWeight; } + CCharAnimTime VGetTimeRemaining() const override; + CSteadyStateAnimInfo VGetSteadyStateAnimInfo() const override; + rstl::auto_ptr< IAnimReader > VClone() const override; +}; + +#endif // _CANIMTREEBLEND \ No newline at end of file diff --git a/include/Kyoto/Animation/IMetaAnim.hpp b/include/Kyoto/Animation/IMetaAnim.hpp index 4636264f..70698c1e 100644 --- a/include/Kyoto/Animation/IMetaAnim.hpp +++ b/include/Kyoto/Animation/IMetaAnim.hpp @@ -1,13 +1,10 @@ #ifndef _IMETAANIM #define _IMETAANIM - #include "Kyoto/Animation/CCharAnimTime.hpp" - #include #include #include #include - enum EMetaAnimType { kMAT_Play, kMAT_Blend, @@ -15,44 +12,35 @@ enum EMetaAnimType { kMAT_Random, kMAT_Sequence, }; - class CAnimTreeNode; class CPrimitive; class CCharAnimTime; class IAnimReader; class CAnimSysContext; - class CPreAdvanceIndicator { bool mIsTime; CCharAnimTime mTime; const char* mString; uint x10_[11]; ushort x3c_; - public: explicit CPreAdvanceIndicator(const CCharAnimTime& time) : mIsTime(true), mTime(time), mString(0) {} explicit CPreAdvanceIndicator(const char* string) : mIsTime(false), mString(string) {} bool IsTime() const; const CCharAnimTime& GetTime() const; - bool IsString() const; const char* const& GetString() const; }; - class CMetaAnimTreeBuildOrders { public: static CMetaAnimTreeBuildOrders NoSpecialOrders(); static CMetaAnimTreeBuildOrders PreAdvanceForAll(const CPreAdvanceIndicator& ind); - -private: rstl::optional_object< CPreAdvanceIndicator > mRecursiveAdvance; rstl::optional_object< CPreAdvanceIndicator > mSingleAdvance; }; - class IMetaAnim { public: virtual ~IMetaAnim() {} - virtual rstl::rc_ptr< CAnimTreeNode > GetAnimationTree(const CAnimSysContext& animSys, const CMetaAnimTreeBuildOrders& orders) const; virtual void GetUniquePrimitives(rstl::set< CPrimitive >& primsOut) const = 0; @@ -60,11 +48,8 @@ class IMetaAnim { virtual rstl::rc_ptr< CAnimTreeNode > VGetAnimationTree(const CAnimSysContext& animSys, const CMetaAnimTreeBuildOrders& orders) const = 0; - void PutTo(COutputStream&) const; - static void AdvanceAnim(IAnimReader& anim, const CCharAnimTime& dt); static CCharAnimTime GetTime(const CPreAdvanceIndicator& ind, const IAnimReader& anim); }; - -#endif // _IMETAANIM +#endif // _IMETAANIM \ No newline at end of file diff --git a/src/Kyoto/Animation/CMetaAnimBlend.cpp b/src/Kyoto/Animation/CMetaAnimBlend.cpp index 498e9b9c..4e729911 100644 --- a/src/Kyoto/Animation/CMetaAnimBlend.cpp +++ b/src/Kyoto/Animation/CMetaAnimBlend.cpp @@ -1,4 +1,5 @@ #include "Kyoto/Animation/CMetaAnimBlend.hpp" +#include "Kyoto/Animation/CAnimTreeBlend.hpp" #include "Kyoto/Animation/CMetaAnimFactory.hpp" #include "Kyoto/Streams/CInputStream.hpp" #include "Kyoto/Streams/COutputStream.hpp" @@ -11,7 +12,26 @@ CMetaAnimBlend::CMetaAnimBlend(CInputStream& in) rstl::rc_ptr< CAnimTreeNode > CMetaAnimBlend::VGetAnimationTree(const CAnimSysContext& animSys, - const CMetaAnimTreeBuildOrders& orders) const {} + const CMetaAnimTreeBuildOrders& orders) const { + CMetaAnimTreeBuildOrders ordersA = CMetaAnimTreeBuildOrders::NoSpecialOrders(); + CMetaAnimTreeBuildOrders ordersB = CMetaAnimTreeBuildOrders::NoSpecialOrders(); + + if (orders.mRecursiveAdvance) { + ordersA = CMetaAnimTreeBuildOrders::PreAdvanceForAll(*orders.mRecursiveAdvance); + } + + if (orders.mSingleAdvance) { + ordersB = CMetaAnimTreeBuildOrders::PreAdvanceForAll(*orders.mSingleAdvance); + } + + rstl::rc_ptr< CAnimTreeNode > treeA = x4_animA->GetAnimationTree(animSys, ordersA); + rstl::rc_ptr< CAnimTreeNode > treeB = x8_animB->GetAnimationTree(animSys, ordersB); + + CAnimTreeBlend* blend = new CAnimTreeBlend(x10_, treeA, treeB, 0, rstl::string_l("??(??)") + ); + blend->SetBlendingWeight(xc_blend); + return rstl::rc_ptr< CAnimTreeNode >(blend); +} void CMetaAnimBlend::GetUniquePrimitives(rstl::set< CPrimitive >& primsOut) const { x4_animA->GetUniquePrimitives(primsOut); @@ -23,4 +43,4 @@ void CMetaAnimBlend::WriteAnimData(COutputStream& out) const { x8_animB->PutTo(out); out.WriteReal32(xc_blend); out.WriteChar(bool(x10_)); -} +} \ No newline at end of file