2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-06-21 07:53:28 +00:00

New code style refactor

This commit is contained in:
Jack Andersen 2018-12-07 19:30:43 -10:00
parent 41ae32be31
commit 636c82a568
1451 changed files with 171430 additions and 203303 deletions

View File

@ -1,5 +1,5 @@
---
IndentWidth: 4
BasedOnStyle: LLVM
ColumnLimit: 120
UseTab: Never
---
@ -8,7 +8,6 @@ DerivePointerAlignment: false
PointerAlignment: Left
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
BreakBeforeBraces: Allman
IndentCaseLabels: false
AllowShortBlocksOnASingleLine: true
AlignOperands: true
@ -24,6 +23,6 @@ NamespaceIndentation: None
BinPackArguments: true
BinPackParameters: true
SortIncludes: false
AccessModifierOffset: -4
AccessModifierOffset: -2
ConstructorInitializerIndentWidth: 0
ConstructorInitializerAllOnOneLineOrOnePerLine: true

1
.idea/vcs.xml generated
View File

@ -10,7 +10,6 @@
<mapping directory="$PROJECT_DIR$/discord-rpc" vcs="Git" />
<mapping directory="$PROJECT_DIR$/hecl" vcs="Git" />
<mapping directory="$PROJECT_DIR$/hecl-gui" vcs="Git" />
<mapping directory="$PROJECT_DIR$/hecl-gui/quazip" vcs="Git" />
<mapping directory="$PROJECT_DIR$/hecl/extern/athena" vcs="Git" />
<mapping directory="$PROJECT_DIR$/hecl/extern/boo" vcs="Git" />
<mapping directory="$PROJECT_DIR$/hecl/extern/boo/glslang" vcs="Git" />

View File

@ -6,79 +6,70 @@ extern "C" const size_t ASSET_NAME_MP32_SZ;
extern "C" const uint8_t ASSET_NAME_MP64[];
extern "C" const size_t ASSET_NAME_MP64_SZ;
namespace DataSpec::AssetNameMap
{
namespace DataSpec::AssetNameMap {
logvisor::Module Log("AssetNameMap");
struct SAsset
{
std::string name;
std::string directory;
hecl::FourCC type;
SAsset() = default;
SAsset(const hecl::FourCC& typeIn, athena::io::IStreamReader& in)
: type(typeIn)
{
uint32_t nameLen = in.readUint32Big();
name = in.readString(nameLen);
uint32_t dirLen = in.readUint32Big();
directory = in.readString(dirLen);
}
struct SAsset {
std::string name;
std::string directory;
hecl::FourCC type;
SAsset() = default;
SAsset(const hecl::FourCC& typeIn, athena::io::IStreamReader& in) : type(typeIn) {
uint32_t nameLen = in.readUint32Big();
name = in.readString(nameLen);
uint32_t dirLen = in.readUint32Big();
directory = in.readString(dirLen);
}
};
static std::unordered_map<uint64_t, SAsset> g_AssetNameMap;
static bool g_AssetNameMapInit = false;
void LoadAssetMap(athena::io::MemoryReader& ar)
{
if (!ar.hasError())
{
hecl::FourCC magic;
if (ar.length() >= 4)
ar.readBytesToBuf(&magic, 4);
if (magic != FOURCC('AIDM'))
Log.report(logvisor::Warning, _SYS_STR("Unable to load asset map; Assets will not have proper filenames for most files."));
else
{
uint32_t assetCount = ar.readUint32Big();
g_AssetNameMap.reserve(assetCount);
for (uint32_t i = 0 ; i<assetCount ; ++i)
{
hecl::FourCC type;
ar.readBytesToBuf(&type, 4);
uint64_t id = ar.readUint64Big();
g_AssetNameMap[id] = SAsset(type, ar);
}
}
void LoadAssetMap(athena::io::MemoryReader& ar) {
if (!ar.hasError()) {
hecl::FourCC magic;
if (ar.length() >= 4)
ar.readBytesToBuf(&magic, 4);
if (magic != FOURCC('AIDM'))
Log.report(logvisor::Warning,
_SYS_STR("Unable to load asset map; Assets will not have proper filenames for most files."));
else {
uint32_t assetCount = ar.readUint32Big();
g_AssetNameMap.reserve(assetCount);
for (uint32_t i = 0; i < assetCount; ++i) {
hecl::FourCC type;
ar.readBytesToBuf(&type, 4);
uint64_t id = ar.readUint64Big();
g_AssetNameMap[id] = SAsset(type, ar);
}
}
}
}
void InitAssetNameMap()
{
if (g_AssetNameMapInit)
return;
void InitAssetNameMap() {
if (g_AssetNameMapInit)
return;
Log.report(logvisor::Info, "Initializing asset name database...");
Log.report(logvisor::Info, "Initializing asset name database...");
/* First load the 32bit map for MP1/2 */
{
athena::io::MemoryReader ar(ASSET_NAME_MP32, ASSET_NAME_MP32_SZ);
LoadAssetMap(ar);
}
/* Now load the 64bit map for MP3 */
{
athena::io::MemoryReader ar(ASSET_NAME_MP64, ASSET_NAME_MP64_SZ);
LoadAssetMap(ar);
}
g_AssetNameMapInit = true;
/* First load the 32bit map for MP1/2 */
{
athena::io::MemoryReader ar(ASSET_NAME_MP32, ASSET_NAME_MP32_SZ);
LoadAssetMap(ar);
}
/* Now load the 64bit map for MP3 */
{
athena::io::MemoryReader ar(ASSET_NAME_MP64, ASSET_NAME_MP64_SZ);
LoadAssetMap(ar);
}
g_AssetNameMapInit = true;
}
const std::string* TranslateIdToName(const UniqueID32& id)
{
if (g_AssetNameMap.find(id.toUint64()) == g_AssetNameMap.end())
return nullptr;
const std::string* TranslateIdToName(const UniqueID32& id) {
if (g_AssetNameMap.find(id.toUint64()) == g_AssetNameMap.end())
return nullptr;
return &g_AssetNameMap[id.toUint64()].name;
return &g_AssetNameMap[id.toUint64()].name;
}
}
} // namespace DataSpec::AssetNameMap

View File

@ -4,9 +4,8 @@
#include <string>
#include "DNACommon/DNACommon.hpp"
namespace DataSpec::AssetNameMap
{
namespace DataSpec::AssetNameMap {
void InitAssetNameMap();
const std::string* TranslateIdToName(const UniqueID32&);
const std::string* TranslateIdToName(const UniqueID64&);
}
} // namespace DataSpec::AssetNameMap

View File

@ -5,20 +5,18 @@
extern "C" uint8_t RETRO_MASTER_SHADER[];
extern "C" size_t RETRO_MASTER_SHADER_SZ;
namespace DataSpec::Blender
{
namespace DataSpec::Blender {
bool BuildMasterShader(const hecl::ProjectPath& path)
{
hecl::blender::Connection& conn = hecl::blender::Connection::SharedConnection();
if (!conn.createBlend(path, hecl::blender::BlendType::None))
return false;
{
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os << RETRO_MASTER_SHADER;
os << "make_master_shader_library()\n";
}
return conn.saveBlend();
bool BuildMasterShader(const hecl::ProjectPath& path) {
hecl::blender::Connection& conn = hecl::blender::Connection::SharedConnection();
if (!conn.createBlend(path, hecl::blender::BlendType::None))
return false;
{
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os << RETRO_MASTER_SHADER;
os << "make_master_shader_library()\n";
}
return conn.saveBlend();
}
}
} // namespace DataSpec::Blender

View File

@ -2,10 +2,8 @@
#include <hecl/hecl.hpp>
namespace DataSpec::Blender
{
namespace DataSpec::Blender {
bool BuildMasterShader(const hecl::ProjectPath& path);
}

View File

@ -7,302 +7,259 @@
#include "DataSpec/DNAMP3/CHAR.hpp"
#include "hecl/Blender/Connection.hpp"
namespace DataSpec::DNAANCS
{
namespace DataSpec::DNAANCS {
template <class PAKRouter, class ANCSDNA, class MaterialSet, class SurfaceHeader, atUint32 CMDLVersion>
bool ReadANCSToBlender(hecl::blender::Connection& conn,
const ANCSDNA& ancs,
const hecl::ProjectPath& outPath,
PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
const SpecBase& dataspec,
std::function<void(const hecl::SystemChar*)> fileChanged,
bool force)
{
/* Extract character CMDL/CSKR first */
std::vector<CharacterResInfo<typename PAKRouter::IDType>> chResInfo;
ancs.getCharacterResInfo(chResInfo);
for (const auto& info : chResInfo)
{
const nod::Node* node;
const typename PAKRouter::EntryType* cmdlE =
pakRouter.lookupEntry(info.cmdl, &node, true, false);
if (cmdlE)
{
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
if (force || cmdlPath.isNone())
{
cmdlPath.makeDirChain(false);
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh))
return false;
bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const SpecBase& dataspec,
std::function<void(const hecl::SystemChar*)> fileChanged, bool force) {
/* Extract character CMDL/CSKR first */
std::vector<CharacterResInfo<typename PAKRouter::IDType>> chResInfo;
ancs.getCharacterResInfo(chResInfo);
for (const auto& info : chResInfo) {
const nod::Node* node;
const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(info.cmdl, &node, true, false);
if (cmdlE) {
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
if (force || cmdlPath.isNone()) {
cmdlPath.makeDirChain(false);
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh))
return false;
std::string bestName = pakRouter.getBestEntryName(*cmdlE);
hecl::SystemStringConv bestNameView(bestName);
fileChanged(bestNameView.c_str());
std::string bestName = pakRouter.getBestEntryName(*cmdlE);
hecl::SystemStringConv bestNameView(bestName);
fileChanged(bestNameView.c_str());
typename ANCSDNA::CSKRType cskr;
pakRouter.lookupAndReadDNA(info.cskr, cskr);
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(info.cinf, cinf);
using RigPair = std::pair<typename ANCSDNA::CSKRType*, typename ANCSDNA::CINFType*>;
RigPair rigPair(&cskr, &cinf);
typename ANCSDNA::CSKRType cskr;
pakRouter.lookupAndReadDNA(info.cskr, cskr);
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(info.cinf, cinf);
using RigPair = std::pair<typename ANCSDNA::CSKRType*, typename ANCSDNA::CINFType*>;
RigPair rigPair(&cskr, &cinf);
PAKEntryReadStream rs = cmdlE->beginReadStream(*node);
DNACMDL::ReadCMDLToBlender<PAKRouter, MaterialSet, RigPair, SurfaceHeader, CMDLVersion>
(conn, rs, pakRouter, *cmdlE, dataspec, rigPair);
PAKEntryReadStream rs = cmdlE->beginReadStream(*node);
DNACMDL::ReadCMDLToBlender<PAKRouter, MaterialSet, RigPair, SurfaceHeader, CMDLVersion>(
conn, rs, pakRouter, *cmdlE, dataspec, rigPair);
conn.saveBlend();
}
conn.saveBlend();
}
}
}
/* Extract attachment CMDL/CSKRs first */
auto attRange = pakRouter.lookupCharacterAttachmentRigs(entry.id);
for (auto it = attRange.first; it != attRange.second; ++it) {
auto cmdlid = it->second.first.second;
const nod::Node* node;
const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(cmdlid, &node, true, false);
if (cmdlE) {
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
if (force || cmdlPath.isNone()) {
cmdlPath.makeDirChain(false);
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh))
return false;
std::string bestName = pakRouter.getBestEntryName(*cmdlE);
hecl::SystemStringConv bestNameView(bestName);
fileChanged(bestNameView.c_str());
const auto* rp = pakRouter.lookupCMDLRigPair(cmdlid);
typename ANCSDNA::CSKRType cskr;
pakRouter.lookupAndReadDNA(rp->first, cskr);
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(rp->second, cinf);
using RigPair = std::pair<typename ANCSDNA::CSKRType*, typename ANCSDNA::CINFType*>;
RigPair rigPair(&cskr, &cinf);
PAKEntryReadStream rs = cmdlE->beginReadStream(*node);
DNACMDL::ReadCMDLToBlender<PAKRouter, MaterialSet, RigPair, SurfaceHeader, CMDLVersion>(
conn, rs, pakRouter, *cmdlE, dataspec, rigPair);
conn.saveBlend();
}
}
}
std::string bestName = pakRouter.getBestEntryName(entry);
hecl::SystemStringConv bestNameView(bestName);
fileChanged(bestNameView.c_str());
/* Establish ANCS blend */
if (!conn.createBlend(outPath, hecl::blender::BlendType::Actor))
return false;
std::string firstName;
typename ANCSDNA::CINFType firstCinf;
{
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os.format(
"import bpy\n"
"from mathutils import Vector\n"
"bpy.context.scene.name = '%s'\n"
"bpy.context.scene.hecl_mesh_obj = bpy.context.scene.name\n"
"\n"
"# Using 'Blender Game'\n"
"bpy.context.scene.render.engine = 'BLENDER_GAME'\n"
"\n"
"# Clear Scene\n"
"for ob in bpy.data.objects:\n"
" if ob.type != 'LAMP' and ob.type != 'CAMERA':\n"
" bpy.context.scene.objects.unlink(ob)\n"
" bpy.data.objects.remove(ob)\n"
"\n"
"actor_data = bpy.context.scene.hecl_sact_data\n"
"arm_obj = None\n",
pakRouter.getBestEntryName(entry).c_str());
std::unordered_set<typename PAKRouter::IDType> cinfsDone;
for (const auto& info : chResInfo) {
/* Provide data to add-on */
os.format(
"actor_subtype = actor_data.subtypes.add()\n"
"actor_subtype.name = '%s'\n\n",
info.name.c_str());
/* Build CINF if needed */
if (cinfsDone.find(info.cinf) == cinfsDone.end()) {
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(info.cinf, cinf);
cinf.sendCINFToBlender(os, info.cinf);
if (cinfsDone.empty()) {
firstName = ANCSDNA::CINFType::GetCINFArmatureName(info.cinf);
firstCinf = cinf;
}
cinfsDone.insert(info.cinf);
} else
os.format("arm_obj = bpy.data.objects['CINF_%s']\n", info.cinf.toString().c_str());
os << "actor_subtype.linked_armature = arm_obj.name\n";
/* Link CMDL */
const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(info.cmdl, nullptr, true, false);
if (cmdlE) {
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
os.linkBlend(cmdlPath.getAbsolutePathUTF8().data(), pakRouter.getBestEntryName(*cmdlE).data(), true);
/* Attach CMDL to CINF */
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.objects.link(obj)\n"
"obj.parent = arm_obj\n"
"obj.parent_type = 'ARMATURE'\n"
"actor_subtype.linked_mesh = obj.name\n\n";
}
/* Link overlays */
for (const auto& overlay : info.overlays) {
os << "overlay = actor_subtype.overlays.add()\n";
os.format("overlay.name = '%s'\n", overlay.first.c_str());
/* Link CMDL */
const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(overlay.second.first, nullptr, true, false);
if (cmdlE) {
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
os.linkBlend(cmdlPath.getAbsolutePathUTF8().data(), pakRouter.getBestEntryName(*cmdlE).data(), true);
/* Attach CMDL to CINF */
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.objects.link(obj)\n"
"obj.parent = arm_obj\n"
"obj.parent_type = 'ARMATURE'\n"
"overlay.linked_mesh = obj.name\n\n";
}
}
}
/* Extract attachment CMDL/CSKRs first */
auto attRange = pakRouter.lookupCharacterAttachmentRigs(entry.id);
for (auto it = attRange.first; it != attRange.second; ++it)
{
auto cmdlid = it->second.first.second;
/* Link attachments */
for (auto it = attRange.first; it != attRange.second; ++it) {
os << "attachment = actor_data.attachments.add()\n";
os.format("attachment.name = '%s'\n", it->second.second.c_str());
const nod::Node* node;
const typename PAKRouter::EntryType* cmdlE =
pakRouter.lookupEntry(cmdlid, &node, true, false);
if (cmdlE)
{
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
if (force || cmdlPath.isNone())
{
cmdlPath.makeDirChain(false);
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh))
return false;
auto cinfid = it->second.first.first;
auto cmdlid = it->second.first.second;
std::string bestName = pakRouter.getBestEntryName(*cmdlE);
hecl::SystemStringConv bestNameView(bestName);
fileChanged(bestNameView.c_str());
if (cinfid) {
/* Build CINF if needed */
if (cinfsDone.find(cinfid) == cinfsDone.end()) {
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(cinfid, cinf);
cinf.sendCINFToBlender(os, cinfid);
if (cinfsDone.empty()) {
firstName = ANCSDNA::CINFType::GetCINFArmatureName(cinfid);
firstCinf = cinf;
}
cinfsDone.insert(cinfid);
} else
os.format("arm_obj = bpy.data.objects['CINF_%s']\n", cinfid.toString().c_str());
os << "attachment.linked_armature = arm_obj.name\n";
}
const auto* rp = pakRouter.lookupCMDLRigPair(cmdlid);
typename ANCSDNA::CSKRType cskr;
pakRouter.lookupAndReadDNA(rp->first, cskr);
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(rp->second, cinf);
using RigPair = std::pair<typename ANCSDNA::CSKRType*, typename ANCSDNA::CINFType*>;
RigPair rigPair(&cskr, &cinf);
/* Link CMDL */
const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(cmdlid, nullptr, true, false);
if (cmdlE) {
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
os.linkBlend(cmdlPath.getAbsolutePathUTF8().data(), pakRouter.getBestEntryName(*cmdlE).data(), true);
PAKEntryReadStream rs = cmdlE->beginReadStream(*node);
DNACMDL::ReadCMDLToBlender<PAKRouter, MaterialSet, RigPair, SurfaceHeader, CMDLVersion>
(conn, rs, pakRouter, *cmdlE, dataspec, rigPair);
conn.saveBlend();
}
}
/* Attach CMDL to CINF */
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.objects.link(obj)\n"
"obj.parent = arm_obj\n"
"obj.parent_type = 'ARMATURE'\n"
"attachment.linked_mesh = obj.name\n\n";
}
}
}
std::string bestName = pakRouter.getBestEntryName(entry);
hecl::SystemStringConv bestNameView(bestName);
fileChanged(bestNameView.c_str());
{
hecl::blender::DataStream ds = conn.beginData();
std::unordered_map<std::string, hecl::blender::Matrix3f> matrices = ds.getBoneMatrices(firstName);
ds.close();
DNAANIM::RigInverter<typename ANCSDNA::CINFType> inverter(firstCinf, matrices);
/* Establish ANCS blend */
if (!conn.createBlend(outPath, hecl::blender::BlendType::Actor))
return false;
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os << "import bpy\n"
"actor_data = bpy.context.scene.hecl_sact_data\n";
std::string firstName;
typename ANCSDNA::CINFType firstCinf;
{
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
/* Get animation primitives */
std::map<atUint32, AnimationResInfo<typename PAKRouter::IDType>> animResInfo;
ancs.getAnimationResInfo(&pakRouter, animResInfo);
for (const auto& id : animResInfo) {
typename ANCSDNA::ANIMType anim;
if (pakRouter.lookupAndReadDNA(id.second.animId, anim, true)) {
os.format(
"act = bpy.data.actions.new('%s')\n"
"act.use_fake_user = True\n",
id.second.name.c_str());
anim.sendANIMToBlender(os, inverter, id.second.additive);
}
os.format("import bpy\n"
"from mathutils import Vector\n"
"bpy.context.scene.name = '%s'\n"
"bpy.context.scene.hecl_mesh_obj = bpy.context.scene.name\n"
"\n"
"# Using 'Blender Game'\n"
"bpy.context.scene.render.engine = 'BLENDER_GAME'\n"
"\n"
"# Clear Scene\n"
"for ob in bpy.data.objects:\n"
" if ob.type != 'LAMP' and ob.type != 'CAMERA':\n"
" bpy.context.scene.objects.unlink(ob)\n"
" bpy.data.objects.remove(ob)\n"
"\n"
"actor_data = bpy.context.scene.hecl_sact_data\n"
"arm_obj = None\n",
pakRouter.getBestEntryName(entry).c_str());
os.format(
"actor_action = actor_data.actions.add()\n"
"actor_action.name = '%s'\n",
id.second.name.c_str());
std::unordered_set<typename PAKRouter::IDType> cinfsDone;
for (const auto& info : chResInfo)
{
/* Provide data to add-on */
os.format("actor_subtype = actor_data.subtypes.add()\n"
"actor_subtype.name = '%s'\n\n",
info.name.c_str());
/* Build CINF if needed */
if (cinfsDone.find(info.cinf) == cinfsDone.end())
{
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(info.cinf, cinf);
cinf.sendCINFToBlender(os, info.cinf);
if (cinfsDone.empty())
{
firstName = ANCSDNA::CINFType::GetCINFArmatureName(info.cinf);
firstCinf = cinf;
}
cinfsDone.insert(info.cinf);
}
else
os.format("arm_obj = bpy.data.objects['CINF_%s']\n", info.cinf.toString().c_str());
os << "actor_subtype.linked_armature = arm_obj.name\n";
/* Link CMDL */
const typename PAKRouter::EntryType* cmdlE =
pakRouter.lookupEntry(info.cmdl, nullptr, true, false);
if (cmdlE)
{
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
os.linkBlend(cmdlPath.getAbsolutePathUTF8().data(),
pakRouter.getBestEntryName(*cmdlE).data(), true);
/* Attach CMDL to CINF */
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.objects.link(obj)\n"
"obj.parent = arm_obj\n"
"obj.parent_type = 'ARMATURE'\n"
"actor_subtype.linked_mesh = obj.name\n\n";
}
/* Link overlays */
for (const auto& overlay : info.overlays)
{
os << "overlay = actor_subtype.overlays.add()\n";
os.format("overlay.name = '%s'\n", overlay.first.c_str());
/* Link CMDL */
const typename PAKRouter::EntryType* cmdlE =
pakRouter.lookupEntry(overlay.second.first, nullptr, true, false);
if (cmdlE)
{
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
os.linkBlend(cmdlPath.getAbsolutePathUTF8().data(),
pakRouter.getBestEntryName(*cmdlE).data(), true);
/* Attach CMDL to CINF */
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.objects.link(obj)\n"
"obj.parent = arm_obj\n"
"obj.parent_type = 'ARMATURE'\n"
"overlay.linked_mesh = obj.name\n\n";
}
}
}
/* Link attachments */
for (auto it = attRange.first; it != attRange.second; ++it)
{
os << "attachment = actor_data.attachments.add()\n";
os.format("attachment.name = '%s'\n", it->second.second.c_str());
auto cinfid = it->second.first.first;
auto cmdlid = it->second.first.second;
if (cinfid)
{
/* Build CINF if needed */
if (cinfsDone.find(cinfid) == cinfsDone.end())
{
typename ANCSDNA::CINFType cinf;
pakRouter.lookupAndReadDNA(cinfid, cinf);
cinf.sendCINFToBlender(os, cinfid);
if (cinfsDone.empty())
{
firstName = ANCSDNA::CINFType::GetCINFArmatureName(cinfid);
firstCinf = cinf;
}
cinfsDone.insert(cinfid);
}
else
os.format("arm_obj = bpy.data.objects['CINF_%s']\n", cinfid.toString().c_str());
os << "attachment.linked_armature = arm_obj.name\n";
}
/* Link CMDL */
const typename PAKRouter::EntryType* cmdlE =
pakRouter.lookupEntry(cmdlid, nullptr, true, false);
if (cmdlE)
{
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
os.linkBlend(cmdlPath.getAbsolutePathUTF8().data(),
pakRouter.getBestEntryName(*cmdlE).data(), true);
/* Attach CMDL to CINF */
os << "if obj.name not in bpy.context.scene.objects:\n"
" bpy.context.scene.objects.link(obj)\n"
"obj.parent = arm_obj\n"
"obj.parent_type = 'ARMATURE'\n"
"attachment.linked_mesh = obj.name\n\n";
}
}
/* Extract EVNT if present */
anim.extractEVNT(id.second, outPath, pakRouter, force);
}
{
hecl::blender::DataStream ds = conn.beginData();
std::unordered_map<std::string,
hecl::blender::Matrix3f> matrices = ds.getBoneMatrices(firstName);
ds.close();
DNAANIM::RigInverter<typename ANCSDNA::CINFType> inverter(firstCinf, matrices);
hecl::blender::PyOutStream os = conn.beginPythonOut(true);
os << "import bpy\n"
"actor_data = bpy.context.scene.hecl_sact_data\n";
/* Get animation primitives */
std::map<atUint32, AnimationResInfo<typename PAKRouter::IDType>> animResInfo;
ancs.getAnimationResInfo(&pakRouter, animResInfo);
for (const auto& id : animResInfo)
{
typename ANCSDNA::ANIMType anim;
if (pakRouter.lookupAndReadDNA(id.second.animId, anim, true))
{
os.format("act = bpy.data.actions.new('%s')\n"
"act.use_fake_user = True\n", id.second.name.c_str());
anim.sendANIMToBlender(os, inverter, id.second.additive);
}
os.format("actor_action = actor_data.actions.add()\n"
"actor_action.name = '%s'\n", id.second.name.c_str());
/* Extract EVNT if present */
anim.extractEVNT(id.second, outPath, pakRouter, force);
}
}
conn.saveBlend();
return true;
}
conn.saveBlend();
return true;
}
template bool ReadANCSToBlender<PAKRouter<DNAMP1::PAKBridge>, DNAMP1::ANCS, DNAMP1::MaterialSet, DNACMDL::SurfaceHeader_1, 2>
(hecl::blender::Connection& conn,
const DNAMP1::ANCS& ancs,
const hecl::ProjectPath& outPath,
PAKRouter<DNAMP1::PAKBridge>& pakRouter,
const typename PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
const SpecBase& dataspec,
std::function<void(const hecl::SystemChar*)> fileChanged,
bool force);
template bool ReadANCSToBlender<PAKRouter<DNAMP2::PAKBridge>, DNAMP2::ANCS, DNAMP2::MaterialSet, DNACMDL::SurfaceHeader_2, 4>
(hecl::blender::Connection& conn,
const DNAMP2::ANCS& ancs,
const hecl::ProjectPath& outPath,
PAKRouter<DNAMP2::PAKBridge>& pakRouter,
const typename PAKRouter<DNAMP2::PAKBridge>::EntryType& entry,
const SpecBase& dataspec,
std::function<void(const hecl::SystemChar*)> fileChanged,
bool force);
template bool ReadANCSToBlender<PAKRouter<DNAMP3::PAKBridge>, DNAMP3::CHAR, DNAMP3::MaterialSet, DNACMDL::SurfaceHeader_3, 4>
(hecl::blender::Connection& conn,
const DNAMP3::CHAR& ancs,
const hecl::ProjectPath& outPath,
PAKRouter<DNAMP3::PAKBridge>& pakRouter,
const typename PAKRouter<DNAMP3::PAKBridge>::EntryType& entry,
const SpecBase& dataspec,
std::function<void(const hecl::SystemChar*)> fileChanged,
bool force);
template bool
ReadANCSToBlender<PAKRouter<DNAMP1::PAKBridge>, DNAMP1::ANCS, DNAMP1::MaterialSet, DNACMDL::SurfaceHeader_1, 2>(
hecl::blender::Connection& conn, const DNAMP1::ANCS& ancs, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP1::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force);
template bool
ReadANCSToBlender<PAKRouter<DNAMP2::PAKBridge>, DNAMP2::ANCS, DNAMP2::MaterialSet, DNACMDL::SurfaceHeader_2, 4>(
hecl::blender::Connection& conn, const DNAMP2::ANCS& ancs, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP2::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP2::PAKBridge>::EntryType& entry,
const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force);
template bool
ReadANCSToBlender<PAKRouter<DNAMP3::PAKBridge>, DNAMP3::CHAR, DNAMP3::MaterialSet, DNACMDL::SurfaceHeader_3, 4>(
hecl::blender::Connection& conn, const DNAMP3::CHAR& ancs, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP3::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP3::PAKBridge>::EntryType& entry,
const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force);
}
} // namespace DataSpec::DNAANCS

View File

@ -5,41 +5,32 @@
#include "CMDL.hpp"
#include "RigInverter.hpp"
namespace DataSpec::DNAANCS
{
namespace DataSpec::DNAANCS {
using Actor = hecl::blender::Actor;
using Armature = hecl::blender::Armature;
using Action = hecl::blender::Action;
template <typename IDTYPE>
struct CharacterResInfo
{
std::string name;
IDTYPE cmdl;
IDTYPE cskr;
IDTYPE cinf;
std::vector<std::pair<std::string, std::pair<IDTYPE, IDTYPE>>> overlays;
struct CharacterResInfo {
std::string name;
IDTYPE cmdl;
IDTYPE cskr;
IDTYPE cinf;
std::vector<std::pair<std::string, std::pair<IDTYPE, IDTYPE>>> overlays;
};
template <typename IDTYPE>
struct AnimationResInfo
{
std::string name;
IDTYPE animId;
IDTYPE evntId;
bool additive;
struct AnimationResInfo {
std::string name;
IDTYPE animId;
IDTYPE evntId;
bool additive;
};
template <class PAKRouter, class ANCSDNA, class MaterialSet, class SurfaceHeader, atUint32 CMDLVersion>
bool ReadANCSToBlender(hecl::blender::Connection& conn,
const ANCSDNA& ancs,
const hecl::ProjectPath& outPath,
PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
const SpecBase& dataspec,
std::function<void(const hecl::SystemChar*)> fileChanged,
bool force=false);
}
bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const SpecBase& dataspec,
std::function<void(const hecl::SystemChar*)> fileChanged, bool force = false);
} // namespace DataSpec::DNAANCS

View File

@ -3,529 +3,439 @@
#define DUMP_KEYS 0
namespace DataSpec::DNAANIM
{
namespace DataSpec::DNAANIM {
size_t ComputeBitstreamSize(size_t keyFrameCount, const std::vector<Channel>& channels)
{
size_t bitsPerKeyFrame = 0;
for (const Channel& chan : channels)
{
switch (chan.type)
{
case Channel::Type::Rotation:
bitsPerKeyFrame += 1;
case Channel::Type::Translation:
case Channel::Type::Scale:
bitsPerKeyFrame += chan.q[0];
bitsPerKeyFrame += chan.q[1];
bitsPerKeyFrame += chan.q[2];
break;
case Channel::Type::KfHead:
bitsPerKeyFrame += 1;
break;
case Channel::Type::RotationMP3:
bitsPerKeyFrame += chan.q[0];
bitsPerKeyFrame += chan.q[1];
bitsPerKeyFrame += chan.q[2];
bitsPerKeyFrame += chan.q[3];
break;
default: break;
}
size_t ComputeBitstreamSize(size_t keyFrameCount, const std::vector<Channel>& channels) {
size_t bitsPerKeyFrame = 0;
for (const Channel& chan : channels) {
switch (chan.type) {
case Channel::Type::Rotation:
bitsPerKeyFrame += 1;
case Channel::Type::Translation:
case Channel::Type::Scale:
bitsPerKeyFrame += chan.q[0];
bitsPerKeyFrame += chan.q[1];
bitsPerKeyFrame += chan.q[2];
break;
case Channel::Type::KfHead:
bitsPerKeyFrame += 1;
break;
case Channel::Type::RotationMP3:
bitsPerKeyFrame += chan.q[0];
bitsPerKeyFrame += chan.q[1];
bitsPerKeyFrame += chan.q[2];
bitsPerKeyFrame += chan.q[3];
break;
default:
break;
}
return (bitsPerKeyFrame * keyFrameCount + 31) / 32 * 4;
}
return (bitsPerKeyFrame * keyFrameCount + 31) / 32 * 4;
}
static inline QuantizedRot QuantizeRotation(const Value& quat, atUint32 div)
{
float q = M_PIF / 2.0f / float(div);
zeus::simd_floats f(quat.simd);
return
{
{
atInt32(std::asin(f[1]) / q),
atInt32(std::asin(f[2]) / q),
atInt32(std::asin(f[3]) / q),
},
(f[0] < 0.f)
};
static inline QuantizedRot QuantizeRotation(const Value& quat, atUint32 div) {
float q = M_PIF / 2.0f / float(div);
zeus::simd_floats f(quat.simd);
return {{
atInt32(std::asin(f[1]) / q),
atInt32(std::asin(f[2]) / q),
atInt32(std::asin(f[3]) / q),
},
(f[0] < 0.f)};
}
static inline Value DequantizeRotation(const QuantizedRot& v, atUint32 div)
{
float q = M_PIF / 2.0f / float(div);
athena::simd_floats f = {
0.0f,
std::sin(v.v[0] * q),
std::sin(v.v[1] * q),
std::sin(v.v[2] * q),
};
f[0] = std::sqrt(std::max((1.0f -
(f[1] * f[1] +
f[2] * f[2] +
f[3] * f[3])), 0.0f));
f[0] = v.w ? -f[0] : f[0];
Value retval;
retval.simd.copy_from(f);
return retval;
static inline Value DequantizeRotation(const QuantizedRot& v, atUint32 div) {
float q = M_PIF / 2.0f / float(div);
athena::simd_floats f = {
0.0f,
std::sin(v.v[0] * q),
std::sin(v.v[1] * q),
std::sin(v.v[2] * q),
};
f[0] = std::sqrt(std::max((1.0f - (f[1] * f[1] + f[2] * f[2] + f[3] * f[3])), 0.0f));
f[0] = v.w ? -f[0] : f[0];
Value retval;
retval.simd.copy_from(f);
return retval;
}
static inline Value DequantizeRotation_3(const QuantizedRot& v, atUint32 div)
{
float q = 1.0f / float(div);
athena::simd_floats f = {
0.0f,
v.v[0] * q,
v.v[1] * q,
v.v[2] * q,
};
f[0] = std::sqrt(std::max((1.0f -
(f[1] * f[1] +
f[2] * f[2] +
f[3] * f[3])), 0.0f));
f[0] = v.w ? -f[0] : f[0];
Value retval;
retval.simd.copy_from(f);
return retval;
static inline Value DequantizeRotation_3(const QuantizedRot& v, atUint32 div) {
float q = 1.0f / float(div);
athena::simd_floats f = {
0.0f,
v.v[0] * q,
v.v[1] * q,
v.v[2] * q,
};
f[0] = std::sqrt(std::max((1.0f - (f[1] * f[1] + f[2] * f[2] + f[3] * f[3])), 0.0f));
f[0] = v.w ? -f[0] : f[0];
Value retval;
retval.simd.copy_from(f);
return retval;
}
bool BitstreamReader::dequantizeBit(const atUint8* data)
{
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
bool BitstreamReader::dequantizeBit(const atUint8* data) {
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
atUint32 tempBuf = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur)) >> bitRem;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
atUint32 tempBuf = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur)) >> bitRem;
/* That's it */
m_bitCur += 1;
return tempBuf & 0x1;
/* That's it */
m_bitCur += 1;
return tempBuf & 0x1;
}
atInt32 BitstreamReader::dequantize(const atUint8* data, atUint8 q)
{
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
atInt32 BitstreamReader::dequantize(const atUint8* data, atUint8 q) {
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
atUint32 tempBuf = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur)) >> bitRem;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
atUint32 tempBuf = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur)) >> bitRem;
/* If this shift underflows the value, buffer the next 32 bits */
/* And tack onto shifted buffer */
if ((bitRem + q) > 32)
{
atUint32 tempBuf2 = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur + 4));
tempBuf |= (tempBuf2 << (32 - bitRem));
/* If this shift underflows the value, buffer the next 32 bits */
/* And tack onto shifted buffer */
if ((bitRem + q) > 32) {
atUint32 tempBuf2 = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur + 4));
tempBuf |= (tempBuf2 << (32 - bitRem));
}
/* Mask it */
atUint32 mask = (1 << q) - 1;
tempBuf &= mask;
/* Sign extend */
atUint32 sign = (tempBuf >> (q - 1)) & 0x1;
if (sign)
tempBuf |= ~0u << q;
/* Return delta value */
m_bitCur += q;
return atInt32(tempBuf);
}
std::vector<std::vector<Value>> BitstreamReader::read(const atUint8* data, size_t keyFrameCount,
const std::vector<Channel>& channels, atUint32 rotDiv,
float transMult, float scaleMult) {
m_bitCur = 0;
std::vector<std::vector<Value>> chanKeys;
std::vector<QuantizedValue> chanAccum;
chanKeys.reserve(channels.size());
chanAccum.reserve(channels.size());
for (const Channel& chan : channels) {
chanAccum.push_back(chan.i);
chanKeys.emplace_back();
std::vector<Value>& keys = chanKeys.back();
keys.reserve(keyFrameCount);
switch (chan.type) {
case Channel::Type::Rotation: {
QuantizedRot qr = {{chan.i[0], chan.i[1], chan.i[2]}, false};
keys.emplace_back(DequantizeRotation(qr, rotDiv));
break;
}
/* Mask it */
atUint32 mask = (1 << q) - 1;
tempBuf &= mask;
/* Sign extend */
atUint32 sign = (tempBuf >> (q - 1)) & 0x1;
if (sign)
tempBuf |= ~0u << q;
/* Return delta value */
m_bitCur += q;
return atInt32(tempBuf);
}
std::vector<std::vector<Value>>
BitstreamReader::read(const atUint8* data,
size_t keyFrameCount,
const std::vector<Channel>& channels,
atUint32 rotDiv,
float transMult,
float scaleMult)
{
m_bitCur = 0;
std::vector<std::vector<Value>> chanKeys;
std::vector<QuantizedValue> chanAccum;
chanKeys.reserve(channels.size());
chanAccum.reserve(channels.size());
for (const Channel& chan : channels)
{
chanAccum.push_back(chan.i);
chanKeys.emplace_back();
std::vector<Value>& keys = chanKeys.back();
keys.reserve(keyFrameCount);
switch (chan.type)
{
case Channel::Type::Rotation:
{
QuantizedRot qr = {{chan.i[0], chan.i[1], chan.i[2]}, false};
keys.emplace_back(DequantizeRotation(qr, rotDiv));
break;
}
case Channel::Type::Translation:
{
keys.push_back({chan.i[0] * transMult, chan.i[1] * transMult, chan.i[2] * transMult});
break;
}
case Channel::Type::Scale:
{
keys.push_back({chan.i[0] * scaleMult, chan.i[1] * scaleMult, chan.i[2] * scaleMult});
break;
}
case Channel::Type::KfHead:
{
break;
}
case Channel::Type::RotationMP3:
{
QuantizedRot qr = {{chan.i[1], chan.i[2], chan.i[3]}, bool(chan.i[0] & 0x1)};
keys.emplace_back(DequantizeRotation_3(qr, rotDiv));
break;
}
default: break;
}
case Channel::Type::Translation: {
keys.push_back({chan.i[0] * transMult, chan.i[1] * transMult, chan.i[2] * transMult});
break;
}
for (size_t f=0 ; f<keyFrameCount ; ++f)
{
#if DUMP_KEYS
fprintf(stderr, "\nFRAME %" PRISize " %u %u\n", f, (m_bitCur / 32) * 4, m_bitCur % 32);
int lastId = -1;
#endif
auto kit = chanKeys.begin();
auto ait = chanAccum.begin();
for (const Channel& chan : channels)
{
#if DUMP_KEYS
if (chan.id != lastId)
{
lastId = chan.id;
fprintf(stderr, "\n");
}
#endif
QuantizedValue& p = *ait;
switch (chan.type)
{
case Channel::Type::Rotation:
{
bool wBit = dequantizeBit(data);
p[0] += dequantize(data, chan.q[0]);
p[1] += dequantize(data, chan.q[1]);
p[2] += dequantize(data, chan.q[2]);
QuantizedRot qr = {{p[0], p[1], p[2]}, wBit};
kit->emplace_back(DequantizeRotation(qr, rotDiv));
#if DUMP_KEYS
fprintf(stderr, "%d R: %d %d %d %d\t", chan.id, wBit, p[0], p[1], p[2]);
#endif
break;
}
case Channel::Type::Translation:
{
atInt32 val1 = dequantize(data, chan.q[0]);
p[0] += val1;
atInt32 val2 = dequantize(data, chan.q[1]);
p[1] += val2;
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
fprintf(stderr, "%d T: %d %d %d\t", chan.id, p[0], p[1], p[2]);
#endif
break;
}
case Channel::Type::Scale:
{
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] * 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
break;
}
case Channel::Type::KfHead:
{
dequantizeBit(data);
break;
}
case Channel::Type::RotationMP3:
{
atInt32 val1 = dequantize(data, chan.q[0]);
p[0] += val1;
atInt32 val2 = dequantize(data, chan.q[1]);
p[1] += val2;
atInt32 val3 = dequantize(data, chan.q[2]);
p[2] += val3;
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));
break;
}
default: break;
}
++kit;
++ait;
}
#if DUMP_KEYS
fprintf(stderr, "\n");
#endif
case Channel::Type::Scale: {
keys.push_back({chan.i[0] * scaleMult, chan.i[1] * scaleMult, chan.i[2] * scaleMult});
break;
}
return chanKeys;
}
void BitstreamWriter::quantizeBit(atUint8* data, bool val)
{
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
*(atUint32*)(data + byteCur) =
hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur)) | (val << bitRem));
m_bitCur += 1;
}
void BitstreamWriter::quantize(atUint8* data, atUint8 q, atInt32 val)
{
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
atUint32 masked = val & ((1 << q) - 1);
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
*(atUint32*)(data + byteCur) =
hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur)) | (masked << bitRem));
/* If this shift underflows the value, buffer the next 32 bits */
/* And tack onto shifted buffer */
if ((bitRem + q) > 32)
{
*(atUint32*)(data + byteCur + 4) =
hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur + 4)) | (masked >> (32 - bitRem)));
case Channel::Type::KfHead: {
break;
}
case Channel::Type::RotationMP3: {
QuantizedRot qr = {{chan.i[1], chan.i[2], chan.i[3]}, bool(chan.i[0] & 0x1)};
keys.emplace_back(DequantizeRotation_3(qr, rotDiv));
break;
}
default:
break;
}
}
m_bitCur += q;
}
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 = quantRange; /* Normalized range of values */
float quantRangeF = float(quantRange);
/* Pre-pass to calculate translation multiplier */
float maxTransVal = 0.0f;
float maxScaleVal = 0.0f;
for (size_t f = 0; f < keyFrameCount; ++f) {
#if DUMP_KEYS
fprintf(stderr, "\nFRAME %" PRISize " %u %u\n", f, (m_bitCur / 32) * 4, m_bitCur % 32);
int lastId = -1;
#endif
auto kit = chanKeys.begin();
for (Channel& chan : channels)
{
switch (chan.type)
{
case Channel::Type::Translation:
{
for (auto it=kit->begin();
it != kit->end();
++it)
{
const Value* key = &*it;
zeus::simd_floats f(key->simd);
maxTransVal = std::max(maxTransVal, std::fabs(f[0]));
maxTransVal = std::max(maxTransVal, std::fabs(f[1]));
maxTransVal = std::max(maxTransVal, std::fabs(f[2]));
}
break;
}
case Channel::Type::Scale:
{
for (auto it=kit->begin();
it != kit->end();
++it)
{
const Value* key = &*it;
zeus::simd_floats f(key->simd);
maxScaleVal = std::max(maxScaleVal, std::fabs(f[0]));
maxScaleVal = std::max(maxScaleVal, std::fabs(f[1]));
maxScaleVal = std::max(maxScaleVal, std::fabs(f[2]));
}
break;
}
default: break;
}
++kit;
auto ait = chanAccum.begin();
for (const Channel& chan : channels) {
#if DUMP_KEYS
if (chan.id != lastId) {
lastId = chan.id;
fprintf(stderr, "\n");
}
#endif
QuantizedValue& p = *ait;
switch (chan.type) {
case Channel::Type::Rotation: {
bool wBit = dequantizeBit(data);
p[0] += dequantize(data, chan.q[0]);
p[1] += dequantize(data, chan.q[1]);
p[2] += dequantize(data, chan.q[2]);
QuantizedRot qr = {{p[0], p[1], p[2]}, wBit};
kit->emplace_back(DequantizeRotation(qr, rotDiv));
#if DUMP_KEYS
fprintf(stderr, "%d R: %d %d %d %d\t", chan.id, wBit, p[0], p[1], p[2]);
#endif
break;
}
case Channel::Type::Translation: {
atInt32 val1 = dequantize(data, chan.q[0]);
p[0] += val1;
atInt32 val2 = dequantize(data, chan.q[1]);
p[1] += val2;
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
fprintf(stderr, "%d T: %d %d %d\t", chan.id, p[0], p[1], p[2]);
#endif
break;
}
case Channel::Type::Scale: {
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] * 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
break;
}
case Channel::Type::KfHead: {
dequantizeBit(data);
break;
}
case Channel::Type::RotationMP3: {
atInt32 val1 = dequantize(data, chan.q[0]);
p[0] += val1;
atInt32 val2 = dequantize(data, chan.q[1]);
p[1] += val2;
atInt32 val3 = dequantize(data, chan.q[2]);
p[2] += val3;
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));
break;
}
default:
break;
}
++kit;
++ait;
}
transMultOut = maxTransVal / quantRangeF;
scaleMultOut = maxScaleVal / quantRangeF;
#if DUMP_KEYS
fprintf(stderr, "\n");
#endif
}
/* Output channel inits */
std::vector<QuantizedValue> initVals;
initVals.reserve(channels.size());
kit = chanKeys.begin();
for (Channel& chan : channels)
{
chan.q[0] = 1;
chan.q[1] = 1;
chan.q[2] = 1;
switch (chan.type)
{
case Channel::Type::Rotation:
{
QuantizedRot qr = QuantizeRotation((*kit)[0], rotDivOut);
chan.i = qr.v;
initVals.push_back(chan.i);
break;
}
case Channel::Type::Translation:
{
zeus::simd_floats f((*kit)[0].simd);
chan.i = {atInt32(f[0] / transMultOut),
atInt32(f[1] / transMultOut),
atInt32(f[2] / transMultOut)};
initVals.push_back(chan.i);
break;
}
case Channel::Type::Scale:
{
zeus::simd_floats f((*kit)[0].simd);
chan.i = {atInt32(f[0] / scaleMultOut),
atInt32(f[1] / scaleMultOut),
atInt32(f[2] / scaleMultOut)};
initVals.push_back(chan.i);
break;
}
default: break;
}
++kit;
}
/* Pre-pass to analyze quantization factors for channels */
std::vector<QuantizedValue> lastVals = initVals;
kit = chanKeys.begin();
auto vit = lastVals.begin();
for (Channel& chan : channels)
{
QuantizedValue& last = *vit++;
switch (chan.type)
{
case Channel::Type::Rotation:
{
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
QuantizedRot qrCur = QuantizeRotation(*it, rotDivOut);
chan.q[0] = std::max(chan.q[0], atUint8(qrCur.v.qFrom(last, 0)));
chan.q[1] = std::max(chan.q[1], atUint8(qrCur.v.qFrom(last, 1)));
chan.q[2] = std::max(chan.q[2], atUint8(qrCur.v.qFrom(last, 2)));
last = qrCur.v;
}
break;
}
case Channel::Type::Translation:
{
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
zeus::simd_floats f(it->simd);
QuantizedValue cur = {atInt32(f[0] / transMultOut),
atInt32(f[1] / transMultOut),
atInt32(f[2] / transMultOut)};
chan.q[0] = std::max(chan.q[0], atUint8(cur.qFrom(last, 0)));
chan.q[1] = std::max(chan.q[1], atUint8(cur.qFrom(last, 1)));
chan.q[2] = std::max(chan.q[2], atUint8(cur.qFrom(last, 2)));
last = cur;
}
break;
}
case Channel::Type::Scale:
{
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
zeus::simd_floats f(it->simd);
QuantizedValue cur = {atInt32(f[0] / scaleMultOut),
atInt32(f[1] / scaleMultOut),
atInt32(f[2] / scaleMultOut)};
chan.q[0] = std::max(chan.q[0], atUint8(cur.qFrom(last, 0)));
chan.q[1] = std::max(chan.q[1], atUint8(cur.qFrom(last, 1)));
chan.q[2] = std::max(chan.q[2], atUint8(cur.qFrom(last, 2)));
last = cur;
}
break;
}
default: break;
}
++kit;
}
/* Generate Bitstream */
sizeOut = ComputeBitstreamSize(keyFrameCount, channels);
std::unique_ptr<atUint8[]> newData(new atUint8[sizeOut]);
memset(newData.get(), 0, sizeOut);
lastVals = initVals;
for (size_t f=0 ; f<keyFrameCount ; ++f)
{
kit = chanKeys.begin();
vit = lastVals.begin();
for (const Channel& chan : channels)
{
const Value& val = (*kit++)[f+1];
QuantizedValue& last = *vit++;
switch (chan.type)
{
case Channel::Type::Rotation:
{
QuantizedRot qrCur = QuantizeRotation(val, rotDivOut);
quantizeBit(newData.get(), qrCur.w);
quantize(newData.get(), chan.q[0], qrCur.v[0] - last.v[0]);
quantize(newData.get(), chan.q[1], qrCur.v[1] - last.v[1]);
quantize(newData.get(), chan.q[2], qrCur.v[2] - last.v[2]);
last = qrCur.v;
break;
}
case Channel::Type::Translation:
{
zeus::simd_floats f(val.simd);
QuantizedValue cur = {atInt32(f[0] / transMultOut),
atInt32(f[1] / transMultOut),
atInt32(f[2] / transMultOut)};
quantize(newData.get(), chan.q[0], cur[0] - last[0]);
quantize(newData.get(), chan.q[1], cur[1] - last[1]);
quantize(newData.get(), chan.q[2], cur[2] - last[2]);
last = cur;
break;
}
case Channel::Type::Scale:
{
zeus::simd_floats f(val.simd);
QuantizedValue cur = {atInt32(f[0] / scaleMultOut),
atInt32(f[1] / scaleMultOut),
atInt32(f[2] / scaleMultOut)};
quantize(newData.get(), chan.q[0], cur[0] - last[0]);
quantize(newData.get(), chan.q[1], cur[1] - last[1]);
quantize(newData.get(), chan.q[2], cur[2] - last[2]);
last = cur;
break;
}
default: break;
}
}
}
return newData;
return chanKeys;
}
void BitstreamWriter::quantizeBit(atUint8* data, bool val) {
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
*(atUint32*)(data + byteCur) = hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur)) | (val << bitRem));
m_bitCur += 1;
}
void BitstreamWriter::quantize(atUint8* data, atUint8 q, atInt32 val) {
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
atUint32 masked = val & ((1 << q) - 1);
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
*(atUint32*)(data + byteCur) = hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur)) | (masked << bitRem));
/* If this shift underflows the value, buffer the next 32 bits */
/* And tack onto shifted buffer */
if ((bitRem + q) > 32) {
*(atUint32*)(data + byteCur + 4) =
hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur + 4)) | (masked >> (32 - bitRem)));
}
m_bitCur += q;
}
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 = quantRange; /* Normalized range of values */
float quantRangeF = float(quantRange);
/* Pre-pass to calculate translation multiplier */
float maxTransVal = 0.0f;
float maxScaleVal = 0.0f;
auto kit = chanKeys.begin();
for (Channel& chan : channels) {
switch (chan.type) {
case Channel::Type::Translation: {
for (auto it = kit->begin(); it != kit->end(); ++it) {
const Value* key = &*it;
zeus::simd_floats f(key->simd);
maxTransVal = std::max(maxTransVal, std::fabs(f[0]));
maxTransVal = std::max(maxTransVal, std::fabs(f[1]));
maxTransVal = std::max(maxTransVal, std::fabs(f[2]));
}
break;
}
case Channel::Type::Scale: {
for (auto it = kit->begin(); it != kit->end(); ++it) {
const Value* key = &*it;
zeus::simd_floats f(key->simd);
maxScaleVal = std::max(maxScaleVal, std::fabs(f[0]));
maxScaleVal = std::max(maxScaleVal, std::fabs(f[1]));
maxScaleVal = std::max(maxScaleVal, std::fabs(f[2]));
}
break;
}
default:
break;
}
++kit;
}
transMultOut = maxTransVal / quantRangeF;
scaleMultOut = maxScaleVal / quantRangeF;
/* Output channel inits */
std::vector<QuantizedValue> initVals;
initVals.reserve(channels.size());
kit = chanKeys.begin();
for (Channel& chan : channels) {
chan.q[0] = 1;
chan.q[1] = 1;
chan.q[2] = 1;
switch (chan.type) {
case Channel::Type::Rotation: {
QuantizedRot qr = QuantizeRotation((*kit)[0], rotDivOut);
chan.i = qr.v;
initVals.push_back(chan.i);
break;
}
case Channel::Type::Translation: {
zeus::simd_floats f((*kit)[0].simd);
chan.i = {atInt32(f[0] / transMultOut), atInt32(f[1] / transMultOut), atInt32(f[2] / transMultOut)};
initVals.push_back(chan.i);
break;
}
case Channel::Type::Scale: {
zeus::simd_floats f((*kit)[0].simd);
chan.i = {atInt32(f[0] / scaleMultOut), atInt32(f[1] / scaleMultOut), atInt32(f[2] / scaleMultOut)};
initVals.push_back(chan.i);
break;
}
default:
break;
}
++kit;
}
/* Pre-pass to analyze quantization factors for channels */
std::vector<QuantizedValue> lastVals = initVals;
kit = chanKeys.begin();
auto vit = lastVals.begin();
for (Channel& chan : channels) {
QuantizedValue& last = *vit++;
switch (chan.type) {
case Channel::Type::Rotation: {
for (auto it = kit->begin() + 1; it != kit->end(); ++it) {
QuantizedRot qrCur = QuantizeRotation(*it, rotDivOut);
chan.q[0] = std::max(chan.q[0], atUint8(qrCur.v.qFrom(last, 0)));
chan.q[1] = std::max(chan.q[1], atUint8(qrCur.v.qFrom(last, 1)));
chan.q[2] = std::max(chan.q[2], atUint8(qrCur.v.qFrom(last, 2)));
last = qrCur.v;
}
break;
}
case Channel::Type::Translation: {
for (auto it = kit->begin() + 1; it != kit->end(); ++it) {
zeus::simd_floats f(it->simd);
QuantizedValue cur = {atInt32(f[0] / transMultOut), atInt32(f[1] / transMultOut), atInt32(f[2] / transMultOut)};
chan.q[0] = std::max(chan.q[0], atUint8(cur.qFrom(last, 0)));
chan.q[1] = std::max(chan.q[1], atUint8(cur.qFrom(last, 1)));
chan.q[2] = std::max(chan.q[2], atUint8(cur.qFrom(last, 2)));
last = cur;
}
break;
}
case Channel::Type::Scale: {
for (auto it = kit->begin() + 1; it != kit->end(); ++it) {
zeus::simd_floats f(it->simd);
QuantizedValue cur = {atInt32(f[0] / scaleMultOut), atInt32(f[1] / scaleMultOut), atInt32(f[2] / scaleMultOut)};
chan.q[0] = std::max(chan.q[0], atUint8(cur.qFrom(last, 0)));
chan.q[1] = std::max(chan.q[1], atUint8(cur.qFrom(last, 1)));
chan.q[2] = std::max(chan.q[2], atUint8(cur.qFrom(last, 2)));
last = cur;
}
break;
}
default:
break;
}
++kit;
}
/* Generate Bitstream */
sizeOut = ComputeBitstreamSize(keyFrameCount, channels);
std::unique_ptr<atUint8[]> newData(new atUint8[sizeOut]);
memset(newData.get(), 0, sizeOut);
lastVals = initVals;
for (size_t f = 0; f < keyFrameCount; ++f) {
kit = chanKeys.begin();
vit = lastVals.begin();
for (const Channel& chan : channels) {
const Value& val = (*kit++)[f + 1];
QuantizedValue& last = *vit++;
switch (chan.type) {
case Channel::Type::Rotation: {
QuantizedRot qrCur = QuantizeRotation(val, rotDivOut);
quantizeBit(newData.get(), qrCur.w);
quantize(newData.get(), chan.q[0], qrCur.v[0] - last.v[0]);
quantize(newData.get(), chan.q[1], qrCur.v[1] - last.v[1]);
quantize(newData.get(), chan.q[2], qrCur.v[2] - last.v[2]);
last = qrCur.v;
break;
}
case Channel::Type::Translation: {
zeus::simd_floats f(val.simd);
QuantizedValue cur = {atInt32(f[0] / transMultOut), atInt32(f[1] / transMultOut), atInt32(f[2] / transMultOut)};
quantize(newData.get(), chan.q[0], cur[0] - last[0]);
quantize(newData.get(), chan.q[1], cur[1] - last[1]);
quantize(newData.get(), chan.q[2], cur[2] - last[2]);
last = cur;
break;
}
case Channel::Type::Scale: {
zeus::simd_floats f(val.simd);
QuantizedValue cur = {atInt32(f[0] / scaleMultOut), atInt32(f[1] / scaleMultOut), atInt32(f[2] / scaleMultOut)};
quantize(newData.get(), chan.q[0], cur[0] - last[0]);
quantize(newData.get(), chan.q[1], cur[1] - last[1]);
quantize(newData.get(), chan.q[2], cur[2] - last[2]);
last = cur;
break;
}
default:
break;
}
}
}
return newData;
}
} // namespace DataSpec::DNAANIM

View File

@ -3,87 +3,61 @@
#include "DNACommon.hpp"
#include <cmath>
namespace DataSpec::DNAANIM
{
namespace DataSpec::DNAANIM {
struct Value
{
athena::simd<float> simd;
Value() = default;
Value(const athena::simd<float>& s) : simd(s) {}
Value(const atVec3f& v) : simd(v.simd) {}
Value(const atVec4f& v) : simd(v.simd) {}
Value(float x, float y, float z) : simd(x, y, z, 0.f) {}
Value(float w, float x, float y, float z) : simd(w, x, y, z) {}
struct Value {
athena::simd<float> simd;
Value() = default;
Value(const athena::simd<float>& s) : simd(s) {}
Value(const atVec3f& v) : simd(v.simd) {}
Value(const atVec4f& v) : simd(v.simd) {}
Value(float x, float y, float z) : simd(x, y, z, 0.f) {}
Value(float w, float x, float y, float z) : simd(w, x, y, z) {}
};
struct QuantizedValue
{
atInt32 v[4];
atInt32& operator[] (size_t idx)
{return v[idx];}
atInt32 operator[] (size_t idx) const
{return v[idx];}
struct QuantizedValue {
atInt32 v[4];
atInt32& operator[](size_t idx) { return v[idx]; }
atInt32 operator[](size_t idx) const { return v[idx]; }
int qFrom(const QuantizedValue& other, size_t idx) const
{
atInt32 delta = std::abs(v[idx] - other.v[idx]);
if (delta == 0)
return 1;
return int(std::ceil(std::log2(delta))) + 1;
}
int qFrom(const QuantizedValue& other, size_t idx) const {
atInt32 delta = std::abs(v[idx] - other.v[idx]);
if (delta == 0)
return 1;
return int(std::ceil(std::log2(delta))) + 1;
}
};
struct QuantizedRot
{
QuantizedValue v;
bool w;
struct QuantizedRot {
QuantizedValue v;
bool w;
};
struct Channel
{
enum class Type
{
Rotation,
Translation,
Scale,
KfHead,
RotationMP3
} type;
atInt32 id = -1;
QuantizedValue i = {};
atUint8 q[4] = {};
struct Channel {
enum class Type { Rotation, Translation, Scale, KfHead, RotationMP3 } type;
atInt32 id = -1;
QuantizedValue i = {};
atUint8 q[4] = {};
};
size_t ComputeBitstreamSize(size_t keyFrameCount, const std::vector<Channel>& channels);
class BitstreamReader
{
size_t m_bitCur;
atInt32 dequantize(const atUint8* data, atUint8 q);
bool dequantizeBit(const atUint8* data);
class BitstreamReader {
size_t m_bitCur;
atInt32 dequantize(const atUint8* data, atUint8 q);
bool dequantizeBit(const atUint8* data);
public:
std::vector<std::vector<Value>>
read(const atUint8* data,
size_t keyFrameCount,
const std::vector<Channel>& channels,
atUint32 rotDiv,
float transMult,
float scaleMult);
std::vector<std::vector<Value>> read(const atUint8* data, size_t keyFrameCount, const std::vector<Channel>& channels,
atUint32 rotDiv, float transMult, float scaleMult);
};
class BitstreamWriter
{
size_t m_bitCur;
void quantize(atUint8* data, atUint8 q, atInt32 val);
void quantizeBit(atUint8* data, bool val);
class BitstreamWriter {
size_t m_bitCur;
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);
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);
};
}
} // namespace DataSpec::DNAANIM

View File

@ -2,8 +2,7 @@
#include "hecl/Blender/Connection.hpp"
#include "../DNAMP1/PATH.hpp"
namespace DataSpec
{
namespace DataSpec {
logvisor::Module Log("AROTBuilder");
#define AROT_MAX_LEVEL 10
@ -12,505 +11,419 @@ logvisor::Module Log("AROTBuilder");
#define COLLISION_MIN_NODE_TRIANGLES 8
#define PATH_MIN_NODE_REGIONS 16
static zeus::CAABox SplitAABB(const zeus::CAABox& aabb, int i)
{
zeus::CAABox pos, neg;
aabb.splitZ(neg, pos);
if (i & 4)
{
zeus::CAABox(pos).splitY(neg, pos);
if (i & 2)
{
zeus::CAABox(pos).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
}
else
{
zeus::CAABox(neg).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
}
static zeus::CAABox SplitAABB(const zeus::CAABox& aabb, int i) {
zeus::CAABox pos, neg;
aabb.splitZ(neg, pos);
if (i & 4) {
zeus::CAABox(pos).splitY(neg, pos);
if (i & 2) {
zeus::CAABox(pos).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
} else {
zeus::CAABox(neg).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
}
else
{
zeus::CAABox(neg).splitY(neg, pos);
if (i & 2)
{
zeus::CAABox(pos).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
}
else
{
zeus::CAABox(neg).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
}
} else {
zeus::CAABox(neg).splitY(neg, pos);
if (i & 2) {
zeus::CAABox(pos).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
} else {
zeus::CAABox(neg).splitX(neg, pos);
if (i & 1)
return pos;
else
return neg;
}
}
}
void AROTBuilder::Node::mergeSets(int a, int b)
{
childNodes[a].childIndices.insert(childNodes[b].childIndices.cbegin(), childNodes[b].childIndices.cend());
childNodes[b].childIndices = childNodes[a].childIndices;
void AROTBuilder::Node::mergeSets(int a, int b) {
childNodes[a].childIndices.insert(childNodes[b].childIndices.cbegin(), childNodes[b].childIndices.cend());
childNodes[b].childIndices = childNodes[a].childIndices;
}
bool AROTBuilder::Node::compareSets(int a, int b) const
{
return childNodes[a].childIndices != childNodes[b].childIndices;
bool AROTBuilder::Node::compareSets(int a, int b) const {
return childNodes[a].childIndices != childNodes[b].childIndices;
}
void AROTBuilder::Node::addChild(int level, int minChildren, const std::vector<zeus::CAABox>& triBoxes,
const zeus::CAABox& curAABB, BspNodeType& typeOut)
{
/* Gather intersecting faces */
for (int i=0 ; i<triBoxes.size() ; ++i)
if (triBoxes[i].intersects(curAABB))
childIndices.insert(i);
const zeus::CAABox& curAABB, BspNodeType& typeOut) {
/* Gather intersecting faces */
for (int i = 0; i < triBoxes.size(); ++i)
if (triBoxes[i].intersects(curAABB))
childIndices.insert(i);
zeus::CVector3f extents = curAABB.extents();
zeus::CVector3f extents = curAABB.extents();
/* Return early if empty, triangle intersection below performance threshold, or at max level */
if (childIndices.empty())
{
typeOut = BspNodeType::Invalid;
return;
}
else if (childIndices.size() < minChildren || level == AROT_MAX_LEVEL ||
std::max(extents.x(), std::max(extents.y(), extents.z())) < AROT_MIN_SUBDIV)
{
typeOut = BspNodeType::Leaf;
return;
}
/* Return early if empty, triangle intersection below performance threshold, or at max level */
if (childIndices.empty()) {
typeOut = BspNodeType::Invalid;
return;
} else if (childIndices.size() < minChildren || level == AROT_MAX_LEVEL ||
std::max(extents.x(), std::max(extents.y(), extents.z())) < AROT_MIN_SUBDIV) {
typeOut = BspNodeType::Leaf;
return;
}
/* Subdivide */
typeOut = BspNodeType::Branch;
childNodes.resize(8);
for (int i=0 ; i<8 ; ++i)
{
BspNodeType chType;
childNodes[i].addChild(level + 1, minChildren, triBoxes, SplitAABB(curAABB, i), chType);
flags |= int(chType) << (i * 2);
}
/* Subdivide */
typeOut = BspNodeType::Branch;
childNodes.resize(8);
for (int i = 0; i < 8; ++i) {
BspNodeType chType;
childNodes[i].addChild(level + 1, minChildren, triBoxes, SplitAABB(curAABB, i), chType);
flags |= int(chType) << (i * 2);
}
/* Unsubdivide minimum axis dimensions */
if (extents.x() < AROT_MIN_SUBDIV)
{
mergeSets(0, 1);
mergeSets(4, 5);
mergeSets(2, 3);
mergeSets(6, 7);
}
if (extents.y() < AROT_MIN_SUBDIV)
{
mergeSets(0, 2);
mergeSets(1, 3);
mergeSets(4, 6);
mergeSets(5, 7);
}
if (extents.z() < AROT_MIN_SUBDIV)
{
mergeSets(0, 4);
mergeSets(1, 5);
mergeSets(2, 6);
mergeSets(3, 7);
}
/* Unsubdivide minimum axis dimensions */
if (extents.x() < AROT_MIN_SUBDIV) {
mergeSets(0, 1);
mergeSets(4, 5);
mergeSets(2, 3);
mergeSets(6, 7);
}
if (extents.y() < AROT_MIN_SUBDIV) {
mergeSets(0, 2);
mergeSets(1, 3);
mergeSets(4, 6);
mergeSets(5, 7);
}
if (extents.z() < AROT_MIN_SUBDIV) {
mergeSets(0, 4);
mergeSets(1, 5);
mergeSets(2, 6);
mergeSets(3, 7);
}
/* Unsubdivide */
compSubdivs = 0;
if (compareSets(0, 1) ||
compareSets(4, 5) ||
compareSets(2, 3) ||
compareSets(6, 7))
compSubdivs |= 0x1;
if (compareSets(0, 2) ||
compareSets(1, 3) ||
compareSets(4, 6) ||
compareSets(5, 7))
compSubdivs |= 0x2;
if (compareSets(0, 4) ||
compareSets(1, 5) ||
compareSets(2, 6) ||
compareSets(3, 7))
compSubdivs |= 0x4;
/* Unsubdivide */
compSubdivs = 0;
if (compareSets(0, 1) || compareSets(4, 5) || compareSets(2, 3) || compareSets(6, 7))
compSubdivs |= 0x1;
if (compareSets(0, 2) || compareSets(1, 3) || compareSets(4, 6) || compareSets(5, 7))
compSubdivs |= 0x2;
if (compareSets(0, 4) || compareSets(1, 5) || compareSets(2, 6) || compareSets(3, 7))
compSubdivs |= 0x4;
if (!compSubdivs)
{
typeOut = BspNodeType::Leaf;
childNodes = std::vector<Node>();
flags = 0;
}
if (!compSubdivs) {
typeOut = BspNodeType::Leaf;
childNodes = std::vector<Node>();
flags = 0;
}
}
size_t AROTBuilder::BitmapPool::addIndices(const std::set<int>& indices)
{
for (size_t i=0 ; i<m_pool.size() ; ++i)
if (m_pool[i] == indices)
return i;
m_pool.push_back(indices);
return m_pool.size() - 1;
size_t AROTBuilder::BitmapPool::addIndices(const std::set<int>& indices) {
for (size_t i = 0; i < m_pool.size(); ++i)
if (m_pool[i] == indices)
return i;
m_pool.push_back(indices);
return m_pool.size() - 1;
}
static const uint32_t AROTChildCounts[] = { 0, 2, 2, 4, 2, 4, 4, 8 };
static const uint32_t AROTChildCounts[] = {0, 2, 2, 4, 2, 4, 4, 8};
void AROTBuilder::Node::nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPool, size_t& curOff)
{
sz += 1;
poolIdx = bmpPool.addIndices(childIndices);
if (poolIdx > 65535)
Log.report(logvisor::Fatal, "AROT bitmap exceeds 16-bit node addressing; area too complex");
void AROTBuilder::Node::nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPool, size_t& curOff) {
sz += 1;
poolIdx = bmpPool.addIndices(childIndices);
if (poolIdx > 65535)
Log.report(logvisor::Fatal, "AROT bitmap exceeds 16-bit node addressing; area too complex");
uint32_t childCount = AROTChildCounts[compSubdivs];
nodeOff = curOff;
nodeSz = childCount * 2 + 4;
curOff += nodeSz;
if (childNodes.size())
{
for (int k=0 ; k < 1 + ((compSubdivs & 0x4) != 0) ; ++k)
{
for (int j=0 ; j < 1 + ((compSubdivs & 0x2) != 0) ; ++j)
{
for (int i=0 ; i < 1 + ((compSubdivs & 0x1) != 0) ; ++i)
{
int idx = k*4 + j*2 + i;
childNodes[idx].nodeCount(sz, idxRefs, bmpPool, curOff);
}
}
uint32_t childCount = AROTChildCounts[compSubdivs];
nodeOff = curOff;
nodeSz = childCount * 2 + 4;
curOff += nodeSz;
if (childNodes.size()) {
for (int k = 0; k < 1 + ((compSubdivs & 0x4) != 0); ++k) {
for (int j = 0; j < 1 + ((compSubdivs & 0x2) != 0); ++j) {
for (int i = 0; i < 1 + ((compSubdivs & 0x1) != 0); ++i) {
int idx = k * 4 + j * 2 + i;
childNodes[idx].nodeCount(sz, idxRefs, bmpPool, curOff);
}
idxRefs += childCount;
}
}
idxRefs += childCount;
}
}
void AROTBuilder::Node::writeIndirectionTable(athena::io::MemoryWriter& w)
{
w.writeUint32Big(nodeOff);
if (childNodes.size())
{
for (int k=0 ; k < 1 + ((compSubdivs & 0x4) != 0) ; ++k)
{
for (int j=0 ; j < 1 + ((compSubdivs & 0x2) != 0) ; ++j)
{
for (int i=0 ; i < 1 + ((compSubdivs & 0x1) != 0) ; ++i)
{
int idx = k*4 + j*2 + i;
childNodes[idx].writeIndirectionTable(w);
}
}
void AROTBuilder::Node::writeIndirectionTable(athena::io::MemoryWriter& w) {
w.writeUint32Big(nodeOff);
if (childNodes.size()) {
for (int k = 0; k < 1 + ((compSubdivs & 0x4) != 0); ++k) {
for (int j = 0; j < 1 + ((compSubdivs & 0x2) != 0); ++j) {
for (int i = 0; i < 1 + ((compSubdivs & 0x1) != 0); ++i) {
int idx = k * 4 + j * 2 + i;
childNodes[idx].writeIndirectionTable(w);
}
}
}
}
}
void AROTBuilder::Node::writeNodes(athena::io::MemoryWriter& w, int nodeIdx)
{
w.writeUint16Big(poolIdx);
w.writeUint16Big(compSubdivs);
void AROTBuilder::Node::writeNodes(athena::io::MemoryWriter& w, int nodeIdx) {
w.writeUint16Big(poolIdx);
w.writeUint16Big(compSubdivs);
if (childNodes.size())
{
int curIdx = nodeIdx + 1;
if (curIdx > 65535)
Log.report(logvisor::Fatal, "AROT node exceeds 16-bit node addressing; area too complex");
if (childNodes.size()) {
int curIdx = nodeIdx + 1;
if (curIdx > 65535)
Log.report(logvisor::Fatal, "AROT node exceeds 16-bit node addressing; area too complex");
int childIndices[8];
int childIndices[8];
for (int k=0 ; k < 1 + ((compSubdivs & 0x4) != 0) ; ++k)
{
for (int j=0 ; j < 1 + ((compSubdivs & 0x2) != 0) ; ++j)
{
for (int i=0 ; i < 1 + ((compSubdivs & 0x1) != 0) ; ++i)
{
int idx = k*4 + j*2 + i;
w.writeUint16Big(curIdx);
childIndices[idx] = curIdx;
childNodes[idx].advanceIndex(curIdx);
}
}
}
for (int k=0 ; k < 1 + ((compSubdivs & 0x4) != 0) ; ++k)
{
for (int j=0 ; j < 1 + ((compSubdivs & 0x2) != 0) ; ++j)
{
for (int i=0 ; i < 1 + ((compSubdivs & 0x1) != 0) ; ++i)
{
int idx = k*4 + j*2 + i;
childNodes[idx].writeNodes(w, childIndices[idx]);
}
}
for (int k = 0; k < 1 + ((compSubdivs & 0x4) != 0); ++k) {
for (int j = 0; j < 1 + ((compSubdivs & 0x2) != 0); ++j) {
for (int i = 0; i < 1 + ((compSubdivs & 0x1) != 0); ++i) {
int idx = k * 4 + j * 2 + i;
w.writeUint16Big(curIdx);
childIndices[idx] = curIdx;
childNodes[idx].advanceIndex(curIdx);
}
}
}
for (int k = 0; k < 1 + ((compSubdivs & 0x4) != 0); ++k) {
for (int j = 0; j < 1 + ((compSubdivs & 0x2) != 0); ++j) {
for (int i = 0; i < 1 + ((compSubdivs & 0x1) != 0); ++i) {
int idx = k * 4 + j * 2 + i;
childNodes[idx].writeNodes(w, childIndices[idx]);
}
}
}
}
}
void AROTBuilder::Node::advanceIndex(int& nodeIdx)
{
++nodeIdx;
if (childNodes.size())
{
for (int k=0 ; k < 1 + ((compSubdivs & 0x4) != 0) ; ++k)
{
for (int j=0 ; j < 1 + ((compSubdivs & 0x2) != 0) ; ++j)
{
for (int i=0 ; i < 1 + ((compSubdivs & 0x1) != 0) ; ++i)
{
int idx = k*4 + j*2 + i;
childNodes[idx].advanceIndex(nodeIdx);
}
}
void AROTBuilder::Node::advanceIndex(int& nodeIdx) {
++nodeIdx;
if (childNodes.size()) {
for (int k = 0; k < 1 + ((compSubdivs & 0x4) != 0); ++k) {
for (int j = 0; j < 1 + ((compSubdivs & 0x2) != 0); ++j) {
for (int i = 0; i < 1 + ((compSubdivs & 0x1) != 0); ++i) {
int idx = k * 4 + j * 2 + i;
childNodes[idx].advanceIndex(nodeIdx);
}
}
}
}
}
void AROTBuilder::Node::colSize(size_t& totalSz)
{
if (childIndices.size())
{
nodeOff = totalSz;
if (childNodes.empty())
{
totalSz += 26 + childIndices.size() * 2;
}
else
{
totalSz += 36;
for (int i=0 ; i<8 ; ++i)
childNodes[i].colSize(totalSz);
}
void AROTBuilder::Node::colSize(size_t& totalSz) {
if (childIndices.size()) {
nodeOff = totalSz;
if (childNodes.empty()) {
totalSz += 26 + childIndices.size() * 2;
} else {
totalSz += 36;
for (int i = 0; i < 8; ++i)
childNodes[i].colSize(totalSz);
}
}
}
void AROTBuilder::Node::writeColNodes(uint8_t*& ptr, const zeus::CAABox& curAABB)
{
if (childIndices.size())
{
if (childNodes.empty())
{
float* aabbOut = reinterpret_cast<float*>(ptr);
aabbOut[0] = hecl::SBig(curAABB.min[0]);
aabbOut[1] = hecl::SBig(curAABB.min[1]);
aabbOut[2] = hecl::SBig(curAABB.min[2]);
aabbOut[3] = hecl::SBig(curAABB.max[0]);
aabbOut[4] = hecl::SBig(curAABB.max[1]);
aabbOut[5] = hecl::SBig(curAABB.max[2]);
athena::io::MemoryWriter w(ptr + 24, INT32_MAX);
w.writeUint16Big(childIndices.size());
for (int idx : childIndices)
w.writeUint16Big(idx);
ptr += 26 + childIndices.size() * 2;
}
else
{
uint16_t* pflags = reinterpret_cast<uint16_t*>(ptr);
uint32_t* offsets = reinterpret_cast<uint32_t*>(ptr + 4);
memset(pflags, 0, sizeof(uint32_t) * 9);
for (int i=0 ; i<8 ; ++i)
{
const Node& chNode = childNodes[i];
BspNodeType type = BspNodeType((flags >> (i * 2)) & 0x3);
if (type != BspNodeType::Invalid)
offsets[i] = hecl::SBig(uint32_t(chNode.nodeOff - nodeOff - 36));
}
void AROTBuilder::Node::writeColNodes(uint8_t*& ptr, const zeus::CAABox& curAABB) {
if (childIndices.size()) {
if (childNodes.empty()) {
float* aabbOut = reinterpret_cast<float*>(ptr);
aabbOut[0] = hecl::SBig(curAABB.min[0]);
aabbOut[1] = hecl::SBig(curAABB.min[1]);
aabbOut[2] = hecl::SBig(curAABB.min[2]);
aabbOut[3] = hecl::SBig(curAABB.max[0]);
aabbOut[4] = hecl::SBig(curAABB.max[1]);
aabbOut[5] = hecl::SBig(curAABB.max[2]);
athena::io::MemoryWriter w(ptr + 24, INT32_MAX);
w.writeUint16Big(childIndices.size());
for (int idx : childIndices)
w.writeUint16Big(idx);
ptr += 26 + childIndices.size() * 2;
} else {
uint16_t* pflags = reinterpret_cast<uint16_t*>(ptr);
uint32_t* offsets = reinterpret_cast<uint32_t*>(ptr + 4);
memset(pflags, 0, sizeof(uint32_t) * 9);
for (int i = 0; i < 8; ++i) {
const Node& chNode = childNodes[i];
BspNodeType type = BspNodeType((flags >> (i * 2)) & 0x3);
if (type != BspNodeType::Invalid)
offsets[i] = hecl::SBig(uint32_t(chNode.nodeOff - nodeOff - 36));
}
*pflags = hecl::SBig(flags);
ptr += 36;
*pflags = hecl::SBig(flags);
ptr += 36;
for (int i=0 ; i<8 ; ++i)
childNodes[i].writeColNodes(ptr, SplitAABB(curAABB, i));
}
for (int i = 0; i < 8; ++i)
childNodes[i].writeColNodes(ptr, SplitAABB(curAABB, i));
}
}
}
void AROTBuilder::Node::pathCountNodesAndLookups(size_t& nodeCount, size_t& lookupCount)
{
++nodeCount;
if (childNodes.empty())
{
lookupCount += childIndices.size();
}
else
{
for (int i=0 ; i<8 ; ++i)
childNodes[i].pathCountNodesAndLookups(nodeCount, lookupCount);
}
void AROTBuilder::Node::pathCountNodesAndLookups(size_t& nodeCount, size_t& lookupCount) {
++nodeCount;
if (childNodes.empty()) {
lookupCount += childIndices.size();
} else {
for (int i = 0; i < 8; ++i)
childNodes[i].pathCountNodesAndLookups(nodeCount, lookupCount);
}
}
void AROTBuilder::Node::pathWrite(DNAMP1::PATH& path, const zeus::CAABox& curAABB)
{
if (childNodes.empty())
{
path.octree.emplace_back();
DNAMP1::PATH::OctreeNode& n = path.octree.back();
n.isLeaf = 1;
n.aabb[0] = curAABB.min;
n.aabb[1] = curAABB.max;
n.centroid = curAABB.center();
for (int i=0 ; i<8 ; ++i)
n.children[i] = 0xffffffff;
n.regionCount = childIndices.size();
n.regionStart = path.octreeRegionLookup.size();
for (int r : childIndices)
path.octreeRegionLookup.push_back(r);
void AROTBuilder::Node::pathWrite(DNAMP1::PATH& path, const zeus::CAABox& curAABB) {
if (childNodes.empty()) {
path.octree.emplace_back();
DNAMP1::PATH::OctreeNode& n = path.octree.back();
n.isLeaf = 1;
n.aabb[0] = curAABB.min;
n.aabb[1] = curAABB.max;
n.centroid = curAABB.center();
for (int i = 0; i < 8; ++i)
n.children[i] = 0xffffffff;
n.regionCount = childIndices.size();
n.regionStart = path.octreeRegionLookup.size();
for (int r : childIndices)
path.octreeRegionLookup.push_back(r);
} else {
atUint32 children[8];
for (int i = 0; i < 8; ++i) {
/* Head recursion (first node will be a leaf) */
children[i] = path.octree.size();
childNodes[i].pathWrite(path, SplitAABB(curAABB, i));
}
else
{
atUint32 children[8];
for (int i=0 ; i<8 ; ++i)
{
/* Head recursion (first node will be a leaf) */
children[i] = path.octree.size();
childNodes[i].pathWrite(path, SplitAABB(curAABB, i));
}
path.octree.emplace_back();
DNAMP1::PATH::OctreeNode& n = path.octree.back();
n.isLeaf = 0;
n.aabb[0] = curAABB.min;
n.aabb[1] = curAABB.max;
n.centroid = curAABB.center();
for (int i=0 ; i<8 ; ++i)
n.children[i] = children[i];
n.regionCount = 0;
n.regionStart = 0;
}
path.octree.emplace_back();
DNAMP1::PATH::OctreeNode& n = path.octree.back();
n.isLeaf = 0;
n.aabb[0] = curAABB.min;
n.aabb[1] = curAABB.max;
n.centroid = curAABB.center();
for (int i = 0; i < 8; ++i)
n.children[i] = children[i];
n.regionCount = 0;
n.regionStart = 0;
}
}
void AROTBuilder::build(std::vector<std::vector<uint8_t>>& secs, const zeus::CAABox& fullAabb,
const std::vector<zeus::CAABox>& meshAabbs, const std::vector<DNACMDL::Mesh>& meshes)
{
/* Recursively split */
BspNodeType rootType;
rootNode.addChild(0, AROT_MIN_MODELS, meshAabbs, fullAabb, rootType);
const std::vector<zeus::CAABox>& meshAabbs, const std::vector<DNACMDL::Mesh>& meshes) {
/* Recursively split */
BspNodeType rootType;
rootNode.addChild(0, AROT_MIN_MODELS, meshAabbs, fullAabb, rootType);
/* Calculate indexing metrics */
size_t totalNodeCount = 0;
size_t idxRefCount = 0;
size_t curOff = 0;
rootNode.nodeCount(totalNodeCount, idxRefCount, bmpPool, curOff);
size_t bmpWordCount = ROUND_UP_32(meshes.size()) / 32;
size_t arotSz = 64 + bmpWordCount * bmpPool.m_pool.size() * 4 + totalNodeCount * 8 + idxRefCount * 2;
/* Calculate indexing metrics */
size_t totalNodeCount = 0;
size_t idxRefCount = 0;
size_t curOff = 0;
rootNode.nodeCount(totalNodeCount, idxRefCount, bmpPool, curOff);
size_t bmpWordCount = ROUND_UP_32(meshes.size()) / 32;
size_t arotSz = 64 + bmpWordCount * bmpPool.m_pool.size() * 4 + totalNodeCount * 8 + idxRefCount * 2;
/* Write header */
secs.emplace_back(arotSz, 0);
athena::io::MemoryWriter w(secs.back().data(), secs.back().size());
w.writeUint32Big('AROT');
w.writeUint32Big(1);
w.writeUint32Big(bmpPool.m_pool.size());
w.writeUint32Big(meshes.size());
w.writeUint32Big(totalNodeCount);
w.writeVec3fBig(fullAabb.min);
w.writeVec3fBig(fullAabb.max);
w.seekAlign32();
/* Write header */
secs.emplace_back(arotSz, 0);
athena::io::MemoryWriter w(secs.back().data(), secs.back().size());
w.writeUint32Big('AROT');
w.writeUint32Big(1);
w.writeUint32Big(bmpPool.m_pool.size());
w.writeUint32Big(meshes.size());
w.writeUint32Big(totalNodeCount);
w.writeVec3fBig(fullAabb.min);
w.writeVec3fBig(fullAabb.max);
w.seekAlign32();
/* Write bitmap */
std::vector<uint32_t> bmpWords;
bmpWords.reserve(bmpWordCount);
for (const std::set<int>& bmp : bmpPool.m_pool)
{
bmpWords.clear();
bmpWords.resize(bmpWordCount);
/* Write bitmap */
std::vector<uint32_t> bmpWords;
bmpWords.reserve(bmpWordCount);
for (const std::set<int>& bmp : bmpPool.m_pool) {
bmpWords.clear();
bmpWords.resize(bmpWordCount);
auto bmpIt = bmp.cbegin();
if (bmpIt != bmp.cend())
{
int curIdx = 0;
for (int w=0 ; w<bmpWordCount ; ++w)
{
for (int b=0 ; b<32 ; ++b)
{
if (*bmpIt == curIdx)
{
bmpWords[w] |= 1 << b;
++bmpIt;
if (bmpIt == bmp.cend())
break;
}
++curIdx;
}
if (bmpIt == bmp.cend())
break;
}
auto bmpIt = bmp.cbegin();
if (bmpIt != bmp.cend()) {
int curIdx = 0;
for (int w = 0; w < bmpWordCount; ++w) {
for (int b = 0; b < 32; ++b) {
if (*bmpIt == curIdx) {
bmpWords[w] |= 1 << b;
++bmpIt;
if (bmpIt == bmp.cend())
break;
}
++curIdx;
}
for (uint32_t word : bmpWords)
w.writeUint32Big(word);
if (bmpIt == bmp.cend())
break;
}
}
/* Write the rest */
rootNode.writeIndirectionTable(w);
rootNode.writeNodes(w, 0);
for (uint32_t word : bmpWords)
w.writeUint32Big(word);
}
/* Write the rest */
rootNode.writeIndirectionTable(w);
rootNode.writeNodes(w, 0);
}
std::pair<std::unique_ptr<uint8_t[]>, uint32_t> AROTBuilder::buildCol(const ColMesh& mesh, BspNodeType& rootOut)
{
/* Accumulate total AABB */
zeus::CAABox fullAABB;
for (const auto& vert : mesh.verts)
fullAABB.accumulateBounds(zeus::CVector3f(vert));
std::pair<std::unique_ptr<uint8_t[]>, uint32_t> AROTBuilder::buildCol(const ColMesh& mesh, BspNodeType& rootOut) {
/* Accumulate total AABB */
zeus::CAABox fullAABB;
for (const auto& vert : mesh.verts)
fullAABB.accumulateBounds(zeus::CVector3f(vert));
/* Predetermine triangle AABBs */
std::vector<zeus::CAABox> triBoxes;
triBoxes.reserve(mesh.trianges.size());
for (const ColMesh::Triangle& tri : mesh.trianges)
{
triBoxes.emplace_back();
zeus::CAABox& aabb = triBoxes.back();
for (int e=0 ; e<3 ; ++e)
{
const ColMesh::Edge& edge = mesh.edges[tri.edges[e]];
for (int v=0 ; v<2 ; ++v)
{
const auto& vert = mesh.verts[edge.verts[v]];
aabb.accumulateBounds(zeus::CVector3f(vert));
}
}
/* Predetermine triangle AABBs */
std::vector<zeus::CAABox> triBoxes;
triBoxes.reserve(mesh.trianges.size());
for (const ColMesh::Triangle& tri : mesh.trianges) {
triBoxes.emplace_back();
zeus::CAABox& aabb = triBoxes.back();
for (int e = 0; e < 3; ++e) {
const ColMesh::Edge& edge = mesh.edges[tri.edges[e]];
for (int v = 0; v < 2; ++v) {
const auto& vert = mesh.verts[edge.verts[v]];
aabb.accumulateBounds(zeus::CVector3f(vert));
}
}
}
/* Recursively split */
rootNode.addChild(0, COLLISION_MIN_NODE_TRIANGLES, triBoxes, fullAABB, rootOut);
/* Recursively split */
rootNode.addChild(0, COLLISION_MIN_NODE_TRIANGLES, triBoxes, fullAABB, rootOut);
/* Calculate offsets and write out */
size_t totalSize = 0;
rootNode.colSize(totalSize);
std::unique_ptr<uint8_t[]> ret(new uint8_t[totalSize]);
uint8_t* ptr = ret.get();
rootNode.writeColNodes(ptr, fullAABB);
/* Calculate offsets and write out */
size_t totalSize = 0;
rootNode.colSize(totalSize);
std::unique_ptr<uint8_t[]> ret(new uint8_t[totalSize]);
uint8_t* ptr = ret.get();
rootNode.writeColNodes(ptr, fullAABB);
return {std::move(ret), totalSize};
return {std::move(ret), totalSize};
}
void AROTBuilder::buildPath(DNAMP1::PATH& path)
{
/* Accumulate total AABB and gather region boxes */
std::vector<zeus::CAABox> regionBoxes;
regionBoxes.reserve(path.regions.size());
zeus::CAABox fullAABB;
for (const DNAMP1::PATH::Region& r : path.regions)
{
regionBoxes.emplace_back(r.aabb[0], r.aabb[1]);
fullAABB.accumulateBounds(regionBoxes.back());
}
void AROTBuilder::buildPath(DNAMP1::PATH& path) {
/* Accumulate total AABB and gather region boxes */
std::vector<zeus::CAABox> regionBoxes;
regionBoxes.reserve(path.regions.size());
zeus::CAABox fullAABB;
for (const DNAMP1::PATH::Region& r : path.regions) {
regionBoxes.emplace_back(r.aabb[0], r.aabb[1]);
fullAABB.accumulateBounds(regionBoxes.back());
}
/* Recursively split */
BspNodeType dontCare;
rootNode.addChild(0, PATH_MIN_NODE_REGIONS, regionBoxes, fullAABB, dontCare);
/* Recursively split */
BspNodeType dontCare;
rootNode.addChild(0, PATH_MIN_NODE_REGIONS, regionBoxes, fullAABB, dontCare);
/* Write out */
size_t nodeCount = 0;
size_t lookupCount = 0;
rootNode.pathCountNodesAndLookups(nodeCount, lookupCount);
path.octreeNodeCount = nodeCount;
path.octree.reserve(nodeCount);
path.octreeRegionLookupCount = lookupCount;
path.octreeRegionLookup.reserve(lookupCount);
rootNode.pathWrite(path, fullAABB);
/* Write out */
size_t nodeCount = 0;
size_t lookupCount = 0;
rootNode.pathCountNodesAndLookups(nodeCount, lookupCount);
path.octreeNodeCount = nodeCount;
path.octree.reserve(nodeCount);
path.octreeRegionLookupCount = lookupCount;
path.octreeRegionLookup.reserve(lookupCount);
rootNode.pathWrite(path, fullAABB);
}
}
} // namespace DataSpec

View File

@ -6,55 +6,49 @@
#include "CMDL.hpp"
#include <set>
namespace DataSpec
{
namespace DNAMP1
{
namespace DataSpec {
namespace DNAMP1 {
struct PATH;
}
struct AROTBuilder
{
using ColMesh = hecl::blender::ColMesh;
struct AROTBuilder {
using ColMesh = hecl::blender::ColMesh;
struct BitmapPool
{
std::vector<std::set<int>> m_pool;
size_t addIndices(const std::set<int>& indices);
} bmpPool;
struct BitmapPool {
std::vector<std::set<int>> m_pool;
size_t addIndices(const std::set<int>& indices);
} bmpPool;
struct Node
{
std::vector<Node> childNodes;
std::set<int> childIndices;
size_t poolIdx = 0;
uint16_t flags = 0;
uint16_t compSubdivs = 0;
struct Node {
std::vector<Node> childNodes;
std::set<int> childIndices;
size_t poolIdx = 0;
uint16_t flags = 0;
uint16_t compSubdivs = 0;
size_t nodeOff = 0;
size_t nodeSz = 4;
size_t nodeOff = 0;
size_t nodeSz = 4;
void addChild(int level, int minChildren, const std::vector<zeus::CAABox>& triBoxes,
const zeus::CAABox& curAABB, BspNodeType& typeOut);
void mergeSets(int a, int b);
bool compareSets(int a, int b) const;
void nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPool, size_t& curOff);
void writeIndirectionTable(athena::io::MemoryWriter& w);
void writeNodes(athena::io::MemoryWriter& w, int nodeIdx);
void advanceIndex(int& nodeIdx);
void addChild(int level, int minChildren, const std::vector<zeus::CAABox>& triBoxes, const zeus::CAABox& curAABB,
BspNodeType& typeOut);
void mergeSets(int a, int b);
bool compareSets(int a, int b) const;
void nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPool, size_t& curOff);
void writeIndirectionTable(athena::io::MemoryWriter& w);
void writeNodes(athena::io::MemoryWriter& w, int nodeIdx);
void advanceIndex(int& nodeIdx);
void colSize(size_t& totalSz);
void writeColNodes(uint8_t*& ptr, const zeus::CAABox& curAABB);
void colSize(size_t& totalSz);
void writeColNodes(uint8_t*& ptr, const zeus::CAABox& curAABB);
void pathCountNodesAndLookups(size_t& nodeCount, size_t& lookupCount);
void pathWrite(DNAMP1::PATH& path, const zeus::CAABox& curAABB);
} rootNode;
void pathCountNodesAndLookups(size_t& nodeCount, size_t& lookupCount);
void pathWrite(DNAMP1::PATH& path, const zeus::CAABox& curAABB);
} rootNode;
void build(std::vector<std::vector<uint8_t>>& secs, const zeus::CAABox& fullAabb,
const std::vector<zeus::CAABox>& meshAabbs, const std::vector<DNACMDL::Mesh>& meshes);
std::pair<std::unique_ptr<uint8_t[]>, uint32_t> buildCol(const ColMesh& mesh, BspNodeType& rootOut);
void buildPath(DNAMP1::PATH& path);
void build(std::vector<std::vector<uint8_t>>& secs, const zeus::CAABox& fullAabb,
const std::vector<zeus::CAABox>& meshAabbs, const std::vector<DNACMDL::Mesh>& meshes);
std::pair<std::unique_ptr<uint8_t[]>, uint32_t> buildCol(const ColMesh& mesh, BspNodeType& rootOut);
void buildPath(DNAMP1::PATH& path);
};
}
} // namespace DataSpec

View File

@ -1,61 +1,55 @@
#include "ATBL.hpp"
namespace DataSpec::DNAAudio
{
namespace DataSpec::DNAAudio {
bool ATBL::Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath)
{
uint32_t idxCount = rs.readUint32Big();
athena::io::YAMLDocWriter w("ATBL");
for (uint32_t i=0 ; i<idxCount ; ++i)
{
uint16_t idx = rs.readUint16Big();
if (idx == 0xffff)
continue;
char iStr[16];
snprintf(iStr, 16, "0x%04X", int(i));
w.writeUint16(iStr, idx);
}
bool ATBL::Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
uint32_t idxCount = rs.readUint32Big();
athena::io::YAMLDocWriter w("ATBL");
for (uint32_t i = 0; i < idxCount; ++i) {
uint16_t idx = rs.readUint16Big();
if (idx == 0xffff)
continue;
char iStr[16];
snprintf(iStr, 16, "0x%04X", int(i));
w.writeUint16(iStr, idx);
}
athena::io::FileWriter fw(outPath.getAbsolutePath());
w.finish(&fw);
athena::io::FileWriter fw(outPath.getAbsolutePath());
w.finish(&fw);
return true;
return true;
}
bool ATBL::Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath)
{
athena::io::FileReader r(inPath.getAbsolutePath());
if (r.hasError())
return false;
bool ATBL::Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath) {
athena::io::FileReader r(inPath.getAbsolutePath());
if (r.hasError())
return false;
athena::io::YAMLDocReader dr;
if (!dr.parse(&r))
return false;
athena::io::YAMLDocReader dr;
if (!dr.parse(&r))
return false;
unsigned long maxI = 0;
for (const auto& pair : dr.getRootNode()->m_mapChildren)
{
unsigned long i = strtoul(pair.first.c_str(), nullptr, 0);
maxI = std::max(maxI, i);
}
unsigned long maxI = 0;
for (const auto& pair : dr.getRootNode()->m_mapChildren) {
unsigned long i = strtoul(pair.first.c_str(), nullptr, 0);
maxI = std::max(maxI, i);
}
std::vector<uint16_t> vecOut;
vecOut.resize(maxI + 1, 0xffff);
std::vector<uint16_t> vecOut;
vecOut.resize(maxI + 1, 0xffff);
for (const auto& pair : dr.getRootNode()->m_mapChildren)
{
unsigned long i = strtoul(pair.first.c_str(), nullptr, 0);
vecOut[i] = hecl::SBig(uint16_t(strtoul(pair.second->m_scalarString.c_str(), nullptr, 0)));
}
for (const auto& pair : dr.getRootNode()->m_mapChildren) {
unsigned long i = strtoul(pair.first.c_str(), nullptr, 0);
vecOut[i] = hecl::SBig(uint16_t(strtoul(pair.second->m_scalarString.c_str(), nullptr, 0)));
}
athena::io::FileWriter w(outPath.getAbsolutePath());
if (w.hasError())
return false;
w.writeUint32Big(uint32_t(vecOut.size()));
w.writeBytes(vecOut.data(), vecOut.size() * 2);
athena::io::FileWriter w(outPath.getAbsolutePath());
if (w.hasError())
return false;
w.writeUint32Big(uint32_t(vecOut.size()));
w.writeBytes(vecOut.data(), vecOut.size() * 2);
return true;
return true;
}
}
} // namespace DataSpec::DNAAudio

View File

@ -3,15 +3,12 @@
#include "DNACommon.hpp"
#include "PAK.hpp"
namespace DataSpec::DNAAudio
{
namespace DataSpec::DNAAudio {
class ATBL
{
class ATBL {
public:
static bool Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
static bool Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath);
static bool Extract(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
static bool Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath);
};
}
} // namespace DataSpec::DNAAudio

View File

@ -4,163 +4,156 @@
#include "zeus/CTransform.hpp"
#include "hecl/Blender/Connection.hpp"
namespace DataSpec
{
namespace DataSpec {
template<class BabeDeadLight>
void ReadBabeDeadLightToBlender(hecl::blender::PyOutStream& os,
const BabeDeadLight& light, unsigned s, unsigned l)
{
switch (light.lightType)
{
case BabeDeadLight::LightType::LocalAmbient:
case BabeDeadLight::LightType::LocalAmbient2:
os.format("bg_node.inputs[0].default_value = (%f,%f,%f,1.0)\n"
"bg_node.inputs[1].default_value = %f\n",
light.color.simd[0], light.color.simd[1], light.color.simd[2],
light.q / 8.f);
return;
case BabeDeadLight::LightType::Directional:
os.format("lamp = bpy.data.lamps.new('LAMP_%01u_%03u', 'SUN')\n"
"lamp.color = (%f,%f,%f)\n"
"lamp_obj = bpy.data.objects.new(lamp.name, lamp)\n"
"lamp_obj.rotation_mode = 'QUATERNION'\n"
"lamp_obj.rotation_quaternion = Vector((0,0,-1)).rotation_difference(Vector((%f,%f,%f)))\n"
"lamp.shadow_method = '%s'\n"
"\n", s, l, light.color.simd[0], light.color.simd[1], light.color.simd[2],
light.direction.simd[0], light.direction.simd[1], light.direction.simd[2],
light.castShadows ? "RAY_SHADOW" : "NOSHADOW");
return;
case BabeDeadLight::LightType::Custom:
os.format("lamp = bpy.data.lamps.new('LAMP_%01u_%03u', 'POINT')\n"
"lamp.color = (%f,%f,%f)\n"
"lamp_obj = bpy.data.objects.new(lamp.name, lamp)\n"
"lamp.shadow_soft_size = 1.0\n"
"lamp.shadow_method = '%s'\n"
"\n", s, l, light.color.simd[0], light.color.simd[1], light.color.simd[2],
light.castShadows ? "RAY_SHADOW" : "NOSHADOW");
break;
case BabeDeadLight::LightType::Spot:
case BabeDeadLight::LightType::Spot2:
os.format("lamp = bpy.data.lamps.new('LAMP_%01u_%03u', 'SPOT')\n"
"lamp.color = (%f,%f,%f)\n"
"lamp.spot_size = %.6g\n"
"lamp_obj = bpy.data.objects.new(lamp.name, lamp)\n"
"lamp_obj.rotation_mode = 'QUATERNION'\n"
"lamp_obj.rotation_quaternion = Vector((0,0,-1)).rotation_difference(Vector((%f,%f,%f)))\n"
"lamp.shadow_soft_size = 0.5\n"
"lamp.shadow_method = '%s'\n"
"\n", s, l, light.color.simd[0], light.color.simd[1], light.color.simd[2],
zeus::degToRad(light.spotCutoff),
light.direction.simd[0], light.direction.simd[1], light.direction.simd[2],
light.castShadows ? "RAY_SHADOW" : "NOSHADOW");
break;
default: return;
}
template <class BabeDeadLight>
void ReadBabeDeadLightToBlender(hecl::blender::PyOutStream& os, const BabeDeadLight& light, unsigned s, unsigned l) {
switch (light.lightType) {
case BabeDeadLight::LightType::LocalAmbient:
case BabeDeadLight::LightType::LocalAmbient2:
os.format(
"bg_node.inputs[0].default_value = (%f,%f,%f,1.0)\n"
"bg_node.inputs[1].default_value = %f\n",
light.color.simd[0], light.color.simd[1], light.color.simd[2], light.q / 8.f);
return;
case BabeDeadLight::LightType::Directional:
os.format(
"lamp = bpy.data.lamps.new('LAMP_%01u_%03u', 'SUN')\n"
"lamp.color = (%f,%f,%f)\n"
"lamp_obj = bpy.data.objects.new(lamp.name, lamp)\n"
"lamp_obj.rotation_mode = 'QUATERNION'\n"
"lamp_obj.rotation_quaternion = Vector((0,0,-1)).rotation_difference(Vector((%f,%f,%f)))\n"
"lamp.shadow_method = '%s'\n"
"\n",
s, l, light.color.simd[0], light.color.simd[1], light.color.simd[2], light.direction.simd[0],
light.direction.simd[1], light.direction.simd[2], light.castShadows ? "RAY_SHADOW" : "NOSHADOW");
return;
case BabeDeadLight::LightType::Custom:
os.format(
"lamp = bpy.data.lamps.new('LAMP_%01u_%03u', 'POINT')\n"
"lamp.color = (%f,%f,%f)\n"
"lamp_obj = bpy.data.objects.new(lamp.name, lamp)\n"
"lamp.shadow_soft_size = 1.0\n"
"lamp.shadow_method = '%s'\n"
"\n",
s, l, light.color.simd[0], light.color.simd[1], light.color.simd[2],
light.castShadows ? "RAY_SHADOW" : "NOSHADOW");
break;
case BabeDeadLight::LightType::Spot:
case BabeDeadLight::LightType::Spot2:
os.format(
"lamp = bpy.data.lamps.new('LAMP_%01u_%03u', 'SPOT')\n"
"lamp.color = (%f,%f,%f)\n"
"lamp.spot_size = %.6g\n"
"lamp_obj = bpy.data.objects.new(lamp.name, lamp)\n"
"lamp_obj.rotation_mode = 'QUATERNION'\n"
"lamp_obj.rotation_quaternion = Vector((0,0,-1)).rotation_difference(Vector((%f,%f,%f)))\n"
"lamp.shadow_soft_size = 0.5\n"
"lamp.shadow_method = '%s'\n"
"\n",
s, l, light.color.simd[0], light.color.simd[1], light.color.simd[2], zeus::degToRad(light.spotCutoff),
light.direction.simd[0], light.direction.simd[1], light.direction.simd[2],
light.castShadows ? "RAY_SHADOW" : "NOSHADOW");
break;
default:
return;
}
os.format("lamp.retro_layer = %u\n"
"lamp.retro_origtype = %u\n"
"lamp.falloff_type = 'INVERSE_COEFFICIENTS'\n"
"lamp.constant_coefficient = 0\n"
"lamp.use_nodes = True\n"
"falloff_node = lamp.node_tree.nodes.new('ShaderNodeLightFalloff')\n"
"lamp.energy = 0.0\n"
"falloff_node.inputs[0].default_value = %f\n"
"hue_sat_node = lamp.node_tree.nodes.new('ShaderNodeHueSaturation')\n"
"hue_sat_node.inputs[1].default_value = 1.25\n"
"hue_sat_node.inputs[4].default_value = (%f,%f,%f,1.0)\n"
"lamp.node_tree.links.new(hue_sat_node.outputs[0], lamp.node_tree.nodes['Emission'].inputs[0])\n"
"lamp_obj.location = (%f,%f,%f)\n"
"bpy.context.scene.objects.link(lamp_obj)\n"
"\n", s, light.lightType, light.q / 8.f,
light.color.simd[0], light.color.simd[1], light.color.simd[2],
light.position.simd[0], light.position.simd[1], light.position.simd[2]);
os.format(
"lamp.retro_layer = %u\n"
"lamp.retro_origtype = %u\n"
"lamp.falloff_type = 'INVERSE_COEFFICIENTS'\n"
"lamp.constant_coefficient = 0\n"
"lamp.use_nodes = True\n"
"falloff_node = lamp.node_tree.nodes.new('ShaderNodeLightFalloff')\n"
"lamp.energy = 0.0\n"
"falloff_node.inputs[0].default_value = %f\n"
"hue_sat_node = lamp.node_tree.nodes.new('ShaderNodeHueSaturation')\n"
"hue_sat_node.inputs[1].default_value = 1.25\n"
"hue_sat_node.inputs[4].default_value = (%f,%f,%f,1.0)\n"
"lamp.node_tree.links.new(hue_sat_node.outputs[0], lamp.node_tree.nodes['Emission'].inputs[0])\n"
"lamp_obj.location = (%f,%f,%f)\n"
"bpy.context.scene.objects.link(lamp_obj)\n"
"\n",
s, light.lightType, light.q / 8.f, light.color.simd[0], light.color.simd[1], light.color.simd[2],
light.position.simd[0], light.position.simd[1], light.position.simd[2]);
switch (light.falloff)
{
case BabeDeadLight::Falloff::Constant:
os << "falloff_node.inputs[0].default_value *= 150.0\n"
"lamp.node_tree.links.new(falloff_node.outputs[2], lamp.node_tree.nodes['Emission'].inputs[1])\n";
if (light.q > FLT_EPSILON)
os.format("lamp.constant_coefficient = 2.0 / %f\n", light.q);
break;
case BabeDeadLight::Falloff::Linear:
os << "lamp.node_tree.links.new(falloff_node.outputs[1], lamp.node_tree.nodes['Emission'].inputs[1])\n";
if (light.q > FLT_EPSILON)
os.format("lamp.linear_coefficient = 250 / %f\n", light.q);
break;
case BabeDeadLight::Falloff::Quadratic:
os << "lamp.node_tree.links.new(falloff_node.outputs[0], lamp.node_tree.nodes['Emission'].inputs[1])\n";
if (light.q > FLT_EPSILON)
os.format("lamp.quadratic_coefficient = 25000 / %f\n", light.q);
break;
default: break;
}
switch (light.falloff) {
case BabeDeadLight::Falloff::Constant:
os << "falloff_node.inputs[0].default_value *= 150.0\n"
"lamp.node_tree.links.new(falloff_node.outputs[2], lamp.node_tree.nodes['Emission'].inputs[1])\n";
if (light.q > FLT_EPSILON)
os.format("lamp.constant_coefficient = 2.0 / %f\n", light.q);
break;
case BabeDeadLight::Falloff::Linear:
os << "lamp.node_tree.links.new(falloff_node.outputs[1], lamp.node_tree.nodes['Emission'].inputs[1])\n";
if (light.q > FLT_EPSILON)
os.format("lamp.linear_coefficient = 250 / %f\n", light.q);
break;
case BabeDeadLight::Falloff::Quadratic:
os << "lamp.node_tree.links.new(falloff_node.outputs[0], lamp.node_tree.nodes['Emission'].inputs[1])\n";
if (light.q > FLT_EPSILON)
os.format("lamp.quadratic_coefficient = 25000 / %f\n", light.q);
break;
default:
break;
}
}
template void ReadBabeDeadLightToBlender<DNAMP1::MREA::BabeDeadLight>
(hecl::blender::PyOutStream& os, const DNAMP1::MREA::BabeDeadLight& light, unsigned s, unsigned l);
template void ReadBabeDeadLightToBlender<DNAMP3::MREA::BabeDeadLight>
(hecl::blender::PyOutStream& os, const DNAMP3::MREA::BabeDeadLight& light, unsigned s, unsigned l);
template void ReadBabeDeadLightToBlender<DNAMP1::MREA::BabeDeadLight>(hecl::blender::PyOutStream& os,
const DNAMP1::MREA::BabeDeadLight& light,
unsigned s, unsigned l);
template void ReadBabeDeadLightToBlender<DNAMP3::MREA::BabeDeadLight>(hecl::blender::PyOutStream& os,
const DNAMP3::MREA::BabeDeadLight& light,
unsigned s, unsigned l);
template<class BabeDeadLight>
void WriteBabeDeadLightFromBlender(BabeDeadLight& lightOut, const hecl::blender::Light& lightIn)
{
using InterType = hecl::blender::Light::Type;
switch (lightIn.type)
{
case InterType::Ambient:
lightOut.lightType = BabeDeadLight::LightType::LocalAmbient;
break;
case InterType::Directional:
lightOut.lightType = BabeDeadLight::LightType::Directional;
break;
case InterType::Custom:
default:
lightOut.lightType = BabeDeadLight::LightType::Custom;
break;
case InterType::Spot:
lightOut.lightType = BabeDeadLight::LightType::Spot;
break;
}
template <class BabeDeadLight>
void WriteBabeDeadLightFromBlender(BabeDeadLight& lightOut, const hecl::blender::Light& lightIn) {
using InterType = hecl::blender::Light::Type;
switch (lightIn.type) {
case InterType::Ambient:
lightOut.lightType = BabeDeadLight::LightType::LocalAmbient;
break;
case InterType::Directional:
lightOut.lightType = BabeDeadLight::LightType::Directional;
break;
case InterType::Custom:
default:
lightOut.lightType = BabeDeadLight::LightType::Custom;
break;
case InterType::Spot:
lightOut.lightType = BabeDeadLight::LightType::Spot;
break;
}
if (lightIn.type == InterType::Ambient)
{
lightOut.falloff = BabeDeadLight::Falloff::Constant;
lightOut.q = lightIn.energy * 8.f;
}
else if (lightIn.linear > lightIn.constant &&
lightIn.linear > lightIn.quadratic)
{
lightOut.falloff = BabeDeadLight::Falloff::Linear;
lightOut.q = 250.f / lightIn.linear;
}
else if (lightIn.quadratic > lightIn.constant &&
lightIn.quadratic > lightIn.linear)
{
lightOut.falloff = BabeDeadLight::Falloff::Quadratic;
lightOut.q = 25000.f / lightIn.quadratic;
}
else
{
lightOut.falloff = BabeDeadLight::Falloff::Constant;
lightOut.q = 2.f / lightIn.constant;
}
if (lightIn.type == InterType::Ambient) {
lightOut.falloff = BabeDeadLight::Falloff::Constant;
lightOut.q = lightIn.energy * 8.f;
} else if (lightIn.linear > lightIn.constant && lightIn.linear > lightIn.quadratic) {
lightOut.falloff = BabeDeadLight::Falloff::Linear;
lightOut.q = 250.f / lightIn.linear;
} else if (lightIn.quadratic > lightIn.constant && lightIn.quadratic > lightIn.linear) {
lightOut.falloff = BabeDeadLight::Falloff::Quadratic;
lightOut.q = 25000.f / lightIn.quadratic;
} else {
lightOut.falloff = BabeDeadLight::Falloff::Constant;
lightOut.q = 2.f / lightIn.constant;
}
lightOut.color = lightIn.color;
lightOut.spotCutoff = zeus::radToDeg(lightIn.spotCutoff);
lightOut.castShadows = lightIn.shadow;
lightOut.position.simd[0] = lightIn.sceneXf[0].simd[3];
lightOut.position.simd[1] = lightIn.sceneXf[1].simd[3];
lightOut.position.simd[2] = lightIn.sceneXf[2].simd[3];
lightOut.color = lightIn.color;
lightOut.spotCutoff = zeus::radToDeg(lightIn.spotCutoff);
lightOut.castShadows = lightIn.shadow;
lightOut.position.simd[0] = lightIn.sceneXf[0].simd[3];
lightOut.position.simd[1] = lightIn.sceneXf[1].simd[3];
lightOut.position.simd[2] = lightIn.sceneXf[2].simd[3];
zeus::CTransform lightXf(&lightIn.sceneXf[0]);
lightOut.direction = (lightXf.basis.transposed() * zeus::CVector3f(0.f, 0.f, -1.f)).normalized();
zeus::CTransform lightXf(&lightIn.sceneXf[0]);
lightOut.direction = (lightXf.basis.transposed() * zeus::CVector3f(0.f, 0.f, -1.f)).normalized();
}
template void WriteBabeDeadLightFromBlender<DNAMP1::MREA::BabeDeadLight>
(DNAMP1::MREA::BabeDeadLight& lightOut, const hecl::blender::Light& lightIn);
template void WriteBabeDeadLightFromBlender<DNAMP3::MREA::BabeDeadLight>
(DNAMP3::MREA::BabeDeadLight& lightOut, const hecl::blender::Light& lightIn);
template void WriteBabeDeadLightFromBlender<DNAMP1::MREA::BabeDeadLight>(DNAMP1::MREA::BabeDeadLight& lightOut,
const hecl::blender::Light& lightIn);
template void WriteBabeDeadLightFromBlender<DNAMP3::MREA::BabeDeadLight>(DNAMP3::MREA::BabeDeadLight& lightOut,
const hecl::blender::Light& lightIn);
}
} // namespace DataSpec

View File

@ -4,15 +4,12 @@
#include "hecl/hecl.hpp"
#include <cfloat>
namespace DataSpec
{
namespace DataSpec {
template<class BabeDeadLight>
void ReadBabeDeadLightToBlender(hecl::blender::PyOutStream& os,
const BabeDeadLight& light, unsigned s, unsigned l);
template <class BabeDeadLight>
void ReadBabeDeadLightToBlender(hecl::blender::PyOutStream& os, const BabeDeadLight& light, unsigned s, unsigned l);
template<class BabeDeadLight>
template <class BabeDeadLight>
void WriteBabeDeadLightFromBlender(BabeDeadLight& lightOut, const hecl::blender::Light& lightIn);
}
} // namespace DataSpec

File diff suppressed because it is too large Load Diff

View File

@ -8,165 +8,144 @@
#include "TXTR.hpp"
#include "zeus/CAABox.hpp"
namespace DataSpec::DNACMDL
{
namespace DataSpec::DNACMDL {
using Mesh = hecl::blender::Mesh;
using Material = hecl::blender::Material;
struct Header : BigDNA
{
struct Header : BigDNA {
AT_DECL_DNA
Value<atUint32> magic;
Value<atUint32> version;
struct Flags : BigDNA {
AT_DECL_DNA
Value<atUint32> magic;
Value<atUint32> version;
struct Flags : BigDNA
{
AT_DECL_DNA
Value<atUint32> flags = 0;
bool skinned() const {return (flags & 0x1) != 0;}
void setSkinned(bool val) {flags &= ~0x1; flags |= val;}
bool shortNormals() const {return (flags & 0x2) != 0;}
void setShortNormals(bool val) {flags &= ~0x2; flags |= val << 1;}
bool shortUVs() const {return (flags & 0x4) != 0;}
void setShortUVs(bool val) {flags &= ~0x4; flags |= val << 2;}
} flags;
Value<atVec3f> aabbMin;
Value<atVec3f> aabbMax;
Value<atUint32> secCount;
Value<atUint32> matSetCount;
Vector<atUint32, AT_DNA_COUNT(secCount)> secSizes;
Align<32> align;
Value<atUint32> flags = 0;
bool skinned() const { return (flags & 0x1) != 0; }
void setSkinned(bool val) {
flags &= ~0x1;
flags |= val;
}
bool shortNormals() const { return (flags & 0x2) != 0; }
void setShortNormals(bool val) {
flags &= ~0x2;
flags |= val << 1;
}
bool shortUVs() const { return (flags & 0x4) != 0; }
void setShortUVs(bool val) {
flags &= ~0x4;
flags |= val << 2;
}
} flags;
Value<atVec3f> aabbMin;
Value<atVec3f> aabbMax;
Value<atUint32> secCount;
Value<atUint32> matSetCount;
Vector<atUint32, AT_DNA_COUNT(secCount)> secSizes;
Align<32> align;
};
struct SurfaceHeader_1 : BigDNA
{
AT_DECL_EXPLICIT_DNA
Value<atVec3f> centroid;
Value<atUint32> matIdx = 0;
Value<atUint32> dlSize = 0;
Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */
Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */
Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal;
Value<atVec3f> aabb[2];
Align<32> align;
struct SurfaceHeader_1 : BigDNA {
AT_DECL_EXPLICIT_DNA
Value<atVec3f> centroid;
Value<atUint32> matIdx = 0;
Value<atUint32> dlSize = 0;
Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */
Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */
Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal;
Value<atVec3f> aabb[2];
Align<32> align;
static constexpr bool UseMatrixSkinning() {return false;}
static constexpr atInt16 skinMatrixBankIdx() {return -1;}
static constexpr bool UseMatrixSkinning() { return false; }
static constexpr atInt16 skinMatrixBankIdx() { return -1; }
};
struct SurfaceHeader_2 : BigDNA
{
AT_DECL_EXPLICIT_DNA
Value<atVec3f> centroid;
Value<atUint32> matIdx = 0;
Value<atUint32> dlSize = 0;
Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */
Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */
Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal;
Value<atInt16> skinMtxBankIdx;
Value<atUint16> surfaceGroup;
Value<atVec3f> aabb[2];
Align<32> align;
struct SurfaceHeader_2 : BigDNA {
AT_DECL_EXPLICIT_DNA
Value<atVec3f> centroid;
Value<atUint32> matIdx = 0;
Value<atUint32> dlSize = 0;
Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */
Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */
Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal;
Value<atInt16> skinMtxBankIdx;
Value<atUint16> surfaceGroup;
Value<atVec3f> aabb[2];
Align<32> align;
static constexpr bool UseMatrixSkinning() {return false;}
atInt16 skinMatrixBankIdx() const {return skinMtxBankIdx;}
static constexpr bool UseMatrixSkinning() { return false; }
atInt16 skinMatrixBankIdx() const { return skinMtxBankIdx; }
};
struct SurfaceHeader_3 : BigDNA
{
AT_DECL_EXPLICIT_DNA
Value<atVec3f> centroid;
Value<atUint32> matIdx = 0;
Value<atUint32> dlSize = 0;
Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */
Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */
Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal;
Value<atInt16> skinMtxBankIdx;
Value<atUint16> surfaceGroup;
Value<atVec3f> aabb[2];
Value<atUint8> unk3;
Align<32> align;
struct SurfaceHeader_3 : BigDNA {
AT_DECL_EXPLICIT_DNA
Value<atVec3f> centroid;
Value<atUint32> matIdx = 0;
Value<atUint32> dlSize = 0;
Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */
Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */
Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal;
Value<atInt16> skinMtxBankIdx;
Value<atUint16> surfaceGroup;
Value<atVec3f> aabb[2];
Value<atUint8> unk3;
Align<32> align;
static constexpr bool UseMatrixSkinning() {return true;}
atInt16 skinMatrixBankIdx() const {return skinMtxBankIdx;}
static constexpr bool UseMatrixSkinning() { return true; }
atInt16 skinMatrixBankIdx() const { return skinMtxBankIdx; }
};
struct VertexAttributes
{
GX::AttrType pos = GX::NONE;
GX::AttrType norm = GX::NONE;
GX::AttrType color0 = GX::NONE;
GX::AttrType color1 = GX::NONE;
unsigned uvCount = 0;
GX::AttrType uvs[7] = {GX::NONE};
GX::AttrType pnMtxIdx = GX::NONE;
unsigned texMtxIdxCount = 0;
GX::AttrType texMtxIdx[7] = {GX::NONE};
bool shortUVs;
struct VertexAttributes {
GX::AttrType pos = GX::NONE;
GX::AttrType norm = GX::NONE;
GX::AttrType color0 = GX::NONE;
GX::AttrType color1 = GX::NONE;
unsigned uvCount = 0;
GX::AttrType uvs[7] = {GX::NONE};
GX::AttrType pnMtxIdx = GX::NONE;
unsigned texMtxIdxCount = 0;
GX::AttrType texMtxIdx[7] = {GX::NONE};
bool shortUVs;
};
template <class MaterialSet>
void GetVertexAttributes(const MaterialSet& matSet,
std::vector<VertexAttributes>& attributesOut);
void GetVertexAttributes(const MaterialSet& matSet, std::vector<VertexAttributes>& attributesOut);
template <class PAKRouter, class MaterialSet>
void ReadMaterialSetToBlender_1_2(hecl::blender::PyOutStream& os,
const MaterialSet& matSet,
const PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
unsigned setIdx);
void ReadMaterialSetToBlender_1_2(hecl::blender::PyOutStream& os, const MaterialSet& matSet, const PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry, unsigned setIdx);
template <class PAKRouter, class MaterialSet>
void ReadMaterialSetToBlender_3(hecl::blender::PyOutStream& os,
const MaterialSet& matSet,
const PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
unsigned setIdx);
void ReadMaterialSetToBlender_3(hecl::blender::PyOutStream& os, const MaterialSet& matSet, const PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry, unsigned setIdx);
void InitGeomBlenderContext(hecl::blender::PyOutStream& os,
const hecl::ProjectPath& masterShaderPath,
void InitGeomBlenderContext(hecl::blender::PyOutStream& os, const hecl::ProjectPath& masterShaderPath,
bool solidShading);
void FinishBlenderMesh(hecl::blender::PyOutStream& os,
unsigned matSetCount, int meshIdx);
void FinishBlenderMesh(hecl::blender::PyOutStream& os, unsigned matSetCount, int meshIdx);
template <class PAKRouter, class MaterialSet, class RigPair, class SurfaceHeader>
atUint32 ReadGeomSectionsToBlender(hecl::blender::PyOutStream& os,
athena::io::IStreamReader& reader,
PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
const RigPair& rp,
bool shortNormals,
bool shortUVs,
std::vector<VertexAttributes>& vertAttribs,
int meshIdx,
atUint32 secCount,
atUint32 matSetCount,
const atUint32* secSizes,
atUint32 surfaceCount=0);
atUint32 ReadGeomSectionsToBlender(hecl::blender::PyOutStream& os, athena::io::IStreamReader& reader,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const RigPair& rp,
bool shortNormals, bool shortUVs, std::vector<VertexAttributes>& vertAttribs,
int meshIdx, atUint32 secCount, atUint32 matSetCount, const atUint32* secSizes,
atUint32 surfaceCount = 0);
template <class PAKRouter, class MaterialSet, class RigPair, class SurfaceHeader, atUint32 Version>
bool ReadCMDLToBlender(hecl::blender::Connection& conn,
athena::io::IStreamReader& reader,
PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry,
const SpecBase& dataspec,
const RigPair& rp);
bool ReadCMDLToBlender(hecl::blender::Connection& conn, athena::io::IStreamReader& reader, PAKRouter& pakRouter,
const typename PAKRouter::EntryType& entry, const SpecBase& dataspec, const RigPair& rp);
template <class PAKRouter, class MaterialSet>
void NameCMDL(athena::io::IStreamReader& reader,
PAKRouter& pakRouter,
typename PAKRouter::EntryType& entry,
void NameCMDL(athena::io::IStreamReader& reader, PAKRouter& pakRouter, typename PAKRouter::EntryType& entry,
const SpecBase& dataspec);
template <class MaterialSet, class SurfaceHeader, atUint32 Version>
bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh);
template <class MaterialSet, class SurfaceHeader, atUint32 Version>
bool WriteHMDLCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath,
const Mesh& mesh, hecl::blender::PoolSkinIndex& poolSkinIndex);
bool WriteHMDLCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh,
hecl::blender::PoolSkinIndex& poolSkinIndex);
template <class MaterialSet, class SurfaceHeader, class MeshHeader>
bool WriteMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
@ -176,5 +155,4 @@ template <class MaterialSet, class SurfaceHeader, class MeshHeader>
bool WriteHMDLMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
const std::vector<Mesh>& meshes, zeus::CAABox& fullAABB, std::vector<zeus::CAABox>& meshAABBs);
}
} // namespace DataSpec::DNACMDL

View File

@ -1,341 +1,268 @@
#include "CRSC.hpp"
namespace DataSpec::DNAParticle
{
static const std::vector<FourCC> GeneratorTypes =
{
SBIG('NODP'),SBIG('DEFS'),SBIG('CRTS'),SBIG('MTLS'),
SBIG('GRAS'),SBIG('ICEE'),SBIG('GOOO'),SBIG('WODS'),
SBIG('WATR'),SBIG('1MUD'),SBIG('1LAV'),SBIG('1SAN'),
SBIG('1PRJ'),SBIG('DCHR'),SBIG('DCHS'),SBIG('DCSH'),
SBIG('DENM'),SBIG('DESP'),SBIG('DESH'),SBIG('BTLE'),
SBIG('WASP'),SBIG('TALP'),SBIG('PTGM'),SBIG('SPIR'),
SBIG('FPIR'),SBIG('FFLE'),SBIG('PARA'),SBIG('BMON'),
SBIG('BFLR'),SBIG('PBOS'),SBIG('IBOS'),SBIG('1SVA'),
SBIG('1RPR'),SBIG('1MTR'),SBIG('1PDS'),SBIG('1FLB'),
SBIG('1DRN'),SBIG('1MRE'),SBIG('CHOZ'),SBIG('JZAP'),
SBIG('1ISE'),SBIG('1BSE'),SBIG('1ATB'),SBIG('1ATA'),
SBIG('BTSP'),SBIG('WWSP'),SBIG('TASP'),SBIG('TGSP'),
SBIG('SPSP'),SBIG('FPSP'),SBIG('FFSP'),SBIG('PSSP'),
SBIG('BMSP'),SBIG('BFSP'),SBIG('PBSP'),SBIG('IBSP'),
SBIG('2SVA'),SBIG('2RPR'),SBIG('2MTR'),SBIG('2PDS'),
SBIG('2FLB'),SBIG('2DRN'),SBIG('2MRE'),SBIG('CHSP'),
SBIG('JZSP'),SBIG('3ISE'),SBIG('3BSE'),SBIG('3ATB'),
SBIG('3ATA'),SBIG('BTSH'),SBIG('WWSH'),SBIG('TASH'),
SBIG('TGSH'),SBIG('SPSH'),SBIG('FPSH'),SBIG('FFSH'),
SBIG('PSSH'),SBIG('BMSH'),SBIG('BFSH'),SBIG('PBSH'),
SBIG('IBSH'),SBIG('3SVA'),SBIG('3RPR'),SBIG('3MTR'),
SBIG('3PDS'),SBIG('3FLB'),SBIG('3DRN'),SBIG('3MRE'),
SBIG('CHSH'),SBIG('JZSH'),SBIG('5ISE'),SBIG('5BSE'),
SBIG('5ATB'),SBIG('5ATA')
namespace DataSpec::DNAParticle {
static const std::vector<FourCC> GeneratorTypes = {
SBIG('NODP'), SBIG('DEFS'), SBIG('CRTS'), SBIG('MTLS'), SBIG('GRAS'), SBIG('ICEE'), SBIG('GOOO'), SBIG('WODS'),
SBIG('WATR'), SBIG('1MUD'), SBIG('1LAV'), SBIG('1SAN'), SBIG('1PRJ'), SBIG('DCHR'), SBIG('DCHS'), SBIG('DCSH'),
SBIG('DENM'), SBIG('DESP'), SBIG('DESH'), SBIG('BTLE'), SBIG('WASP'), SBIG('TALP'), SBIG('PTGM'), SBIG('SPIR'),
SBIG('FPIR'), SBIG('FFLE'), SBIG('PARA'), SBIG('BMON'), SBIG('BFLR'), SBIG('PBOS'), SBIG('IBOS'), SBIG('1SVA'),
SBIG('1RPR'), SBIG('1MTR'), SBIG('1PDS'), SBIG('1FLB'), SBIG('1DRN'), SBIG('1MRE'), SBIG('CHOZ'), SBIG('JZAP'),
SBIG('1ISE'), SBIG('1BSE'), SBIG('1ATB'), SBIG('1ATA'), SBIG('BTSP'), SBIG('WWSP'), SBIG('TASP'), SBIG('TGSP'),
SBIG('SPSP'), SBIG('FPSP'), SBIG('FFSP'), SBIG('PSSP'), SBIG('BMSP'), SBIG('BFSP'), SBIG('PBSP'), SBIG('IBSP'),
SBIG('2SVA'), SBIG('2RPR'), SBIG('2MTR'), SBIG('2PDS'), SBIG('2FLB'), SBIG('2DRN'), SBIG('2MRE'), SBIG('CHSP'),
SBIG('JZSP'), SBIG('3ISE'), SBIG('3BSE'), SBIG('3ATB'), SBIG('3ATA'), SBIG('BTSH'), SBIG('WWSH'), SBIG('TASH'),
SBIG('TGSH'), SBIG('SPSH'), SBIG('FPSH'), SBIG('FFSH'), SBIG('PSSH'), SBIG('BMSH'), SBIG('BFSH'), SBIG('PBSH'),
SBIG('IBSH'), SBIG('3SVA'), SBIG('3RPR'), SBIG('3MTR'), SBIG('3PDS'), SBIG('3FLB'), SBIG('3DRN'), SBIG('3MRE'),
SBIG('CHSH'), SBIG('JZSH'), SBIG('5ISE'), SBIG('5BSE'), SBIG('5ATB'), SBIG('5ATA')};
static const std::vector<FourCC> SFXTypes = {
SBIG('DSFX'), SBIG('CSFX'), SBIG('MSFX'), SBIG('GRFX'), SBIG('NSFX'), SBIG('DSFX'), SBIG('CSFX'), SBIG('MSFX'),
SBIG('GRFX'), SBIG('ICFX'), SBIG('GOFX'), SBIG('WSFX'), SBIG('WTFX'), SBIG('2MUD'), SBIG('2LAV'), SBIG('2SAN'),
SBIG('2PRJ'), SBIG('DCFX'), SBIG('DSFX'), SBIG('DSHX'), SBIG('DEFX'), SBIG('ESFX'), SBIG('SHFX'), SBIG('BEFX'),
SBIG('WWFX'), SBIG('TAFX'), SBIG('GTFX'), SBIG('SPFX'), SBIG('FPFX'), SBIG('FFFX'), SBIG('PAFX'), SBIG('BMFX'),
SBIG('BFFX'), SBIG('PBFX'), SBIG('IBFX'), SBIG('4SVA'), SBIG('4RPR'), SBIG('4MTR'), SBIG('4PDS'), SBIG('4FLB'),
SBIG('4DRN'), SBIG('4MRE'), SBIG('CZFX'), SBIG('JZAS'), SBIG('2ISE'), SBIG('2BSE'), SBIG('2ATB'), SBIG('2ATA'),
SBIG('BSFX'), SBIG('WSFX'), SBIG('TSFX'), SBIG('GSFX'), SBIG('SSFX'), SBIG('FSFX'), SBIG('SFFX'), SBIG('PSFX'),
SBIG('MSFX'), SBIG('SBFX'), SBIG('PBSX'), SBIG('IBSX'), SBIG('5SVA'), SBIG('5RPR'), SBIG('5MTR'), SBIG('5PDS'),
SBIG('5FLB'), SBIG('5DRN'), SBIG('5MRE'), SBIG('CSFX'), SBIG('JZPS'), SBIG('4ISE'), SBIG('4BSE'), SBIG('4ATB'),
SBIG('4ATA'), SBIG('BHFX'), SBIG('WHFX'), SBIG('THFX'), SBIG('GHFX'), SBIG('SHFX'), SBIG('FHFX'), SBIG('HFFX'),
SBIG('PHFX'), SBIG('MHFX'), SBIG('HBFX'), SBIG('PBHX'), SBIG('IBHX'), SBIG('6SVA'), SBIG('6RPR'), SBIG('6MTR'),
SBIG('6PDS'), SBIG('6FLB'), SBIG('6DRN'), SBIG('6MRE'), SBIG('CHFX'), SBIG('JZHS'), SBIG('6ISE'), SBIG('6BSE'),
SBIG('6ATB'), SBIG('6ATA'),
};
static const std::vector<FourCC> SFXTypes =
{
SBIG('DSFX'),SBIG('CSFX'),SBIG('MSFX'),SBIG('GRFX'),
SBIG('NSFX'),SBIG('DSFX'),SBIG('CSFX'),SBIG('MSFX'),
SBIG('GRFX'),SBIG('ICFX'),SBIG('GOFX'),SBIG('WSFX'),
SBIG('WTFX'),SBIG('2MUD'),SBIG('2LAV'),SBIG('2SAN'),
SBIG('2PRJ'),SBIG('DCFX'),SBIG('DSFX'),SBIG('DSHX'),
SBIG('DEFX'),SBIG('ESFX'),SBIG('SHFX'),SBIG('BEFX'),
SBIG('WWFX'),SBIG('TAFX'),SBIG('GTFX'),SBIG('SPFX'),
SBIG('FPFX'),SBIG('FFFX'),SBIG('PAFX'),SBIG('BMFX'),
SBIG('BFFX'),SBIG('PBFX'),SBIG('IBFX'),SBIG('4SVA'),
SBIG('4RPR'),SBIG('4MTR'),SBIG('4PDS'),SBIG('4FLB'),
SBIG('4DRN'),SBIG('4MRE'),SBIG('CZFX'),SBIG('JZAS'),
SBIG('2ISE'),SBIG('2BSE'),SBIG('2ATB'),SBIG('2ATA'),
SBIG('BSFX'),SBIG('WSFX'),SBIG('TSFX'),SBIG('GSFX'),
SBIG('SSFX'),SBIG('FSFX'),SBIG('SFFX'),SBIG('PSFX'),
SBIG('MSFX'),SBIG('SBFX'),SBIG('PBSX'),SBIG('IBSX'),
SBIG('5SVA'),SBIG('5RPR'),SBIG('5MTR'),SBIG('5PDS'),
SBIG('5FLB'),SBIG('5DRN'),SBIG('5MRE'),SBIG('CSFX'),
SBIG('JZPS'),SBIG('4ISE'),SBIG('4BSE'),SBIG('4ATB'),
SBIG('4ATA'),SBIG('BHFX'),SBIG('WHFX'),SBIG('THFX'),
SBIG('GHFX'),SBIG('SHFX'),SBIG('FHFX'),SBIG('HFFX'),
SBIG('PHFX'),SBIG('MHFX'),SBIG('HBFX'),SBIG('PBHX'),
SBIG('IBHX'),SBIG('6SVA'),SBIG('6RPR'),SBIG('6MTR'),
SBIG('6PDS'),SBIG('6FLB'),SBIG('6DRN'),SBIG('6MRE'),
SBIG('CHFX'),SBIG('JZHS'),SBIG('6ISE'),SBIG('6BSE'),
SBIG('6ATB'),SBIG('6ATA'),
};
static const std::vector<FourCC> DecalTypes =
{
SBIG('NCDL'),SBIG('DDCL'),SBIG('CODL'),SBIG('MEDL'),
SBIG('GRDL'),SBIG('ICDL'),SBIG('GODL'),SBIG('WODL'),
SBIG('WTDL'),SBIG('3MUD'),SBIG('3LAV'),SBIG('3SAN'),
SBIG('CHDL'),SBIG('ENDL')
};
static const std::vector<FourCC> DecalTypes = {SBIG('NCDL'), SBIG('DDCL'), SBIG('CODL'), SBIG('MEDL'), SBIG('GRDL'),
SBIG('ICDL'), SBIG('GODL'), SBIG('WODL'), SBIG('WTDL'), SBIG('3MUD'),
SBIG('3LAV'), SBIG('3SAN'), SBIG('CHDL'), SBIG('ENDL')};
template <>
const char* CRSM<UniqueID32>::DNAType() { return "CRSM<UniqueID32>"; }
const char* CRSM<UniqueID32>::DNAType() {
return "CRSM<UniqueID32>";
}
template <>
const char* CRSM<UniqueID64>::DNAType() { return "CRSM<UniqueID64>"; }
template <class IDType>
void CRSM<IDType>::_read(athena::io::YAMLDocReader& r)
{
for (const auto& elem : r.getCurNode()->m_mapChildren)
{
if (elem.first.size() < 4)
{
LogModule.report(logvisor::Warning, "short FourCC in element '%s'", elem.first.c_str());
continue;
}
if (auto rec = r.enterSubRecord(elem.first.c_str()))
{
FourCC clsId(elem.first.c_str());
auto gen = std::find_if(GeneratorTypes.begin(), GeneratorTypes.end(), [&clsId](const FourCC& other) -> bool{
return clsId == other;
});
if (gen != GeneratorTypes.end())
{
x0_generators[clsId].read(r);
continue;
}
auto sfx = std::find_if(SFXTypes.begin(), SFXTypes.end(), [&clsId](const FourCC& other) -> bool{
return clsId == other;
});
if (sfx != SFXTypes.end())
{
x10_sfx[clsId] = r.readInt32(clsId.toString().c_str());
continue;
}
auto decal = std::find_if(DecalTypes.begin(), DecalTypes.end(), [&clsId](const FourCC& other) -> bool{
return clsId == other;
});
if (decal != DecalTypes.end())
{
x20_decals[clsId].read(r);
continue;
}
if (clsId == SBIG('RNGE'))
x30_RNGE = r.readFloat(nullptr);
else if (clsId == SBIG('FOFF'))
x34_FOFF = r.readFloat(nullptr);
}
}
const char* CRSM<UniqueID64>::DNAType() {
return "CRSM<UniqueID64>";
}
template <class IDType>
void CRSM<IDType>::_write(athena::io::YAMLDocWriter& w) const
{
for (const auto& pair : x0_generators)
if (pair.second)
if (auto rec = w.enterSubRecord(pair.first.toString().c_str()))
pair.second.write(w);
void CRSM<IDType>::_read(athena::io::YAMLDocReader& r) {
for (const auto& elem : r.getCurNode()->m_mapChildren) {
if (elem.first.size() < 4) {
LogModule.report(logvisor::Warning, "short FourCC in element '%s'", elem.first.c_str());
continue;
}
for (const auto& pair : x10_sfx)
if (pair.second != ~0)
w.writeUint32(pair.first.toString().c_str(), pair.second);
if (auto rec = r.enterSubRecord(elem.first.c_str())) {
FourCC clsId(elem.first.c_str());
auto gen = std::find_if(GeneratorTypes.begin(), GeneratorTypes.end(),
[&clsId](const FourCC& other) -> bool { return clsId == other; });
if (gen != GeneratorTypes.end()) {
x0_generators[clsId].read(r);
continue;
}
for (const auto& pair : x20_decals)
if (pair.second)
if (auto rec = w.enterSubRecord(pair.first.toString().c_str()))
pair.second.write(w);
auto sfx = std::find_if(SFXTypes.begin(), SFXTypes.end(),
[&clsId](const FourCC& other) -> bool { return clsId == other; });
if (sfx != SFXTypes.end()) {
x10_sfx[clsId] = r.readInt32(clsId.toString().c_str());
continue;
}
if (x30_RNGE != 50.f)
w.writeFloat("RNGE", x30_RNGE);
if (x34_FOFF != 0.2f)
w.writeFloat("FOFF", x34_FOFF);
auto decal = std::find_if(DecalTypes.begin(), DecalTypes.end(),
[&clsId](const FourCC& other) -> bool { return clsId == other; });
if (decal != DecalTypes.end()) {
x20_decals[clsId].read(r);
continue;
}
if (clsId == SBIG('RNGE'))
x30_RNGE = r.readFloat(nullptr);
else if (clsId == SBIG('FOFF'))
x34_FOFF = r.readFloat(nullptr);
}
}
}
template <class IDType>
void CRSM<IDType>::_binarySize(size_t& __isz) const
{
__isz += 4;
for (const auto& pair : x0_generators)
{
if (pair.second)
{
__isz += 4;
pair.second.binarySize(__isz);
}
}
for (const auto& pair : x10_sfx)
{
if (pair.second != ~0)
__isz += 12;
}
void CRSM<IDType>::_write(athena::io::YAMLDocWriter& w) const {
for (const auto& pair : x0_generators)
if (pair.second)
if (auto rec = w.enterSubRecord(pair.first.toString().c_str()))
pair.second.write(w);
for (const auto& pair : x20_decals)
{
if (pair.second)
{
__isz += 4;
pair.second.binarySize(__isz);
}
}
for (const auto& pair : x10_sfx)
if (pair.second != ~0)
w.writeUint32(pair.first.toString().c_str(), pair.second);
if (x30_RNGE != 50.f)
__isz += 12;
if (x34_FOFF != 0.2f)
__isz += 12;
for (const auto& pair : x20_decals)
if (pair.second)
if (auto rec = w.enterSubRecord(pair.first.toString().c_str()))
pair.second.write(w);
if (x30_RNGE != 50.f)
w.writeFloat("RNGE", x30_RNGE);
if (x34_FOFF != 0.2f)
w.writeFloat("FOFF", x34_FOFF);
}
template <class IDType>
void CRSM<IDType>::_read(athena::io::IStreamReader &r)
{
uint32_t clsId;
void CRSM<IDType>::_binarySize(size_t& __isz) const {
__isz += 4;
for (const auto& pair : x0_generators) {
if (pair.second) {
__isz += 4;
pair.second.binarySize(__isz);
}
}
for (const auto& pair : x10_sfx) {
if (pair.second != ~0)
__isz += 12;
}
for (const auto& pair : x20_decals) {
if (pair.second) {
__isz += 4;
pair.second.binarySize(__isz);
}
}
if (x30_RNGE != 50.f)
__isz += 12;
if (x34_FOFF != 0.2f)
__isz += 12;
}
template <class IDType>
void CRSM<IDType>::_read(athena::io::IStreamReader& r) {
uint32_t clsId;
r.readBytesToBuf(&clsId, 4);
if (clsId != SBIG('CRSM')) {
LogModule.report(logvisor::Warning, "non CRSM provided to CRSM parser");
return;
}
while (clsId != SBIG('_END')) {
r.readBytesToBuf(&clsId, 4);
if (clsId != SBIG('CRSM'))
{
LogModule.report(logvisor::Warning, "non CRSM provided to CRSM parser");
return;
auto gen = std::find_if(GeneratorTypes.begin(), GeneratorTypes.end(),
[&clsId](const FourCC& other) -> bool { return clsId == other; });
if (gen != GeneratorTypes.end()) {
x0_generators[clsId].read(r);
continue;
}
while (clsId != SBIG('_END'))
{
r.readBytesToBuf(&clsId, 4);
auto gen = std::find_if(GeneratorTypes.begin(), GeneratorTypes.end(), [&clsId](const FourCC& other) -> bool{
return clsId == other;
});
if (gen != GeneratorTypes.end())
{
x0_generators[clsId].read(r);
continue;
}
auto sfx = std::find_if(SFXTypes.begin(), SFXTypes.end(), [&clsId](const FourCC& other) -> bool{
return clsId == other;
});
if (sfx != SFXTypes.end())
{
uint32_t fcc;
r.readBytesToBuf(&fcc, 4);
if (fcc != SBIG('NONE'))
x10_sfx[clsId] = r.readInt32Big();
else
x10_sfx[clsId] = ~0;
continue;
}
auto decal = std::find_if(DecalTypes.begin(), DecalTypes.end(), [&clsId](const FourCC& other) -> bool{
return clsId == other;
});
if (decal != DecalTypes.end())
{
x20_decals[clsId].read(r);
continue;
}
if (clsId == SBIG('RNGE'))
{
r.readUint32();
x30_RNGE = r.readFloatBig();
continue;
}
if (clsId == SBIG('FOFF'))
{
r.readUint32();
x34_FOFF = r.readFloatBig();
continue;
}
if (clsId != SBIG('_END'))
LogModule.report(logvisor::Fatal, "Unknown CRSM class %.4s @%" PRIi64, &clsId, r.position());
auto sfx = std::find_if(SFXTypes.begin(), SFXTypes.end(),
[&clsId](const FourCC& other) -> bool { return clsId == other; });
if (sfx != SFXTypes.end()) {
uint32_t fcc;
r.readBytesToBuf(&fcc, 4);
if (fcc != SBIG('NONE'))
x10_sfx[clsId] = r.readInt32Big();
else
x10_sfx[clsId] = ~0;
continue;
}
auto decal = std::find_if(DecalTypes.begin(), DecalTypes.end(),
[&clsId](const FourCC& other) -> bool { return clsId == other; });
if (decal != DecalTypes.end()) {
x20_decals[clsId].read(r);
continue;
}
if (clsId == SBIG('RNGE')) {
r.readUint32();
x30_RNGE = r.readFloatBig();
continue;
}
if (clsId == SBIG('FOFF')) {
r.readUint32();
x34_FOFF = r.readFloatBig();
continue;
}
if (clsId != SBIG('_END'))
LogModule.report(logvisor::Fatal, "Unknown CRSM class %.4s @%" PRIi64, &clsId, r.position());
}
}
template <class IDType>
void CRSM<IDType>::_write(athena::io::IStreamWriter& w) const
{
w.writeBytes("CRSM", 4);
for (const auto& pair : x0_generators)
{
w.writeBytes(pair.first.getChars(), 4);
pair.second.write(w);
}
void CRSM<IDType>::_write(athena::io::IStreamWriter& w) const {
w.writeBytes("CRSM", 4);
for (const auto& pair : x0_generators) {
w.writeBytes(pair.first.getChars(), 4);
pair.second.write(w);
}
for (const auto& pair : x10_sfx)
{
w.writeBytes(pair.first.getChars(), 4);
if (pair.second != ~0)
{
w.writeBytes("CNST", 4);
w.writeUint32Big(pair.second);
}
else
{
w.writeBytes("NONE", 4);
}
for (const auto& pair : x10_sfx) {
w.writeBytes(pair.first.getChars(), 4);
if (pair.second != ~0) {
w.writeBytes("CNST", 4);
w.writeUint32Big(pair.second);
} else {
w.writeBytes("NONE", 4);
}
}
for (const auto& pair : x20_decals)
{
w.writeBytes(pair.first.getChars(), 4);
pair.second.write(w);
}
for (const auto& pair : x20_decals) {
w.writeBytes(pair.first.getChars(), 4);
pair.second.write(w);
}
if (x30_RNGE != 50.f)
{
w.writeBytes("RNGECNST", 8);
w.writeFloatBig(x30_RNGE);
}
if (x34_FOFF != 0.2f)
{
w.writeBytes("FOFFCNST", 8);
w.writeFloatBig(x34_FOFF);
}
w.writeBytes("_END", 4);
if (x30_RNGE != 50.f) {
w.writeBytes("RNGECNST", 8);
w.writeFloatBig(x30_RNGE);
}
if (x34_FOFF != 0.2f) {
w.writeBytes("FOFFCNST", 8);
w.writeFloatBig(x34_FOFF);
}
w.writeBytes("_END", 4);
}
AT_SUBSPECIALIZE_DNA_YAML(CRSM<UniqueID32>)
AT_SUBSPECIALIZE_DNA_YAML(CRSM<UniqueID64>)
template <class IDType>
void CRSM<IDType>::gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
{
for (const auto& p : x0_generators)
g_curSpec->flattenDependencies(p.second.id, pathsOut);
for (const auto& p : x20_decals)
g_curSpec->flattenDependencies(p.second.id, pathsOut);
void CRSM<IDType>::gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const {
for (const auto& p : x0_generators)
g_curSpec->flattenDependencies(p.second.id, pathsOut);
for (const auto& p : x20_decals)
g_curSpec->flattenDependencies(p.second.id, pathsOut);
}
template <class IDType>
CRSM<IDType>::CRSM()
: x30_RNGE(50.f),
x34_FOFF(0.2f)
{
for (const auto& sfx : SFXTypes)
x10_sfx[sfx] = ~0;
CRSM<IDType>::CRSM() : x30_RNGE(50.f), x34_FOFF(0.2f) {
for (const auto& sfx : SFXTypes)
x10_sfx[sfx] = ~0;
}
template struct CRSM<UniqueID32>;
template struct CRSM<UniqueID64>;
template <class IDType>
bool ExtractCRSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath)
{
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen())
{
CRSM<IDType> crsm;
crsm.read(rs);
athena::io::ToYAMLStream(crsm, writer);
return true;
}
return false;
bool ExtractCRSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
CRSM<IDType> crsm;
crsm.read(rs);
athena::io::ToYAMLStream(crsm, writer);
return true;
}
return false;
}
template bool ExtractCRSM<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractCRSM<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteCRSM(const CRSM<IDType>& crsm, const hecl::ProjectPath& outPath)
{
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
crsm.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i=0 ; i<32-rem ; ++i)
w.writeUByte(0xff);
return true;
bool WriteCRSM(const CRSM<IDType>& crsm, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
crsm.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteCRSM<UniqueID32>(const CRSM<UniqueID32>& crsm, const hecl::ProjectPath& outPath);
template bool WriteCRSM<UniqueID64>(const CRSM<UniqueID64>& crsm, const hecl::ProjectPath& outPath);
}
} // namespace DataSpec::DNAParticle

View File

@ -5,26 +5,24 @@
#include "athena/FileWriter.hpp"
#include "optional.hpp"
namespace DataSpec::DNAParticle
{
namespace DataSpec::DNAParticle {
template <class IDType>
struct CRSM : BigDNA
{
AT_DECL_EXPLICIT_DNA_YAML
AT_SUBDECL_DNA
std::unordered_map<FourCC, ChildResourceFactory<IDType>> x0_generators;
std::unordered_map<FourCC, uint32_t> x10_sfx;
std::unordered_map<FourCC, ChildResourceFactory<IDType>> x20_decals;
float x30_RNGE;
float x34_FOFF;
struct CRSM : BigDNA {
AT_DECL_EXPLICIT_DNA_YAML
AT_SUBDECL_DNA
std::unordered_map<FourCC, ChildResourceFactory<IDType>> x0_generators;
std::unordered_map<FourCC, uint32_t> x10_sfx;
std::unordered_map<FourCC, ChildResourceFactory<IDType>> x20_decals;
float x30_RNGE;
float x34_FOFF;
CRSM();
CRSM();
void gatherDependencies(std::vector<hecl::ProjectPath>&) const;
void gatherDependencies(std::vector<hecl::ProjectPath>&) const;
};
template <class IDType>
bool ExtractCRSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteCRSM(const CRSM<IDType>& crsm, const hecl::ProjectPath& outPath);
}
} // namespace DataSpec::DNAParticle

View File

@ -3,39 +3,35 @@
#include "athena/FileWriter.hpp"
#include "DGRP.hpp"
namespace DataSpec::DNADGRP
{
namespace DataSpec::DNADGRP {
template <class IDType>
bool ExtractDGRP(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath)
{
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen())
{
DGRP<IDType> dgrp;
dgrp.read(rs);
athena::io::ToYAMLStream(dgrp, writer);
return true;
}
return false;
bool ExtractDGRP(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
DGRP<IDType> dgrp;
dgrp.read(rs);
athena::io::ToYAMLStream(dgrp, writer);
return true;
}
return false;
}
template bool ExtractDGRP<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractDGRP<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteDGRP(const DGRP<IDType>& dgrp, const hecl::ProjectPath& outPath)
{
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
dgrp.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i=0 ; i<32-rem ; ++i)
w.writeUByte(0xff);
return true;
bool WriteDGRP(const DGRP<IDType>& dgrp, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
dgrp.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteDGRP<UniqueID32>(const DGRP<UniqueID32>& dgrp, const hecl::ProjectPath& outPath);
template bool WriteDGRP<UniqueID64>(const DGRP<UniqueID64>& dgrp, const hecl::ProjectPath& outPath);
}
} // namespace DataSpec::DNADGRP

View File

@ -3,41 +3,36 @@
#include "DNACommon.hpp"
#include "PAK.hpp"
namespace DataSpec::DNADGRP
{
namespace DataSpec::DNADGRP {
template <class IDType>
struct AT_SPECIALIZE_PARMS(DataSpec::UniqueID32, DataSpec::UniqueID64) DGRP : BigDNA
{
struct AT_SPECIALIZE_PARMS(DataSpec::UniqueID32, DataSpec::UniqueID64) DGRP : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> dependCount;
struct ObjectTag : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> dependCount;
struct ObjectTag : BigDNA
{
AT_DECL_DNA_YAML
DNAFourCC type;
Value<IDType> id;
DNAFourCC type;
Value<IDType> id;
bool validate() const
{
if (!id.operator bool())
return false;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
return path && !path.isNone();
}
};
Vector<ObjectTag, AT_DNA_COUNT(dependCount)> depends;
void validateDeps()
{
std::vector<ObjectTag> newDeps;
newDeps.reserve(depends.size());
for (const ObjectTag& tag : depends)
if (tag.validate())
newDeps.push_back(tag);
depends = std::move(newDeps);
dependCount = atUint32(depends.size());
bool validate() const {
if (!id.operator bool())
return false;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
return path && !path.isNone();
}
};
Vector<ObjectTag, AT_DNA_COUNT(dependCount)> depends;
void validateDeps() {
std::vector<ObjectTag> newDeps;
newDeps.reserve(depends.size());
for (const ObjectTag& tag : depends)
if (tag.validate())
newDeps.push_back(tag);
depends = std::move(newDeps);
dependCount = atUint32(depends.size());
}
};
template <class IDType>
@ -45,5 +40,4 @@ bool ExtractDGRP(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteDGRP(const DGRP<IDType>& dgrp, const hecl::ProjectPath& outPath);
}
} // namespace DataSpec::DNADGRP

View File

@ -2,8 +2,7 @@
#include "PAK.hpp"
#include "boo/ThreadLocalPtr.hpp"
namespace DataSpec
{
namespace DataSpec {
logvisor::Module LogDNACommon("urde::DNACommon");
ThreadLocalPtr<SpecBase> g_curSpec;
@ -16,305 +15,270 @@ ThreadLocalPtr<IDRestorer<UniqueID128>> UniqueIDBridge::s_restorer128;
UniqueID32 UniqueID32::kInvalidId;
template <class IDType>
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const IDType& id, bool silenceWarnings)
{
/* Try PAKRouter first (only available at extract) */
PAKRouterBase* pakRouter = g_PakRouter.get();
if (pakRouter)
{
hecl::ProjectPath path = pakRouter->getWorking(id, silenceWarnings);
if (path)
return path;
}
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const IDType& id, bool silenceWarnings) {
/* Try PAKRouter first (only available at extract) */
PAKRouterBase* pakRouter = g_PakRouter.get();
if (pakRouter) {
hecl::ProjectPath path = pakRouter->getWorking(id, silenceWarnings);
if (path)
return path;
}
/* Try project cache second (populated with paths read from YAML resources) */
hecl::Database::Project* project = s_Project.get();
if (!project)
{
if (pakRouter)
{
if (hecl::VerbosityLevel >= 1 && !silenceWarnings && id)
LogDNACommon.report(logvisor::Warning,
"unable to translate %s to path", id.toString().c_str());
return {};
}
LogDNACommon.report(logvisor::Fatal,
"g_PakRouter or s_Project must be set to non-null before "
"calling UniqueIDBridge::TranslatePakIdToPath");
return {};
/* Try project cache second (populated with paths read from YAML resources) */
hecl::Database::Project* project = s_Project.get();
if (!project) {
if (pakRouter) {
if (hecl::VerbosityLevel >= 1 && !silenceWarnings && id)
LogDNACommon.report(logvisor::Warning, "unable to translate %s to path", id.toString().c_str());
return {};
}
LogDNACommon.report(logvisor::Fatal,
"g_PakRouter or s_Project must be set to non-null before "
"calling UniqueIDBridge::TranslatePakIdToPath");
return {};
}
const hecl::ProjectPath* search = project->lookupBridgePath(id.toUint64());
if (!search)
{
if (IDRestorer<IDType>* restorer = GetIDRestorer<IDType>())
if (IDType newId = restorer->originalToNew(id))
if (const hecl::ProjectPath* newSearch = project->lookupBridgePath(newId.toUint64()))
return *newSearch;
if (hecl::VerbosityLevel >= 1 && !silenceWarnings && id)
LogDNACommon.report(logvisor::Warning,
"unable to translate %s to path", id.toString().c_str());
return {};
}
return *search;
const hecl::ProjectPath* search = project->lookupBridgePath(id.toUint64());
if (!search) {
if (IDRestorer<IDType>* restorer = GetIDRestorer<IDType>())
if (IDType newId = restorer->originalToNew(id))
if (const hecl::ProjectPath* newSearch = project->lookupBridgePath(newId.toUint64()))
return *newSearch;
if (hecl::VerbosityLevel >= 1 && !silenceWarnings && id)
LogDNACommon.report(logvisor::Warning, "unable to translate %s to path", id.toString().c_str());
return {};
}
return *search;
}
template
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID32& id, bool silenceWarnings);
template
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID64& id, bool silenceWarnings);
template
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID128& id, bool silenceWarnings);
template hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID32& id, bool silenceWarnings);
template hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID64& id, bool silenceWarnings);
template hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID128& id, bool silenceWarnings);
template <class IDType>
hecl::ProjectPath UniqueIDBridge::MakePathFromString(std::string_view str)
{
if (str.empty())
return {};
hecl::Database::Project* project = s_Project.get();
if (!project)
LogDNACommon.report(logvisor::Fatal,
"UniqueIDBridge::setGlobalProject must be called before MakePathFromString");
hecl::ProjectPath path = hecl::ProjectPath(*project, str);
project->addBridgePathToCache(IDType(path).toUint64(), path);
return path;
hecl::ProjectPath UniqueIDBridge::MakePathFromString(std::string_view str) {
if (str.empty())
return {};
hecl::Database::Project* project = s_Project.get();
if (!project)
LogDNACommon.report(logvisor::Fatal, "UniqueIDBridge::setGlobalProject must be called before MakePathFromString");
hecl::ProjectPath path = hecl::ProjectPath(*project, str);
project->addBridgePathToCache(IDType(path).toUint64(), path);
return path;
}
template
hecl::ProjectPath UniqueIDBridge::MakePathFromString<UniqueID32>(std::string_view str);
template
hecl::ProjectPath UniqueIDBridge::MakePathFromString<UniqueID64>(std::string_view str);
template hecl::ProjectPath UniqueIDBridge::MakePathFromString<UniqueID32>(std::string_view str);
template hecl::ProjectPath UniqueIDBridge::MakePathFromString<UniqueID64>(std::string_view str);
template <class IDType>
void UniqueIDBridge::TransformOldHashToNewHash(IDType& id)
{
id = TranslatePakIdToPath(id);
void UniqueIDBridge::TransformOldHashToNewHash(IDType& id) {
id = TranslatePakIdToPath(id);
}
template
void UniqueIDBridge::TransformOldHashToNewHash(UniqueID32& id);
template
void UniqueIDBridge::TransformOldHashToNewHash(UniqueID64& id);
template void UniqueIDBridge::TransformOldHashToNewHash(UniqueID32& id);
template void UniqueIDBridge::TransformOldHashToNewHash(UniqueID64& id);
void UniqueIDBridge::SetThreadProject(hecl::Database::Project& project)
{
s_Project.reset(&project);
}
void UniqueIDBridge::SetThreadProject(hecl::Database::Project& project) { s_Project.reset(&project); }
/** PAK 32-bit Unique ID */
void UniqueID32::assign(uint32_t id, bool noOriginal)
{
m_id = id ? id : 0xffffffff;
if (!noOriginal)
if (IDRestorer<UniqueID32>* restorer = UniqueIDBridge::GetIDRestorer<UniqueID32>())
if (UniqueID32 origId = restorer->newToOriginal(*this))
*this = origId;
void UniqueID32::assign(uint32_t id, bool noOriginal) {
m_id = id ? id : 0xffffffff;
if (!noOriginal)
if (IDRestorer<UniqueID32>* restorer = UniqueIDBridge::GetIDRestorer<UniqueID32>())
if (UniqueID32 origId = restorer->newToOriginal(*this))
*this = origId;
}
template <>
void UniqueID32::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
{assign(reader.readUint32Big());}
template <>
void UniqueID32::Enumerate<BigDNA::Write>(typename Write::StreamT& writer)
{writer.writeUint32Big(m_id);}
template <>
void UniqueID32::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader)
{
*this = UniqueIDBridge::MakePathFromString<UniqueID32>(reader.readString(nullptr));
void UniqueID32::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
assign(reader.readUint32Big());
}
template <>
void UniqueID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer)
{
if (!operator bool())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this);
if (!path)
return;
writer.writeString(nullptr, path.getAuxInfo().size() ?
(std::string(path.getRelativePathUTF8()) + '|' + path.getAuxInfoUTF8().data()) :
path.getRelativePathUTF8());
void UniqueID32::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
writer.writeUint32Big(m_id);
}
template <>
void UniqueID32::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s)
{s += 4;}
void UniqueID32::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader) {
*this = UniqueIDBridge::MakePathFromString<UniqueID32>(reader.readString(nullptr));
}
template <>
void UniqueID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer) {
if (!operator bool())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this);
if (!path)
return;
writer.writeString(nullptr, path.getAuxInfo().size()
? (std::string(path.getRelativePathUTF8()) + '|' + path.getAuxInfoUTF8().data())
: path.getRelativePathUTF8());
}
template <>
void UniqueID32::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 4;
}
std::string UniqueID32::toString() const
{
char buf[9];
snprintf(buf, 9, "%08X", m_id);
return std::string(buf);
std::string UniqueID32::toString() const {
char buf[9];
snprintf(buf, 9, "%08X", m_id);
return std::string(buf);
}
template <>
void UniqueID32Zero::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
{UniqueID32::Enumerate<BigDNA::Read>(reader);}
void UniqueID32Zero::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
UniqueID32::Enumerate<BigDNA::Read>(reader);
}
template <>
void UniqueID32Zero::Enumerate<BigDNA::Write>(typename Write::StreamT& writer)
{writer.writeUint32Big(*this ? m_id : 0);}
void UniqueID32Zero::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
writer.writeUint32Big(*this ? m_id : 0);
}
template <>
void UniqueID32Zero::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader)
{UniqueID32::Enumerate<BigDNA::ReadYaml>(reader);}
void UniqueID32Zero::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader) {
UniqueID32::Enumerate<BigDNA::ReadYaml>(reader);
}
template <>
void UniqueID32Zero::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer)
{UniqueID32::Enumerate<BigDNA::WriteYaml>(writer);}
void UniqueID32Zero::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer) {
UniqueID32::Enumerate<BigDNA::WriteYaml>(writer);
}
template <>
void UniqueID32Zero::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s)
{UniqueID32::Enumerate<BigDNA::BinarySize>(s);}
AuxiliaryID32& AuxiliaryID32::operator=(const hecl::ProjectPath& path)
{
assign(path.ensureAuxInfo(m_auxStr).hash().val32());
return *this;
void UniqueID32Zero::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
UniqueID32::Enumerate<BigDNA::BinarySize>(s);
}
AuxiliaryID32& AuxiliaryID32::operator=(const UniqueID32& id)
{
m_baseId = id;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
if (path)
{
if (m_addExtension)
path = path.getWithExtension(m_addExtension);
*this = path;
}
return *this;
AuxiliaryID32& AuxiliaryID32::operator=(const hecl::ProjectPath& path) {
assign(path.ensureAuxInfo(m_auxStr).hash().val32());
return *this;
}
template <>
void AuxiliaryID32::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
{
assign(reader.readUint32Big());
m_baseId = *this;
}
template <>
void AuxiliaryID32::Enumerate<BigDNA::Write>(typename Write::StreamT& writer)
{
writer.writeUint32Big(m_id);
}
template <>
void AuxiliaryID32::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader)
{
hecl::ProjectPath readPath = UniqueIDBridge::MakePathFromString<UniqueID32>(reader.readString(nullptr));
*this = readPath.ensureAuxInfo(m_auxStr);
}
template <>
void AuxiliaryID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer)
{
if (!operator bool())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath<UniqueID32>(*this, true);
if (!path)
path = UniqueIDBridge::TranslatePakIdToPath(m_baseId);
if (!path)
return;
AuxiliaryID32& AuxiliaryID32::operator=(const UniqueID32& id) {
m_baseId = id;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
if (path) {
if (m_addExtension)
path = path.getWithExtension(m_addExtension);
hecl::SystemUTF8Conv ufx8AuxStr(m_auxStr);
writer.writeString(nullptr, std::string(path.getRelativePathUTF8()) + '|' + ufx8AuxStr);
path = path.getWithExtension(m_addExtension);
*this = path;
}
return *this;
}
template <>
void AuxiliaryID32::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
assign(reader.readUint32Big());
m_baseId = *this;
}
template <>
void AuxiliaryID32::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
writer.writeUint32Big(m_id);
}
template <>
void AuxiliaryID32::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader) {
hecl::ProjectPath readPath = UniqueIDBridge::MakePathFromString<UniqueID32>(reader.readString(nullptr));
*this = readPath.ensureAuxInfo(m_auxStr);
}
template <>
void AuxiliaryID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer) {
if (!operator bool())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath<UniqueID32>(*this, true);
if (!path)
path = UniqueIDBridge::TranslatePakIdToPath(m_baseId);
if (!path)
return;
if (m_addExtension)
path = path.getWithExtension(m_addExtension);
hecl::SystemUTF8Conv ufx8AuxStr(m_auxStr);
writer.writeString(nullptr, std::string(path.getRelativePathUTF8()) + '|' + ufx8AuxStr);
}
/** PAK 64-bit Unique ID */
void UniqueID64::assign(uint64_t id, bool noOriginal)
{
m_id = id ? id : 0xffffffffffffffff;
if (!noOriginal)
if (IDRestorer<UniqueID64>* restorer = UniqueIDBridge::GetIDRestorer<UniqueID64>())
if (UniqueID64 origId = restorer->newToOriginal(*this))
*this = origId;
void UniqueID64::assign(uint64_t id, bool noOriginal) {
m_id = id ? id : 0xffffffffffffffff;
if (!noOriginal)
if (IDRestorer<UniqueID64>* restorer = UniqueIDBridge::GetIDRestorer<UniqueID64>())
if (UniqueID64 origId = restorer->newToOriginal(*this))
*this = origId;
}
template <>
void UniqueID64::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
{assign(reader.readUint64Big());}
template <>
void UniqueID64::Enumerate<BigDNA::Write>(typename Write::StreamT& writer)
{writer.writeUint64Big(m_id);}
template <>
void UniqueID64::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader)
{
*this = UniqueIDBridge::MakePathFromString<UniqueID64>(reader.readString(nullptr));
void UniqueID64::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
assign(reader.readUint64Big());
}
template <>
void UniqueID64::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer)
{
if (!operator bool())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this);
if (!path)
return;
writer.writeString(nullptr, path.getAuxInfo().size() ?
(std::string(path.getRelativePathUTF8()) + '|' + path.getAuxInfoUTF8().data()) :
path.getRelativePathUTF8());
void UniqueID64::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
writer.writeUint64Big(m_id);
}
template <>
void UniqueID64::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s)
{s += 8;}
void UniqueID64::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader) {
*this = UniqueIDBridge::MakePathFromString<UniqueID64>(reader.readString(nullptr));
}
template <>
void UniqueID64::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer) {
if (!operator bool())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this);
if (!path)
return;
writer.writeString(nullptr, path.getAuxInfo().size()
? (std::string(path.getRelativePathUTF8()) + '|' + path.getAuxInfoUTF8().data())
: path.getRelativePathUTF8());
}
template <>
void UniqueID64::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 8;
}
std::string UniqueID64::toString() const
{
char buf[17];
snprintf(buf, 17, "%016" PRIX64, m_id);
return std::string(buf);
std::string UniqueID64::toString() const {
char buf[17];
snprintf(buf, 17, "%016" PRIX64, m_id);
return std::string(buf);
}
/** PAK 128-bit Unique ID */
template <>
void UniqueID128::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
{
m_id.id[0] = reader.readUint64Big();
m_id.id[1] = reader.readUint64Big();
void UniqueID128::Enumerate<BigDNA::Read>(typename Read::StreamT& reader) {
m_id.id[0] = reader.readUint64Big();
m_id.id[1] = reader.readUint64Big();
}
template <>
void UniqueID128::Enumerate<BigDNA::Write>(typename Write::StreamT& writer)
{
writer.writeUint64Big(m_id.id[0]);
writer.writeUint64Big(m_id.id[1]);
void UniqueID128::Enumerate<BigDNA::Write>(typename Write::StreamT& writer) {
writer.writeUint64Big(m_id.id[0]);
writer.writeUint64Big(m_id.id[1]);
}
template <>
void UniqueID128::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader)
{
*this = UniqueIDBridge::MakePathFromString<UniqueID128>(reader.readString(nullptr));
void UniqueID128::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader) {
*this = UniqueIDBridge::MakePathFromString<UniqueID128>(reader.readString(nullptr));
}
template <>
void UniqueID128::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer)
{
if (!operator bool())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this);
if (!path)
return;
writer.writeString(nullptr, path.getAuxInfo().size() ?
(std::string(path.getRelativePathUTF8()) + '|' + path.getAuxInfoUTF8().data()) :
path.getRelativePathUTF8());
void UniqueID128::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& writer) {
if (!operator bool())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this);
if (!path)
return;
writer.writeString(nullptr, path.getAuxInfo().size()
? (std::string(path.getRelativePathUTF8()) + '|' + path.getAuxInfoUTF8().data())
: path.getRelativePathUTF8());
}
template <>
void UniqueID128::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s)
{s += 16;}
std::string UniqueID128::toString() const
{
char buf[33];
snprintf(buf, 33, "%016" PRIX64 "%016" PRIX64, m_id.id[0], m_id.id[1]);
return std::string(buf);
void UniqueID128::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s) {
s += 16;
}
std::string UniqueID128::toString() const {
char buf[33];
snprintf(buf, 33, "%016" PRIX64 "%016" PRIX64, m_id.id[0], m_id.id[1]);
return std::string(buf);
}
/** Word Bitmap reader/writer */
void WordBitmap::read(athena::io::IStreamReader& reader, size_t bitCount)
{
m_bitCount = bitCount;
size_t wordCount = (bitCount + 31) / 32;
m_words.clear();
m_words.reserve(wordCount);
for (size_t w=0 ; w<wordCount ; ++w)
m_words.push_back(reader.readUint32Big());
void WordBitmap::read(athena::io::IStreamReader& reader, size_t bitCount) {
m_bitCount = bitCount;
size_t wordCount = (bitCount + 31) / 32;
m_words.clear();
m_words.reserve(wordCount);
for (size_t w = 0; w < wordCount; ++w)
m_words.push_back(reader.readUint32Big());
}
void WordBitmap::write(athena::io::IStreamWriter& writer) const
{
for (atUint32 word : m_words)
writer.writeUint32Big(word);
}
void WordBitmap::binarySize(size_t& __isz) const
{
__isz += m_words.size() * 4;
void WordBitmap::write(athena::io::IStreamWriter& writer) const {
for (atUint32 word : m_words)
writer.writeUint32Big(word);
}
void WordBitmap::binarySize(size_t& __isz) const { __isz += m_words.size() * 4; }
}
} // namespace DataSpec

View File

@ -8,8 +8,7 @@
#include "boo/ThreadLocalPtr.hpp"
#include "zeus/CColor.hpp"
namespace DataSpec
{
namespace DataSpec {
struct SpecBase;
extern logvisor::Module LogDNACommon;
@ -25,43 +24,46 @@ typedef athena::io::DNAVYaml<athena::Big> BigDNAVYaml;
/** FourCC with DNA read/write */
using DNAFourCC = hecl::DNAFourCC;
class DNAColor final : public BigDNA, public zeus::CColor
{
class DNAColor final : public BigDNA, public zeus::CColor {
public:
DNAColor() = default;
DNAColor(const zeus::CColor& color) : zeus::CColor(color) {}
AT_DECL_EXPLICIT_DNA_YAML
DNAColor() = default;
DNAColor(const zeus::CColor& color) : zeus::CColor(color) {}
AT_DECL_EXPLICIT_DNA_YAML
};
template <> inline void DNAColor::Enumerate<BigDNA::Read>(typename Read::StreamT& _r)
{ zeus::CColor::readRGBABig(_r); }
template <> inline void DNAColor::Enumerate<BigDNA::Write>(typename Write::StreamT& _w)
{ zeus::CColor::writeRGBABig(_w); }
template <> inline void DNAColor::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& _r)
{
size_t count;
if (auto v = _r.enterSubVector(nullptr, count))
{
zeus::simd_floats f;
f[0] = (count >= 1) ? _r.readFloat(nullptr) : 0.f;
f[1] = (count >= 2) ? _r.readFloat(nullptr) : 0.f;
f[2] = (count >= 3) ? _r.readFloat(nullptr) : 0.f;
f[3] = (count >= 4) ? _r.readFloat(nullptr) : 0.f;
mSimd.copy_from(f);
}
template <>
inline void DNAColor::Enumerate<BigDNA::Read>(typename Read::StreamT& _r) {
zeus::CColor::readRGBABig(_r);
}
template <> inline void DNAColor::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& _w)
{
if (auto v = _w.enterSubVector(nullptr))
{
zeus::simd_floats f(mSimd);
_w.writeFloat(nullptr, f[0]);
_w.writeFloat(nullptr, f[1]);
_w.writeFloat(nullptr, f[2]);
_w.writeFloat(nullptr, f[3]);
}
template <>
inline void DNAColor::Enumerate<BigDNA::Write>(typename Write::StreamT& _w) {
zeus::CColor::writeRGBABig(_w);
}
template <>
inline void DNAColor::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& _r) {
size_t count;
if (auto v = _r.enterSubVector(nullptr, count)) {
zeus::simd_floats f;
f[0] = (count >= 1) ? _r.readFloat(nullptr) : 0.f;
f[1] = (count >= 2) ? _r.readFloat(nullptr) : 0.f;
f[2] = (count >= 3) ? _r.readFloat(nullptr) : 0.f;
f[3] = (count >= 4) ? _r.readFloat(nullptr) : 0.f;
mSimd.copy_from(f);
}
}
template <>
inline void DNAColor::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& _w) {
if (auto v = _w.enterSubVector(nullptr)) {
zeus::simd_floats f(mSimd);
_w.writeFloat(nullptr, f[0]);
_w.writeFloat(nullptr, f[1]);
_w.writeFloat(nullptr, f[2]);
_w.writeFloat(nullptr, f[3]);
}
}
template <>
inline void DNAColor::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& _s) {
_s += 16;
}
template <> inline void DNAColor::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& _s)
{ _s += 16; }
using FourCC = hecl::FourCC;
class UniqueID32;
@ -69,277 +71,266 @@ class UniqueID64;
class UniqueID128;
/** Common virtual interface for runtime ambiguity resolution */
class PAKRouterBase
{
class PAKRouterBase {
protected:
const SpecBase& m_dataSpec;
const SpecBase& m_dataSpec;
public:
PAKRouterBase(const SpecBase& dataSpec) : m_dataSpec(dataSpec) {}
hecl::Database::Project& getProject() const {return m_dataSpec.getProject();}
virtual hecl::ProjectPath getWorking(const UniqueID32&, bool silenceWarnings=false) const
{
LogDNACommon.report(logvisor::Fatal,
"PAKRouter IDType mismatch; expected UniqueID32 specialization");
return hecl::ProjectPath();
}
virtual hecl::ProjectPath getWorking(const UniqueID64&, bool silenceWarnings=false) const
{
LogDNACommon.report(logvisor::Fatal,
"PAKRouter IDType mismatch; expected UniqueID64 specialization");
return hecl::ProjectPath();
}
virtual hecl::ProjectPath getWorking(const UniqueID128&, bool silenceWarnings=false) const
{
LogDNACommon.report(logvisor::Fatal,
"PAKRouter IDType mismatch; expected UniqueID128 specialization");
return hecl::ProjectPath();
}
PAKRouterBase(const SpecBase& dataSpec) : m_dataSpec(dataSpec) {}
hecl::Database::Project& getProject() const { return m_dataSpec.getProject(); }
virtual hecl::ProjectPath getWorking(const UniqueID32&, bool silenceWarnings = false) const {
LogDNACommon.report(logvisor::Fatal, "PAKRouter IDType mismatch; expected UniqueID32 specialization");
return hecl::ProjectPath();
}
virtual hecl::ProjectPath getWorking(const UniqueID64&, bool silenceWarnings = false) const {
LogDNACommon.report(logvisor::Fatal, "PAKRouter IDType mismatch; expected UniqueID64 specialization");
return hecl::ProjectPath();
}
virtual hecl::ProjectPath getWorking(const UniqueID128&, bool silenceWarnings = false) const {
LogDNACommon.report(logvisor::Fatal, "PAKRouter IDType mismatch; expected UniqueID128 specialization");
return hecl::ProjectPath();
}
};
/** Globally-accessed manager allowing UniqueID* classes to directly
* lookup destination paths of resources */
class UniqueIDBridge
{
friend class UniqueID32;
friend class UniqueID64;
class UniqueIDBridge {
friend class UniqueID32;
friend class UniqueID64;
static ThreadLocalPtr<hecl::Database::Project> s_Project;
static ThreadLocalPtr<IDRestorer<UniqueID32>> s_restorer32;
static ThreadLocalPtr<IDRestorer<UniqueID64>> s_restorer64;
static ThreadLocalPtr<IDRestorer<UniqueID128>> s_restorer128;
static ThreadLocalPtr<hecl::Database::Project> s_Project;
static ThreadLocalPtr<IDRestorer<UniqueID32>> s_restorer32;
static ThreadLocalPtr<IDRestorer<UniqueID64>> s_restorer64;
static ThreadLocalPtr<IDRestorer<UniqueID128>> s_restorer128;
public:
template <class IDType>
static hecl::ProjectPath TranslatePakIdToPath(const IDType& id, bool silenceWarnings=false);
template <class IDType>
static hecl::ProjectPath MakePathFromString(std::string_view str);
template <class IDType>
static void TransformOldHashToNewHash(IDType& id);
template <class IDType>
static hecl::ProjectPath TranslatePakIdToPath(const IDType& id, bool silenceWarnings = false);
template <class IDType>
static hecl::ProjectPath MakePathFromString(std::string_view str);
template <class IDType>
static void TransformOldHashToNewHash(IDType& id);
static void SetThreadProject(hecl::Database::Project& project);
static void SetThreadProject(hecl::Database::Project& project);
template <class IDType>
static IDRestorer<IDType>* GetIDRestorer();
template <class IDType>
static void SetIDRestorer(IDRestorer<IDType>* restorer);
template <class IDType>
static IDRestorer<IDType>* GetIDRestorer();
template <class IDType>
static void SetIDRestorer(IDRestorer<IDType>* restorer);
};
template <>
inline IDRestorer<UniqueID32>* UniqueIDBridge::GetIDRestorer<UniqueID32>()
{
return s_restorer32.get();
inline IDRestorer<UniqueID32>* UniqueIDBridge::GetIDRestorer<UniqueID32>() {
return s_restorer32.get();
}
template <>
inline void UniqueIDBridge::SetIDRestorer<UniqueID32>(IDRestorer<UniqueID32>* restorer)
{
s_restorer32.reset(restorer);
inline void UniqueIDBridge::SetIDRestorer<UniqueID32>(IDRestorer<UniqueID32>* restorer) {
s_restorer32.reset(restorer);
}
template <>
inline IDRestorer<UniqueID64>* UniqueIDBridge::GetIDRestorer<UniqueID64>()
{
return s_restorer64.get();
inline IDRestorer<UniqueID64>* UniqueIDBridge::GetIDRestorer<UniqueID64>() {
return s_restorer64.get();
}
template <>
inline void UniqueIDBridge::SetIDRestorer<UniqueID64>(IDRestorer<UniqueID64>* restorer)
{
s_restorer64.reset(restorer);
inline void UniqueIDBridge::SetIDRestorer<UniqueID64>(IDRestorer<UniqueID64>* restorer) {
s_restorer64.reset(restorer);
}
template <>
inline IDRestorer<UniqueID128>* UniqueIDBridge::GetIDRestorer<UniqueID128>()
{
return s_restorer128.get();
inline IDRestorer<UniqueID128>* UniqueIDBridge::GetIDRestorer<UniqueID128>() {
return s_restorer128.get();
}
template <>
inline void UniqueIDBridge::SetIDRestorer<UniqueID128>(IDRestorer<UniqueID128>* restorer)
{
s_restorer128.reset(restorer);
inline void UniqueIDBridge::SetIDRestorer<UniqueID128>(IDRestorer<UniqueID128>* restorer) {
s_restorer128.reset(restorer);
}
/** PAK 32-bit Unique ID */
class UniqueID32 : public BigDNA
{
class UniqueID32 : public BigDNA {
protected:
uint32_t m_id = 0xffffffff;
uint32_t m_id = 0xffffffff;
public:
using value_type = uint32_t;
static UniqueID32 kInvalidId;
AT_DECL_EXPLICIT_DNA_YAML
operator bool() const {return m_id != 0xffffffff && m_id != 0;}
void assign(uint32_t id, bool noOriginal = false);
using value_type = uint32_t;
static UniqueID32 kInvalidId;
AT_DECL_EXPLICIT_DNA_YAML
operator bool() const { return m_id != 0xffffffff && m_id != 0; }
void assign(uint32_t id, bool noOriginal = false);
UniqueID32& operator=(const hecl::ProjectPath& path)
{assign(path.hash().val32()); return *this;}
UniqueID32& operator=(const hecl::ProjectPath& path) {
assign(path.hash().val32());
return *this;
}
bool operator!=(const UniqueID32& other) const {return m_id != other.m_id;}
bool operator==(const UniqueID32& other) const {return m_id == other.m_id;}
bool operator<(const UniqueID32& other) const {return m_id < other.m_id;}
uint32_t toUint32() const {return m_id;}
uint64_t toUint64() const {return m_id;}
std::string toString() const;
void clear() {m_id = 0xffffffff;}
bool operator!=(const UniqueID32& other) const { return m_id != other.m_id; }
bool operator==(const UniqueID32& other) const { return m_id == other.m_id; }
bool operator<(const UniqueID32& other) const { return m_id < other.m_id; }
uint32_t toUint32() const { return m_id; }
uint64_t toUint64() const { return m_id; }
std::string toString() const;
void clear() { m_id = 0xffffffff; }
UniqueID32() = default;
UniqueID32(uint32_t idin, bool noOriginal = false) {assign(idin, noOriginal);}
UniqueID32(athena::io::IStreamReader& reader) {read(reader);}
UniqueID32(const hecl::ProjectPath& path) {*this = path;}
UniqueID32(const char* hexStr)
{
char copy[9];
strncpy(copy, hexStr, 8);
copy[8] = '\0';
assign(strtoul(copy, nullptr, 16));
}
UniqueID32(const wchar_t* hexStr)
{
wchar_t copy[9];
wcsncpy(copy, hexStr, 8);
copy[8] = L'\0';
assign(wcstoul(copy, nullptr, 16));
}
UniqueID32() = default;
UniqueID32(uint32_t idin, bool noOriginal = false) { assign(idin, noOriginal); }
UniqueID32(athena::io::IStreamReader& reader) { read(reader); }
UniqueID32(const hecl::ProjectPath& path) { *this = path; }
UniqueID32(const char* hexStr) {
char copy[9];
strncpy(copy, hexStr, 8);
copy[8] = '\0';
assign(strtoul(copy, nullptr, 16));
}
UniqueID32(const wchar_t* hexStr) {
wchar_t copy[9];
wcsncpy(copy, hexStr, 8);
copy[8] = L'\0';
assign(wcstoul(copy, nullptr, 16));
}
static constexpr size_t BinarySize() {return 4;}
static constexpr size_t BinarySize() { return 4; }
};
/** PAK 32-bit Unique ID - writes zero when invalid */
class UniqueID32Zero : public UniqueID32
{
class UniqueID32Zero : public UniqueID32 {
public:
AT_DECL_DNA_YAML
Delete __d2;
using UniqueID32::UniqueID32;
AT_DECL_DNA_YAML
Delete __d2;
using UniqueID32::UniqueID32;
};
class AuxiliaryID32 : public UniqueID32
{
const hecl::SystemChar* m_auxStr;
const hecl::SystemChar* m_addExtension;
UniqueID32 m_baseId;
public:
AT_DECL_DNA
Delete __d2;
AuxiliaryID32(const hecl::SystemChar* auxStr,
const hecl::SystemChar* addExtension=nullptr)
: m_auxStr(auxStr), m_addExtension(addExtension) {}
class AuxiliaryID32 : public UniqueID32 {
const hecl::SystemChar* m_auxStr;
const hecl::SystemChar* m_addExtension;
UniqueID32 m_baseId;
AuxiliaryID32& operator=(const hecl::ProjectPath& path);
AuxiliaryID32& operator=(const UniqueID32& id);
const UniqueID32& getBaseId() const {return m_baseId;}
public:
AT_DECL_DNA
Delete __d2;
AuxiliaryID32(const hecl::SystemChar* auxStr, const hecl::SystemChar* addExtension = nullptr)
: m_auxStr(auxStr), m_addExtension(addExtension) {}
AuxiliaryID32& operator=(const hecl::ProjectPath& path);
AuxiliaryID32& operator=(const UniqueID32& id);
const UniqueID32& getBaseId() const { return m_baseId; }
};
/** PAK 64-bit Unique ID */
class UniqueID64 : public BigDNA
{
uint64_t m_id = 0xffffffffffffffff;
class UniqueID64 : public BigDNA {
uint64_t m_id = 0xffffffffffffffff;
public:
using value_type = uint64_t;
AT_DECL_EXPLICIT_DNA_YAML
operator bool() const {return m_id != 0xffffffffffffffff && m_id != 0;}
void assign(uint64_t id, bool noOriginal = false);
using value_type = uint64_t;
AT_DECL_EXPLICIT_DNA_YAML
operator bool() const { return m_id != 0xffffffffffffffff && m_id != 0; }
void assign(uint64_t id, bool noOriginal = false);
UniqueID64& operator=(const hecl::ProjectPath& path)
{assign(path.hash().val64()); return *this;}
UniqueID64& operator=(const hecl::ProjectPath& path) {
assign(path.hash().val64());
return *this;
}
bool operator!=(const UniqueID64& other) const {return m_id != other.m_id;}
bool operator==(const UniqueID64& other) const {return m_id == other.m_id;}
bool operator<(const UniqueID64& other) const {return m_id < other.m_id;}
uint64_t toUint64() const {return m_id;}
std::string toString() const;
void clear() {m_id = 0xffffffffffffffff;}
bool operator!=(const UniqueID64& other) const { return m_id != other.m_id; }
bool operator==(const UniqueID64& other) const { return m_id == other.m_id; }
bool operator<(const UniqueID64& other) const { return m_id < other.m_id; }
uint64_t toUint64() const { return m_id; }
std::string toString() const;
void clear() { m_id = 0xffffffffffffffff; }
UniqueID64() = default;
UniqueID64(uint64_t idin, bool noOriginal = false) {assign(idin, noOriginal);}
UniqueID64(athena::io::IStreamReader& reader) {read(reader);}
UniqueID64(const hecl::ProjectPath& path) {*this = path;}
UniqueID64(const char* hexStr)
{
char copy[17];
strncpy(copy, hexStr, 16);
copy[16] = '\0';
UniqueID64() = default;
UniqueID64(uint64_t idin, bool noOriginal = false) { assign(idin, noOriginal); }
UniqueID64(athena::io::IStreamReader& reader) { read(reader); }
UniqueID64(const hecl::ProjectPath& path) { *this = path; }
UniqueID64(const char* hexStr) {
char copy[17];
strncpy(copy, hexStr, 16);
copy[16] = '\0';
#if _WIN32
assign(_strtoui64(copy, nullptr, 16));
assign(_strtoui64(copy, nullptr, 16));
#else
assign(strtouq(copy, nullptr, 16));
assign(strtouq(copy, nullptr, 16));
#endif
}
UniqueID64(const wchar_t* hexStr)
{
wchar_t copy[17];
wcsncpy(copy, hexStr, 16);
copy[16] = L'\0';
}
UniqueID64(const wchar_t* hexStr) {
wchar_t copy[17];
wcsncpy(copy, hexStr, 16);
copy[16] = L'\0';
#if _WIN32
assign(_wcstoui64(copy, nullptr, 16));
assign(_wcstoui64(copy, nullptr, 16));
#else
assign(wcstoull(copy, nullptr, 16));
assign(wcstoull(copy, nullptr, 16));
#endif
}
}
static constexpr size_t BinarySize() {return 8;}
static constexpr size_t BinarySize() { return 8; }
};
/** PAK 128-bit Unique ID */
class UniqueID128 : public BigDNA
{
class UniqueID128 : public BigDNA {
public:
union Value
{
uint64_t id[2];
union Value {
uint64_t id[2];
#if __SSE__
__m128i id128;
__m128i id128;
#endif
};
};
private:
Value m_id;
Value m_id;
public:
using value_type = uint64_t;
AT_DECL_EXPLICIT_DNA_YAML
UniqueID128() {m_id.id[0]=0xffffffffffffffff; m_id.id[1]=0xffffffffffffffff;}
UniqueID128(uint64_t idin, bool noOriginal = false)
{
m_id.id[0] = idin;
m_id.id[1] = 0;
}
operator bool() const
{return m_id.id[0] != 0xffffffffffffffff && m_id.id[0] != 0 && m_id.id[1] != 0xffffffffffffffff && m_id.id[1] != 0;}
using value_type = uint64_t;
AT_DECL_EXPLICIT_DNA_YAML
UniqueID128() {
m_id.id[0] = 0xffffffffffffffff;
m_id.id[1] = 0xffffffffffffffff;
}
UniqueID128(uint64_t idin, bool noOriginal = false) {
m_id.id[0] = idin;
m_id.id[1] = 0;
}
operator bool() const {
return m_id.id[0] != 0xffffffffffffffff && m_id.id[0] != 0 && m_id.id[1] != 0xffffffffffffffff && m_id.id[1] != 0;
}
UniqueID128& operator=(const hecl::ProjectPath& path)
{
m_id.id[0] = path.hash().val64();
m_id.id[1] = 0;
return *this;
}
UniqueID128(const hecl::ProjectPath& path) {*this = path;}
UniqueID128& operator=(const hecl::ProjectPath& path) {
m_id.id[0] = path.hash().val64();
m_id.id[1] = 0;
return *this;
}
UniqueID128(const hecl::ProjectPath& path) { *this = path; }
bool operator!=(const UniqueID128& other) const
{
bool operator!=(const UniqueID128& other) const {
#if __SSE__
__m128i vcmp = _mm_cmpeq_epi32(m_id.id128, other.m_id.id128);
int vmask = _mm_movemask_epi8(vcmp);
return vmask != 0xffff;
__m128i vcmp = _mm_cmpeq_epi32(m_id.id128, other.m_id.id128);
int vmask = _mm_movemask_epi8(vcmp);
return vmask != 0xffff;
#else
return (m_id.id[0] != other.m_id.id[0]) || (m_id.id[1] != other.m_id.id[1]);
return (m_id.id[0] != other.m_id.id[0]) || (m_id.id[1] != other.m_id.id[1]);
#endif
}
bool operator==(const UniqueID128& other) const
{
}
bool operator==(const UniqueID128& other) const {
#if __SSE__
__m128i vcmp = _mm_cmpeq_epi32(m_id.id128, other.m_id.id128);
int vmask = _mm_movemask_epi8(vcmp);
return vmask == 0xffff;
__m128i vcmp = _mm_cmpeq_epi32(m_id.id128, other.m_id.id128);
int vmask = _mm_movemask_epi8(vcmp);
return vmask == 0xffff;
#else
return (m_id.id[0] == other.m_id.id[0]) && (m_id.id[1] == other.m_id.id[1]);
return (m_id.id[0] == other.m_id.id[0]) && (m_id.id[1] == other.m_id.id[1]);
#endif
}
void clear() {m_id.id[0] = 0xffffffffffffffff; m_id.id[1] = 0xffffffffffffffff;}
uint64_t toUint64() const {return m_id.id[0];}
uint64_t toHighUint64() const {return m_id.id[0];}
uint64_t toLowUint64() const {return m_id.id[1];}
std::string toString() const;
}
void clear() {
m_id.id[0] = 0xffffffffffffffff;
m_id.id[1] = 0xffffffffffffffff;
}
uint64_t toUint64() const { return m_id.id[0]; }
uint64_t toHighUint64() const { return m_id.id[0]; }
uint64_t toLowUint64() const { return m_id.id[1]; }
std::string toString() const;
static constexpr size_t BinarySize() {return 16;}
static constexpr size_t BinarySize() { return 16; }
};
/** Casts ID type to its null-zero equivalent */
@ -347,63 +338,66 @@ template <class T>
using CastIDToZero = typename std::conditional_t<std::is_same_v<T, UniqueID32>, UniqueID32Zero, T>;
/** Word Bitmap reader/writer */
class WordBitmap
{
std::vector<atUint32> m_words;
size_t m_bitCount = 0;
class WordBitmap {
std::vector<atUint32> m_words;
size_t m_bitCount = 0;
public:
void read(athena::io::IStreamReader& reader, size_t bitCount);
void write(athena::io::IStreamWriter& writer) const;
void reserve(size_t bitCount) { m_words.reserve((bitCount + 31) / 32); }
void binarySize(size_t& __isz) const;
size_t getBitCount() const {return m_bitCount;}
bool getBit(size_t idx) const
{
size_t wordIdx = idx / 32;
if (wordIdx >= m_words.size())
return false;
size_t wordCur = idx % 32;
return (m_words[wordIdx] >> wordCur) & 0x1;
}
void setBit(size_t idx)
{
size_t wordIdx = idx / 32;
while (wordIdx >= m_words.size())
m_words.push_back(0);
size_t wordCur = idx % 32;
m_words[wordIdx] |= (1 << wordCur);
m_bitCount = std::max(m_bitCount, idx + 1);
}
void unsetBit(size_t idx)
{
size_t wordIdx = idx / 32;
while (wordIdx >= m_words.size())
m_words.push_back(0);
size_t wordCur = idx % 32;
m_words[wordIdx] &= ~(1 << wordCur);
m_bitCount = std::max(m_bitCount, idx + 1);
}
void clear() { m_words.clear(); m_bitCount = 0; }
void read(athena::io::IStreamReader& reader, size_t bitCount);
void write(athena::io::IStreamWriter& writer) const;
void reserve(size_t bitCount) { m_words.reserve((bitCount + 31) / 32); }
void binarySize(size_t& __isz) const;
size_t getBitCount() const { return m_bitCount; }
bool getBit(size_t idx) const {
size_t wordIdx = idx / 32;
if (wordIdx >= m_words.size())
return false;
size_t wordCur = idx % 32;
return (m_words[wordIdx] >> wordCur) & 0x1;
}
void setBit(size_t idx) {
size_t wordIdx = idx / 32;
while (wordIdx >= m_words.size())
m_words.push_back(0);
size_t wordCur = idx % 32;
m_words[wordIdx] |= (1 << wordCur);
m_bitCount = std::max(m_bitCount, idx + 1);
}
void unsetBit(size_t idx) {
size_t wordIdx = idx / 32;
while (wordIdx >= m_words.size())
m_words.push_back(0);
size_t wordCur = idx % 32;
m_words[wordIdx] &= ~(1 << wordCur);
m_bitCount = std::max(m_bitCount, idx + 1);
}
void clear() {
m_words.clear();
m_bitCount = 0;
}
class Iterator
{
friend class WordBitmap;
const WordBitmap& m_bmp;
size_t m_idx = 0;
Iterator(const WordBitmap& bmp, size_t idx) : m_bmp(bmp), m_idx(idx) {}
public:
using iterator_category = std::forward_iterator_tag;
using value_type = bool;
using difference_type = std::ptrdiff_t;
using pointer = bool*;
using reference = bool&;
class Iterator {
friend class WordBitmap;
const WordBitmap& m_bmp;
size_t m_idx = 0;
Iterator(const WordBitmap& bmp, size_t idx) : m_bmp(bmp), m_idx(idx) {}
Iterator& operator++() {++m_idx; return *this;}
bool operator*() {return m_bmp.getBit(m_idx);}
bool operator!=(const Iterator& other) const {return m_idx != other.m_idx;}
};
Iterator begin() const {return Iterator(*this, 0);}
Iterator end() const {return Iterator(*this, m_bitCount);}
public:
using iterator_category = std::forward_iterator_tag;
using value_type = bool;
using difference_type = std::ptrdiff_t;
using pointer = bool*;
using reference = bool&;
Iterator& operator++() {
++m_idx;
return *this;
}
bool operator*() { return m_bmp.getBit(m_idx); }
bool operator!=(const Iterator& other) const { return m_idx != other.m_idx; }
};
Iterator begin() const { return Iterator(*this, 0); }
Iterator end() const { return Iterator(*this, m_bitCount); }
};
/** Resource cooker function */
@ -411,60 +405,47 @@ typedef std::function<bool(const hecl::ProjectPath&, const hecl::ProjectPath&)>
/** Mappings of resources involved in extracting characters */
template <class IDType>
struct CharacterAssociations
{
using RigPair = std::pair<IDType, IDType>;
/* CMDL -> (CSKR, CINF) */
std::unordered_map<IDType, RigPair> m_cmdlRigs;
/* (CSKR, CINF) -> ANCS */
std::unordered_map<IDType, std::pair<IDType, std::string>> m_cskrCinfToCharacter;
/* ANCS -> (CINF, CMDL) */
std::unordered_multimap<IDType, std::pair<RigPair, std::string>> m_characterToAttachmentRigs;
using MultimapIteratorPair = std::pair<
typename std::unordered_multimap<IDType, std::pair<RigPair, std::string>>::const_iterator,
typename std::unordered_multimap<IDType, std::pair<RigPair, std::string>>::const_iterator>;
void addAttachmentRig(IDType character, IDType cinf, IDType cmdl, const char* name)
{
auto range = m_characterToAttachmentRigs.equal_range(character);
for (auto it = range.first; it != range.second; ++it)
if (it->second.second == name)
return;
m_characterToAttachmentRigs.insert(
std::make_pair(character, std::make_pair(std::make_pair(cinf, cmdl), name)));
}
struct CharacterAssociations {
using RigPair = std::pair<IDType, IDType>;
/* CMDL -> (CSKR, CINF) */
std::unordered_map<IDType, RigPair> m_cmdlRigs;
/* (CSKR, CINF) -> ANCS */
std::unordered_map<IDType, std::pair<IDType, std::string>> m_cskrCinfToCharacter;
/* ANCS -> (CINF, CMDL) */
std::unordered_multimap<IDType, std::pair<RigPair, std::string>> m_characterToAttachmentRigs;
using MultimapIteratorPair =
std::pair<typename std::unordered_multimap<IDType, std::pair<RigPair, std::string>>::const_iterator,
typename std::unordered_multimap<IDType, std::pair<RigPair, std::string>>::const_iterator>;
void addAttachmentRig(IDType character, IDType cinf, IDType cmdl, const char* name) {
auto range = m_characterToAttachmentRigs.equal_range(character);
for (auto it = range.first; it != range.second; ++it)
if (it->second.second == name)
return;
m_characterToAttachmentRigs.insert(std::make_pair(character, std::make_pair(std::make_pair(cinf, cmdl), name)));
}
};
}
} // namespace DataSpec
/* Hash template-specializations for UniqueID types */
namespace std
{
template<>
struct hash<DataSpec::DNAFourCC>
{
size_t operator()(const DataSpec::DNAFourCC& fcc) const
{return fcc.toUint32();}
namespace std {
template <>
struct hash<DataSpec::DNAFourCC> {
size_t operator()(const DataSpec::DNAFourCC& fcc) const { return fcc.toUint32(); }
};
template<>
struct hash<DataSpec::UniqueID32>
{
size_t operator()(const DataSpec::UniqueID32& id) const
{return id.toUint32();}
template <>
struct hash<DataSpec::UniqueID32> {
size_t operator()(const DataSpec::UniqueID32& id) const { return id.toUint32(); }
};
template<>
struct hash<DataSpec::UniqueID64>
{
size_t operator()(const DataSpec::UniqueID64& id) const
{return id.toUint64();}
template <>
struct hash<DataSpec::UniqueID64> {
size_t operator()(const DataSpec::UniqueID64& id) const { return id.toUint64(); }
};
template<>
struct hash<DataSpec::UniqueID128>
{
size_t operator()(const DataSpec::UniqueID128& id) const
{return id.toHighUint64() ^ id.toLowUint64();}
template <>
struct hash<DataSpec::UniqueID128> {
size_t operator()(const DataSpec::UniqueID128& id) const { return id.toHighUint64() ^ id.toLowUint64(); }
};
}
} // namespace std

View File

@ -1,418 +1,377 @@
#include "DPSC.hpp"
namespace DataSpec::DNAParticle
{
namespace DataSpec::DNAParticle {
template <>
const char* DPSM<UniqueID32>::DNAType() { return "DPSM<UniqueID32>"; }
const char* DPSM<UniqueID32>::DNAType() {
return "DPSM<UniqueID32>";
}
template <>
const char* DPSM<UniqueID64>::DNAType() { return "DPSM<UniqueID64>"; }
template <class IDType>
void DPSM<IDType>::_read(athena::io::YAMLDocReader& r)
{
for (const auto& elem : r.getCurNode()->m_mapChildren)
{
if (elem.first.size() < 4)
{
LogModule.report(logvisor::Warning, "short FourCC in element '%s'", elem.first.c_str());
continue;
}
if (auto rec = r.enterSubRecord(elem.first.c_str()))
{
bool loadFirstDesc = false;
uint32_t clsId = *reinterpret_cast<const uint32_t*>(elem.first.c_str());
switch(clsId)
{
case SBIG('1SZE'):
case SBIG('1LFT'):
case SBIG('1ROT'):
case SBIG('1OFF'):
case SBIG('1CLR'):
case SBIG('1TEX'):
case SBIG('1ADD'):
loadFirstDesc = true;
case SBIG('2SZE'):
case SBIG('2LFT'):
case SBIG('2ROT'):
case SBIG('2OFF'):
case SBIG('2CLR'):
case SBIG('2TEX'):
case SBIG('2ADD'):
if (loadFirstDesc)
readQuadDecalInfo(r, clsId, x0_quad);
else
readQuadDecalInfo(r, clsId, x1c_quad);
break;
case SBIG('DMDL'):
x38_DMDL.read(r);
break;
case SBIG('DLFT'):
x48_DLFT.read(r);
break;
case SBIG('DMOP'):
x4c_DMOP.read(r);
break;
case SBIG('DMRT'):
x50_DMRT.read(r);
break;
case SBIG('DMSC'):
x54_DMSC.read(r);
break;
case SBIG('DMCL'):
x58_DMCL.read(r);
break;
case SBIG('DMAB'):
x5c_24_DMAB = r.readBool(nullptr);
break;
case SBIG('DMOO'):
x5c_25_DMOO = r.readBool(nullptr);
break;
}
}
}
const char* DPSM<UniqueID64>::DNAType() {
return "DPSM<UniqueID64>";
}
template <class IDType>
void DPSM<IDType>::_write(athena::io::YAMLDocWriter& w) const
{
writeQuadDecalInfo(w, x0_quad, true);
writeQuadDecalInfo(w, x1c_quad, false);
void DPSM<IDType>::_read(athena::io::YAMLDocReader& r) {
for (const auto& elem : r.getCurNode()->m_mapChildren) {
if (elem.first.size() < 4) {
LogModule.report(logvisor::Warning, "short FourCC in element '%s'", elem.first.c_str());
continue;
}
if (x38_DMDL)
if (auto rec = w.enterSubRecord("DMDL"))
x38_DMDL.write(w);
if (x48_DLFT)
if (auto rec = w.enterSubRecord("DLFT"))
x48_DLFT.write(w);
if (x4c_DMOP)
if (auto rec = w.enterSubRecord("DMOP"))
x4c_DMOP.write(w);
if (x50_DMRT)
if (auto rec = w.enterSubRecord("DMRT"))
x50_DMRT.write(w);
if (x54_DMSC)
if (auto rec = w.enterSubRecord("DMSC"))
x54_DMSC.write(w);
if (x58_DMCL)
if (auto rec = w.enterSubRecord("DMCL"))
x54_DMSC.write(w);
if (auto rec = r.enterSubRecord(elem.first.c_str())) {
bool loadFirstDesc = false;
uint32_t clsId = *reinterpret_cast<const uint32_t*>(elem.first.c_str());
switch (clsId) {
case SBIG('1SZE'):
case SBIG('1LFT'):
case SBIG('1ROT'):
case SBIG('1OFF'):
case SBIG('1CLR'):
case SBIG('1TEX'):
case SBIG('1ADD'):
loadFirstDesc = true;
case SBIG('2SZE'):
case SBIG('2LFT'):
case SBIG('2ROT'):
case SBIG('2OFF'):
case SBIG('2CLR'):
case SBIG('2TEX'):
case SBIG('2ADD'):
if (loadFirstDesc)
readQuadDecalInfo(r, clsId, x0_quad);
else
readQuadDecalInfo(r, clsId, x1c_quad);
break;
case SBIG('DMDL'):
x38_DMDL.read(r);
break;
case SBIG('DLFT'):
x48_DLFT.read(r);
break;
case SBIG('DMOP'):
x4c_DMOP.read(r);
break;
case SBIG('DMRT'):
x50_DMRT.read(r);
break;
case SBIG('DMSC'):
x54_DMSC.read(r);
break;
case SBIG('DMCL'):
x58_DMCL.read(r);
break;
case SBIG('DMAB'):
x5c_24_DMAB = r.readBool(nullptr);
break;
case SBIG('DMOO'):
x5c_25_DMOO = r.readBool(nullptr);
break;
}
}
}
}
if (x5c_24_DMAB)
w.writeBool("DMAB", x5c_24_DMAB);
if (x5c_25_DMOO)
w.writeBool("DMOO", x5c_25_DMOO);
template <class IDType>
void DPSM<IDType>::_write(athena::io::YAMLDocWriter& w) const {
writeQuadDecalInfo(w, x0_quad, true);
writeQuadDecalInfo(w, x1c_quad, false);
if (x38_DMDL)
if (auto rec = w.enterSubRecord("DMDL"))
x38_DMDL.write(w);
if (x48_DLFT)
if (auto rec = w.enterSubRecord("DLFT"))
x48_DLFT.write(w);
if (x4c_DMOP)
if (auto rec = w.enterSubRecord("DMOP"))
x4c_DMOP.write(w);
if (x50_DMRT)
if (auto rec = w.enterSubRecord("DMRT"))
x50_DMRT.write(w);
if (x54_DMSC)
if (auto rec = w.enterSubRecord("DMSC"))
x54_DMSC.write(w);
if (x58_DMCL)
if (auto rec = w.enterSubRecord("DMCL"))
x54_DMSC.write(w);
if (x5c_24_DMAB)
w.writeBool("DMAB", x5c_24_DMAB);
if (x5c_25_DMOO)
w.writeBool("DMOO", x5c_25_DMOO);
}
template <class IDType>
template <class Reader>
void DPSM<IDType>::readQuadDecalInfo(Reader& r, uint32_t clsId, typename DPSM<IDType>::SQuadDescr& quad)
{
switch(clsId)
{
case SBIG('1LFT'):
case SBIG('2LFT'):
quad.x0_LFT.read(r);
void DPSM<IDType>::readQuadDecalInfo(Reader& r, uint32_t clsId, typename DPSM<IDType>::SQuadDescr& quad) {
switch (clsId) {
case SBIG('1LFT'):
case SBIG('2LFT'):
quad.x0_LFT.read(r);
break;
case SBIG('1SZE'):
case SBIG('2SZE'):
quad.x4_SZE.read(r);
case SBIG('1SZE'):
case SBIG('2SZE'):
quad.x4_SZE.read(r);
break;
case SBIG('1ROT'):
case SBIG('2ROT'):
quad.x8_ROT.read(r);
case SBIG('1ROT'):
case SBIG('2ROT'):
quad.x8_ROT.read(r);
break;
case SBIG('1OFF'):
case SBIG('2OFF'):
quad.xc_OFF.read(r);
case SBIG('1OFF'):
case SBIG('2OFF'):
quad.xc_OFF.read(r);
break;
case SBIG('1CLR'):
case SBIG('2CLR'):
quad.x10_CLR.read(r);
case SBIG('1CLR'):
case SBIG('2CLR'):
quad.x10_CLR.read(r);
break;
case SBIG('1TEX'):
case SBIG('2TEX'):
quad.x14_TEX.read(r);
case SBIG('1TEX'):
case SBIG('2TEX'):
quad.x14_TEX.read(r);
break;
case SBIG('1ADD'):
case SBIG('2ADD'):
quad.x18_ADD.read(r);
case SBIG('1ADD'):
case SBIG('2ADD'):
quad.x18_ADD.read(r);
break;
}
}
}
template <class IDType>
void DPSM<IDType>::writeQuadDecalInfo(athena::io::YAMLDocWriter& w,
const typename DPSM<IDType>::SQuadDescr& quad, bool first) const
{
if (quad.x0_LFT)
if (auto rec = w.enterSubRecord((first ? "1LFT" : "2LFT")))
quad.x0_LFT.write(w);
if (quad.x4_SZE)
if (auto rec = w.enterSubRecord((first ? "1SZE" : "2SZE")))
quad.x4_SZE.write(w);
if (quad.x8_ROT)
if (auto rec = w.enterSubRecord((first ? "1ROT" : "2ROT")))
quad.x8_ROT.write(w);
if (quad.xc_OFF)
if (auto rec = w.enterSubRecord((first ? "1OFF" : "2OFF")))
quad.xc_OFF.write(w);
if (quad.x10_CLR)
if (auto rec = w.enterSubRecord((first ? "1CLR" : "2CLR")))
quad.x10_CLR.write(w);
if (quad.x14_TEX)
if (auto rec = w.enterSubRecord((first ? "1TEX" : "2TEX")))
quad.x14_TEX.write(w);
if (quad.x18_ADD)
if (auto rec = w.enterSubRecord((first ? "1ADD" : "2ADD")))
quad.x18_ADD.write(w);
void DPSM<IDType>::writeQuadDecalInfo(athena::io::YAMLDocWriter& w, const typename DPSM<IDType>::SQuadDescr& quad,
bool first) const {
if (quad.x0_LFT)
if (auto rec = w.enterSubRecord((first ? "1LFT" : "2LFT")))
quad.x0_LFT.write(w);
if (quad.x4_SZE)
if (auto rec = w.enterSubRecord((first ? "1SZE" : "2SZE")))
quad.x4_SZE.write(w);
if (quad.x8_ROT)
if (auto rec = w.enterSubRecord((first ? "1ROT" : "2ROT")))
quad.x8_ROT.write(w);
if (quad.xc_OFF)
if (auto rec = w.enterSubRecord((first ? "1OFF" : "2OFF")))
quad.xc_OFF.write(w);
if (quad.x10_CLR)
if (auto rec = w.enterSubRecord((first ? "1CLR" : "2CLR")))
quad.x10_CLR.write(w);
if (quad.x14_TEX)
if (auto rec = w.enterSubRecord((first ? "1TEX" : "2TEX")))
quad.x14_TEX.write(w);
if (quad.x18_ADD)
if (auto rec = w.enterSubRecord((first ? "1ADD" : "2ADD")))
quad.x18_ADD.write(w);
}
template <class IDType>
void DPSM<IDType>::_binarySize(size_t& s) const
{
void DPSM<IDType>::_binarySize(size_t& s) const {
s += 4;
getQuadDecalBinarySize(s, x0_quad);
getQuadDecalBinarySize(s, x1c_quad);
if (x38_DMDL) {
s += 4;
getQuadDecalBinarySize(s, x0_quad);
getQuadDecalBinarySize(s, x1c_quad);
if (x38_DMDL)
{
s += 4;
x38_DMDL.binarySize(s);
}
if (x48_DLFT)
{
s += 4;
x48_DLFT.binarySize(s);
}
if (x4c_DMOP)
{
s += 4;
x4c_DMOP.binarySize(s);
}
if (x50_DMRT)
{
s += 4;
x50_DMRT.binarySize(s);
}
if (x54_DMSC)
{
s += 4;
x54_DMSC.binarySize(s);
}
if (x58_DMCL)
{
x58_DMCL.binarySize(s);
}
if (x5c_24_DMAB)
s += 9;
if (x5c_25_DMOO)
s += 9;
x38_DMDL.binarySize(s);
}
if (x48_DLFT) {
s += 4;
x48_DLFT.binarySize(s);
}
if (x4c_DMOP) {
s += 4;
x4c_DMOP.binarySize(s);
}
if (x50_DMRT) {
s += 4;
x50_DMRT.binarySize(s);
}
if (x54_DMSC) {
s += 4;
x54_DMSC.binarySize(s);
}
if (x58_DMCL) {
x58_DMCL.binarySize(s);
}
if (x5c_24_DMAB)
s += 9;
if (x5c_25_DMOO)
s += 9;
}
template <class IDType>
void DPSM<IDType>::getQuadDecalBinarySize(size_t& s, const typename DPSM<IDType>::SQuadDescr& quad) const
{
if (quad.x0_LFT)
{
s += 4;
quad.x0_LFT.binarySize(s);
}
if (quad.x4_SZE)
{
s += 4;
quad.x4_SZE.binarySize(s);
}
if (quad.x8_ROT)
{
s += 4;
quad.x8_ROT.binarySize(s);
}
if (quad.xc_OFF)
{
s += 4;
quad.xc_OFF.binarySize(s);
}
if (quad.x10_CLR)
{
s += 4;
quad.x10_CLR.binarySize(s);
}
if (quad.x14_TEX)
{
s += 4;
quad.x14_TEX.binarySize(s);
}
if (quad.x18_ADD)
{
s += 4;
quad.x18_ADD.binarySize(s);
}
void DPSM<IDType>::getQuadDecalBinarySize(size_t& s, const typename DPSM<IDType>::SQuadDescr& quad) const {
if (quad.x0_LFT) {
s += 4;
quad.x0_LFT.binarySize(s);
}
if (quad.x4_SZE) {
s += 4;
quad.x4_SZE.binarySize(s);
}
if (quad.x8_ROT) {
s += 4;
quad.x8_ROT.binarySize(s);
}
if (quad.xc_OFF) {
s += 4;
quad.xc_OFF.binarySize(s);
}
if (quad.x10_CLR) {
s += 4;
quad.x10_CLR.binarySize(s);
}
if (quad.x14_TEX) {
s += 4;
quad.x14_TEX.binarySize(s);
}
if (quad.x18_ADD) {
s += 4;
quad.x18_ADD.binarySize(s);
}
}
template <class IDType>
void DPSM<IDType>::_read(athena::io::IStreamReader& r)
{
uint32_t clsId;
void DPSM<IDType>::_read(athena::io::IStreamReader& r) {
uint32_t clsId;
r.readBytesToBuf(&clsId, 4);
if (clsId != SBIG('DPSM')) {
LogModule.report(logvisor::Warning, "non DPSM provided to DPSM parser");
return;
}
bool loadFirstDesc = false;
r.readBytesToBuf(&clsId, 4);
while (clsId != SBIG('_END')) {
switch (clsId) {
case SBIG('1SZE'):
case SBIG('1LFT'):
case SBIG('1ROT'):
case SBIG('1OFF'):
case SBIG('1CLR'):
case SBIG('1TEX'):
case SBIG('1ADD'):
loadFirstDesc = true;
case SBIG('2SZE'):
case SBIG('2LFT'):
case SBIG('2ROT'):
case SBIG('2OFF'):
case SBIG('2CLR'):
case SBIG('2TEX'):
case SBIG('2ADD'):
if (loadFirstDesc)
readQuadDecalInfo(r, clsId, x0_quad);
else
readQuadDecalInfo(r, clsId, x1c_quad);
break;
case SBIG('DMDL'):
x38_DMDL.read(r);
break;
case SBIG('DLFT'):
x48_DLFT.read(r);
break;
case SBIG('DMOP'):
x4c_DMOP.read(r);
break;
case SBIG('DMRT'):
x50_DMRT.read(r);
break;
case SBIG('DMSC'):
x54_DMSC.read(r);
break;
case SBIG('DMCL'):
x58_DMCL.read(r);
break;
case SBIG('DMAB'):
r.readUint32();
x5c_24_DMAB = r.readBool();
break;
case SBIG('DMOO'):
r.readUint32();
x5c_25_DMOO = r.readBool();
break;
default:
LogModule.report(logvisor::Fatal, "Unknown DPSM class %.4s @%" PRIi64, &clsId, r.position());
break;
}
r.readBytesToBuf(&clsId, 4);
if (clsId != SBIG('DPSM'))
{
LogModule.report(logvisor::Warning, "non DPSM provided to DPSM parser");
return;
}
bool loadFirstDesc = false;
r.readBytesToBuf(&clsId, 4);
while (clsId != SBIG('_END'))
{
switch(clsId)
{
case SBIG('1SZE'):
case SBIG('1LFT'):
case SBIG('1ROT'):
case SBIG('1OFF'):
case SBIG('1CLR'):
case SBIG('1TEX'):
case SBIG('1ADD'):
loadFirstDesc = true;
case SBIG('2SZE'):
case SBIG('2LFT'):
case SBIG('2ROT'):
case SBIG('2OFF'):
case SBIG('2CLR'):
case SBIG('2TEX'):
case SBIG('2ADD'):
if (loadFirstDesc)
readQuadDecalInfo(r, clsId, x0_quad);
else
readQuadDecalInfo(r, clsId, x1c_quad);
break;
case SBIG('DMDL'):
x38_DMDL.read(r);
break;
case SBIG('DLFT'):
x48_DLFT.read(r);
break;
case SBIG('DMOP'):
x4c_DMOP.read(r);
break;
case SBIG('DMRT'):
x50_DMRT.read(r);
break;
case SBIG('DMSC'):
x54_DMSC.read(r);
break;
case SBIG('DMCL'):
x58_DMCL.read(r);
break;
case SBIG('DMAB'):
r.readUint32();
x5c_24_DMAB = r.readBool();
break;
case SBIG('DMOO'):
r.readUint32();
x5c_25_DMOO = r.readBool();
break;
default:
LogModule.report(logvisor::Fatal, "Unknown DPSM class %.4s @%" PRIi64, &clsId, r.position());
break;
}
r.readBytesToBuf(&clsId, 4);
}
}
}
template <class IDType>
void DPSM<IDType>::_write(athena::io::IStreamWriter& w) const
{
w.writeBytes("DPSM", 4);
writeQuadDecalInfo(w, x0_quad, true);
writeQuadDecalInfo(w, x1c_quad, false);
if (x38_DMDL)
{
w.writeBytes("DMDL", 4);
x38_DMDL.write(w);
}
if (x48_DLFT)
{
w.writeBytes("DLFT", 4);
x48_DLFT.write(w);
}
if (x4c_DMOP)
{
w.writeBytes("DMOP", 4);
x4c_DMOP.write(w);
}
if (x50_DMRT)
{
w.writeBytes("DMRT", 4);
x50_DMRT.write(w);
}
if (x54_DMSC)
{
w.writeBytes("DMSC", 4);
x54_DMSC.write(w);
}
if (x58_DMCL)
{
w.writeBytes("DMCL", 4);
x58_DMCL.write(w);
}
if (x5c_24_DMAB)
w.writeBytes("DMABCNST\x01", 9);
if (x5c_25_DMOO)
w.writeBytes("DMOOCNST\x01", 9);
w.writeBytes("_END", 4);
void DPSM<IDType>::_write(athena::io::IStreamWriter& w) const {
w.writeBytes("DPSM", 4);
writeQuadDecalInfo(w, x0_quad, true);
writeQuadDecalInfo(w, x1c_quad, false);
if (x38_DMDL) {
w.writeBytes("DMDL", 4);
x38_DMDL.write(w);
}
if (x48_DLFT) {
w.writeBytes("DLFT", 4);
x48_DLFT.write(w);
}
if (x4c_DMOP) {
w.writeBytes("DMOP", 4);
x4c_DMOP.write(w);
}
if (x50_DMRT) {
w.writeBytes("DMRT", 4);
x50_DMRT.write(w);
}
if (x54_DMSC) {
w.writeBytes("DMSC", 4);
x54_DMSC.write(w);
}
if (x58_DMCL) {
w.writeBytes("DMCL", 4);
x58_DMCL.write(w);
}
if (x5c_24_DMAB)
w.writeBytes("DMABCNST\x01", 9);
if (x5c_25_DMOO)
w.writeBytes("DMOOCNST\x01", 9);
w.writeBytes("_END", 4);
}
template <class IDType>
void DPSM<IDType>::writeQuadDecalInfo(athena::io::IStreamWriter& w,
const typename DPSM<IDType>::SQuadDescr& quad, bool first) const
{
if (quad.x0_LFT)
{
w.writeBytes((first ? "1LFT" : "2LFT"), 4);
quad.x0_LFT.write(w);
}
if (quad.x4_SZE)
{
w.writeBytes((first ? "1SZE" : "2SZE"), 4);
quad.x4_SZE.write(w);
}
if (quad.x8_ROT)
{
w.writeBytes((first ? "1ROT" : "2ROT"), 4);
quad.x8_ROT.write(w);
}
if (quad.xc_OFF)
{
w.writeBytes((first ? "1OFF" : "2OFF"), 4);
quad.xc_OFF.write(w);
}
if (quad.x10_CLR)
{
w.writeBytes((first ? "1CLR" : "2CLR"), 4);
quad.x10_CLR.write(w);
}
if (quad.x14_TEX)
{
w.writeBytes((first ? "1TEX" : "2TEX"), 4);
quad.x14_TEX.write(w);
}
if (quad.x18_ADD)
{
w.writeBytes((first ? "1ADD" : "2ADD"), 4);
quad.x18_ADD.write(w);
}
void DPSM<IDType>::writeQuadDecalInfo(athena::io::IStreamWriter& w, const typename DPSM<IDType>::SQuadDescr& quad,
bool first) const {
if (quad.x0_LFT) {
w.writeBytes((first ? "1LFT" : "2LFT"), 4);
quad.x0_LFT.write(w);
}
if (quad.x4_SZE) {
w.writeBytes((first ? "1SZE" : "2SZE"), 4);
quad.x4_SZE.write(w);
}
if (quad.x8_ROT) {
w.writeBytes((first ? "1ROT" : "2ROT"), 4);
quad.x8_ROT.write(w);
}
if (quad.xc_OFF) {
w.writeBytes((first ? "1OFF" : "2OFF"), 4);
quad.xc_OFF.write(w);
}
if (quad.x10_CLR) {
w.writeBytes((first ? "1CLR" : "2CLR"), 4);
quad.x10_CLR.write(w);
}
if (quad.x14_TEX) {
w.writeBytes((first ? "1TEX" : "2TEX"), 4);
quad.x14_TEX.write(w);
}
if (quad.x18_ADD) {
w.writeBytes((first ? "1ADD" : "2ADD"), 4);
quad.x18_ADD.write(w);
}
}
template <class IDType>
void DPSM<IDType>::gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
{
if (x0_quad.x14_TEX.m_elem)
x0_quad.x14_TEX.m_elem->gatherDependencies(pathsOut);
if (x1c_quad.x14_TEX.m_elem)
x1c_quad.x14_TEX.m_elem->gatherDependencies(pathsOut);
g_curSpec->flattenDependencies(x38_DMDL.id, pathsOut);
void DPSM<IDType>::gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const {
if (x0_quad.x14_TEX.m_elem)
x0_quad.x14_TEX.m_elem->gatherDependencies(pathsOut);
if (x1c_quad.x14_TEX.m_elem)
x1c_quad.x14_TEX.m_elem->gatherDependencies(pathsOut);
g_curSpec->flattenDependencies(x38_DMDL.id, pathsOut);
}
AT_SUBSPECIALIZE_DNA_YAML(DPSM<UniqueID32>)
@ -421,36 +380,32 @@ template struct DPSM<UniqueID32>;
template struct DPSM<UniqueID64>;
template <class IDType>
bool ExtractDPSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath)
{
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen())
{
DPSM<IDType> dpsm;
dpsm.read(rs);
athena::io::ToYAMLStream(dpsm, writer);
return true;
}
return false;
bool ExtractDPSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath) {
athena::io::FileWriter writer(outPath.getAbsolutePath());
if (writer.isOpen()) {
DPSM<IDType> dpsm;
dpsm.read(rs);
athena::io::ToYAMLStream(dpsm, writer);
return true;
}
return false;
}
template bool ExtractDPSM<UniqueID32>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template bool ExtractDPSM<UniqueID64>(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteDPSM(const DPSM<IDType>& dpsm, const hecl::ProjectPath& outPath)
{
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
dpsm.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i=0 ; i<32-rem ; ++i)
w.writeUByte(0xff);
return true;
bool WriteDPSM(const DPSM<IDType>& dpsm, const hecl::ProjectPath& outPath) {
athena::io::FileWriter w(outPath.getAbsolutePath(), true, false);
if (w.hasError())
return false;
dpsm.write(w);
int64_t rem = w.position() % 32;
if (rem)
for (int64_t i = 0; i < 32 - rem; ++i)
w.writeUByte(0xff);
return true;
}
template bool WriteDPSM<UniqueID32>(const DPSM<UniqueID32>& dpsm, const hecl::ProjectPath& outPath);
template bool WriteDPSM<UniqueID64>(const DPSM<UniqueID64>& dpsm, const hecl::ProjectPath& outPath);
}
} // namespace DataSpec::DNAParticle

View File

@ -4,46 +4,45 @@
#include "PAK.hpp"
#include "athena/FileWriter.hpp"
namespace DataSpec::DNAParticle
{
namespace DataSpec::DNAParticle {
template <class IDType>
struct DPSM : BigDNA
{
AT_DECL_EXPLICIT_DNA_YAML
AT_SUBDECL_DNA
struct DPSM : BigDNA {
AT_DECL_EXPLICIT_DNA_YAML
AT_SUBDECL_DNA
struct SQuadDescr
{
IntElementFactory x0_LFT;
RealElementFactory x4_SZE;
RealElementFactory x8_ROT;
VectorElementFactory xc_OFF;
ColorElementFactory x10_CLR;
UVElementFactory<IDType> x14_TEX;
BoolHelper x18_ADD;
struct SQuadDescr {
IntElementFactory x0_LFT;
RealElementFactory x4_SZE;
RealElementFactory x8_ROT;
VectorElementFactory xc_OFF;
ColorElementFactory x10_CLR;
UVElementFactory<IDType> x14_TEX;
BoolHelper x18_ADD;
};
SQuadDescr x0_quad;
SQuadDescr x1c_quad;
ChildResourceFactory<IDType> x38_DMDL;
IntElementFactory x48_DLFT;
VectorElementFactory x4c_DMOP;
VectorElementFactory x50_DMRT;
VectorElementFactory x54_DMSC;
ColorElementFactory x58_DMCL;
union {
struct {
bool x5c_24_DMAB : 1;
bool x5c_25_DMOO : 1;
};
uint8_t dummy;
};
template <class Reader>
void readQuadDecalInfo(Reader& r, uint32_t clsId, SQuadDescr& quad);
void writeQuadDecalInfo(athena::io::YAMLDocWriter& w, const SQuadDescr& quad, bool first) const;
void getQuadDecalBinarySize(size_t& s, const SQuadDescr& desc) const;
void writeQuadDecalInfo(athena::io::IStreamWriter& w, const SQuadDescr& quad, bool first) const;
SQuadDescr x0_quad;
SQuadDescr x1c_quad;
ChildResourceFactory<IDType> x38_DMDL;
IntElementFactory x48_DLFT;
VectorElementFactory x4c_DMOP;
VectorElementFactory x50_DMRT;
VectorElementFactory x54_DMSC;
ColorElementFactory x58_DMCL;
union
{
struct { bool x5c_24_DMAB : 1; bool x5c_25_DMOO : 1;};
uint8_t dummy;
};
template <class Reader>
void readQuadDecalInfo(Reader& r, uint32_t clsId, SQuadDescr& quad);
void writeQuadDecalInfo(athena::io::YAMLDocWriter& w, const SQuadDescr& quad, bool first) const;
void getQuadDecalBinarySize(size_t& s, const SQuadDescr& desc) const;
void writeQuadDecalInfo(athena::io::IStreamWriter& w, const SQuadDescr& quad, bool first) const;
void gatherDependencies(std::vector<hecl::ProjectPath>&) const;
void gatherDependencies(std::vector<hecl::ProjectPath>&) const;
};
template <class IDType>
@ -52,5 +51,4 @@ bool ExtractDPSM(PAKEntryReadStream& rs, const hecl::ProjectPath& outPath);
template <class IDType>
bool WriteDPSM(const DPSM<IDType>& dpsm, const hecl::ProjectPath& outPath);
}
} // namespace DataSpec::DNAParticle

View File

@ -6,260 +6,246 @@
#include "hecl/Blender/Connection.hpp"
#include <cinttypes>
namespace DataSpec
{
namespace DataSpec {
template<class DEAFBABE>
void DeafBabeSendToBlender(hecl::blender::PyOutStream& os, const DEAFBABE& db, bool isDcln, atInt32 idx)
{
os << "material_index = []\n"
"col_bm = bmesh.new()\n";
for (const atVec3f& vert : db.verts)
{
zeus::simd_floats f(vert.simd);
os.format("col_bm.verts.new((%f,%f,%f))\n", f[0], f[1], f[2]);
template <class DEAFBABE>
void DeafBabeSendToBlender(hecl::blender::PyOutStream& os, const DEAFBABE& db, bool isDcln, atInt32 idx) {
os << "material_index = []\n"
"col_bm = bmesh.new()\n";
for (const atVec3f& vert : db.verts) {
zeus::simd_floats f(vert.simd);
os.format("col_bm.verts.new((%f,%f,%f))\n", f[0], f[1], f[2]);
}
os << "col_bm.verts.ensure_lookup_table()\n";
int triIdx = 0;
for (const typename DEAFBABE::Triangle& tri : db.triangleEdgeConnections) {
const typename DEAFBABE::Material& triMat = db.materials[db.triMats[triIdx++]];
const typename DEAFBABE::Edge& edge0 = db.edgeVertConnections[tri.edges[0]];
const typename DEAFBABE::Edge& edge1 = db.edgeVertConnections[tri.edges[1]];
const typename DEAFBABE::Edge& edge2 = db.edgeVertConnections[tri.edges[2]];
if (!edge0.verts[0] && !edge1.verts[0] && !edge2.verts[0])
break;
int vindices[3];
vindices[2] =
(edge1.verts[0] != edge0.verts[0] && edge1.verts[0] != edge0.verts[1]) ? edge1.verts[0] : edge1.verts[1];
if (triMat.flipFace()) {
vindices[0] = edge0.verts[1];
vindices[1] = edge0.verts[0];
} else {
vindices[0] = edge0.verts[0];
vindices[1] = edge0.verts[1];
}
os << "col_bm.verts.ensure_lookup_table()\n";
os << "tri_verts = []\n";
os.format("tri_verts.append(col_bm.verts[%u])\n", vindices[0]);
os.format("tri_verts.append(col_bm.verts[%u])\n", vindices[1]);
os.format("tri_verts.append(col_bm.verts[%u])\n", vindices[2]);
int triIdx = 0;
for (const typename DEAFBABE::Triangle& tri : db.triangleEdgeConnections)
{
const typename DEAFBABE::Material& triMat = db.materials[db.triMats[triIdx++]];
const typename DEAFBABE::Edge& edge0 = db.edgeVertConnections[tri.edges[0]];
const typename DEAFBABE::Edge& edge1 = db.edgeVertConnections[tri.edges[1]];
const typename DEAFBABE::Edge& edge2 = db.edgeVertConnections[tri.edges[2]];
if (!edge0.verts[0] && !edge1.verts[0] && !edge2.verts[0])
break;
os.format(
"face = col_bm.faces.get(tri_verts)\n"
"if face is None:\n"
" face = col_bm.faces.new(tri_verts)\n"
"else:\n"
" face = face.copy()\n"
" for i in range(3):\n"
" face.verts[i].co = tri_verts[i].co\n"
" col_bm.verts.ensure_lookup_table()\n"
"face.material_index = select_material(0x%016" PRIX64
")\n"
"face.smooth = False\n"
"\n",
atUint64(triMat.material));
}
int vindices[3];
vindices[2] =
(edge1.verts[0] != edge0.verts[0] && edge1.verts[0] != edge0.verts[1]) ?
edge1.verts[0] : edge1.verts[1];
db.insertNoClimb(os);
if (triMat.flipFace())
{
vindices[0] = edge0.verts[1];
vindices[1] = edge0.verts[0];
}
else
{
vindices[0] = edge0.verts[0];
vindices[1] = edge0.verts[1];
}
if (isDcln)
os.format("col_mesh = bpy.data.meshes.new('CMESH_%i')\n", idx);
else
os << "col_mesh = bpy.data.meshes.new('CMESH')\n";
os << "tri_verts = []\n";
os.format("tri_verts.append(col_bm.verts[%u])\n", vindices[0]);
os.format("tri_verts.append(col_bm.verts[%u])\n", vindices[1]);
os.format("tri_verts.append(col_bm.verts[%u])\n", vindices[2]);
os << "col_bm.to_mesh(col_mesh)\n"
"col_mesh_obj = bpy.data.objects.new(col_mesh.name, col_mesh)\n"
"\n"
"for mat_name in material_index:\n"
" mat = material_dict[mat_name]\n"
" col_mesh.materials.append(mat)\n"
"\n"
"bpy.context.scene.objects.link(col_mesh_obj)\n"
"bpy.context.scene.objects.active = col_mesh_obj\n"
"bpy.ops.object.mode_set(mode='EDIT')\n"
"bpy.ops.mesh.tris_convert_to_quads()\n"
"bpy.ops.object.mode_set(mode='OBJECT')\n"
"bpy.context.scene.objects.active = None\n";
if (!isDcln)
os << "col_mesh_obj.layers[1] = True\n"
"col_mesh_obj.layers[0] = False\n";
os.format("face = col_bm.faces.get(tri_verts)\n"
"if face is None:\n"
" face = col_bm.faces.new(tri_verts)\n"
"else:\n"
" face = face.copy()\n"
" for i in range(3):\n"
" face.verts[i].co = tri_verts[i].co\n"
" col_bm.verts.ensure_lookup_table()\n"
"face.material_index = select_material(0x%016" PRIX64 ")\n"
"face.smooth = False\n"
"\n",
atUint64(triMat.material));
}
db.insertNoClimb(os);
if (isDcln)
os.format("col_mesh = bpy.data.meshes.new('CMESH_%i')\n", idx);
else
os << "col_mesh = bpy.data.meshes.new('CMESH')\n";
os << "col_bm.to_mesh(col_mesh)\n"
"col_mesh_obj = bpy.data.objects.new(col_mesh.name, col_mesh)\n"
"\n"
"for mat_name in material_index:\n"
" mat = material_dict[mat_name]\n"
" col_mesh.materials.append(mat)\n"
"\n"
"bpy.context.scene.objects.link(col_mesh_obj)\n"
"bpy.context.scene.objects.active = col_mesh_obj\n"
"bpy.ops.object.mode_set(mode='EDIT')\n"
"bpy.ops.mesh.tris_convert_to_quads()\n"
"bpy.ops.object.mode_set(mode='OBJECT')\n"
"bpy.context.scene.objects.active = None\n";
if (!isDcln)
os << "col_mesh_obj.layers[1] = True\n"
"col_mesh_obj.layers[0] = False\n";
os << "col_mesh_obj.draw_type = 'SOLID'\n"
"col_mesh_obj.game.physics_type = 'STATIC'\n"
"\n";
os << "col_mesh_obj.draw_type = 'SOLID'\n"
"col_mesh_obj.game.physics_type = 'STATIC'\n"
"\n";
}
template void DeafBabeSendToBlender<DNAMP1::DeafBabe>(hecl::blender::PyOutStream& os, const DNAMP1::DeafBabe& db, bool isDcln, atInt32 idx);
template void DeafBabeSendToBlender<DNAMP2::DeafBabe>(hecl::blender::PyOutStream& os, const DNAMP2::DeafBabe& db, bool isDcln, atInt32 idx);
template void DeafBabeSendToBlender<DNAMP1::DCLN::Collision>(hecl::blender::PyOutStream& os, const DNAMP1::DCLN::Collision& db, bool isDcln, atInt32 idx);
template void DeafBabeSendToBlender<DNAMP1::DeafBabe>(hecl::blender::PyOutStream& os, const DNAMP1::DeafBabe& db,
bool isDcln, atInt32 idx);
template void DeafBabeSendToBlender<DNAMP2::DeafBabe>(hecl::blender::PyOutStream& os, const DNAMP2::DeafBabe& db,
bool isDcln, atInt32 idx);
template void DeafBabeSendToBlender<DNAMP1::DCLN::Collision>(hecl::blender::PyOutStream& os,
const DNAMP1::DCLN::Collision& db, bool isDcln,
atInt32 idx);
template<class DEAFBABE>
static void PopulateAreaFields(DEAFBABE& db,
const hecl::blender::ColMesh& colMesh,
const zeus::CAABox& fullAABB,
std::enable_if_t<std::is_same<DEAFBABE, DNAMP1::DeafBabe>::value ||
std::is_same<DEAFBABE, DNAMP2::DeafBabe>::value, int>* = 0)
{
AROTBuilder builder;
auto octree = builder.buildCol(colMesh, db.rootNodeType);
static_cast<std::unique_ptr<atUint8[]>&>(db.bspTree) = std::move(octree.first);
db.bspSize = octree.second;
template <class DEAFBABE>
static void PopulateAreaFields(
DEAFBABE& db, const hecl::blender::ColMesh& colMesh, const zeus::CAABox& fullAABB,
std::enable_if_t<std::is_same<DEAFBABE, DNAMP1::DeafBabe>::value || std::is_same<DEAFBABE, DNAMP2::DeafBabe>::value,
int>* = 0) {
AROTBuilder builder;
auto octree = builder.buildCol(colMesh, db.rootNodeType);
static_cast<std::unique_ptr<atUint8[]>&>(db.bspTree) = std::move(octree.first);
db.bspSize = octree.second;
db.unk1 = 0x1000000;
size_t dbSize = 0;
db.binarySize(dbSize);
db.length = dbSize - 8;
db.magic = 0xDEAFBABE;
db.version = 3;
db.aabb[0] = fullAABB.min;
db.aabb[1] = fullAABB.max;
db.unk1 = 0x1000000;
size_t dbSize = 0;
db.binarySize(dbSize);
db.length = dbSize - 8;
db.magic = 0xDEAFBABE;
db.version = 3;
db.aabb[0] = fullAABB.min;
db.aabb[1] = fullAABB.max;
}
template<class DEAFBABE>
static void PopulateAreaFields(DEAFBABE& db,
const hecl::blender::ColMesh& colMesh,
const zeus::CAABox& fullAABB,
std::enable_if_t<std::is_same<DEAFBABE, DNAMP1::DCLN::Collision>::value, int>* = 0)
{
db.magic = 0xDEAFBABE;
db.version = 2;
db.memSize = 0;
template <class DEAFBABE>
static void PopulateAreaFields(DEAFBABE& db, const hecl::blender::ColMesh& colMesh, const zeus::CAABox& fullAABB,
std::enable_if_t<std::is_same<DEAFBABE, DNAMP1::DCLN::Collision>::value, int>* = 0) {
db.magic = 0xDEAFBABE;
db.version = 2;
db.memSize = 0;
}
class MaterialPool
{
std::unordered_map<u64, int> m_materials;
class MaterialPool {
std::unordered_map<u64, int> m_materials;
public:
template <class M, class V>
int AddOrLookup(const M& mat, V& vec)
{
auto search = m_materials.find(mat.material);
if (search != m_materials.end())
return search->second;
auto idx = int(vec.size());
vec.push_back(mat);
m_materials[mat.material] = idx;
return idx;
}
template <class M, class V>
int AddOrLookup(const M& mat, V& vec) {
auto search = m_materials.find(mat.material);
if (search != m_materials.end())
return search->second;
auto idx = int(vec.size());
vec.push_back(mat);
m_materials[mat.material] = idx;
return idx;
}
};
template<class DEAFBABE>
void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::blender::ColMesh& colMesh)
{
using BlendMat = hecl::blender::ColMesh::Material;
template <class DEAFBABE>
void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::blender::ColMesh& colMesh) {
using BlendMat = hecl::blender::ColMesh::Material;
auto MakeMat = [](const BlendMat& mat, bool flipFace) -> typename DEAFBABE::Material
{
typename DEAFBABE::Material dbMat = {};
dbMat.setUnknown(mat.unknown);
dbMat.setSurfaceStone(mat.surfaceStone);
dbMat.setSurfaceMetal(mat.surfaceMetal);
dbMat.setSurfaceGrass(mat.surfaceGrass);
dbMat.setSurfaceIce(mat.surfaceIce);
dbMat.setPillar(mat.pillar);
dbMat.setSurfaceMetalGrating(mat.surfaceMetalGrating);
dbMat.setSurfacePhazon(mat.surfacePhazon);
dbMat.setSurfaceDirt(mat.surfaceDirt);
dbMat.setSurfaceLava(mat.surfaceLava);
dbMat.setSurfaceSPMetal(mat.surfaceSPMetal);
dbMat.setSurfaceLavaStone(mat.surfaceLavaStone);
dbMat.setSurfaceSnow(mat.surfaceSnow);