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

View File

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

View File

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

View File

@ -540,6 +540,7 @@ struct ANCS : BigYAML
const hecl::ProjectPath& inPath, const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor, const DNAANCS::Actor& actor,
hecl::BlenderConnection::DataStream& ds, hecl::BlenderConnection::DataStream& ds,
bool pc,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc); 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); size_t bsSize = DNAANIM::ComputeBitstreamSize(keyframeCount, channels);
std::unique_ptr<atUint8[]> bsData = reader.readUBytes(bsSize); std::unique_ptr<atUint8[]> bsData = reader.readUBytes(bsSize);
DNAANIM::BitstreamReader bsReader; 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 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.evnt = evnt;
head.unk0 = 1; head.unk0 = 1;
head.interval = mainInterval; head.interval = mainInterval;
head.unk1 = 3; head.rootBoneId = 3;
head.unk2 = 0; head.unk2 = 0;
head.unk3 = 1; head.unk3 = 1;
@ -357,8 +357,10 @@ void ANIM::ANIM2::write(athena::io::IStreamWriter& writer) const
std::vector<DNAANIM::Channel> qChannels = channels; std::vector<DNAANIM::Channel> qChannels = channels;
DNAANIM::BitstreamWriter bsWriter; DNAANIM::BitstreamWriter bsWriter;
size_t bsSize; size_t bsSize;
float scaleMult;
std::unique_ptr<atUint8[]> bsData = bsWriter.write(chanKeys, keyframeCount, qChannels, 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 */ /* TODO: Figure out proper scratch size computation */
head.scratchSize = keyframeCount * channels.size() * 16; head.scratchSize = keyframeCount * channels.size() * 16;
@ -424,9 +426,10 @@ size_t ANIM::ANIM2::binarySize(size_t __isz) const
ANIM::ANIM(const BlenderAction& act, ANIM::ANIM(const BlenderAction& act,
const std::unordered_map<std::string, atInt32>& idMap, 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; IANIM& newAnim = *m_anim;
newAnim.bones.reserve(act.channels.size()); newAnim.bones.reserve(act.channels.size());

View File

@ -53,18 +53,18 @@ struct ANIM : BigDNA
struct ANIM2 : IANIM struct ANIM2 : IANIM
{ {
DECL_EXPLICIT_DNA DECL_EXPLICIT_DNA
ANIM2() : IANIM(2) {} ANIM2(bool pc) : IANIM(pc ? 3 : 2) {}
struct Header : BigDNA struct Header : BigDNA
{ {
DECL_DNA DECL_DNA
Value<atUint32> scratchSize; Value<atUint32> scratchSize;
UniqueID32 evnt; UniqueID32 evnt;
Value<atUint32> unk0; Value<atUint32> unk0 = 1;
Value<float> duration; Value<float> duration;
Value<float> interval; Value<float> interval;
Value<atUint32> unk1; Value<atUint32> rootBoneId = 3;
Value<atUint32> unk2; Value<atUint32> unk2 = 0;
Value<atUint32> rotDiv; Value<atUint32> rotDiv;
Value<float> translationMult; Value<float> translationMult;
Value<atUint32> boneChannelCount; Value<atUint32> boneChannelCount;
@ -154,7 +154,11 @@ struct ANIM : BigDNA
m_anim->read(reader); m_anim->read(reader);
break; break;
case 2: 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); m_anim->read(reader);
break; break;
default: default:
@ -184,7 +188,8 @@ struct ANIM : BigDNA
ANIM() = default; ANIM() = default;
ANIM(const BlenderAction& act, ANIM(const BlenderAction& act,
const std::unordered_map<std::string, atInt32>& idMap, 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); size_t bsSize = DNAANIM::ComputeBitstreamSize(keyframeCount, channels);
std::unique_ptr<atUint8[]> bsData = reader.readUBytes(bsSize); std::unique_ptr<atUint8[]> bsData = reader.readUBytes(bsSize);
DNAANIM::BitstreamReader bsReader; 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 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.unk1 = 1;
head.unk2 = 1; head.unk2 = 1;
head.interval = mainInterval; head.interval = mainInterval;
head.unk3 = 0; head.rootBoneId = 0;
head.unk4 = 0; head.scaleMult = 0.f;
head.unk5 = 0;
head.unk6 = 1;
WordBitmap keyBmp; WordBitmap keyBmp;
size_t frameCount = 0; size_t frameCount = 0;
@ -500,7 +498,8 @@ void ANIM::ANIM2::write(athena::io::IStreamWriter& writer) const
DNAANIM::BitstreamWriter bsWriter; DNAANIM::BitstreamWriter bsWriter;
size_t bsSize; size_t bsSize;
std::unique_ptr<atUint8[]> bsData = bsWriter.write(chanKeys, keyframeCount, qChannels, 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 */ /* TODO: Figure out proper scratch size computation */
head.scratchSize = keyframeCount * channels.size() * 16; head.scratchSize = keyframeCount * channels.size() * 16;

View File

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

View File

@ -20,7 +20,8 @@ struct CINF : BigDNA
Value<atUint32> id; Value<atUint32> id;
Value<atUint32> parentId; Value<atUint32> parentId;
Value<atVec3f> origin; Value<atVec3f> origin;
Value<float> skinMetrics[8]; Value<atVec4f> q1;
Value<atVec4f> q2;
Value<atUint32> linkedCount; Value<atUint32> linkedCount;
Vector<atUint32, DNA_COUNT(linkedCount)> linked; 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); size_t bsSize = DNAANIM::ComputeBitstreamSize(head.keyCount-1, channels);
std::unique_ptr<atUint8[]> bsData = reader.readUBytes(bsSize); std::unique_ptr<atUint8[]> bsData = reader.readUBytes(bsSize);
DNAANIM::BitstreamReader bsReader; 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 void ANIM::ANIM1::write(athena::io::IStreamWriter& writer) const

View File

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

View File

@ -371,7 +371,7 @@ struct SpecMP1 : SpecBase
FCookProgress progress) FCookProgress progress)
{ {
Actor actor = ds.compileActor(); 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 [&](const hecl::ProjectPath& modelPath) -> bool
{ {
hecl::ProjectPath cooked; hecl::ProjectPath cooked;

View File

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

View File

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

View File

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

View File

@ -9,9 +9,6 @@
namespace urde namespace urde
{ {
template <class T>
using TSubAnimTypeToken = TCachedToken<T>;
class IAnimSourceInfo class IAnimSourceInfo
{ {
public: 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 CParticlePOINode.hpp CParticlePOINode.cpp
CAnimSourceReader.hpp CAnimSourceReader.cpp CAnimSourceReader.hpp CAnimSourceReader.cpp
CAnimSource.hpp CAnimSource.cpp CAnimSource.hpp CAnimSource.cpp
CFBStreamedAnimReader.hpp CFBStreamedAnimReader.cpp
CFBStreamedCompression.hpp CFBStreamedCompression.cpp
CAllFormatsAnimSource.hpp CAllFormatsAnimSource.cpp CAllFormatsAnimSource.hpp CAllFormatsAnimSource.cpp
CSegStatementSet.hpp CSegStatementSet.cpp CSegStatementSet.hpp CSegStatementSet.cpp
CAnimPerSegmentData.hpp CAnimPerSegmentData.hpp

View File

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