#pragma once #include "DNACommon.hpp" #include namespace DataSpec::DNAANIM { struct Value { athena::simd simd; Value() = default; Value(const athena::simd& s) : simd(s) {} Value(const atVec3f& v) : simd(v.simd) {} Value(const atVec4f& v) : simd(v.simd) {} Value(float x, float y, float z) : simd(x, y, z, 0.f) {} Value(float w, float x, float y, float z) : simd(w, x, y, z) {} }; struct QuantizedValue { atInt32 v[4]; atInt32& operator[](size_t idx) { return v[idx]; } atInt32 operator[](size_t idx) const { return v[idx]; } int qFrom(const QuantizedValue& other, size_t idx) const { atInt32 delta = v[idx] - other.v[idx]; atInt32 absDelta = std::abs(delta); if (absDelta == 0) return 1; int ret = int(std::ceil(std::log2(absDelta))) + 1; if (delta > 0 && (delta >> (ret - 1))) ++ret; assert(ret <= 24 && "Bad q value"); return ret; } }; struct QuantizedRot { QuantizedValue v; bool w; }; struct Channel { enum class Type { Rotation, Translation, Scale, KfHead, RotationMP3 } type; atInt32 id = -1; QuantizedValue i = {}; atUint8 q[4] = {}; }; size_t ComputeBitstreamSize(size_t keyFrameCount, const std::vector& channels); class BitstreamReader { size_t m_bitCur; atInt32 dequantize(const atUint8* data, atUint8 q); bool dequantizeBit(const atUint8* data); public: std::vector> read(const atUint8* data, size_t keyFrameCount, const std::vector& channels, atUint32 rotDiv, float transMult, float scaleMult); }; class BitstreamWriter { size_t m_bitCur; void quantize(atUint8* data, atUint8 q, atInt32 val); void quantizeBit(atUint8* data, bool val); public: std::unique_ptr write(const std::vector>& chanKeys, size_t keyFrameCount, std::vector& channels, atUint32 quantRange, atUint32& rotDivOut, float& transMultOut, float& scaleMultOut, size_t& sizeOut); }; } // namespace DataSpec::DNAANIM