mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-12-09 08:27:42 +00:00
ANIM fixes and explicit-endian refactor
This commit is contained in:
87
DataSpec/DNAMP2/ANCS.hpp
Normal file
87
DataSpec/DNAMP2/ANCS.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef _DNAMP2_ANCS_HPP_
|
||||
#define _DNAMP2_ANCS_HPP_
|
||||
|
||||
#include <map>
|
||||
#include "../DNACommon/DNACommon.hpp"
|
||||
#include "../DNACommon/ANCS.hpp"
|
||||
#include "CMDLMaterials.hpp"
|
||||
#include "BlenderConnection.hpp"
|
||||
#include "CINF.hpp"
|
||||
#include "CSKR.hpp"
|
||||
#include "ANIM.hpp"
|
||||
#include "../DNAMP1/ANCS.hpp"
|
||||
|
||||
namespace Retro
|
||||
{
|
||||
namespace DNAMP2
|
||||
{
|
||||
|
||||
struct ANCS : BigYAML
|
||||
{
|
||||
using CINFType = CINF;
|
||||
using CSKRType = CSKR;
|
||||
using ANIMType = ANIM;
|
||||
|
||||
DECL_YAML
|
||||
Value<atUint16> version;
|
||||
|
||||
DNAMP1::ANCS::CharacterSet characterSet;
|
||||
DNAMP1::ANCS::AnimationSet animationSet;
|
||||
|
||||
void getCharacterResInfo(std::vector<DNAANCS::CharacterResInfo<UniqueID32>>& out) const
|
||||
{
|
||||
out.clear();
|
||||
out.reserve(characterSet.characters.size());
|
||||
for (const DNAMP1::ANCS::CharacterSet::CharacterInfo& ci : characterSet.characters)
|
||||
{
|
||||
out.emplace_back();
|
||||
DNAANCS::CharacterResInfo<UniqueID32>& chOut = out.back();
|
||||
chOut.name = ci.name;
|
||||
chOut.cmdl = ci.cmdl;
|
||||
chOut.cskr = ci.cskr;
|
||||
chOut.cinf = ci.cinf;
|
||||
}
|
||||
}
|
||||
|
||||
void getAnimationResInfo(std::map<atUint32, std::pair<std::string, UniqueID32>>& out) const
|
||||
{
|
||||
out.clear();
|
||||
for (const DNAMP1::ANCS::AnimationSet::Animation& ai : animationSet.animations)
|
||||
ai.metaAnim.m_anim->gatherPrimitives(out);
|
||||
}
|
||||
|
||||
static bool Extract(const SpecBase& dataSpec,
|
||||
PAKEntryReadStream& rs,
|
||||
const HECL::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const DNAMP1::PAK::Entry& entry,
|
||||
bool force)
|
||||
{
|
||||
ANCS ancs;
|
||||
ancs.read(rs);
|
||||
|
||||
HECL::ProjectPath yamlPath = outPath.getWithExtension(_S(".yaml"));
|
||||
if (force || yamlPath.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||
{
|
||||
FILE* fp = HECL::Fopen(yamlPath.getAbsolutePath().c_str(), _S("wb"));
|
||||
ancs.toYAMLFile(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
HECL::ProjectPath blendPath = outPath.getWithExtension(_S(".blend"));
|
||||
if (force || blendPath.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||
{
|
||||
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
|
||||
DNAANCS::ReadANCSToBlender<PAKRouter<PAKBridge>, ANCS, MaterialSet, 4>
|
||||
(conn, ancs, blendPath, pakRouter, entry, dataSpec.getMasterShaderPath(), force);
|
||||
return conn.saveBlend();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _DNAMP2_ANCS_HPP_
|
||||
352
DataSpec/DNAMP2/ANIM.cpp
Normal file
352
DataSpec/DNAMP2/ANIM.cpp
Normal file
@@ -0,0 +1,352 @@
|
||||
#include "ANIM.hpp"
|
||||
|
||||
namespace Retro
|
||||
{
|
||||
namespace DNAMP2
|
||||
{
|
||||
|
||||
void ANIM::IANIM::sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf) const
|
||||
{
|
||||
os.format("act.hecl_fps = round(%f)\n", (1.0f / mainInterval));
|
||||
|
||||
auto kit = chanKeys.begin();
|
||||
for (const std::pair<atUint32, bool>& bone : bones)
|
||||
{
|
||||
os.format("bone_string = '%s'\n", cinf.getBoneNameFromId(bone.first)->c_str());
|
||||
os << "action_group = act.groups.new(bone_string)\n"
|
||||
"\n"
|
||||
"rotCurves = []\n"
|
||||
"rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=0, action_group=bone_string))\n"
|
||||
"rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=1, action_group=bone_string))\n"
|
||||
"rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=2, action_group=bone_string))\n"
|
||||
"rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=3, action_group=bone_string))\n"
|
||||
"\n";
|
||||
|
||||
if (bone.second)
|
||||
os << "bone_trans_head = (0.0,0.0,0.0)\n"
|
||||
"if arm_obj.data.bones[bone_string].parent is not None:\n"
|
||||
" bone_trans_head = Vector(arm_obj.data.bones[bone_string].head_local) - Vector(arm_obj.data.bones[bone_string].parent.head_local)\n"
|
||||
"transCurves = []\n"
|
||||
"transCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=0, action_group=bone_string))\n"
|
||||
"transCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=1, action_group=bone_string))\n"
|
||||
"transCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=2, action_group=bone_string))\n"
|
||||
"\n";
|
||||
|
||||
os << "crv = act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_mode', action_group=bone_string)\n"
|
||||
"crv.keyframe_points.add()\n"
|
||||
"crv.keyframe_points[-1].co = (0, 0)\n"
|
||||
"crv.keyframe_points[-1].interpolation = 'LINEAR'\n"
|
||||
"\n";
|
||||
|
||||
const std::vector<DNAANIM::Value>& rotKeys = *kit++;
|
||||
auto frameit = frames.begin();
|
||||
for (const DNAANIM::Value& val : rotKeys)
|
||||
{
|
||||
atUint32 frame = *frameit++;
|
||||
for (int c=0 ; c<4 ; ++c)
|
||||
os.format("crv = rotCurves[%d]\n"
|
||||
"crv.keyframe_points.add()\n"
|
||||
"crv.keyframe_points[-1].interpolation = 'LINEAR'\n"
|
||||
"crv.keyframe_points[-1].co = (%u, %f)\n",
|
||||
c, frame, val.v4.vec[c]);
|
||||
}
|
||||
|
||||
if (bone.second)
|
||||
{
|
||||
const std::vector<DNAANIM::Value>& transKeys = *kit++;
|
||||
auto frameit = frames.begin();
|
||||
for (const DNAANIM::Value& val : transKeys)
|
||||
{
|
||||
atUint32 frame = *frameit++;
|
||||
for (int c=0 ; c<3 ; ++c)
|
||||
os.format("crv = transCurves[%d]\n"
|
||||
"crv.keyframe_points.add()\n"
|
||||
"crv.keyframe_points[-1].interpolation = 'LINEAR'\n"
|
||||
"crv.keyframe_points[-1].co = (%u, %f - bone_trans_head[%d])\n",
|
||||
c, frame, val.v4.vec[c], c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ANIM::ANIM0::read(Athena::io::IStreamReader& reader)
|
||||
{
|
||||
Header head;
|
||||
head.read(reader);
|
||||
mainInterval = head.interval;
|
||||
|
||||
frames.clear();
|
||||
frames.reserve(head.keyCount);
|
||||
for (size_t k=0 ; k<head.keyCount ; ++k)
|
||||
frames.push_back(k);
|
||||
|
||||
std::map<atUint8, atUint32> boneMap;
|
||||
for (size_t b=0 ; b<head.boneSlotCount ; ++b)
|
||||
{
|
||||
atUint8 idx = reader.readUByte();
|
||||
if (idx == 0xff)
|
||||
continue;
|
||||
boneMap[idx] = b;
|
||||
}
|
||||
|
||||
atUint32 boneCount = reader.readUint32Big();
|
||||
bones.clear();
|
||||
bones.reserve(boneCount);
|
||||
channels.clear();
|
||||
for (size_t b=0 ; b<boneCount ; ++b)
|
||||
{
|
||||
bones.emplace_back(boneMap[b], false);
|
||||
atUint8 idx = reader.readUByte();
|
||||
channels.emplace_back();
|
||||
DNAANIM::Channel& chan = channels.back();
|
||||
chan.type = DNAANIM::Channel::ROTATION;
|
||||
if (idx != 0xff)
|
||||
{
|
||||
bones.back().second = true;
|
||||
channels.emplace_back();
|
||||
DNAANIM::Channel& chan = channels.back();
|
||||
chan.type = DNAANIM::Channel::TRANSLATION;
|
||||
}
|
||||
}
|
||||
|
||||
reader.readUint32Big();
|
||||
chanKeys.clear();
|
||||
chanKeys.reserve(channels.size());
|
||||
for (const std::pair<atUint32, bool>& bone : bones)
|
||||
{
|
||||
chanKeys.emplace_back();
|
||||
std::vector<DNAANIM::Value>& keys = chanKeys.back();
|
||||
for (size_t k=0 ; k<head.keyCount ; ++k)
|
||||
keys.emplace_back(reader.readVec4fBig());
|
||||
|
||||
if (bone.second)
|
||||
chanKeys.emplace_back();
|
||||
}
|
||||
|
||||
reader.readUint32Big();
|
||||
auto kit = chanKeys.begin();
|
||||
for (const std::pair<atUint32, bool>& bone : bones)
|
||||
{
|
||||
++kit;
|
||||
if (bone.second)
|
||||
{
|
||||
std::vector<DNAANIM::Value>& keys = *kit++;
|
||||
for (size_t k=0 ; k<head.keyCount ; ++k)
|
||||
keys.emplace_back(reader.readVec3fBig());
|
||||
}
|
||||
}
|
||||
|
||||
evnt.read(reader);
|
||||
}
|
||||
|
||||
void ANIM::ANIM0::write(Athena::io::IStreamWriter& writer) const
|
||||
{
|
||||
Header head;
|
||||
head.unk0 = 0;
|
||||
head.unk1 = 0;
|
||||
head.unk2 = 0;
|
||||
head.keyCount = frames.size();
|
||||
head.duration = head.keyCount * mainInterval;
|
||||
head.interval = mainInterval;
|
||||
|
||||
atUint32 maxId = 0;
|
||||
for (const std::pair<atUint32, bool>& bone : bones)
|
||||
maxId = MAX(maxId, bone.first);
|
||||
head.boneSlotCount = maxId + 1;
|
||||
head.write(writer);
|
||||
|
||||
for (size_t s=0 ; s<head.boneSlotCount ; ++s)
|
||||
{
|
||||
size_t boneIdx = 0;
|
||||
bool found = false;
|
||||
for (const std::pair<atUint32, bool>& bone : bones)
|
||||
{
|
||||
if (s == bone.first)
|
||||
{
|
||||
writer.writeUByte(boneIdx);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
++boneIdx;
|
||||
}
|
||||
if (!found)
|
||||
writer.writeUByte(0xff);
|
||||
}
|
||||
|
||||
writer.writeUint32Big(bones.size());
|
||||
size_t boneIdx = 0;
|
||||
for (const std::pair<atUint32, bool>& bone : bones)
|
||||
{
|
||||
if (bone.second)
|
||||
writer.writeUByte(boneIdx);
|
||||
else
|
||||
writer.writeUByte(0xff);
|
||||
++boneIdx;
|
||||
}
|
||||
|
||||
writer.writeUint32Big(bones.size() * head.keyCount);
|
||||
auto cit = chanKeys.begin();
|
||||
atUint32 transKeyCount = 0;
|
||||
for (const std::pair<atUint32, bool>& bone : bones)
|
||||
{
|
||||
const std::vector<DNAANIM::Value>& keys = *cit++;
|
||||
auto kit = keys.begin();
|
||||
for (size_t k=0 ; k<head.keyCount ; ++k)
|
||||
writer.writeVec4fBig((*kit++).v4);
|
||||
if (bone.second)
|
||||
{
|
||||
transKeyCount += head.keyCount;
|
||||
++cit;
|
||||
}
|
||||
}
|
||||
|
||||
writer.writeUint32Big(transKeyCount);
|
||||
cit = chanKeys.begin();
|
||||
for (const std::pair<atUint32, bool>& bone : bones)
|
||||
{
|
||||
++cit;
|
||||
if (bone.second)
|
||||
{
|
||||
const std::vector<DNAANIM::Value>& keys = *cit++;
|
||||
auto kit = keys.begin();
|
||||
for (size_t k=0 ; k<head.keyCount ; ++k)
|
||||
writer.writeVec3fBig((*kit++).v3);
|
||||
}
|
||||
}
|
||||
|
||||
evnt.write(writer);
|
||||
}
|
||||
|
||||
void ANIM::ANIM2::read(Athena::io::IStreamReader& reader)
|
||||
{
|
||||
Header head;
|
||||
head.read(reader);
|
||||
evnt = head.evnt;
|
||||
mainInterval = head.interval;
|
||||
|
||||
WordBitmap keyBmp;
|
||||
keyBmp.read(reader, head.keyBitmapBitCount);
|
||||
frames.clear();
|
||||
atUint32 frameAccum = 0;
|
||||
for (bool bit : keyBmp)
|
||||
{
|
||||
if (bit)
|
||||
frames.push_back(frameAccum);
|
||||
++frameAccum;
|
||||
}
|
||||
reader.seek(8);
|
||||
|
||||
bones.clear();
|
||||
bones.reserve(head.boneChannelCount);
|
||||
channels.clear();
|
||||
channels.reserve(head.boneChannelCount);
|
||||
size_t keyframeCount = 0;
|
||||
for (size_t b=0 ; b<head.boneChannelCount ; ++b)
|
||||
{
|
||||
ChannelDesc desc;
|
||||
desc.read(reader);
|
||||
bones.emplace_back(desc.id, desc.keyCount2);
|
||||
|
||||
if (desc.keyCount1)
|
||||
{
|
||||
channels.emplace_back();
|
||||
DNAANIM::Channel& chan = channels.back();
|
||||
chan.type = DNAANIM::Channel::ROTATION;
|
||||
chan.i[0] = desc.initRX;
|
||||
chan.q[0] = desc.qRX;
|
||||
chan.i[1] = desc.initRY;
|
||||
chan.q[1] = desc.qRY;
|
||||
chan.i[2] = desc.initRZ;
|
||||
chan.q[2] = desc.qRZ;
|
||||
}
|
||||
keyframeCount = MAX(keyframeCount, desc.keyCount1);
|
||||
|
||||
if (desc.keyCount2)
|
||||
{
|
||||
channels.emplace_back();
|
||||
DNAANIM::Channel& chan = channels.back();
|
||||
chan.type = DNAANIM::Channel::TRANSLATION;
|
||||
chan.i[0] = desc.initTX;
|
||||
chan.q[0] = desc.qTX;
|
||||
chan.i[1] = desc.initTY;
|
||||
chan.q[1] = desc.qTY;
|
||||
chan.i[2] = desc.initTZ;
|
||||
chan.q[2] = desc.qTZ;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void ANIM::ANIM2::write(Athena::io::IStreamWriter& writer) const
|
||||
{
|
||||
Header head;
|
||||
head.evnt = evnt;
|
||||
head.unk0 = 1;
|
||||
head.interval = mainInterval;
|
||||
head.unk1 = 3;
|
||||
head.unk2 = 0;
|
||||
head.unk3 = 1;
|
||||
|
||||
WordBitmap keyBmp;
|
||||
size_t frameCount = 0;
|
||||
for (atUint32 frame : frames)
|
||||
{
|
||||
while (keyBmp.getBit(frame))
|
||||
++frame;
|
||||
keyBmp.setBit(frame);
|
||||
frameCount = frame + 1;
|
||||
}
|
||||
head.keyBitmapBitCount = frameCount;
|
||||
head.duration = frameCount * mainInterval;
|
||||
head.boneChannelCount = bones.size();
|
||||
|
||||
size_t keyframeCount = frames.size();
|
||||
std::vector<DNAANIM::Channel> qChannels = channels;
|
||||
DNAANIM::BitstreamWriter bsWriter;
|
||||
size_t bsSize;
|
||||
std::unique_ptr<atUint8[]> bsData = bsWriter.write(chanKeys, keyframeCount, qChannels,
|
||||
head.rotDiv, head.translationMult, bsSize);
|
||||
|
||||
/* TODO: Figure out proper scratch size computation */
|
||||
head.scratchSize = keyframeCount * channels.size() * 16;
|
||||
|
||||
head.write(writer);
|
||||
keyBmp.write(writer);
|
||||
writer.writeUint32Big(head.boneChannelCount);
|
||||
writer.writeUint32Big(head.boneChannelCount);
|
||||
auto cit = qChannels.begin();
|
||||
for (const std::pair<atUint32, bool>& bone : bones)
|
||||
{
|
||||
ChannelDesc desc;
|
||||
desc.id = bone.first;
|
||||
DNAANIM::Channel& chan = *cit++;
|
||||
desc.keyCount1 = keyframeCount;
|
||||
desc.initRX = chan.i[0];
|
||||
desc.qRX = chan.q[0];
|
||||
desc.initRY = chan.i[1];
|
||||
desc.qRY = chan.q[1];
|
||||
desc.initRZ = chan.i[2];
|
||||
desc.qRZ = chan.q[2];
|
||||
if (bone.second)
|
||||
{
|
||||
DNAANIM::Channel& chan = *cit++;
|
||||
desc.keyCount2 = keyframeCount;
|
||||
desc.initTX = chan.i[0];
|
||||
desc.qTX = chan.q[0];
|
||||
desc.initTY = chan.i[1];
|
||||
desc.qTY = chan.q[1];
|
||||
desc.initTZ = chan.i[2];
|
||||
desc.qTZ = chan.q[2];
|
||||
}
|
||||
desc.write(writer);
|
||||
}
|
||||
|
||||
writer.writeUBytes(bsData.get(), bsSize);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
174
DataSpec/DNAMP2/ANIM.hpp
Normal file
174
DataSpec/DNAMP2/ANIM.hpp
Normal file
@@ -0,0 +1,174 @@
|
||||
#ifndef _DNAMP2_ANIM_HPP_
|
||||
#define _DNAMP2_ANIM_HPP_
|
||||
|
||||
#include "BlenderConnection.hpp"
|
||||
#include "DNAMP2.hpp"
|
||||
#include "../DNACommon/ANIM.hpp"
|
||||
#include "CINF.hpp"
|
||||
|
||||
namespace Retro
|
||||
{
|
||||
namespace DNAMP2
|
||||
{
|
||||
|
||||
struct ANIM : BigDNA
|
||||
{
|
||||
Delete expl;
|
||||
|
||||
struct IANIM : BigDNA
|
||||
{
|
||||
Delete expl;
|
||||
atUint32 m_version;
|
||||
IANIM(atUint32 version) : m_version(version) {}
|
||||
|
||||
std::vector<std::pair<atUint32, bool>> bones;
|
||||
std::vector<atUint32> frames;
|
||||
std::vector<DNAANIM::Channel> channels;
|
||||
std::vector<std::vector<DNAANIM::Value>> chanKeys;
|
||||
float mainInterval = 0.0;
|
||||
UniqueID32 evnt;
|
||||
|
||||
void sendANIMToBlender(HECL::BlenderConnection::PyOutStream&, const CINF&) const;
|
||||
};
|
||||
|
||||
struct ANIM0 : IANIM
|
||||
{
|
||||
DECL_EXPLICIT_DNA
|
||||
ANIM0() : IANIM(0) {}
|
||||
|
||||
struct Header : BigDNA
|
||||
{
|
||||
DECL_DNA
|
||||
Value<float> duration;
|
||||
Value<atUint32> unk0;
|
||||
Value<float> interval;
|
||||
Value<atUint32> unk1;
|
||||
Value<atUint32> keyCount;
|
||||
Value<atUint32> unk2;
|
||||
Value<atUint32> boneSlotCount;
|
||||
};
|
||||
};
|
||||
|
||||
struct ANIM2 : IANIM
|
||||
{
|
||||
DECL_EXPLICIT_DNA
|
||||
ANIM2() : IANIM(2) {}
|
||||
|
||||
struct Header : BigDNA
|
||||
{
|
||||
DECL_DNA
|
||||
Value<atUint32> scratchSize;
|
||||
UniqueID32 evnt;
|
||||
Value<atUint32> unk0;
|
||||
Value<float> duration;
|
||||
Value<float> interval;
|
||||
Value<atUint32> unk1;
|
||||
Value<atUint32> unk2;
|
||||
Value<atUint32> rotDiv;
|
||||
Value<float> translationMult;
|
||||
Value<atUint32> boneChannelCount;
|
||||
Value<atUint32> unk3;
|
||||
Value<atUint32> keyBitmapBitCount;
|
||||
};
|
||||
|
||||
struct ChannelDesc : BigDNA
|
||||
{
|
||||
Delete expl;
|
||||
Value<atUint32> id = 0;
|
||||
Value<atUint16> keyCount1 = 0;
|
||||
Value<atUint16> initRX = 0;
|
||||
Value<atUint8> qRX = 0;
|
||||
Value<atUint16> initRY = 0;
|
||||
Value<atUint8> qRY = 0;
|
||||
Value<atUint16> initRZ = 0;
|
||||
Value<atUint8> qRZ = 0;
|
||||
Value<atUint16> keyCount2 = 0;
|
||||
Value<atUint16> initTX = 0;
|
||||
Value<atUint8> qTX = 0;
|
||||
Value<atUint16> initTY = 0;
|
||||
Value<atUint8> qTY = 0;
|
||||
Value<atUint16> initTZ = 0;
|
||||
Value<atUint8> qTZ = 0;
|
||||
|
||||
void read(Athena::io::IStreamReader& reader)
|
||||
{
|
||||
id = reader.readUint32Big();
|
||||
keyCount1 = reader.readUint16Big();
|
||||
initRX = reader.readUint16Big();
|
||||
qRX = reader.readUByte();
|
||||
initRY = reader.readUint16Big();
|
||||
qRY = reader.readUByte();
|
||||
initRZ = reader.readUint16Big();
|
||||
qRZ = reader.readUByte();
|
||||
keyCount2 = reader.readUint16Big();
|
||||
if (keyCount2)
|
||||
{
|
||||
initTX = reader.readUint16Big();
|
||||
qTX = reader.readUByte();
|
||||
initTY = reader.readUint16Big();
|
||||
qTY = reader.readUByte();
|
||||
initTZ = reader.readUint16Big();
|
||||
qTZ = reader.readUByte();
|
||||
}
|
||||
}
|
||||
void write(Athena::io::IStreamWriter& writer) const
|
||||
{
|
||||
writer.writeUint32Big(id);
|
||||
writer.writeUint16Big(keyCount1);
|
||||
writer.writeUint16Big(initRX);
|
||||
writer.writeUByte(qRX);
|
||||
writer.writeUint16Big(initRY);
|
||||
writer.writeUByte(qRY);
|
||||
writer.writeUint16Big(initRZ);
|
||||
writer.writeUByte(qRZ);
|
||||
writer.writeUint16Big(keyCount2);
|
||||
if (keyCount2)
|
||||
{
|
||||
writer.writeUint16Big(initTX);
|
||||
writer.writeUByte(qTX);
|
||||
writer.writeUint16Big(initTY);
|
||||
writer.writeUByte(qTY);
|
||||
writer.writeUint16Big(initTZ);
|
||||
writer.writeUByte(qTZ);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
std::unique_ptr<IANIM> m_anim;
|
||||
void read(Athena::io::IStreamReader& reader)
|
||||
{
|
||||
atUint32 version = reader.readUint32Big();
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
m_anim.reset(new struct ANIM0);
|
||||
m_anim->read(reader);
|
||||
break;
|
||||
case 2:
|
||||
m_anim.reset(new struct ANIM2);
|
||||
m_anim->read(reader);
|
||||
break;
|
||||
default:
|
||||
Log.report(LogVisor::Error, "unrecognized ANIM version");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void write(Athena::io::IStreamWriter& writer) const
|
||||
{
|
||||
writer.writeUint32Big(m_anim->m_version);
|
||||
m_anim->write(writer);
|
||||
}
|
||||
|
||||
void sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf) const
|
||||
{
|
||||
m_anim->sendANIMToBlender(os, cinf);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _DNAMP2_ANIM_HPP_
|
||||
@@ -1,10 +1,13 @@
|
||||
make_dnalist(liblist
|
||||
MLVL
|
||||
ANIM
|
||||
ANCS
|
||||
CMDLMaterials
|
||||
CINF
|
||||
CSKR)
|
||||
add_library(DNAMP2
|
||||
DNAMP2.hpp DNAMP2.cpp
|
||||
${liblist}
|
||||
ANIM.cpp
|
||||
CMDL.hpp
|
||||
STRG.hpp STRG.cpp)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "STRG.hpp"
|
||||
#include "MLVL.hpp"
|
||||
#include "CMDL.hpp"
|
||||
#include "ANCS.hpp"
|
||||
#include "../DNACommon/TXTR.hpp"
|
||||
|
||||
namespace Retro
|
||||
@@ -188,7 +189,9 @@ ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const DNAMP1::PAK::Entry& ent
|
||||
case SBIG('TXTR'):
|
||||
return {TXTR::Extract, nullptr, ".png"};
|
||||
case SBIG('CMDL'):
|
||||
return {nullptr, CMDL::Extract, ".blend", 1};
|
||||
return {nullptr, CMDL::Extract, ".blend", 2};
|
||||
case SBIG('ANCS'):
|
||||
return {nullptr, ANCS::Extract, nullptr, 1};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace DNAMP2
|
||||
|
||||
void STRG::_read(Athena::io::IStreamReader& reader)
|
||||
{
|
||||
atUint32 langCount = reader.readUint32();
|
||||
atUint32 strCount = reader.readUint32();
|
||||
atUint32 langCount = reader.readUint32Big();
|
||||
atUint32 strCount = reader.readUint32Big();
|
||||
|
||||
std::vector<FourCC> readLangs;
|
||||
readLangs.reserve(langCount);
|
||||
@@ -21,8 +21,8 @@ void STRG::_read(Athena::io::IStreamReader& reader)
|
||||
reader.seek(8);
|
||||
}
|
||||
|
||||
atUint32 nameCount = reader.readUint32();
|
||||
atUint32 nameTableSz = reader.readUint32();
|
||||
atUint32 nameCount = reader.readUint32Big();
|
||||
atUint32 nameTableSz = reader.readUint32Big();
|
||||
std::unique_ptr<uint8_t[]> nameTableBuf(new uint8_t[nameTableSz]);
|
||||
reader.readUBytesToBuf(nameTableBuf.get(), nameTableSz);
|
||||
struct NameIdxEntry
|
||||
@@ -43,7 +43,7 @@ void STRG::_read(Athena::io::IStreamReader& reader)
|
||||
std::vector<std::wstring> strs;
|
||||
reader.seek(strCount * 4);
|
||||
for (atUint32 s=0 ; s<strCount ; ++s)
|
||||
strs.emplace_back(reader.readWString());
|
||||
strs.emplace_back(reader.readWStringBig());
|
||||
langs.emplace_back(lang, strs);
|
||||
}
|
||||
|
||||
@@ -55,12 +55,11 @@ void STRG::_read(Athena::io::IStreamReader& reader)
|
||||
|
||||
void STRG::read(Athena::io::IStreamReader& reader)
|
||||
{
|
||||
reader.setEndian(Athena::BigEndian);
|
||||
atUint32 magic = reader.readUint32();
|
||||
atUint32 magic = reader.readUint32Big();
|
||||
if (magic != 0x87654321)
|
||||
Log.report(LogVisor::Error, "invalid STRG magic");
|
||||
|
||||
atUint32 version = reader.readUint32();
|
||||
atUint32 version = reader.readUint32Big();
|
||||
if (version != 1)
|
||||
Log.report(LogVisor::Error, "invalid STRG version");
|
||||
|
||||
@@ -69,18 +68,17 @@ void STRG::read(Athena::io::IStreamReader& reader)
|
||||
|
||||
void STRG::write(Athena::io::IStreamWriter& writer) const
|
||||
{
|
||||
writer.setEndian(Athena::BigEndian);
|
||||
writer.writeUint32(0x87654321);
|
||||
writer.writeUint32(1);
|
||||
writer.writeUint32(langs.size());
|
||||
writer.writeUint32Big(0x87654321);
|
||||
writer.writeUint32Big(1);
|
||||
writer.writeUint32Big(langs.size());
|
||||
atUint32 strCount = STRG::count();
|
||||
writer.writeUint32(strCount);
|
||||
writer.writeUint32Big(strCount);
|
||||
|
||||
atUint32 offset = 0;
|
||||
for (const std::pair<FourCC, std::vector<std::wstring>>& lang : langs)
|
||||
{
|
||||
lang.first.write(writer);
|
||||
writer.writeUint32(offset);
|
||||
writer.writeUint32Big(offset);
|
||||
offset += strCount * 4 + 4;
|
||||
atUint32 langStrCount = lang.second.size();
|
||||
atUint32 tableSz = strCount * 4;
|
||||
@@ -98,19 +96,19 @@ void STRG::write(Athena::io::IStreamWriter& writer) const
|
||||
tableSz += 1;
|
||||
}
|
||||
}
|
||||
writer.writeUint32(tableSz);
|
||||
writer.writeUint32Big(tableSz);
|
||||
}
|
||||
|
||||
atUint32 nameTableSz = names.size() * 8;
|
||||
for (const std::pair<std::string, int32_t>& name : names)
|
||||
nameTableSz += name.first.size() + 1;
|
||||
writer.writeUint32(names.size());
|
||||
writer.writeUint32(nameTableSz);
|
||||
writer.writeUint32Big(names.size());
|
||||
writer.writeUint32Big(nameTableSz);
|
||||
offset = names.size() * 8;
|
||||
for (const std::pair<std::string, int32_t>& name : names)
|
||||
{
|
||||
writer.writeUint32(offset);
|
||||
writer.writeInt32(name.second);
|
||||
writer.writeUint32Big(offset);
|
||||
writer.writeInt32Big(name.second);
|
||||
offset += name.first.size() + 1;
|
||||
}
|
||||
for (const std::pair<std::string, int32_t>& name : names)
|
||||
@@ -122,7 +120,7 @@ void STRG::write(Athena::io::IStreamWriter& writer) const
|
||||
atUint32 langStrCount = lang.second.size();
|
||||
for (atUint32 s=0 ; s<strCount ; ++s)
|
||||
{
|
||||
writer.writeUint32(offset);
|
||||
writer.writeUint32Big(offset);
|
||||
if (s < langStrCount)
|
||||
offset += lang.second[s].size() * 2 + 1;
|
||||
else
|
||||
@@ -132,7 +130,7 @@ void STRG::write(Athena::io::IStreamWriter& writer) const
|
||||
for (atUint32 s=0 ; s<strCount ; ++s)
|
||||
{
|
||||
if (s < langStrCount)
|
||||
writer.writeWString(lang.second[s]);
|
||||
writer.writeWStringBig(lang.second[s]);
|
||||
else
|
||||
writer.writeUByte(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user