Work on CFBStreamedCompression; defined 24-bit ANIM3 format

This commit is contained in:
Jack Andersen 2016-08-26 12:23:59 -10:00
parent d9448cae05
commit f9cef44029
22 changed files with 526 additions and 85 deletions

View File

@ -44,9 +44,9 @@ static inline QuantizedRot QuantizeRotation(const Value& quat, atUint32 div)
return
{
{
atInt16(std::asin(quat.v4.vec[1]) / q),
atInt16(std::asin(quat.v4.vec[2]) / q),
atInt16(std::asin(quat.v4.vec[3]) / q),
atInt32(std::asin(quat.v4.vec[1]) / q),
atInt32(std::asin(quat.v4.vec[2]) / q),
atInt32(std::asin(quat.v4.vec[3]) / q),
},
(quat.v4.vec[0] < 0.f) ? true : false
};
@ -102,7 +102,7 @@ bool BitstreamReader::dequantizeBit(const atUint8* data)
return tempBuf & 0x1;
}
atInt16 BitstreamReader::dequantize(const atUint8* data, atUint8 q)
atInt32 BitstreamReader::dequantize(const atUint8* data, atUint8 q)
{
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
@ -138,7 +138,8 @@ BitstreamReader::read(const atUint8* data,
size_t keyFrameCount,
const std::vector<Channel>& channels,
atUint32 rotDiv,
float transMult)
float transMult,
float scaleMult)
{
m_bitCur = 0;
std::vector<std::vector<Value>> chanKeys;
@ -167,7 +168,7 @@ BitstreamReader::read(const atUint8* data,
}
case Channel::Type::Scale:
{
keys.push_back({chan.i[0] / float(rotDiv), chan.i[1] / float(rotDiv), chan.i[2] / float(rotDiv)});
keys.push_back({chan.i[0] * scaleMult, chan.i[1] * scaleMult, chan.i[2] * scaleMult});
break;
}
case Channel::Type::KfHead:
@ -219,11 +220,11 @@ BitstreamReader::read(const atUint8* data,
}
case Channel::Type::Translation:
{
atInt16 val1 = dequantize(data, chan.q[0]);
atInt32 val1 = dequantize(data, chan.q[0]);
p[0] += val1;
atInt16 val2 = dequantize(data, chan.q[1]);
atInt32 val2 = dequantize(data, chan.q[1]);
p[1] += val2;
atInt16 val3 = dequantize(data, chan.q[2]);
atInt32 val3 = dequantize(data, chan.q[2]);
p[2] += val3;
kit->push_back({p[0] * transMult, p[1] * transMult, p[2] * transMult});
#if DUMP_KEYS
@ -236,7 +237,7 @@ BitstreamReader::read(const atUint8* data,
p[0] += dequantize(data, chan.q[0]);
p[1] += dequantize(data, chan.q[1]);
p[2] += dequantize(data, chan.q[2]);
kit->push_back({p[0] / float(rotDiv), p[1] / float(rotDiv), p[2] / float(rotDiv)});
kit->push_back({p[0] * scaleMult, p[1] * scaleMult, p[2] * scaleMult});
#if DUMP_KEYS
fprintf(stderr, "%d S: %d %d %d\t", chan.id, p[0], p[1], p[2]);
#endif
@ -249,13 +250,13 @@ BitstreamReader::read(const atUint8* data,
}
case Channel::Type::RotationMP3:
{
atInt16 val1 = dequantize(data, chan.q[0]);
atInt32 val1 = dequantize(data, chan.q[0]);
p[0] += val1;
atInt16 val2 = dequantize(data, chan.q[1]);
atInt32 val2 = dequantize(data, chan.q[1]);
p[1] += val2;
atInt16 val3 = dequantize(data, chan.q[2]);
atInt32 val3 = dequantize(data, chan.q[2]);
p[2] += val3;
atInt16 val4 = dequantize(data, chan.q[3]);
atInt32 val4 = dequantize(data, chan.q[3]);
p[3] += val4;
QuantizedRot qr = {{p[1], p[2], p[3]}, bool(p[0] & 0x1)};
kit->emplace_back(DequantizeRotation_3(qr, rotDiv));
@ -287,7 +288,7 @@ void BitstreamWriter::quantizeBit(atUint8* data, bool val)
m_bitCur += 1;
}
void BitstreamWriter::quantize(atUint8* data, atUint8 q, atInt16 val)
void BitstreamWriter::quantize(atUint8* data, atUint8 q, atInt32 val)
{
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
@ -313,15 +314,19 @@ void BitstreamWriter::quantize(atUint8* data, atUint8 q, atInt16 val)
std::unique_ptr<atUint8[]>
BitstreamWriter::write(const std::vector<std::vector<Value>>& chanKeys,
size_t keyFrameCount, std::vector<Channel>& channels,
atUint32 quantRange,
atUint32& rotDivOut,
float& transMultOut,
float& scaleMultOut,
size_t& sizeOut)
{
m_bitCur = 0;
rotDivOut = 32767; /* Normalized range of values */
rotDivOut = quantRange; /* Normalized range of values */
float quantRangeF = float(quantRange);
/* Pre-pass to calculate translation multiplier */
float maxTransDiff = 0.0f;
float maxScaleDiff = 0.0f;
auto kit = chanKeys.begin();
for (Channel& chan : channels)
{
@ -342,11 +347,27 @@ BitstreamWriter::write(const std::vector<std::vector<Value>>& chanKeys,
}
break;
}
case Channel::Type::Scale:
{
const Value* last = &(*kit)[0];
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
const Value* current = &*it;
maxScaleDiff = std::max(maxScaleDiff, current->v3.vec[0] - last->v3.vec[0]);
maxScaleDiff = std::max(maxScaleDiff, current->v3.vec[1] - last->v3.vec[1]);
maxScaleDiff = std::max(maxScaleDiff, current->v3.vec[2] - last->v3.vec[2]);
last = current;
}
break;
}
default: break;
}
++kit;
}
transMultOut = maxTransDiff / 32767;
transMultOut = maxTransDiff / quantRangeF;
scaleMultOut = maxScaleDiff / quantRangeF;
/* Output channel inits */
kit = chanKeys.begin();
@ -365,16 +386,16 @@ BitstreamWriter::write(const std::vector<std::vector<Value>>& chanKeys,
}
case Channel::Type::Translation:
{
chan.i = {atInt16((*kit)[0].v3.vec[0] / transMultOut),
atInt16((*kit)[0].v3.vec[1] / transMultOut),
atInt16((*kit)[0].v3.vec[2] / transMultOut)};
chan.i = {atInt32((*kit)[0].v3.vec[0] / transMultOut),
atInt32((*kit)[0].v3.vec[1] / transMultOut),
atInt32((*kit)[0].v3.vec[2] / transMultOut)};
break;
}
case Channel::Type::Scale:
{
chan.i = {atInt16((*kit)[0].v3.vec[0] * rotDivOut),
atInt16((*kit)[0].v3.vec[1] * rotDivOut),
atInt16((*kit)[0].v3.vec[2] * rotDivOut)};
chan.i = {atInt32((*kit)[0].v3.vec[0] / scaleMultOut),
atInt32((*kit)[0].v3.vec[1] / scaleMultOut),
atInt32((*kit)[0].v3.vec[2] / scaleMultOut)};
break;
}
default: break;
@ -405,16 +426,16 @@ BitstreamWriter::write(const std::vector<std::vector<Value>>& chanKeys,
}
case Channel::Type::Translation:
{
QuantizedValue last = {atInt16((*kit)[0].v3.vec[0] / transMultOut),
atInt16((*kit)[0].v3.vec[1] / transMultOut),
atInt16((*kit)[0].v3.vec[2] / transMultOut)};
QuantizedValue last = {atInt32((*kit)[0].v3.vec[0] / transMultOut),
atInt32((*kit)[0].v3.vec[1] / transMultOut),
atInt32((*kit)[0].v3.vec[2] / transMultOut)};
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
QuantizedValue cur = {atInt16(it->v3.vec[0] / transMultOut),
atInt16(it->v3.vec[1] / transMultOut),
atInt16(it->v3.vec[2] / transMultOut)};
QuantizedValue cur = {atInt32(it->v3.vec[0] / transMultOut),
atInt32(it->v3.vec[1] / transMultOut),
atInt32(it->v3.vec[2] / transMultOut)};
chan.q[0] = std::max(chan.q[0], atUint8(ceilf(log2f(cur[0] - last[0]))));
chan.q[1] = std::max(chan.q[1], atUint8(ceilf(log2f(cur[1] - last[1]))));
chan.q[2] = std::max(chan.q[2], atUint8(ceilf(log2f(cur[2] - last[2]))));
@ -424,16 +445,16 @@ BitstreamWriter::write(const std::vector<std::vector<Value>>& chanKeys,
}
case Channel::Type::Scale:
{
QuantizedValue last = {atInt16((*kit)[0].v3.vec[0] * rotDivOut),
atInt16((*kit)[0].v3.vec[1] * rotDivOut),
atInt16((*kit)[0].v3.vec[2] * rotDivOut)};
QuantizedValue last = {atInt32((*kit)[0].v3.vec[0] / scaleMultOut),
atInt32((*kit)[0].v3.vec[1] / scaleMultOut),
atInt32((*kit)[0].v3.vec[2] / scaleMultOut)};
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
QuantizedValue cur = {atInt16(it->v3.vec[0] * rotDivOut),
atInt16(it->v3.vec[1] * rotDivOut),
atInt16(it->v3.vec[2] * rotDivOut)};
QuantizedValue cur = {atInt32(it->v3.vec[0] * rotDivOut),
atInt32(it->v3.vec[1] * rotDivOut),
atInt32(it->v3.vec[2] * rotDivOut)};
chan.q[0] = std::max(chan.q[0], atUint8(ceilf(log2f(cur[0] - last[0]))));
chan.q[1] = std::max(chan.q[1], atUint8(ceilf(log2f(cur[1] - last[1]))));
chan.q[2] = std::max(chan.q[2], atUint8(ceilf(log2f(cur[2] - last[2]))));
@ -474,16 +495,16 @@ BitstreamWriter::write(const std::vector<std::vector<Value>>& chanKeys,
}
case Channel::Type::Translation:
{
QuantizedValue last = {atInt16((*kit)[0].v3.vec[0] / transMultOut),
atInt16((*kit)[0].v3.vec[1] / transMultOut),
atInt16((*kit)[0].v3.vec[2] / transMultOut)};
QuantizedValue last = {atInt32((*kit)[0].v3.vec[0] / transMultOut),
atInt32((*kit)[0].v3.vec[1] / transMultOut),
atInt32((*kit)[0].v3.vec[2] / transMultOut)};
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
QuantizedValue cur = {atInt16(it->v3.vec[0] / transMultOut),
atInt16(it->v3.vec[1] / transMultOut),
atInt16(it->v3.vec[2] / transMultOut)};
QuantizedValue cur = {atInt32(it->v3.vec[0] / transMultOut),
atInt32(it->v3.vec[1] / transMultOut),
atInt32(it->v3.vec[2] / transMultOut)};
quantize(newData, chan.q[0], cur[0] - last[0]);
quantize(newData, chan.q[1], cur[1] - last[1]);
quantize(newData, chan.q[2], cur[2] - last[2]);
@ -493,16 +514,16 @@ BitstreamWriter::write(const std::vector<std::vector<Value>>& chanKeys,
}
case Channel::Type::Scale:
{
QuantizedValue last = {atInt16((*kit)[0].v3.vec[0] * rotDivOut),
atInt16((*kit)[0].v3.vec[1] * rotDivOut),
atInt16((*kit)[0].v3.vec[2] * rotDivOut)};
QuantizedValue last = {atInt32((*kit)[0].v3.vec[0] / scaleMultOut),
atInt32((*kit)[0].v3.vec[1] / scaleMultOut),
atInt32((*kit)[0].v3.vec[2] / scaleMultOut)};
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
QuantizedValue cur = {atInt16(it->v3.vec[0] * rotDivOut),
atInt16(it->v3.vec[1] * rotDivOut),
atInt16(it->v3.vec[2] * rotDivOut)};
QuantizedValue cur = {atInt32(it->v3.vec[0] / scaleMultOut),
atInt32(it->v3.vec[1] / scaleMultOut),
atInt32(it->v3.vec[2] / scaleMultOut)};
quantize(newData, chan.q[0], cur[0] - last[0]);
quantize(newData, chan.q[1], cur[1] - last[1]);
quantize(newData, chan.q[2], cur[2] - last[2]);

View File

@ -31,10 +31,10 @@ union Value
};
struct QuantizedValue
{
atInt16 v[4];
atInt16& operator[] (size_t idx)
atInt32 v[4];
atInt32& operator[] (size_t idx)
{return v[idx];}
const atInt16& operator[] (size_t idx) const
const atInt32& operator[] (size_t idx) const
{return v[idx];}
};
struct QuantizedRot
@ -62,7 +62,7 @@ size_t ComputeBitstreamSize(size_t keyFrameCount, const std::vector<Channel>& ch
class BitstreamReader
{
size_t m_bitCur;
atInt16 dequantize(const atUint8* data, atUint8 q);
atInt32 dequantize(const atUint8* data, atUint8 q);
bool dequantizeBit(const atUint8* data);
public:
std::vector<std::vector<Value>>
@ -70,20 +70,23 @@ public:
size_t keyFrameCount,
const std::vector<Channel>& channels,
atUint32 rotDiv,
float transMult);
float transMult,
float scaleMult);
};
class BitstreamWriter
{
size_t m_bitCur;
void quantize(atUint8* data, atUint8 q, atInt16 val);
void quantize(atUint8* data, atUint8 q, atInt32 val);
void quantizeBit(atUint8* data, bool val);
public:
std::unique_ptr<atUint8[]>
write(const std::vector<std::vector<Value>>& chanKeys,
size_t keyFrameCount, std::vector<Channel>& channels,
atUint32 quantRange,
atUint32& rotDivOut,
float& transMultOut,
float& scaleMultOut,
size_t& sizeOut);
};

View File

@ -1075,6 +1075,7 @@ bool ANCS::Cook(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor,
hecl::BlenderConnection::DataStream& ds,
bool pc,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc)
{
/* Search for yaml */
@ -1248,7 +1249,7 @@ bool ANCS::Cook(const hecl::ProjectPath& outPath,
if (w.hasError())
Log.report(logvisor::Fatal, _S("unable to open '%s' for writing"),
cookedOut.getRelativePath().c_str());
ANIM anim(act, boneIdMap, *rigInv);
ANIM anim(act, boneIdMap, *rigInv, pc);
ancs.animationSet.animResources.emplace_back();
ancs.animationSet.animResources.back().animId = pathOut;

View File

@ -540,6 +540,7 @@ struct ANCS : BigYAML
const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor,
hecl::BlenderConnection::DataStream& ds,
bool pc,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc);
};

View File

@ -327,7 +327,7 @@ void ANIM::ANIM2::read(athena::io::IStreamReader& reader)
size_t bsSize = DNAANIM::ComputeBitstreamSize(keyframeCount, channels);
std::unique_ptr<atUint8[]> bsData = reader.readUBytes(bsSize);
DNAANIM::BitstreamReader bsReader;
chanKeys = bsReader.read(bsData.get(), keyframeCount, channels, head.rotDiv, head.translationMult);
chanKeys = bsReader.read(bsData.get(), keyframeCount, channels, head.rotDiv, head.translationMult, 0.f);
}
void ANIM::ANIM2::write(athena::io::IStreamWriter& writer) const
@ -336,7 +336,7 @@ void ANIM::ANIM2::write(athena::io::IStreamWriter& writer) const
head.evnt = evnt;
head.unk0 = 1;
head.interval = mainInterval;
head.unk1 = 3;
head.rootBoneId = 3;
head.unk2 = 0;
head.unk3 = 1;
@ -357,8 +357,10 @@ void ANIM::ANIM2::write(athena::io::IStreamWriter& writer) const
std::vector<DNAANIM::Channel> qChannels = channels;
DNAANIM::BitstreamWriter bsWriter;
size_t bsSize;
float scaleMult;
std::unique_ptr<atUint8[]> bsData = bsWriter.write(chanKeys, keyframeCount, qChannels,
head.rotDiv, head.translationMult, bsSize);
m_version == 3 ? 0x7fffff : 0x7fff,
head.rotDiv, head.translationMult, scaleMult, bsSize);
/* TODO: Figure out proper scratch size computation */
head.scratchSize = keyframeCount * channels.size() * 16;
@ -424,9 +426,10 @@ size_t ANIM::ANIM2::binarySize(size_t __isz) const
ANIM::ANIM(const BlenderAction& act,
const std::unordered_map<std::string, atInt32>& idMap,
const DNAANIM::RigInverter<CINF>& rig)
const DNAANIM::RigInverter<CINF>& rig,
bool pc)
{
m_anim.reset(new struct ANIM0);
m_anim.reset(new struct ANIM2(pc));
IANIM& newAnim = *m_anim;
newAnim.bones.reserve(act.channels.size());

View File

@ -53,18 +53,18 @@ struct ANIM : BigDNA
struct ANIM2 : IANIM
{
DECL_EXPLICIT_DNA
ANIM2() : IANIM(2) {}
ANIM2(bool pc) : IANIM(pc ? 3 : 2) {}
struct Header : BigDNA
{
DECL_DNA
Value<atUint32> scratchSize;
UniqueID32 evnt;
Value<atUint32> unk0;
Value<atUint32> unk0 = 1;
Value<float> duration;
Value<float> interval;
Value<atUint32> unk1;
Value<atUint32> unk2;
Value<atUint32> rootBoneId = 3;
Value<atUint32> unk2 = 0;
Value<atUint32> rotDiv;
Value<float> translationMult;
Value<atUint32> boneChannelCount;
@ -154,7 +154,11 @@ struct ANIM : BigDNA
m_anim->read(reader);
break;
case 2:
m_anim.reset(new struct ANIM2);
m_anim.reset(new struct ANIM2(false));
m_anim->read(reader);
break;
case 3:
m_anim.reset(new struct ANIM2(true));
m_anim->read(reader);
break;
default:
@ -184,7 +188,8 @@ struct ANIM : BigDNA
ANIM() = default;
ANIM(const BlenderAction& act,
const std::unordered_map<std::string, atInt32>& idMap,
const DNAANIM::RigInverter<CINF>& rig);
const DNAANIM::RigInverter<CINF>& rig,
bool pc);
};
}

View File

@ -468,7 +468,7 @@ void ANIM::ANIM2::read(athena::io::IStreamReader& reader)
size_t bsSize = DNAANIM::ComputeBitstreamSize(keyframeCount, channels);
std::unique_ptr<atUint8[]> bsData = reader.readUBytes(bsSize);
DNAANIM::BitstreamReader bsReader;
chanKeys = bsReader.read(bsData.get(), keyframeCount, channels, head.rotDiv, head.translationMult);
chanKeys = bsReader.read(bsData.get(), keyframeCount, channels, head.rotDiv, head.translationMult, head.scaleMult);
}
void ANIM::ANIM2::write(athena::io::IStreamWriter& writer) const
@ -477,10 +477,8 @@ void ANIM::ANIM2::write(athena::io::IStreamWriter& writer) const
head.unk1 = 1;
head.unk2 = 1;
head.interval = mainInterval;
head.unk3 = 0;
head.unk4 = 0;
head.unk5 = 0;
head.unk6 = 1;
head.rootBoneId = 0;
head.scaleMult = 0.f;
WordBitmap keyBmp;
size_t frameCount = 0;
@ -500,7 +498,8 @@ void ANIM::ANIM2::write(athena::io::IStreamWriter& writer) const
DNAANIM::BitstreamWriter bsWriter;
size_t bsSize;
std::unique_ptr<atUint8[]> bsData = bsWriter.write(chanKeys, keyframeCount, qChannels,
head.rotDiv, head.translationMult, bsSize);
m_version == 3 ? 0x7fffff : 0x7fff,
head.rotDiv, head.translationMult, head.scaleMult, bsSize);
/* TODO: Figure out proper scratch size computation */
head.scratchSize = keyframeCount * channels.size() * 16;

View File

@ -58,17 +58,16 @@ struct ANIM : BigDNA
{
DECL_DNA
Value<atUint32> scratchSize;
Value<atUint8> unk1;
Value<atUint8> unk2;
Value<atUint16> unk1;
Value<float> duration;
Value<float> interval;
Value<atUint32> unk3;
Value<atUint32> unk4;
Value<atUint32> rootBoneId = 3;
Value<atUint32> unk2 = 0;
Value<atUint32> rotDiv;
Value<float> translationMult;
Value<atUint32> unk5;
Value<float> scaleMult;
Value<atUint32> boneChannelCount;
Value<atUint32> unk6;
Value<atUint32> unk3 = 1;
Value<atUint32> keyBitmapBitCount;
};

View File

@ -20,7 +20,8 @@ struct CINF : BigDNA
Value<atUint32> id;
Value<atUint32> parentId;
Value<atVec3f> origin;
Value<float> skinMetrics[8];
Value<atVec4f> q1;
Value<atVec4f> q2;
Value<atUint32> linkedCount;
Vector<atUint32, DNA_COUNT(linkedCount)> linked;
};

View File

@ -537,7 +537,7 @@ void ANIM::ANIM1::read(athena::io::IStreamReader& reader)
size_t bsSize = DNAANIM::ComputeBitstreamSize(head.keyCount-1, channels);
std::unique_ptr<atUint8[]> bsData = reader.readUBytes(bsSize);
DNAANIM::BitstreamReader bsReader;
chanKeys = bsReader.read(bsData.get(), head.keyCount-1, channels, 32767, head.translationMult);
chanKeys = bsReader.read(bsData.get(), head.keyCount-1, channels, 32767, head.translationMult, head.scaleMult);
}
void ANIM::ANIM1::write(athena::io::IStreamWriter& writer) const

