diff --git a/Editor/ProjectResourceFactoryBase.cpp b/Editor/ProjectResourceFactoryBase.cpp index f5104386c..d74603735 100644 --- a/Editor/ProjectResourceFactoryBase.cpp +++ b/Editor/ProjectResourceFactoryBase.cpp @@ -1,6 +1,8 @@ #include "ProjectResourceFactoryBase.hpp" #include "Runtime/IObj.hpp" +#define DUMP_CACHE_FILL 1 + namespace urde { static logvisor::Module Log("urde::ProjectResourceFactoryBase"); @@ -93,6 +95,15 @@ static void WriteTag(athena::io::YAMLDocWriter& cacheWriter, cacheWriter.leaveSubVector(); } +#if DUMP_CACHE_FILL +static void DumpCacheAdd(const SObjectTag& pathTag, const hecl::ProjectPath& path) +{ + fprintf(stderr, "%s %08X %s\n", + pathTag.type.toString().c_str(), uint32_t(pathTag.id), + path.getRelativePathUTF8().c_str()); +} +#endif + void ProjectResourceFactoryBase::BackgroundIndexRecursiveProc(const hecl::ProjectPath& dir, athena::io::YAMLDocWriter& cacheWriter, athena::io::YAMLDocWriter& nameWriter, @@ -127,10 +138,8 @@ void ProjectResourceFactoryBase::BackgroundIndexRecursiveProc(const hecl::Projec std::unique_lock lk(m_backgroundIndexMutex); m_tagToPath[pathTag] = path; WriteTag(cacheWriter, pathTag, path); -#if 1 - fprintf(stderr, "%s %08X %s\n", - pathTag.type.toString().c_str(), uint32_t(pathTag.id), - path.getRelativePathUTF8().c_str()); +#if DUMP_CACHE_FILL + DumpCacheAdd(pathTag, path); #endif /* Special multi-resource intermediates */ @@ -150,11 +159,11 @@ void ProjectResourceFactoryBase::BackgroundIndexRecursiveProc(const hecl::Projec hecl::SystemStringView sysStr(arm); hecl::ProjectPath subPath = path.getWithExtension((_S('.') + sysStr.sys_str()).c_str(), true).ensureAuxInfo(_S("CINF")); SObjectTag pathTag = TagFromPath(subPath, m_backgroundBlender); - if (pathTag) - { - m_tagToPath[pathTag] = path; - WriteTag(cacheWriter, pathTag, path); - } + m_tagToPath[pathTag] = subPath; + WriteTag(cacheWriter, pathTag, subPath); +#if DUMP_CACHE_FILL + DumpCacheAdd(pathTag, subPath); +#endif } for (const std::string& sub : subtypeNames) @@ -162,11 +171,11 @@ void ProjectResourceFactoryBase::BackgroundIndexRecursiveProc(const hecl::Projec hecl::SystemStringView sysStr(sub); hecl::ProjectPath subPath = path.getWithExtension((_S('.') + sysStr.sys_str()).c_str(), true).ensureAuxInfo(_S("CSKR")); SObjectTag pathTag = TagFromPath(subPath, m_backgroundBlender); - if (pathTag) - { - m_tagToPath[pathTag] = path; - WriteTag(cacheWriter, pathTag, path); - } + m_tagToPath[pathTag] = subPath; + WriteTag(cacheWriter, pathTag, subPath); +#if DUMP_CACHE_FILL + DumpCacheAdd(pathTag, subPath); +#endif } for (const std::string& act : actionNames) @@ -174,11 +183,11 @@ void ProjectResourceFactoryBase::BackgroundIndexRecursiveProc(const hecl::Projec hecl::SystemStringView sysStr(act); hecl::ProjectPath subPath = path.getWithExtension((_S('.') + sysStr.sys_str()).c_str(), true).ensureAuxInfo(_S("ANIM")); SObjectTag pathTag = TagFromPath(subPath, m_backgroundBlender); - if (pathTag) - { - m_tagToPath[pathTag] = path; - WriteTag(cacheWriter, pathTag, path); - } + m_tagToPath[pathTag] = subPath; + WriteTag(cacheWriter, pathTag, subPath); +#if DUMP_CACHE_FILL + DumpCacheAdd(pathTag, subPath); +#endif } } } diff --git a/Editor/ProjectResourceFactoryMP1.cpp b/Editor/ProjectResourceFactoryMP1.cpp index 4efa29e07..8c53e8db0 100644 --- a/Editor/ProjectResourceFactoryMP1.cpp +++ b/Editor/ProjectResourceFactoryMP1.cpp @@ -49,6 +49,13 @@ void ProjectResourceFactoryMP1::IndexMP1Resources(hecl::Database::Project& proj) SObjectTag ProjectResourceFactoryMP1::TagFromPath(const hecl::ProjectPath& path, hecl::BlenderToken& btok) const { + if (!path.getAuxInfo().compare(_S("CINF"))) + return SObjectTag(SBIG('CINF'), path.hash().val32()); + else if (!path.getAuxInfo().compare(_S("CSKR"))) + return SObjectTag(SBIG('CSKR'), path.hash().val32()); + else if (!path.getAuxInfo().compare(_S("ANIM"))) + return SObjectTag(SBIG('ANIM'), path.hash().val32()); + if (hecl::IsPathBlend(path)) { hecl::BlenderConnection& conn = btok.getBlenderConnection(); diff --git a/Runtime/Character/CAdditiveAnimPlayback.cpp b/Runtime/Character/CAdditiveAnimPlayback.cpp new file mode 100644 index 000000000..182197a3c --- /dev/null +++ b/Runtime/Character/CAdditiveAnimPlayback.cpp @@ -0,0 +1,33 @@ +#include "CAdditiveAnimPlayback.hpp" +#include "CSegStatementSet.hpp" + +namespace urde +{ + +CAdditiveAnimPlayback::CAdditiveAnimPlayback(const std::weak_ptr& anim, float weight, bool a, + const CAdditiveAnimationInfo& info, bool b) +: x0_info(info), x8_anim(anim), xc_weight(weight), x14_a(a) +{ + if (!a && b) + x20_ = true; +} + +void CAdditiveAnimPlayback::AddToSegStatementSet(const CSegIdList& list, + const CCharLayoutInfo&, + CSegStatementSet&) const +{ +} + +void CAdditiveAnimPlayback::Update(float dt) +{ +} + +void CAdditiveAnimPlayback::FadeOut() +{ +} + +void CAdditiveAnimPlayback::SetWeight(float w) +{ +} + +} diff --git a/Runtime/Character/CAdditiveAnimPlayback.hpp b/Runtime/Character/CAdditiveAnimPlayback.hpp new file mode 100644 index 000000000..6cf825fe6 --- /dev/null +++ b/Runtime/Character/CAdditiveAnimPlayback.hpp @@ -0,0 +1,60 @@ +#ifndef __URDE_CADDITIVEANIMPLAYBACK_HPP__ +#define __URDE_CADDITIVEANIMPLAYBACK_HPP__ + +#include "RetroTypes.hpp" + +namespace urde +{ +class CAnimTreeNode; +class CAdditiveAnimationInfo; +class CSegIdList; +class CCharLayoutInfo; +class CSegStatementSet; + +class CAdditiveAnimationInfo +{ + float x0_a = 0.f; + float x4_b = 0.f; +public: + void read(CInputStream& in) + { + x0_a = in.readFloatBig(); + x4_b = in.readFloatBig(); + } + CAdditiveAnimationInfo() = default; + CAdditiveAnimationInfo(CInputStream& in) {read(in);} +}; + +class CAdditiveAnimPlayback +{ +public: + enum class EAdditivePlaybackState + { + Zero, + One, + Two, + Three, + Four + }; +private: + CAdditiveAnimationInfo x0_info; + std::weak_ptr x8_anim; + float xc_weight; + float x10_ = 0.f; + bool x14_a; + float x18_ = 0.f; + EAdditivePlaybackState x1c_ = EAdditivePlaybackState::One; + bool x20_ = false; +public: + CAdditiveAnimPlayback(const std::weak_ptr& anim, float weight, bool a, + const CAdditiveAnimationInfo& info, bool b); + + void AddToSegStatementSet(const CSegIdList& list, const CCharLayoutInfo&, CSegStatementSet&) const; + void Update(float dt); + void FadeOut(); + void SetWeight(float w); +}; + +} + +#endif // __URDE_CADDITIVEANIMPLAYBACK_HPP__ diff --git a/Runtime/Character/CAnimData.cpp b/Runtime/Character/CAnimData.cpp index db27de545..e3e08c727 100644 --- a/Runtime/Character/CAnimData.cpp +++ b/Runtime/Character/CAnimData.cpp @@ -5,6 +5,7 @@ #include "CCharacterFactory.hpp" #include "CAnimationManager.hpp" #include "CTransitionManager.hpp" +#include "CAdditiveAnimPlayback.hpp" #include "IAnimReader.hpp" namespace urde @@ -46,8 +47,9 @@ CAnimData::CAnimData(ResId id, xe4_iceModelData = *iceModel; } -ResId CAnimData::GetEventResourceIdForAnimResourceId(ResId) const +ResId CAnimData::GetEventResourceIdForAnimResourceId(ResId id) const { + return x0_charFactory->GetEventResourceIdForAnimResourceId(id); } void CAnimData::AddAdditiveSegData(const CSegIdList& list, CSegStatementSet& stSet) diff --git a/Runtime/Character/CAnimData.hpp b/Runtime/Character/CAnimData.hpp index fb2be8c2e..94e2fb539 100644 --- a/Runtime/Character/CAnimData.hpp +++ b/Runtime/Character/CAnimData.hpp @@ -36,6 +36,7 @@ class CSkinRules; class CAnimTreeNode; class CSegIdList; class CSegStatementSet; +class CAdditiveAnimPlayback; struct SAdvancementDeltas; class CAnimData @@ -96,7 +97,7 @@ class CAnimData u32 x1038_ = 0; u32 x103c_ = 0; u32 x1040_ = 0; - u32 x1044_ = 0; + rstl::reserved_vector, 8> x1044_additiveAnims; public: CAnimData(ResId, diff --git a/Runtime/Character/CAnimPerSegmentData.hpp b/Runtime/Character/CAnimPerSegmentData.hpp new file mode 100644 index 000000000..24fe8efa7 --- /dev/null +++ b/Runtime/Character/CAnimPerSegmentData.hpp @@ -0,0 +1,19 @@ +#ifndef __URDE_CANIMPERSEGMENTDATA_HPP__ +#define __URDE_CANIMPERSEGMENTDATA_HPP__ + +#include "zeus/CQuaternion.hpp" +#include "zeus/CVector3f.hpp" + +namespace urde +{ + +struct CAnimPerSegmentData +{ + zeus::CQuaternion x0_rotation; + zeus::CVector3f x10_offset; + bool x1c_hasOffset = false; +}; + +} + +#endif // __URDE_CANIMPERSEGMENTDATA_HPP__ diff --git a/Runtime/Character/CAnimSource.cpp b/Runtime/Character/CAnimSource.cpp index ac828a6d0..99cd8d32c 100644 --- a/Runtime/Character/CAnimSource.cpp +++ b/Runtime/Character/CAnimSource.cpp @@ -1,6 +1,8 @@ #include "CAnimSource.hpp" #include "CAnimPOIData.hpp" #include "CSegId.hpp" +#include "CSegIdList.hpp" +#include "CSegStatementSet.hpp" namespace urde { @@ -148,7 +150,37 @@ void CAnimSource::GetSegStatementSet(const CSegIdList& list, if (std::fabs(remTime) < 0.00001f) remTime = 0.f; float t = ClampZeroToOne(remTime / x8_interval); - /* TODO: Finish */ + const u32 floatsPerFrame = x40_data.x10_transPerFrame * 3 + x40_data.xc_rotPerFrame * 4; + const u32 rotFloatsPerFrame = x40_data.xc_rotPerFrame * 4; + + for (const CSegId& id : list.GetList()) + { + u8 rotIdx = x20_rotationChannels[id]; + if (rotIdx != 0xff) + { + const float* frameDataA = + &x40_data.x0_storage[frameIdx*floatsPerFrame+rotIdx*4]; + const float* frameDataB = + &x40_data.x0_storage[(frameIdx+1)*floatsPerFrame+rotIdx*4]; + + zeus::CQuaternion quatA(frameDataA[0], frameDataA[1], frameDataA[2], frameDataA[3]); + zeus::CQuaternion quatB(frameDataB[0], frameDataB[1], frameDataB[2], frameDataB[3]); + set.x4_segData[id].x0_rotation = zeus::CQuaternion::slerp(quatA, quatB, t); + + u8 transIdx = x30_translationChannels[rotIdx]; + if (transIdx != 0xff) + { + const float* frameDataA = + &x40_data.x0_storage[frameIdx*floatsPerFrame+rotFloatsPerFrame+transIdx*3]; + const float* frameDataB = + &x40_data.x0_storage[(frameIdx-1)*floatsPerFrame+rotFloatsPerFrame+transIdx*3]; + zeus::CVector3f vecA(frameDataA[0], frameDataA[1], frameDataA[2]); + zeus::CVector3f vecB(frameDataB[0], frameDataB[1], frameDataB[2]); + set.x4_segData[id].x10_offset = zeus::CVector3f::lerp(vecA, vecB, t); + set.x4_segData[id].x1c_hasOffset = true; + } + } + } } const std::vector& CAnimSource::GetSoundPOIStream() const diff --git a/Runtime/Character/CAnimSource.hpp b/Runtime/Character/CAnimSource.hpp index 9c4f9764d..e8cc440cd 100644 --- a/Runtime/Character/CAnimSource.hpp +++ b/Runtime/Character/CAnimSource.hpp @@ -74,6 +74,7 @@ public: const std::vector& GetParticlePOIStream() const; const std::vector& GetInt32POIStream() const; const std::vector& GetBoolPOIStream() const; + const TCachedToken& GetPOIData() const {return x58_evntData;} zeus::CQuaternion GetRotation(const CSegId& seg, const CCharAnimTime& time) const; zeus::CVector3f GetOffset(const CSegId& seg, const CCharAnimTime& time) const; bool HasOffset(const CSegId& seg) const; diff --git a/Runtime/Character/CAnimSourceReader.cpp b/Runtime/Character/CAnimSourceReader.cpp index 6e5400eb9..0bdf78fe4 100644 --- a/Runtime/Character/CAnimSourceReader.cpp +++ b/Runtime/Character/CAnimSourceReader.cpp @@ -241,61 +241,210 @@ CAnimSourceReaderBase::CAnimSourceReaderBase(std::unique_ptr&& const CCharAnimTime& time) : x4_sourceInfo(std::move(sourceInfo)), xc_curTime(time) {} -SAdvancementResults CAnimSourceReader::VGetAdvancementResults(const CCharAnimTime& a, - const CCharAnimTime& b) const +CAnimSourceReaderBase::CAnimSourceReaderBase(std::unique_ptr&& sourceInfo, + const CAnimSourceReaderBase& other) +: x4_sourceInfo(std::move(sourceInfo)), + xc_curTime(other.xc_curTime), + x14_passedBoolCount(other.x14_passedBoolCount), + x18_passedIntCount(other.x18_passedIntCount), + x1c_passedParticleCount(other.x1c_passedParticleCount), + x20_passedSoundCount(other.x20_passedSoundCount), + x24_boolStates(other.x24_boolStates), + x34_int32States(other.x34_int32States), + x44_particleStates(other.x44_particleStates) +{} + +SAdvancementResults CAnimSourceReader::VGetAdvancementResults(const CCharAnimTime& dt, + const CCharAnimTime& startOff) const { + SAdvancementResults ret; + CCharAnimTime accum = xc_curTime + startOff; + + if (xc_curTime + startOff >= x54_source->GetDuration()) + { + ret.x0_remTime = dt; + return ret; + } + else if (dt.EqualsZero()) + { + return ret; + } + else + { + CCharAnimTime prevTime = accum; + accum += dt; + CCharAnimTime remTime; + if (accum > x54_source->GetDuration()) + { + remTime = accum - x54_source->GetDuration(); + accum = x54_source->GetDuration(); + } + + zeus::CQuaternion ra = x54_source->GetRotation(3, prevTime).inverse(); + zeus::CQuaternion rb = x54_source->GetRotation(3, accum); + ret.x0_remTime = remTime; + ret.x8_deltas.xc_rotDelta = rb * ra; + + if (x54_source->HasOffset(3)) + { + zeus::CVector3f ta = x54_source->GetOffset(3, prevTime); + zeus::CVector3f tb = x54_source->GetOffset(3, accum); + ret.x8_deltas.x0_posDelta = zeus::CMatrix3f(rb) * (tb - ta); + } + + return ret; + } } -void CAnimSourceReader::VSetPhase(float) +void CAnimSourceReader::VSetPhase(float phase) { + xc_curTime = phase * x54_source->GetDuration(); + if (x54_source->GetPOIData()) + { + UpdatePOIStates(); + if (!xc_curTime.GreaterThanZero()) + { + x14_passedBoolCount = 0; + x18_passedIntCount = 0; + x1c_passedParticleCount = 0; + x20_passedSoundCount = 0; + } + } } -SAdvancementResults CAnimSourceReader::VReverseView(const CCharAnimTime& time) +SAdvancementResults CAnimSourceReader::VReverseView(const CCharAnimTime& dt) { + SAdvancementResults ret; + + if (xc_curTime.EqualsZero()) + { + ret.x0_remTime = dt; + return ret; + } + else if (dt.EqualsZero()) + { + return ret; + } + else + { + CCharAnimTime prevTime = xc_curTime; + xc_curTime -= dt; + CCharAnimTime remTime; + if (xc_curTime < CCharAnimTime()) + { + remTime = CCharAnimTime() - xc_curTime; + xc_curTime = CCharAnimTime(); + } + + if (x54_source->GetPOIData()) + UpdatePOIStates(); + + zeus::CQuaternion ra = x54_source->GetRotation(3, prevTime).inverse(); + zeus::CQuaternion rb = x54_source->GetRotation(3, xc_curTime); + ret.x0_remTime = remTime; + ret.x8_deltas.xc_rotDelta = rb * ra; + + if (x54_source->HasOffset(3)) + { + zeus::CVector3f ta = x54_source->GetOffset(3, prevTime); + zeus::CVector3f tb = x54_source->GetOffset(3, xc_curTime); + ret.x8_deltas.x0_posDelta = zeus::CMatrix3f(rb) * (tb - ta); + } + + return ret; + } } std::shared_ptr CAnimSourceReader::VClone() const { + return std::make_shared(*this); } void CAnimSourceReader::VGetSegStatementSet(const CSegIdList& list, CSegStatementSet& setOut) const { + x54_source->GetSegStatementSet(list, setOut, xc_curTime); } void CAnimSourceReader::VGetSegStatementSet(const CSegIdList& list, CSegStatementSet& setOut, const CCharAnimTime& time) const { + x54_source->GetSegStatementSet(list, setOut, time); } -SAdvancementResults CAnimSourceReader::VAdvanceView(const CCharAnimTime& a) +SAdvancementResults CAnimSourceReader::VAdvanceView(const CCharAnimTime& dt) { + SAdvancementResults ret; + + if (xc_curTime >= x54_source->GetDuration()) + { + ret.x0_remTime = dt; + return ret; + } + else if (dt.EqualsZero()) + { + return ret; + } + else + { + CCharAnimTime prevTime = xc_curTime; + xc_curTime += dt; + CCharAnimTime remTime; + if (xc_curTime > x54_source->GetDuration()) + { + remTime = xc_curTime - x54_source->GetDuration(); + xc_curTime = x54_source->GetDuration(); + } + + if (x54_source->GetPOIData()) + UpdatePOIStates(); + + zeus::CQuaternion ra = x54_source->GetRotation(3, prevTime).inverse(); + zeus::CQuaternion rb = x54_source->GetRotation(3, xc_curTime); + ret.x0_remTime = remTime; + ret.x8_deltas.xc_rotDelta = rb * ra; + + if (x54_source->HasOffset(3)) + { + zeus::CVector3f ta = x54_source->GetOffset(3, prevTime); + zeus::CVector3f tb = x54_source->GetOffset(3, xc_curTime); + ret.x8_deltas.x0_posDelta = zeus::CMatrix3f(rb) * (tb - ta); + } + + return ret; + } } CCharAnimTime CAnimSourceReader::VGetTimeRemaining() const { + return x54_source->GetDuration() - xc_curTime; } -void CAnimSourceReader::VGetSteadyStateAnimInfo() const +CSteadyStateAnimInfo CAnimSourceReader::VGetSteadyStateAnimInfo() const { + return x64_steadyStateInfo; } bool CAnimSourceReader::VHasOffset(const CSegId& seg) const { + return x54_source->HasOffset(seg); } zeus::CVector3f CAnimSourceReader::VGetOffset(const CSegId& seg) const { + return x54_source->GetOffset(seg, xc_curTime); } zeus::CVector3f CAnimSourceReader::VGetOffset(const CSegId& seg, const CCharAnimTime& time) const { + return x54_source->GetOffset(seg, time); } zeus::CQuaternion CAnimSourceReader::VGetRotation(const CSegId& seg) const { + return x54_source->GetRotation(seg, xc_curTime); } CAnimSourceReader::CAnimSourceReader(const TSubAnimTypeToken& source, @@ -304,10 +453,15 @@ CAnimSourceReader::CAnimSourceReader(const TSubAnimTypeToken& sourc x54_source(source) { CAnimSource* sourceData = x54_source.GetObj(); - x64_duration = sourceData->GetDuration(); - x6c_curRootOffset = sourceData->GetOffset(sourceData->GetRootBoneId(), time); + x64_steadyStateInfo.x64_duration = sourceData->GetDuration(); + x64_steadyStateInfo.x6c_curRootOffset = sourceData->GetOffset(sourceData->GetRootBoneId(), time); PostConstruct(time); } +CAnimSourceReader::CAnimSourceReader(const CAnimSourceReader& other) +: CAnimSourceReaderBase(std::make_unique(other.x54_source), other), + x54_source(other.x54_source), x64_steadyStateInfo(other.x64_steadyStateInfo) +{} + } diff --git a/Runtime/Character/CAnimSourceReader.hpp b/Runtime/Character/CAnimSourceReader.hpp index 66aaf9be5..49ad52263 100644 --- a/Runtime/Character/CAnimSourceReader.hpp +++ b/Runtime/Character/CAnimSourceReader.hpp @@ -39,6 +39,7 @@ public: class CAnimSourceReaderBase : public IAnimReader { +protected: std::unique_ptr x4_sourceInfo; CCharAnimTime xc_curTime; u32 x14_passedBoolCount = 0; @@ -56,11 +57,13 @@ class CAnimSourceReaderBase : public IAnimReader protected: void PostConstruct(const CCharAnimTime& time); void UpdatePOIStates(); - + CAnimSourceReaderBase(std::unique_ptr&& sourceInfo, + const CAnimSourceReaderBase& other); public: CAnimSourceReaderBase(std::unique_ptr&& sourceInfo, const CCharAnimTime& time); + u32 VGetBoolPOIList(const CCharAnimTime& time, CBoolPOINode* listOut, u32 capacity, u32 iterator, u32) const; u32 VGetInt32POIList(const CCharAnimTime& time, CInt32POINode* listOut, u32 capacity, u32 iterator, u32) const; u32 VGetParticlePOIList(const CCharAnimTime& time, CParticlePOINode* listOut, u32 capacity, u32 iterator, u32) const; @@ -77,11 +80,10 @@ public: class CAnimSourceReader : public CAnimSourceReaderBase { TSubAnimTypeToken x54_source; - CCharAnimTime x64_duration; - zeus::CVector3f x6c_curRootOffset; - bool x78_ = false; + CSteadyStateAnimInfo x64_steadyStateInfo; public: CAnimSourceReader(const TSubAnimTypeToken& source, const CCharAnimTime& time); + CAnimSourceReader(const CAnimSourceReader& other); SAdvancementResults VGetAdvancementResults(const CCharAnimTime& a, const CCharAnimTime& b) const; bool VSupportsReverseView() const {return true;} @@ -92,7 +94,7 @@ public: void VGetSegStatementSet(const CSegIdList& list, CSegStatementSet& setOut, const CCharAnimTime& time) const; SAdvancementResults VAdvanceView(const CCharAnimTime& a); CCharAnimTime VGetTimeRemaining() const; - void VGetSteadyStateAnimInfo() const; + CSteadyStateAnimInfo VGetSteadyStateAnimInfo() const; bool VHasOffset(const CSegId& seg) const; zeus::CVector3f VGetOffset(const CSegId& seg) const; zeus::CVector3f VGetOffset(const CSegId& seg, const CCharAnimTime& time) const; diff --git a/Runtime/Character/CAnimationSet.hpp b/Runtime/Character/CAnimationSet.hpp index 11ae6aa72..45a9e681b 100644 --- a/Runtime/Character/CAnimationSet.hpp +++ b/Runtime/Character/CAnimationSet.hpp @@ -5,24 +5,11 @@ #include "CAnimation.hpp" #include "CTransition.hpp" #include "CHalfTransition.hpp" +#include "CAdditiveAnimPlayback.hpp" namespace urde { -class CAdditiveAnimationInfo -{ - float x0_a = 0.f; - float x4_b = 0.f; -public: - void read(CInputStream& in) - { - x0_a = in.readFloatBig(); - x4_b = in.readFloatBig(); - } - CAdditiveAnimationInfo() = default; - CAdditiveAnimationInfo(CInputStream& in) {read(in);} -}; - class CAnimationSet { u16 x0_tableCount; diff --git a/Runtime/Character/CCharLayoutInfo.cpp b/Runtime/Character/CCharLayoutInfo.cpp index f7b60b5d1..38bcc611e 100644 --- a/Runtime/Character/CCharLayoutInfo.cpp +++ b/Runtime/Character/CCharLayoutInfo.cpp @@ -6,13 +6,12 @@ namespace urde zeus::CVector3f CCharLayoutInfo::GetFromParentUnrotated(const CSegId& id) const { - const CCharLayoutNode::Bone& bone = x0_node->GetBone(id); - const CSegId& prev = x0_node->GetPrevBone(bone.x0_parentId); - if (prev == 0xff) + const CCharLayoutNode::Bone& bone = x0_node->GetBoneMap()[id]; + if (!x0_node->GetBoneMap().HasElement(bone.x0_parentId)) return bone.x4_origin; else { - const CCharLayoutNode::Bone& pBone = x0_node->GetBone(bone.x0_parentId); + const CCharLayoutNode::Bone& pBone = x0_node->GetBoneMap()[bone.x0_parentId]; return bone.x4_origin - pBone.x4_origin; } } @@ -34,11 +33,8 @@ CCharLayoutNode::CCharLayoutNode(CInputStream& in) for (u32 i=0 ; i x0_boneMap; public: CCharLayoutNode(CInputStream& in); - - const Bone& GetBone(const CSegId& id) const {return x6c_bones[id];} - const CSegId& GetPrevBone(const CSegId& id) const {return x8_prevBones[id];} + const TSegIdMap& GetBoneMap() const {return x0_boneMap;} }; class CCharLayoutInfo diff --git a/Runtime/Character/CCharacterFactory.cpp b/Runtime/Character/CCharacterFactory.cpp index 94fd08de0..1204536d9 100644 --- a/Runtime/Character/CCharacterFactory.cpp +++ b/Runtime/Character/CCharacterFactory.cpp @@ -8,6 +8,7 @@ #include "CRandom16.hpp" #include "CPrimitive.hpp" #include "CAnimData.hpp" +#include "CAdditiveAnimPlayback.hpp" #include "GameGlobalObjects.hpp" #include "Graphics/CSkinnedModel.hpp" diff --git a/Runtime/Character/CHierarchyPoseBuilder.cpp b/Runtime/Character/CHierarchyPoseBuilder.cpp index 4a40884a9..942771b4a 100644 --- a/Runtime/Character/CHierarchyPoseBuilder.cpp +++ b/Runtime/Character/CHierarchyPoseBuilder.cpp @@ -8,30 +8,26 @@ namespace urde void CHierarchyPoseBuilder::BuildIntoHierarchy(const CCharLayoutInfo& layout, const CSegId& boneId, const CSegId& nullId) { - const CSegId& idA = x8_prevBones[boneId]; - if (idA == 0xff) + if (!x0_treeMap.HasElement(boneId)) { - const CCharLayoutNode::Bone& bone = layout.GetRootNode()->GetBone(boneId); + const CCharLayoutNode::Bone& bone = layout.GetRootNode()->GetBoneMap()[boneId]; if (bone.x0_parentId == nullId) { xcec_rootId = boneId; xcf0_hasRoot = true; zeus::CVector3f origin = layout.GetFromParentUnrotated(boneId); - x6c_nodes[boneId] = CTreeNode(origin); + x0_treeMap[boneId] = CTreeNode(origin); } else { BuildIntoHierarchy(layout, bone.x0_parentId, nullId); zeus::CVector3f origin = layout.GetFromParentUnrotated(boneId); - CTreeNode& pNode = x6c_nodes[bone.x0_parentId]; + CTreeNode& pNode = x0_treeMap[bone.x0_parentId]; CTreeNode node(origin); node.x1_sibling = pNode.x0_child; pNode.x0_child = boneId; - x6c_nodes[boneId] = node; + x0_treeMap[boneId] = node; } - x8_prevBones[boneId] = x1_curPrevBone; - x1_curPrevBone = boneId; - ++x0_boneCount; } } @@ -47,7 +43,7 @@ void CHierarchyPoseBuilder::RecursivelyBuildNoScale(const CSegId& boneId, const CSegId curBone = node.x0_child; while (curBone != 0) { - const CTreeNode& node = x6c_nodes[curBone]; + const CTreeNode& node = x0_treeMap[curBone]; RecursivelyBuild(curBone, node, pose, quat, xf, xfOffset); curBone = node.x1_sibling; } @@ -77,7 +73,7 @@ void CHierarchyPoseBuilder::RecursivelyBuild(const CSegId& boneId, const CTreeNo CSegId curBone = node.x0_child; while (curBone != 0) { - const CTreeNode& node = x6c_nodes[curBone]; + const CTreeNode& node = x0_treeMap[curBone]; RecursivelyBuild(curBone, node, pose, quat, quat, xfOffset); curBone = node.x1_sibling; } @@ -106,7 +102,7 @@ void CHierarchyPoseBuilder::BuildTransform(const CSegId& boneId, zeus::CTransfor while (curId != 2) { buildIDs[idCount++] = curId; - curId = layoutInfo.GetRootNode()->GetBone(curId).x0_parentId; + curId = layoutInfo.GetRootNode()->GetBoneMap()[curId].x0_parentId; } } @@ -116,7 +112,7 @@ void CHierarchyPoseBuilder::BuildTransform(const CSegId& boneId, zeus::CTransfor for (CSegId* id=&buildIDs[idCount] ; id != buildIDs ; --id) { CSegId& thisId = id[-1]; - const CTreeNode& node = x6c_nodes[thisId]; + const CTreeNode& node = x0_treeMap[thisId]; accumRot *= node.x4_rotation; accumPos += accumXF * node.x14_offset; if (scale == 1.f) @@ -132,7 +128,7 @@ void CHierarchyPoseBuilder::BuildTransform(const CSegId& boneId, zeus::CTransfor void CHierarchyPoseBuilder::BuildNoScale(CPoseAsTransforms& pose) { pose.Clear(); - const CTreeNode& node = x6c_nodes[xcec_rootId]; + const CTreeNode& node = x0_treeMap[xcec_rootId]; zeus::CQuaternion quat; zeus::CMatrix3f mtx; zeus::CVector3f vec; diff --git a/Runtime/Character/CHierarchyPoseBuilder.hpp b/Runtime/Character/CHierarchyPoseBuilder.hpp index 6d82c9fb9..ffffb3aab 100644 --- a/Runtime/Character/CHierarchyPoseBuilder.hpp +++ b/Runtime/Character/CHierarchyPoseBuilder.hpp @@ -2,6 +2,7 @@ #define __URDE_CHIERARCHYPOSEBUILDER_HPP__ #include "CSegId.hpp" +#include "TSegIdMap.hpp" #include "zeus/CQuaternion.hpp" #include "CLayoutDescription.hpp" @@ -13,10 +14,6 @@ class CPoseAsTransforms; class CHierarchyPoseBuilder { - CSegId x0_boneCount = 0; - CSegId x1_curPrevBone = 0; - CSegId x8_prevBones[100]; - struct CTreeNode { CSegId x0_child = 0; @@ -26,7 +23,8 @@ class CHierarchyPoseBuilder CTreeNode() = default; CTreeNode(const zeus::CVector3f& offset) : x14_offset(offset) {} }; - CTreeNode x6c_nodes[100]; + TSegIdMap x0_treeMap; + CSegId xcec_rootId; bool xcf0_hasRoot = false; CLayoutDescription xcf4_layoutDesc; diff --git a/Runtime/Character/CMakeLists.txt b/Runtime/Character/CMakeLists.txt index 6e1bb566b..985ac2ce4 100644 --- a/Runtime/Character/CMakeLists.txt +++ b/Runtime/Character/CMakeLists.txt @@ -71,6 +71,8 @@ add_library(RuntimeCommonCharacter CAnimSource.hpp CAnimSource.cpp CAllFormatsAnimSource.hpp CAllFormatsAnimSource.cpp CSegStatementSet.hpp CSegStatementSet.cpp + CAnimPerSegmentData.hpp + CAdditiveAnimPlayback.hpp CAdditiveAnimPlayback.cpp CActorLights.hpp CActorLights.cpp CAnimSysContext.hpp CBodyState.hpp) diff --git a/Runtime/Character/CModelData.cpp b/Runtime/Character/CModelData.cpp index 1f7622233..e92205e76 100644 --- a/Runtime/Character/CModelData.cpp +++ b/Runtime/Character/CModelData.cpp @@ -12,6 +12,7 @@ #include "GameGlobalObjects.hpp" #include "CAssetFactory.hpp" #include "CCharacterFactory.hpp" +#include "CAdditiveAnimPlayback.hpp" namespace urde { diff --git a/Runtime/Character/CSegStatementSet.cpp b/Runtime/Character/CSegStatementSet.cpp index e69de29bb..36762903b 100644 --- a/Runtime/Character/CSegStatementSet.cpp +++ b/Runtime/Character/CSegStatementSet.cpp @@ -0,0 +1,23 @@ +#include "CSegStatementSet.hpp" +#include "CSegIdList.hpp" +#include "CCharLayoutInfo.hpp" + +namespace urde +{ + +void CSegStatementSet::Add(const CSegIdList& list, const CCharLayoutInfo& layout, + const CSegStatementSet& other, float weight) +{ + for (const CSegId& id : list.GetList()) + { + x4_segData[id].x0_rotation *= zeus::CQuaternion::slerp(zeus::CQuaternion::skNoRotation, + other.x4_segData[id].x0_rotation, weight); + if (other.x4_segData[id].x1c_hasOffset && x4_segData[id].x1c_hasOffset) + { + zeus::CVector3f off = other.x4_segData[id].x10_offset - layout.GetFromParentUnrotated(id); + x4_segData[id].x10_offset += off * weight; + } + } +} + +} diff --git a/Runtime/Character/CSegStatementSet.hpp b/Runtime/Character/CSegStatementSet.hpp index c4aed3a47..7c45571ff 100644 --- a/Runtime/Character/CSegStatementSet.hpp +++ b/Runtime/Character/CSegStatementSet.hpp @@ -1,11 +1,21 @@ #ifndef __URDE_CSEGSTATEMENTSET_HPP__ #define __URDE_CSEGSTATEMENTSET_HPP__ +#include "CAnimPerSegmentData.hpp" + namespace urde { +class CSegIdList; +class CCharLayoutInfo; class CSegStatementSet { +public: + /* Used to be a pointer to arbitrary subclass-provided storage, + * now it's a self-stored array */ + CAnimPerSegmentData x4_segData[100]; + void Add(const CSegIdList& list, const CCharLayoutInfo& layout, + const CSegStatementSet& other, float weight); }; } diff --git a/Runtime/Character/IAnimReader.hpp b/Runtime/Character/IAnimReader.hpp index 555f3d03e..be8d3138d 100644 --- a/Runtime/Character/IAnimReader.hpp +++ b/Runtime/Character/IAnimReader.hpp @@ -29,6 +29,13 @@ struct SAdvancementResults SAdvancementDeltas x8_deltas; }; +struct CSteadyStateAnimInfo +{ + CCharAnimTime x64_duration; + zeus::CVector3f x6c_curRootOffset; + bool x78_ = false; +}; + class IAnimReader { public: @@ -36,7 +43,7 @@ public: virtual bool IsCAnimTreeNode() const {return false;} virtual SAdvancementResults VAdvanceView(const CCharAnimTime& a)=0; virtual CCharAnimTime VGetTimeRemaining() const=0; - virtual void VGetSteadyStateAnimInfo() const=0; + virtual CSteadyStateAnimInfo VGetSteadyStateAnimInfo() const=0; virtual bool VHasOffset(const CSegId& seg) const=0; virtual zeus::CVector3f VGetOffset(const CSegId& seg) const=0; virtual zeus::CQuaternion VGetRotation(const CSegId& seg) const=0; diff --git a/Runtime/Character/TSegIdMap.hpp b/Runtime/Character/TSegIdMap.hpp index 3c415337a..d85006a56 100644 --- a/Runtime/Character/TSegIdMap.hpp +++ b/Runtime/Character/TSegIdMap.hpp @@ -10,9 +10,46 @@ namespace urde template class TSegIdMap { - std::map x0_map; + CSegId x0_boneCount = 0; + CSegId x1_curPrevBone = 0; + u32 x4_capacity = 100; + CSegId x8_prevBones[100]; + T x6c_bones[100]; public: - const T& AccessElement(const CSegId& id) const {return x0_map[id];} + T& operator[](const CSegId& id) {return SetElement(id);} + const T& operator[](const CSegId& id) const {return x6c_bones[id];} + T& SetElement(const CSegId& id, T&& obj) + { + x6c_bones[id] = std::move(obj); + if (x8_prevBones[id] == 0xff) + { + x8_prevBones[id] = x1_curPrevBone; + x1_curPrevBone = id; + ++x0_boneCount; + } + return x6c_bones[id]; + } + T& SetElement(const CSegId& id) + { + if (x8_prevBones[id] == 0xff) + { + x8_prevBones[id] = x1_curPrevBone; + x1_curPrevBone = id; + ++x0_boneCount; + } + return x6c_bones[id]; + } + void DelElement(const CSegId& id) + { + if (x8_prevBones[id] != 0xff) + { + if (id == x1_curPrevBone) + x1_curPrevBone = x8_prevBones[id]; + x8_prevBones[id] = 0xff; + --x0_boneCount; + } + } + bool HasElement(const CSegId& id) const {return x8_prevBones[id] != 0xff;} }; } diff --git a/Runtime/MP1/MP1.hpp b/Runtime/MP1/MP1.hpp index f8575e9a3..eb0c829e4 100644 --- a/Runtime/MP1/MP1.hpp +++ b/Runtime/MP1/MP1.hpp @@ -161,7 +161,7 @@ public: bool finished = false; m_inputGenerator.Update(1.0 / 60.0, m_archQueue); - while(m_archQueue) + while (m_archQueue) { CArchitectureMessage msg = m_archQueue.Pop(); if (msg.GetTarget() == EArchMsgTarget::ArchitectureSupport) diff --git a/specter b/specter index e40a836ea..36cd3fbf9 160000 --- a/specter +++ b/specter @@ -1 +1 @@ -Subproject commit e40a836ea15a2a2c06a2a8c8ba511db23d4395de +Subproject commit 36cd3fbf9dafdd9c83268593dfcd905edea32a9a