diff --git a/Runtime/Character/CFBStreamedAnimReader.cpp b/Runtime/Character/CFBStreamedAnimReader.cpp index c86cf3db6..e9cceb386 100644 --- a/Runtime/Character/CFBStreamedAnimReader.cpp +++ b/Runtime/Character/CFBStreamedAnimReader.cpp @@ -5,81 +5,273 @@ namespace urde void CFBStreamedAnimReaderTotals::Allocate(u32 chanCount) { - u32 chan16 = chanCount * 16; u32 chan2 = chanCount * 2; u32 chan32 = chanCount * 32; - x0_buffer.reset(new u8[chan16 + chanCount + chan2 + chan32]); - x4_first16 = x0_buffer.get(); - x8_second1 = x4_first16 + chan16; - xc_third2 = x8_second1 + chanCount; - x10_fourth32 = xc_third2 + chan2; + x0_buffer.reset(new u8[chan32 + chanCount + chan2 + chan32]); + x4_cumulativeInts32 = reinterpret_cast(x0_buffer.get()); + x8_hasTrans1 = reinterpret_cast(x4_cumulativeInts32 + chanCount * 8); + xc_segIds2 = reinterpret_cast(x8_hasTrans1 + chanCount); + x10_computedFloats32 = reinterpret_cast(xc_segIds2 + chanCount); } -CFBStreamedAnimReaderTotals::CFBStreamedAnimReaderTotals(const CFBStreamedCompression& source) +void CFBStreamedAnimReaderTotals::Initialize(const CFBStreamedCompression& source) { - const CFBStreamedCompression::Header* header = - reinterpret_cast(source.xc_rotsAndOffs.get()); - const u32* bitmap = reinterpret_cast(source.xc_rotsAndOffs.get() + 9); - u32 bitmapWordCount = (bitmap[0] + 31) / 32; - - x14_rotDiv = header->rotDiv; - x18_transMult = header->translationMult; - - const u8* chans = reinterpret_cast(bitmap + bitmapWordCount + 1); - u32 boneChanCount = *reinterpret_cast(chans); - x24_boneChanCount = boneChanCount; - Allocate(x24_boneChanCount); -} - -CFBStreamedPairOfTotals::CFBStreamedPairOfTotals(const TSubAnimTypeToken& source) -: x0_source(source), xc_rotsAndOffs(source->xc_rotsAndOffs.get()), x14_(*source), x3c_(*source) -{ - const u32* bitmap = reinterpret_cast(source->xc_rotsAndOffs.get() + 9); - u32 bitmapWordCount = (bitmap[0] + 31) / 32; - - const u8* chans = reinterpret_cast(bitmap + bitmapWordCount + 1); + const u8* chans = source.GetPerChannelHeaders(); u32 boneChanCount = *reinterpret_cast(chans); chans += 4; - if (source->m_pc) + if (source.m_pc) { for (int b=0 ; b(chans); + chans += 8; + + s32* cumulativesOut = &x4_cumulativeInts32[8*b]; + const s32* cumulativesIn = reinterpret_cast(chans); + cumulativesOut[0] = cumulativesIn[0] >> 8; + cumulativesOut[1] = cumulativesIn[1] >> 8; + cumulativesOut[2] = cumulativesIn[2] >> 8; + chans += 12; u32 tCount = *reinterpret_cast(chans); chans += 4; if (tCount) + { + x8_hasTrans1[b] = true; + const s32* cumulativesIn = reinterpret_cast(chans); + cumulativesOut[3] = cumulativesIn[0] >> 8; + cumulativesOut[4] = cumulativesIn[1] >> 8; + cumulativesOut[5] = cumulativesIn[2] >> 8; chans += 12; + } + else + x8_hasTrans1[b] = false; } } else { for (int b=0 ; b(chans); + chans += 6; + + s32* cumulativesOut = &x4_cumulativeInts32[8*b]; + cumulativesOut[0] = *reinterpret_cast(chans); + cumulativesOut[1] = *reinterpret_cast(chans + 3); + cumulativesOut[2] = *reinterpret_cast(chans + 6); + chans += 9; u16 tCount = *reinterpret_cast(chans); chans += 2; if (tCount) + { + x8_hasTrans1[b] = true; + cumulativesOut[3] = *reinterpret_cast(chans); + cumulativesOut[4] = *reinterpret_cast(chans + 3); + cumulativesOut[5] = *reinterpret_cast(chans + 6); chans += 9; + } + else + x8_hasTrans1[b] = false; } } +} - x88_ = chans; - x8c_ = &x88_; - x90_ = *reinterpret_cast(*x8c_); +CFBStreamedAnimReaderTotals::CFBStreamedAnimReaderTotals(const CFBStreamedCompression& source) +{ + const CFBStreamedCompression::Header& header = source.MainHeader(); + x14_rotDiv = header.rotDiv; + x18_transMult = header.translationMult; + + const u8* chans = source.GetPerChannelHeaders(); + x24_boneChanCount = *reinterpret_cast(chans); + Allocate(x24_boneChanCount); + Initialize(source); +} + +void CFBStreamedAnimReaderTotals::IncrementInto(CBitLevelLoader& loader, + const CFBStreamedCompression& source, + CFBStreamedAnimReaderTotals& dest) +{ + const u8* chans = source.GetPerChannelHeaders(); + u32 boneChanCount = *reinterpret_cast(chans); + chans += 4; + + if (source.m_pc) + { + for (int b=0 ; b(chans); + cumulativesOut[0] = loader.LoadBool(); + cumulativesOut[1] = cumulativesIn[1] + loader.LoadSigned(qsIn[0] & 0xff); + cumulativesOut[2] = cumulativesIn[2] + loader.LoadSigned(qsIn[1] & 0xff); + cumulativesOut[3] = cumulativesIn[3] + loader.LoadSigned(qsIn[2] & 0xff); + chans += 12; + + u32 tCount = *reinterpret_cast(chans); + chans += 4; + if (tCount) + { + const s32* qsIn = reinterpret_cast(chans); + cumulativesOut[4] = cumulativesIn[4] + loader.LoadSigned(qsIn[0] & 0xff); + cumulativesOut[5] = cumulativesIn[5] + loader.LoadSigned(qsIn[1] & 0xff); + cumulativesOut[6] = cumulativesIn[6] + loader.LoadSigned(qsIn[2] & 0xff); + chans += 12; + } + } + } + else + { + for (int b=0 ; b(chans + 2)); + cumulativesOut[2] = cumulativesIn[2] + loader.LoadSigned(*reinterpret_cast(chans + 5)); + cumulativesOut[3] = cumulativesIn[3] + loader.LoadSigned(*reinterpret_cast(chans + 8)); + chans += 9; + + u16 tCount = *reinterpret_cast(chans); + chans += 2; + if (tCount) + { + cumulativesOut[4] = cumulativesIn[4] + loader.LoadSigned(*reinterpret_cast(chans + 2)); + cumulativesOut[5] = cumulativesIn[5] + loader.LoadSigned(*reinterpret_cast(chans + 5)); + cumulativesOut[6] = cumulativesIn[5] + loader.LoadSigned(*reinterpret_cast(chans + 8)); + chans += 9; + } + } + } +} + +void CFBStreamedAnimReaderTotals::CalculateDown() +{ + for (int b=0 ; b& source) +: x0_source(source), xc_rotsAndOffs(source->xc_rotsAndOffs.get()), x14_(*source), x3c_(*source) +{ +} + +u32 CBitLevelLoader::LoadUnsigned(u8 q) +{ + u32 byteCur = (m_bitIdx / 32) * 4; + u32 bitRem = m_bitIdx % 32; + + /* Fill 32 bit buffer with region containing bits */ + /* Make them least significant */ + u32 tempBuf = hecl::SBig(*reinterpret_cast(m_data + byteCur)) >> bitRem; + + /* If this shift underflows the value, buffer the next 32 bits */ + /* And tack onto shifted buffer */ + if ((bitRem + q) > 32) + { + u32 tempBuf2 = hecl::SBig(*reinterpret_cast(m_data + byteCur + 4)); + tempBuf |= (tempBuf2 << (32 - bitRem)); + } + + /* Mask it */ + u32 mask = (1 << q) - 1; + tempBuf &= mask; + + /* Return delta value */ + m_bitIdx += q; + return tempBuf; +} + +s32 CBitLevelLoader::LoadSigned(u8 q) +{ + u32 byteCur = (m_bitIdx / 32) * 4; + u32 bitRem = m_bitIdx % 32; + + /* Fill 32 bit buffer with region containing bits */ + /* Make them least significant */ + u32 tempBuf = hecl::SBig(*reinterpret_cast(m_data + byteCur)) >> bitRem; + + /* If this shift underflows the value, buffer the next 32 bits */ + /* And tack onto shifted buffer */ + if ((bitRem + q) > 32) + { + u32 tempBuf2 = hecl::SBig(*reinterpret_cast(m_data + byteCur + 4)); + tempBuf |= (tempBuf2 << (32 - bitRem)); + } + + /* Mask it */ + u32 mask = (1 << q) - 1; + tempBuf &= mask; + + /* Sign extend */ + u32 sign = (tempBuf >> (q - 1)) & 0x1; + if (sign) + tempBuf |= ~0u << q; + + /* Return delta value */ + m_bitIdx += q; + return s32(tempBuf); +} + +bool CBitLevelLoader::LoadBool() +{ + u32 byteCur = (m_bitIdx / 32) * 4; + u32 bitRem = m_bitIdx % 32; + + /* Fill 32 bit buffer with region containing bits */ + /* Make them least significant */ + u32 tempBuf = hecl::SBig(*reinterpret_cast(m_data + byteCur)) >> bitRem; + + /* That's it */ + m_bitIdx += 1; + return tempBuf & 0x1; } CSegIdToIndexConverter::CSegIdToIndexConverter(const CFBStreamedAnimReaderTotals& totals) { + for (u32 b=0 ; b= 96) + continue; + x0_indices[segId] = b; + } } CFBStreamedAnimReader::CFBStreamedAnimReader(const TSubAnimTypeToken& source, const CCharAnimTime& time) : CAnimSourceReaderBase(std::make_unique>(source), time), x54_source(source), x64_steadyStateInfo(source->IsLooping(), source->GetAnimationDuration(), source->GetRootOffset()), - x7c_(source), x114_(x7c_.x10_ ? x7c_.x14_ : x7c_.x3c_) + x7c_totals(source), x88_bitstreamData(source->GetBitstreamPointer()), x8c_bitLoader(x88_bitstreamData), + x114_segIdToIndex(x7c_totals.x10_ ? x7c_totals.x14_ : x7c_totals.x3c_) { PostConstruct(time); } diff --git a/Runtime/Character/CFBStreamedAnimReader.hpp b/Runtime/Character/CFBStreamedAnimReader.hpp index 768370221..47101f843 100644 --- a/Runtime/Character/CFBStreamedAnimReader.hpp +++ b/Runtime/Character/CFBStreamedAnimReader.hpp @@ -6,6 +6,7 @@ namespace urde { +class CBitLevelLoader; template class TAnimSourceInfo : public IAnimSourceInfo @@ -23,19 +24,24 @@ public: class CFBStreamedAnimReaderTotals { + friend class CSegIdToIndexConverter; std::unique_ptr x0_buffer; - u8* x4_first16; - u8* x8_second1; - u8* xc_third2; - u8* x10_fourth32; + s32* x4_cumulativeInts32; /* Used to be 16 per channel */ + u8* x8_hasTrans1; + u16* xc_segIds2; + float* x10_computedFloats32; u32 x14_rotDiv; float x18_transMult; - u32 x1c_ = 0; + u32 x1c_curKey = 0; bool x20_ = false; u32 x24_boneChanCount; void Allocate(u32 chanCount); + void Initialize(const CFBStreamedCompression& source); public: CFBStreamedAnimReaderTotals(const CFBStreamedCompression& source); + void IncrementInto(CBitLevelLoader& loader, const CFBStreamedCompression& source, + CFBStreamedAnimReaderTotals& dest); + void CalculateDown(); }; class CFBStreamedPairOfTotals @@ -47,27 +53,38 @@ class CFBStreamedPairOfTotals bool x10_ = true; CFBStreamedAnimReaderTotals x14_; CFBStreamedAnimReaderTotals x3c_; - const u8* x88_; - const u8** x8c_; - u32 x90_; - u32 x94_ = 0; public: CFBStreamedPairOfTotals(const TSubAnimTypeToken& source); }; +class CBitLevelLoader +{ + const u8* m_data; + size_t m_bitIdx = 0; +public: + CBitLevelLoader(const void* data) + : m_data(reinterpret_cast(data)) {} + u32 LoadUnsigned(u8 q); + s32 LoadSigned(u8 q); + bool LoadBool(); +}; + class CSegIdToIndexConverter { u32 x0_indices[96] = {-1}; public: CSegIdToIndexConverter(const CFBStreamedAnimReaderTotals& totals); + u32 SegIdToIndex(const CSegId& id) const { return x0_indices[id]; } }; class CFBStreamedAnimReader : public CAnimSourceReaderBase { TSubAnimTypeToken x54_source; CSteadyStateAnimInfo x64_steadyStateInfo; - CFBStreamedPairOfTotals x7c_; - CSegIdToIndexConverter x114_; + CFBStreamedPairOfTotals x7c_totals; + const u8* x88_bitstreamData; + CBitLevelLoader x8c_bitLoader; + CSegIdToIndexConverter x114_segIdToIndex; public: CFBStreamedAnimReader(const TSubAnimTypeToken& source, const CCharAnimTime& time); diff --git a/Runtime/Character/CFBStreamedCompression.cpp b/Runtime/Character/CFBStreamedCompression.cpp index 8f36d74de..5da775581 100644 --- a/Runtime/Character/CFBStreamedCompression.cpp +++ b/Runtime/Character/CFBStreamedCompression.cpp @@ -15,6 +15,50 @@ CFBStreamedCompression::CFBStreamedCompression(CInputStream& in, IObjectStore& o x8_evntToken = objStore.GetObj(SObjectTag{FOURCC('EVNT'), x4_evnt}); } +const u8* CFBStreamedCompression::GetPerChannelHeaders() const +{ + const u32* bitmap = reinterpret_cast(xc_rotsAndOffs.get() + 9); + u32 bitmapWordCount = (bitmap[0] + 31) / 32; + return reinterpret_cast(bitmap + bitmapWordCount + 1); +} + +const u8* CFBStreamedCompression::GetBitstreamPointer() const +{ + const u32* bitmap = reinterpret_cast(xc_rotsAndOffs.get() + 9); + u32 bitmapWordCount = (bitmap[0] + 31) / 32; + + const u8* chans = reinterpret_cast(bitmap + bitmapWordCount + 1); + u32 boneChanCount = *reinterpret_cast(chans); + chans += 4; + + if (m_pc) + { + for (int b=0 ; b(chans); + chans += 4; + if (tCount) + chans += 12; + } + } + else + { + for (int b=0 ; b(chans); + chans += 2; + if (tCount) + chans += 9; + } + } + + return chans; +} + std::unique_ptr CFBStreamedCompression::GetRotationsAndOffsets(u32 words, CInputStream& in) { std::unique_ptr ret(new u32[words]); diff --git a/Runtime/Character/CFBStreamedCompression.hpp b/Runtime/Character/CFBStreamedCompression.hpp index 49c9f9b96..3e587c8b8 100644 --- a/Runtime/Character/CFBStreamedCompression.hpp +++ b/Runtime/Character/CFBStreamedCompression.hpp @@ -67,6 +67,8 @@ private: public: CFBStreamedCompression(CInputStream& in, IObjectStore& objStore, bool pc); const Header& MainHeader() const { return *reinterpret_cast(xc_rotsAndOffs.get()); } + const u8* GetPerChannelHeaders() const; + const u8* GetBitstreamPointer() const; bool IsLooping() const { return MainHeader().looping; } CCharAnimTime GetAnimationDuration() const { return MainHeader().duration; } const zeus::CVector3f& GetRootOffset() const { return x14_rootOffset; }