From 7cd9ddfad92aab3d5ae5545f7077123e1aa68fe1 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Tue, 9 Aug 2016 16:52:00 -1000 Subject: [PATCH] Initial round of MREA cooking imps --- DataSpec/DNACommon/CMDL.cpp | 71 ++++++++++++++++ DataSpec/DNACommon/CMDL.hpp | 8 ++ DataSpec/DNACommon/PAK.cpp | 55 +++++++++++++ DataSpec/DNACommon/PAK.hpp | 2 + DataSpec/DNAMP1/DNAMP1.cpp | 2 +- DataSpec/DNAMP1/MREA.cpp | 158 ++++++++++++++++++++++++++++++++++++ DataSpec/DNAMP1/MREA.hpp | 9 ++ DataSpec/DNAMP1/SCLY.cpp | 13 ++- DataSpec/DNAMP2/DNAMP2.cpp | 2 +- DataSpec/DNAMP3/DNAMP3.cpp | 2 +- DataSpec/SpecMP1.cpp | 19 +++++ hecl | 2 +- 12 files changed, 336 insertions(+), 7 deletions(-) diff --git a/DataSpec/DNACommon/CMDL.cpp b/DataSpec/DNACommon/CMDL.cpp index a81e862e8..b284212d9 100644 --- a/DataSpec/DNACommon/CMDL.cpp +++ b/DataSpec/DNACommon/CMDL.cpp @@ -1,6 +1,7 @@ #include "CMDL.hpp" #include "../DNAMP1/CMDLMaterials.hpp" #include "../DNAMP1/CSKR.hpp" +#include "../DNAMP1/MREA.hpp" #include "../DNAMP2/CMDLMaterials.hpp" #include "../DNAMP2/CSKR.hpp" #include "../DNAMP3/CMDLMaterials.hpp" @@ -1633,6 +1634,76 @@ bool WriteHMDLCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& in template bool WriteHMDLCMDL (const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh); +template +bool WriteMREASecs(std::vector>& secsOut, const hecl::ProjectPath& inPath, + const std::vector& meshes) +{ + return false; +} + +template +bool WriteHMDLMREASecs(std::vector>& secsOut, const hecl::ProjectPath& inPath, + const std::vector& meshes) +{ + /* Build material set */ + { + MaterialSet matSet; + hecl::Frontend::Frontend FE; + size_t endOff = 0; + std::vector texPaths; + for (const Mesh& mesh : meshes) + { + if (mesh.materialSets.size()) + { + for (const Mesh::Material& mat : mesh.materialSets[0]) + { + for (const hecl::ProjectPath& path : mat.texs) + { + bool found = false; + for (const hecl::ProjectPath& ePath : texPaths) + { + if (path == ePath) + { + found = true; + break; + } + } + if (!found) + texPaths.push_back(path); + } + + std::string diagName = hecl::Format("%s:%s", inPath.getLastComponentUTF8(), mat.name.c_str()); + matSet.materials.emplace_back(FE, diagName, mat, mat.iprops, texPaths); + endOff = matSet.materials.back().binarySize(endOff); + matSet.head.addMaterialEndOff(endOff); + } + } + } + for (const hecl::ProjectPath& path : texPaths) + matSet.head.addTexture(path); + + secsOut.emplace_back(matSet.binarySize(0), 0); + athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size()); + matSet.write(w); + } + + /* Iterate meshes */ + for (const Mesh& mesh : meshes) + { + MeshHeader meshHeader = {}; + meshHeader.visorFlags.setFromBlenderProps(mesh.customProps); + memmove(meshHeader.xfMtx, &mesh.sceneXf, 48); + memmove(&meshHeader.aabb[0], &mesh.aabbMin, 12); + memmove(&meshHeader.aabb[1], &mesh.aabbMax, 12); + } + + return true; +} + +template bool WriteHMDLMREASecs +(std::vector>& secsOut, const hecl::ProjectPath& inPath, + const std::vector& meshes); + void SurfaceHeader_1::read(athena::io::IStreamReader& reader) { /* centroid */ diff --git a/DataSpec/DNACommon/CMDL.hpp b/DataSpec/DNACommon/CMDL.hpp index 832aaca75..a73006720 100644 --- a/DataSpec/DNACommon/CMDL.hpp +++ b/DataSpec/DNACommon/CMDL.hpp @@ -169,6 +169,14 @@ bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath template bool WriteHMDLCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh); +template +bool WriteMREASecs(std::vector>& secsOut, const hecl::ProjectPath& inPath, + const std::vector& meshes); + +template +bool WriteHMDLMREASecs(std::vector>& secsOut, const hecl::ProjectPath& inPath, + const std::vector& meshes); + } } diff --git a/DataSpec/DNACommon/PAK.cpp b/DataSpec/DNACommon/PAK.cpp index 84b6d11b0..32388104c 100644 --- a/DataSpec/DNACommon/PAK.cpp +++ b/DataSpec/DNACommon/PAK.cpp @@ -587,6 +587,34 @@ hecl::ProjectPath PAKRouter::getAreaLayerWorking(const IDType& areaI return hecl::ProjectPath(); } +template +hecl::ProjectPath PAKRouter::getAreaLayerWorking(const IDType& areaId, int layerIdx, bool& activeOut) const +{ + activeOut = false; + if (!m_bridges) + LogDNACommon.report(logvisor::Fatal, + "PAKRouter::build() must be called before PAKRouter::getAreaLayerWorking()"); + auto bridgePathIt = m_bridgePaths.cbegin(); + for (const BRIDGETYPE& bridge : *m_bridges) + { + for (const auto& level : bridge.m_levelDeps) + for (const auto& area : level.second.areas) + if (area.first == areaId) + { + hecl::ProjectPath levelPath(bridgePathIt->first, level.second.name); + hecl::ProjectPath areaPath(levelPath, area.second.name); + if (layerIdx < 0) + return areaPath; + const typename Level::Area::Layer& layer = area.second.layers.at(layerIdx); + activeOut = layer.active; + return hecl::ProjectPath(areaPath, layer.name); + } + ++bridgePathIt; + } + return hecl::ProjectPath(); +} + + template hecl::ProjectPath PAKRouter::getAreaLayerCooked(const IDType& areaId, int layerIdx) const { @@ -611,6 +639,33 @@ hecl::ProjectPath PAKRouter::getAreaLayerCooked(const IDType& areaId return hecl::ProjectPath(); } +template +hecl::ProjectPath PAKRouter::getAreaLayerCooked(const IDType& areaId, int layerIdx, bool& activeOut) const +{ + activeOut = false; + if (!m_bridges) + LogDNACommon.report(logvisor::Fatal, + "PAKRouter::build() must be called before PAKRouter::getAreaLayerCooked()"); + auto bridgePathIt = m_bridgePaths.cbegin(); + for (const BRIDGETYPE& bridge : *m_bridges) + { + for (const auto& level : bridge.m_levelDeps) + for (const auto& area : level.second.areas) + if (area.first == areaId) + { + hecl::ProjectPath levelPath(bridgePathIt->second, level.second.name); + hecl::ProjectPath areaPath(levelPath, area.second.name); + if (layerIdx < 0) + return areaPath; + const typename Level::Area::Layer& layer = area.second.layers.at(layerIdx); + activeOut = layer.active; + return hecl::ProjectPath(areaPath, layer.name); + } + ++bridgePathIt; + } + return hecl::ProjectPath(); +} + template class PAKRouter; template class PAKRouter; template class PAKRouter; diff --git a/DataSpec/DNACommon/PAK.hpp b/DataSpec/DNACommon/PAK.hpp index ac8286518..8f1a1e039 100644 --- a/DataSpec/DNACommon/PAK.hpp +++ b/DataSpec/DNACommon/PAK.hpp @@ -182,7 +182,9 @@ public: const RigPair* lookupCMDLRigPair(const IDType& id) const; hecl::ProjectPath getAreaLayerWorking(const IDType& areaId, int layerIdx) const; + hecl::ProjectPath getAreaLayerWorking(const IDType& areaId, int layerIdx, bool& activeOut) const; hecl::ProjectPath getAreaLayerCooked(const IDType& areaId, int layerIdx) const; + hecl::ProjectPath getAreaLayerCooked(const IDType& areaId, int layerIdx, bool& activeOut) const; }; } diff --git a/DataSpec/DNAMP1/DNAMP1.cpp b/DataSpec/DNAMP1/DNAMP1.cpp index 9bd83dbde..23f9e4fbb 100644 --- a/DataSpec/DNAMP1/DNAMP1.cpp +++ b/DataSpec/DNAMP1/DNAMP1.cpp @@ -196,7 +196,7 @@ void PAKBridge::build() while (layer.name.size() && isspace(layer.name.back())) layer.name.pop_back(); #endif - hecl::SNPrintf(num, 16, layer.active ? _S("%02ua ") : _S("%02u "), l-1); + hecl::SNPrintf(num, 16, _S("%02u "), l-1); layer.name = num + layer.name; layer.resources.reserve(area.depLayers[l] - r); diff --git a/DataSpec/DNAMP1/MREA.cpp b/DataSpec/DNAMP1/MREA.cpp index a5a77dffd..5446b2bec 100644 --- a/DataSpec/DNAMP1/MREA.cpp +++ b/DataSpec/DNAMP1/MREA.cpp @@ -220,5 +220,163 @@ void MREA::Name(const SpecBase& dataSpec, pathEnt->name = entry.name + "_path"; } +void MREA::MeshHeader::VisorFlags::setFromBlenderProps(const std::unordered_map& props) +{ + auto search = props.find("retro_disable_enviro_visor"); + if (search != props.cend() && !search->second.compare("True")) + setDisableEnviro(true); + search = props.find("retro_disable_thermal_visor"); + if (search != props.cend() && !search->second.compare("True")) + setDisableThermal(true); + search = props.find("retro_disable_xray_visor"); + if (search != props.cend() && !search->second.compare("True")) + setDisableXray(true); + search = props.find("retro_thermal_level"); + if (search != props.cend()) + { + if (!search->second.compare("COOL")) + setThermalLevel(ThermalLevel::Cool); + else if (!search->second.compare("HOT")) + setThermalLevel(ThermalLevel::Hot); + else if (!search->second.compare("WARM")) + setThermalLevel(ThermalLevel::Warm); + } +} + +bool MREA::Cook(const hecl::ProjectPath& outPath, + const hecl::ProjectPath& inPath, + const std::vector& meshes) +{ + return false; +} + +bool MREA::PCCook(const hecl::ProjectPath& outPath, + const hecl::ProjectPath& inPath, + const std::vector& meshes) +{ + /* Discover area layers */ + hecl::ProjectPath areaDirPath = inPath.getParentPath(); + std::vector layerScriptPaths; + { + hecl::DirectoryEnumerator dEnum(inPath.getParentPath().getAbsolutePath(), + hecl::DirectoryEnumerator::Mode::DirsSorted, + false, false, true); + for (const hecl::DirectoryEnumerator::Entry& ent : dEnum) + { + hecl::ProjectPath layerScriptPath(areaDirPath, ent.m_name + _S("/objects.yaml")); + if (layerScriptPath.getPathType() == hecl::ProjectPath::Type::File) + layerScriptPaths.push_back(std::move(layerScriptPath)); + } + } + + size_t secCount = 1 + meshes.size() * 4; /* (materials, 4 fixed model secs) */ + + /* tally up surfaces */ + for (const DNACMDL::Mesh& mesh : meshes) + secCount += mesh.surfaces.size(); + + /* Header */ + Header head = {}; + head.magic = 0xDEADBEEF; + head.version = 0x1000F; + head.localToWorldMtx[0].vec[0] = 1.f; + head.localToWorldMtx[1].vec[1] = 1.f; + head.localToWorldMtx[2].vec[2] = 1.f; + head.meshCount = meshes.size(); + head.geomSecIdx = 0; + head.arotSecIdx = secCount++; + head.sclySecIdx = secCount++; + head.collisionSecIdx = secCount++; + head.unkSecIdx = secCount++; + head.lightSecIdx = secCount++; + head.visiSecIdx = secCount++; + head.pathSecIdx = secCount++; + head.secCount = secCount; + + std::vector> secs; + secs.reserve(secCount + 2); + + /* Header section */ + secs.emplace_back(head.binarySize(0), 0); + { + athena::io::MemoryWriter w(secs.back().data(), secs.back().size()); + head.write(w); + int i = w.position(); + int end = ROUND_UP_32(i); + for (; i& sizesSec = secs.back(); + + /* Models */ + if (!DNACMDL::WriteHMDLMREASecs(secs, inPath, meshes)) + return false; + + /* AROT */ + + /* SCLY */ + for (const hecl::ProjectPath& layer : layerScriptPaths) + { + FILE* yamlFile = hecl::Fopen(layer.getAbsolutePath().c_str(), _S("r")); + if (!yamlFile) + { + Log.report(logvisor::Fatal, _S("unable to open %s for reading"), layer.getAbsolutePath().c_str()); + return false; + } + + athena::io::YAMLDocReader reader; + yaml_parser_set_input_file(reader.getParser(), yamlFile); + if (!reader.parse()) + { + Log.report(logvisor::Fatal, _S("unable to parse %s"), layer.getAbsolutePath().c_str()); + fclose(yamlFile); + return false; + } + fclose(yamlFile); + + std::string classStr = reader.readString("DNAType"); + if (classStr.empty()) + return false; + } + + /* Collision */ + + + /* Unk */ + + /* Lights */ + + /* VISI */ + + /* PATH */ + + /* Assemble sizes and add padding */ + { + sizesSec.assign(head.secCount, 0); + int totalEnd = sizesSec.size() * 4; + int totalPadEnd = ROUND_UP_32(totalEnd); + athena::io::MemoryWriter w(sizesSec.data(), totalPadEnd); + for (auto it = secs.begin() + 2 ; it != secs.end() ; ++it) + { + std::vector& sec = *it; + int i = sec.size(); + int end = ROUND_UP_32(i); + for (; i& sec : secs) + writer.writeUBytes(sec.data(), sec.size()); + + return true; +} + } } diff --git a/DataSpec/DNAMP1/MREA.hpp b/DataSpec/DNAMP1/MREA.hpp index e9f840fc7..0e56f135e 100644 --- a/DataSpec/DNAMP1/MREA.hpp +++ b/DataSpec/DNAMP1/MREA.hpp @@ -64,6 +64,7 @@ struct MREA ThermalLevel thermalLevel() const {return ThermalLevel(flags >> 4 & 0x3);} void setThermalLevel(ThermalLevel v) {flags &= ~0x30; flags |= atUint32(v) << 4;} const char* thermalLevelStr() const {return GetThermalLevelStr(thermalLevel());} + void setFromBlenderProps(const std::unordered_map& props); } visorFlags; Value xfMtx[3]; Value aabb[2]; @@ -120,6 +121,14 @@ struct MREA PAKEntryReadStream& rs, PAKRouter& pakRouter, PAK::Entry& entry); + + static bool Cook(const hecl::ProjectPath& outPath, + const hecl::ProjectPath& inPath, + const std::vector& meshes); + + static bool PCCook(const hecl::ProjectPath& outPath, + const hecl::ProjectPath& inPath, + const std::vector& meshes); }; } diff --git a/DataSpec/DNAMP1/SCLY.cpp b/DataSpec/DNAMP1/SCLY.cpp index b58afe1b2..37f176277 100644 --- a/DataSpec/DNAMP1/SCLY.cpp +++ b/DataSpec/DNAMP1/SCLY.cpp @@ -36,15 +36,22 @@ size_t SCLY::binarySize(size_t __isz) const return __EnumerateSize(__isz, layers); } -void SCLY::exportToLayerDirectories(const PAK::Entry& entry, PAKRouter &pakRouter, bool force) const +void SCLY::exportToLayerDirectories(const PAK::Entry& entry, PAKRouter& pakRouter, bool force) const { for (atUint32 i = 0; i < layerCount; i++) { - hecl::ProjectPath layerPath = pakRouter.getAreaLayerWorking(entry.id, i); + bool active; + hecl::ProjectPath layerPath = pakRouter.getAreaLayerWorking(entry.id, i, active); if (layerPath.getPathType() == hecl::ProjectPath::Type::None) layerPath.makeDir(); - hecl::ProjectPath yamlFile = hecl::ProjectPath(layerPath, _S("objects.yaml")); + if (active) + { + hecl::ProjectPath activePath(layerPath, "!defaultactive"); + fclose(hecl::Fopen(activePath.getAbsolutePath().c_str(), _S("wb"))); + } + + hecl::ProjectPath yamlFile(layerPath, _S("objects.yaml")); if (force || yamlFile.getPathType() == hecl::ProjectPath::Type::None) { FILE* yaml = hecl::Fopen(yamlFile.getAbsolutePath().c_str(), _S("wb")); diff --git a/DataSpec/DNAMP2/DNAMP2.cpp b/DataSpec/DNAMP2/DNAMP2.cpp index 33de86f00..c365f55f0 100644 --- a/DataSpec/DNAMP2/DNAMP2.cpp +++ b/DataSpec/DNAMP2/DNAMP2.cpp @@ -168,7 +168,7 @@ void PAKBridge::build() while (layer.name.size() && isspace(layer.name.back())) layer.name.pop_back(); #endif - hecl::SNPrintf(num, 16, layer.active ? _S("%02ua ") : _S("%02u "), l-1); + hecl::SNPrintf(num, 16, _S("%02u "), l-1); layer.name = num + layer.name; layer.resources.reserve(area.depLayers[l] - r); diff --git a/DataSpec/DNAMP3/DNAMP3.cpp b/DataSpec/DNAMP3/DNAMP3.cpp index fa5837744..ad32e2a5b 100644 --- a/DataSpec/DNAMP3/DNAMP3.cpp +++ b/DataSpec/DNAMP3/DNAMP3.cpp @@ -178,7 +178,7 @@ void PAKBridge::build() while (layer.name.size() && isspace(layer.name.back())) layer.name.pop_back(); #endif - hecl::SNPrintf(num, 16, layer.active ? _S("%02ua ") : _S("%02u "), l-1); + hecl::SNPrintf(num, 16, _S("%02u "), l-1); layer.name = num + layer.name; } } diff --git a/DataSpec/SpecMP1.cpp b/DataSpec/SpecMP1.cpp index 4a514ddf5..58ef7cb01 100644 --- a/DataSpec/SpecMP1.cpp +++ b/DataSpec/SpecMP1.cpp @@ -8,6 +8,7 @@ #include "DNAMP1/MLVL.hpp" #include "DNAMP1/STRG.hpp" #include "DNAMP1/CMDL.hpp" +#include "DNAMP1/MREA.hpp" #include "DNAMP1/ANCS.hpp" #include "DNACommon/PART.hpp" #include "DNACommon/SWHC.hpp" @@ -384,6 +385,24 @@ struct SpecMP1 : SpecBase BlendStream& ds, bool fast, hecl::BlenderToken& btok, FCookProgress progress) { + std::vector meshes = ds.getMeshList(); + std::vector meshCompiles; + meshCompiles.reserve(meshes.size()); + + for (const std::string& mesh : meshes) + { + hecl::SystemStringView meshSys(mesh); + meshCompiles.push_back(ds.compileMesh(fast ? hecl::HMDLTopology::Triangles : hecl::HMDLTopology::TriStrips, -1, + [&](int surfCount) + { + progress(hecl::SysFormat(_S("%s %d"), meshSys.c_str(), surfCount).c_str()); + })); + } + + if (m_pc) + DNAMP1::MREA::PCCook(out, in, meshCompiles); + else + DNAMP1::MREA::Cook(out, in, meshCompiles); } void cookYAML(const hecl::ProjectPath& out, const hecl::ProjectPath& in, diff --git a/hecl b/hecl index 0ab6b7c07..e8905db61 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit 0ab6b7c072be623b687c1264c314c69aaccfa83e +Subproject commit e8905db61ac226492210fbb1ed96bda7c33a7110