View File

@ -63,7 +63,7 @@ struct ANIM : BigDNA
Value<atUint32> unk3;
Value<atUint8> unk4[3];
Value<float> translationMult;
Value<atUint32> unk6;
Value<float> scaleMult;
Value<atUint32> unk7;
Value<float> unk8;
Value<float> unk9;

View File

@ -371,7 +371,7 @@ struct SpecMP1 : SpecBase
FCookProgress progress)
{
Actor actor = ds.compileActor();
DNAMP1::ANCS::Cook(out, in, actor, ds,
DNAMP1::ANCS::Cook(out, in, actor, ds, m_pc,
[&](const hecl::ProjectPath& modelPath) -> bool
{
hecl::ProjectPath cooked;

View File

@ -277,6 +277,8 @@ public:
}
T* operator->() {return GetObj();}
const T* operator->() const {return GetObj();}
T& operator*() {return *GetObj();}
const T& operator*() const {return *GetObj();}
};
template <class T>

View File

@ -15,6 +15,9 @@ void CAnimFormatUnion::SubConstruct(u8* storage, EAnimFormat fmt,
case EAnimFormat::Uncompressed:
new (storage) CAnimSource(in, store);
break;
case EAnimFormat::BitstreamCompressed24:
new (storage) CAnimSource(in, store);
break;
default:
Log.report(logvisor::Fatal, "unable to read ANIM format %d", int(fmt));
}

View File

@ -15,7 +15,8 @@ enum class EAnimFormat
{
Uncompressed,
Unknown,
BitstreamCompressed
BitstreamCompressed,
BitstreamCompressed24
};
class CAnimFormatUnion

View File

@ -9,9 +9,6 @@
namespace urde
{
template <class T>
using TSubAnimTypeToken = TCachedToken<T>;
class IAnimSourceInfo
{
public:

View File

@ -0,0 +1,125 @@
#include "CFBStreamedAnimReader.hpp"
namespace urde
{
CFBStreamedAnimReaderTotals::CFBStreamedAnimReaderTotals(const CFBStreamedCompression& source)
{
const CFBStreamedCompression::Header* header =
reinterpret_cast<const CFBStreamedCompression::Header*>(source.xc_rotsAndOffs.get());
const u32* bitmap = reinterpret_cast<const u32*>(source.xc_rotsAndOffs.get() + 9);
u32 bitmapWordCount = (bitmap[0] + 31) / 32;
x14_rotDiv = header->rotDiv;
x18_transMult = header->translationMult;
const u8* chans = reinterpret_cast<const u8*>(bitmap + bitmapWordCount + 1);
u32 boneChanCount = *reinterpret_cast<const u32*>(chans);
x24_boneChanCount = boneChanCount;
}
CFBStreamedPairOfTotals::CFBStreamedPairOfTotals(const TSubAnimTypeToken<CFBStreamedCompression>& source)
: x0_source(source), xc_rotsAndOffs(source->xc_rotsAndOffs.get()), x14_(*source), x3c_(*source)
{
x0_source.Lock();
const u32* bitmap = reinterpret_cast<const u32*>(source->xc_rotsAndOffs.get() + 9);
u32 bitmapWordCount = (bitmap[0] + 31) / 32;
const u8* chans = reinterpret_cast<const u8*>(bitmap + bitmapWordCount + 1);
u32 boneChanCount = *reinterpret_cast<const u32*>(chans);
chans += 4;
for (int b=0 ; b<boneChanCount ; ++b)
{
chans += 15;
u16 tCount = *reinterpret_cast<const u16*>(chans);
chans += 2;
if (tCount)
chans += 9;
}
x88_ = chans;
x8c_ = &x88_;
x90_ = *reinterpret_cast<const u32*>(*x8c_);
}
CSegIdToIndexConverter::CSegIdToIndexConverter(const CFBStreamedAnimReaderTotals& totals)
{
}
CFBStreamedAnimReader::CFBStreamedAnimReader(const TSubAnimTypeToken<CFBStreamedCompression>& source, const CCharAnimTime& time)
: CAnimSourceReaderBase(std::make_unique<TAnimSourceInfo<CFBStreamedCompression>>(source), time),
x54_source(source), x7c_(source), x114_(x7c_.x10_ ? x7c_.x14_ : x7c_.x3c_)
{
x54_source.Lock();
x64_steadyStateInfo.x64_duration = x54_source->GetAnimationDuration();
x64_steadyStateInfo.x6c_curRootOffset = x54_source->x14_rootOffset;
const CFBStreamedCompression::Header* header =
reinterpret_cast<const CFBStreamedCompression::Header*>(x54_source->xc_rotsAndOffs.get());
x64_steadyStateInfo.x78_ = header->unk2;
PostConstruct(time);
}
SAdvancementResults CFBStreamedAnimReader::VGetAdvancementResults(const CCharAnimTime& dt,
const CCharAnimTime& startOff) const
{
}
void CFBStreamedAnimReader::VSetPhase(float)
{
}
SAdvancementResults CFBStreamedAnimReader::VReverseView(const CCharAnimTime& time)
{
}
std::shared_ptr<IAnimReader> CFBStreamedAnimReader::VClone() const
{
}
void CFBStreamedAnimReader::VGetSegStatementSet(const CSegIdList& list, CSegStatementSet& setOut) const
{
}
void CFBStreamedAnimReader::VGetSegStatementSet(const CSegIdList& list,
CSegStatementSet& setOut,
const CCharAnimTime& time) const
{
}
SAdvancementResults CFBStreamedAnimReader::VAdvanceView(const CCharAnimTime& a)
{
}
CCharAnimTime CFBStreamedAnimReader::VGetTimeRemaining() const
{
}
CSteadyStateAnimInfo CFBStreamedAnimReader::VGetSteadyStateAnimInfo() const
{
}
bool CFBStreamedAnimReader::VHasOffset(const CSegId& seg) const
{
}
zeus::CVector3f CFBStreamedAnimReader::VGetOffset(const CSegId& seg) const
{
}
zeus::CVector3f CFBStreamedAnimReader::VGetOffset(const CSegId& seg, const CCharAnimTime& time) const
{
}
zeus::CQuaternion CFBStreamedAnimReader::VGetRotation(const CSegId& seg) const
{
}
template class TAnimSourceInfo<CFBStreamedCompression>;
}

View File

@ -0,0 +1,91 @@
#ifndef __URDE_CFSTREAMEDANIMREADER_HPP__
#define __URDE_CFSTREAMEDANIMREADER_HPP__
#include "CAnimSourceReader.hpp"
#include "CFBStreamedCompression.hpp"
namespace urde
{
template <class T>
class TAnimSourceInfo : public IAnimSourceInfo
{
TSubAnimTypeToken<T> x4_token;
public:
TAnimSourceInfo(const TSubAnimTypeToken<T>& token);
bool HasPOIData() const { return x4_token->GetPOIToken(); }
const std::vector<CBoolPOINode>& GetBoolPOIStream() const { return x4_token->GetPOIToken()->GetBoolPOIStream(); }
const std::vector<CInt32POINode>& GetInt32POIStream() const { return x4_token->GetPOIToken()->GetInt32POIStream(); }
const std::vector<CParticlePOINode>& GetParticlePOIStream() const { return x4_token->GetPOIToken()->GetParticlePOIStream(); }
const std::vector<CSoundPOINode>& GetSoundPOIStream() const { return x4_token->GetPOIToken()->GetSoundPOIStream(); }
CCharAnimTime GetAnimationDuration() const { return x4_token->GetAnimationDuration(); }
};
class CFBStreamedAnimReaderTotals
{
std::unique_ptr<u8[]> x0_buffer;
u32 x4_ = 0;
u32 x8_ = 0;
u32 xc_ = 0;
u32 x10_ = 0;
u32 x14_rotDiv;
float x18_transMult;
u32 x1c_ = 0;
bool x20_ = false;
u32 x24_boneChanCount;
public:
CFBStreamedAnimReaderTotals(const CFBStreamedCompression& source);
};
class CFBStreamedPairOfTotals
{
friend class CFBStreamedAnimReader;
TSubAnimTypeToken<CFBStreamedCompression> x0_source;
u32* xc_rotsAndOffs;
bool x10_ = true;
CFBStreamedAnimReaderTotals x14_;
CFBStreamedAnimReaderTotals x3c_;
const u8* x88_;
const u8** x8c_;
u32 x90_;
u32 x94_ = 0;
public:
CFBStreamedPairOfTotals(const TSubAnimTypeToken<CFBStreamedCompression>& source);
};
class CSegIdToIndexConverter
{
u32 x0_indices[96] = {-1};
public:
CSegIdToIndexConverter(const CFBStreamedAnimReaderTotals& totals);
};
class CFBStreamedAnimReader : public CAnimSourceReaderBase
{
TSubAnimTypeToken<CFBStreamedCompression> x54_source;
CSteadyStateAnimInfo x64_steadyStateInfo;
CFBStreamedPairOfTotals x7c_;
CSegIdToIndexConverter x114_;
public:
CFBStreamedAnimReader(const TSubAnimTypeToken<CFBStreamedCompression>& source, const CCharAnimTime& time);
SAdvancementResults VGetAdvancementResults(const CCharAnimTime& a, const CCharAnimTime& b) const;
bool VSupportsReverseView() const {return false;}
void VSetPhase(float);
SAdvancementResults VReverseView(const CCharAnimTime& time);
std::shared_ptr<IAnimReader> VClone() const;
void VGetSegStatementSet(const CSegIdList& list, CSegStatementSet& setOut) const;
void VGetSegStatementSet(const CSegIdList& list, CSegStatementSet& setOut, const CCharAnimTime& time) const;
SAdvancementResults VAdvanceView(const CCharAnimTime& a);
CCharAnimTime VGetTimeRemaining() 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;
zeus::CQuaternion VGetRotation(const CSegId& seg) const;
};
}
#endif // __URDE_CFSTREAMEDANIMREADER_HPP__

View File

@ -0,0 +1,112 @@
#include "CFBStreamedCompression.hpp"
namespace urde
{
CFBStreamedCompression::CFBStreamedCompression(CInputStream& in, IObjectStore& objStore)
{
x0_scratchSize = in.readUint32Big();
x4_evnt = in.readUint32Big();
xc_rotsAndOffs = GetRotationsAndOffsets(x0_scratchSize / 4 + 1, in);
if (x4_evnt)
x8_evntToken = objStore.GetObj(SObjectTag{FOURCC('EVNT'), x4_evnt});
}
std::unique_ptr<u32[]> CFBStreamedCompression::GetRotationsAndOffsets(u32 words, CInputStream& in)
{
std::unique_ptr<u32[]> ret(new u32[words]);
Header head;
head.read(in);
*reinterpret_cast<Header*>(ret.get()) = head;
u32* bitmapOut = &ret[9];
u32 bitmapBitCount = in.readUint32Big();
bitmapOut[0] = bitmapBitCount;
u32 bitmapWordCount = (bitmapBitCount + 31) / 32;
for (u32 i=0 ; i<bitmapWordCount ; ++i)
bitmapOut[i+1] = in.readUint32Big();
in.readUint32Big();
u8* chans = reinterpret_cast<u8*>(bitmapOut + bitmapWordCount + 1);
u8* bs = ReadBoneChannelDescriptors(chans, in);
u32 bsWords = ComputeBitstreamWords(chans);
u32* bsPtr = reinterpret_cast<u32*>(bs);
for (u32 w=0 ; w<bsWords ; ++w)
bsPtr[w] = in.readUint32Big();
return ret;
}
u8* CFBStreamedCompression::ReadBoneChannelDescriptors(u8* out, CInputStream& in)
{
u32 boneChanCount = in.readUint32Big();
*reinterpret_cast<u32*>(out) = boneChanCount;
out += 4;
for (int b=0 ; b<boneChanCount ; ++b)
{
*reinterpret_cast<u32*>(out) = in.readUint32Big();
out += 4;
*reinterpret_cast<u16*>(out) = in.readUint16Big();
out += 2;
for (int i=0 ; i<3 ; ++i)
{
*reinterpret_cast<s16*>(out) = in.readInt16Big();
out += 2;
*reinterpret_cast<u8*>(out) = in.readUByte();
out += 1;
}
u16 tCount = in.readUint16Big();
*reinterpret_cast<u16*>(out) = tCount;
out += 2;
if (tCount)
{
for (int i=0 ; i<3 ; ++i)
{
*reinterpret_cast<s16*>(out) = in.readInt16Big();
out += 2;
*reinterpret_cast<u8*>(out) = in.readUByte();
out += 1;
}
}
}
return out;
}
u32 CFBStreamedCompression::ComputeBitstreamWords(const u8* chans)
{
u32 boneChanCount = *reinterpret_cast<const u32*>(chans);
chans += 4;
u16 keyCount = *reinterpret_cast<const u16*>(chans);
u32 totalBits = 0;
for (u32 c=0 ; c<boneChanCount ; ++c)
{
totalBits += *reinterpret_cast<const u8*>(chans + 0x8);
totalBits += *reinterpret_cast<const u8*>(chans + 0xb);
totalBits += *reinterpret_cast<const u8*>(chans + 0xe);
u16 tKeyCount = *reinterpret_cast<const u16*>(chans + 0xf);
chans += 0x11;
if (tKeyCount)
{
totalBits += *reinterpret_cast<const u8*>(chans + 0x2);
totalBits += *reinterpret_cast<const u8*>(chans + 0x5);
totalBits += *reinterpret_cast<const u8*>(chans + 0x8);
chans += 0x9;
}
}
return (totalBits * keyCount + 31) / 32;
}
}

View File

@ -0,0 +1,71 @@
#ifndef __URDE_CFSTREAMEDCOMPRESSION_HPP__
#define __URDE_CFSTREAMEDCOMPRESSION_HPP__
#include "RetroTypes.hpp"
#include "CToken.hpp"
#include "CAnimPOIData.hpp"
#include "zeus/CVector3f.hpp"
namespace urde
{
class IObjectStore;
class CFBStreamedCompression
{
friend class CFBStreamedAnimReader;
friend class CFBStreamedAnimReaderTotals;
friend class CFBStreamedPairOfTotals;
struct Header
{
u32 unk0;
float duration;
float interval;
u32 rootBoneId;
u32 unk2;
u32 rotDiv;
float translationMult;
u32 boneChannelCount;
u32 unk3;
void read(CInputStream& in)
{
/* unk0 */
unk0 = in.readUint32Big();
/* duration */
duration = in.readFloatBig();
/* interval */
interval = in.readFloatBig();
/* rootBoneId */
rootBoneId = in.readUint32Big();
/* unk2 */
unk2 = in.readUint32Big();
/* rotDiv */
rotDiv = in.readUint32Big();
/* translationMult */
translationMult = in.readFloatBig();
/* boneChannelCount */
boneChannelCount = in.readUint32Big();
/* unk3 */
unk3 = in.readUint32Big();
}
};
u32 x0_scratchSize;
ResId x4_evnt;
TLockedToken<CAnimPOIData> x8_evntToken;
std::unique_ptr<u32[]> xc_rotsAndOffs;
zeus::CVector3f x14_rootOffset;
static u8* ReadBoneChannelDescriptors(u8* out, CInputStream& in);
static std::unique_ptr<u32[]> GetRotationsAndOffsets(u32 words, CInputStream& in);
static u32 ComputeBitstreamWords(const u8* chans);
public:
CFBStreamedCompression(CInputStream& in, IObjectStore& objStore);
CCharAnimTime GetAnimationDuration() const { return reinterpret_cast<const Header*>(xc_rotsAndOffs.get())->duration; }
const TLockedToken<CAnimPOIData>& GetPOIToken() const { return x8_evntToken; }
};
}
#endif // __URDE_CFSTREAMEDCOMPRESSION_HPP__

View File

@ -73,6 +73,8 @@ set(CHARACTER_SOURCES
CParticlePOINode.hpp CParticlePOINode.cpp
CAnimSourceReader.hpp CAnimSourceReader.cpp
CAnimSource.hpp CAnimSource.cpp
CFBStreamedAnimReader.hpp CFBStreamedAnimReader.cpp
CFBStreamedCompression.hpp CFBStreamedCompression.cpp
CAllFormatsAnimSource.hpp CAllFormatsAnimSource.cpp
CSegStatementSet.hpp CSegStatementSet.cpp
CAnimPerSegmentData.hpp

View File

@ -6,6 +6,7 @@
#include "zeus/CVector3f.hpp"
#include "zeus/CQuaternion.hpp"
#include "CParticleData.hpp"
#include "CToken.hpp"
namespace urde
{
@ -36,6 +37,9 @@ struct CSteadyStateAnimInfo
bool x78_ = false;
};
template <class T>
using TSubAnimTypeToken = TCachedToken<T>;
class IAnimReader
{
public: