mirror of https://github.com/AxioDL/metaforce.git
Work on CFBStreamedCompression; defined 24-bit ANIM3 format
This commit is contained in:
parent
d9448cae05
commit
f9cef44029
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ enum class EAnimFormat
|
|||
{
|
||||
Uncompressed,
|
||||
Unknown,
|
||||
BitstreamCompressed
|
||||
BitstreamCompressed,
|
||||
BitstreamCompressed24
|
||||
};
|
||||
|
||||
class CAnimFormatUnion
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
namespace urde
|
||||
{
|
||||
|
||||
template <class T>
|
||||
using TSubAnimTypeToken = TCachedToken<T>;
|
||||
|
||||
class IAnimSourceInfo
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -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>;
|
||||
|
||||
}
|
|
@ -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__
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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__
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue