mirror of https://github.com/AxioDL/metaforce.git
Initial work on GameCube package targeting
This commit is contained in:
parent
7c0bf75f7a
commit
7a2fbfc582
|
@ -1199,7 +1199,8 @@ template void NameCMDL<PAKRouter<DNAMP1::PAKBridge>, DNAMP1::MaterialSet>
|
|||
PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
|
||||
const SpecBase& dataspec);
|
||||
|
||||
static void WriteDLVal(athena::io::FileWriter& writer, GX::AttrType type, atUint32 val)
|
||||
template <typename W>
|
||||
static void WriteDLVal(W& writer, GX::AttrType type, atUint32 val)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
@ -1356,7 +1357,7 @@ bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath
|
|||
size_t vertSz = matSets.at(0).materials.at(surf.materialIdx).getVAFlags().vertDLSize();
|
||||
if (surf.verts.size() > 65536)
|
||||
LogDNACommon.report(logvisor::Fatal, "GX DisplayList overflow");
|
||||
size_t secSz = 67 + surf.verts.size() * vertSz;
|
||||
size_t secSz = 68 + surf.verts.size() * vertSz;
|
||||
secSz32 = ROUND_UP_32(secSz);
|
||||
if (secSz32 == 0)
|
||||
secSz32 = 32;
|
||||
|
@ -1430,7 +1431,7 @@ bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath
|
|||
SurfaceHeader header;
|
||||
header.centroid = surf.centroid;
|
||||
header.matIdx = surf.materialIdx;
|
||||
header.dlSize = 3 + surf.verts.size() * vertSz;
|
||||
header.dlSize = ROUND_UP_32(4 + surf.verts.size() * vertSz);
|
||||
header.reflectionNormal = surf.reflectionNormal;
|
||||
header.write(writer);
|
||||
|
||||
|
@ -1461,6 +1462,8 @@ bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath
|
|||
WriteDLVal(writer, vaFlags.tex6(), vert.iUv[6]);
|
||||
}
|
||||
|
||||
writer.writeUByte(0);
|
||||
|
||||
writer.fill(atUint8(0), *padIt);
|
||||
++padIt;
|
||||
}
|
||||
|
@ -1649,13 +1652,319 @@ template bool WriteHMDLCMDL<DNAMP1::HMDLMaterialSet, DNACMDL::SurfaceHeader_2, 2
|
|||
(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh,
|
||||
hecl::blender::PoolSkinIndex& poolSkinIndex);
|
||||
|
||||
struct MaterialPool
|
||||
{
|
||||
std::vector<const Material*> materials;
|
||||
size_t addMaterial(const Material& mat, bool& newMat)
|
||||
{
|
||||
size_t ret = 0;
|
||||
newMat = false;
|
||||
for (const Material* testMat : materials)
|
||||
{
|
||||
if (mat == *testMat)
|
||||
return ret;
|
||||
++ret;
|
||||
}
|
||||
materials.push_back(&mat);
|
||||
newMat = true;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <class MaterialSet, class SurfaceHeader, class MeshHeader>
|
||||
bool WriteMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
|
||||
const std::vector<Mesh>& meshes, zeus::CAABox& fullAABB, std::vector<zeus::CAABox>& meshAABBs)
|
||||
{
|
||||
return false;
|
||||
/* Build material set */
|
||||
std::vector<size_t> surfToGlobalMats;
|
||||
MaterialSet matSet;
|
||||
{
|
||||
MaterialPool matPool;
|
||||
|
||||
size_t surfCount = 0;
|
||||
for (const Mesh& mesh : meshes)
|
||||
surfCount += mesh.surfaces.size();
|
||||
surfToGlobalMats.reserve(surfCount);
|
||||
|
||||
hecl::Frontend::Frontend FE;
|
||||
size_t endOff = 0;
|
||||
std::vector<hecl::ProjectPath> texPaths;
|
||||
std::vector<hecl::Backend::GX> setBackends;
|
||||
atUint32 nextGroupIdx = 0;
|
||||
for (const Mesh& mesh : meshes)
|
||||
{
|
||||
if (mesh.materialSets.size())
|
||||
{
|
||||
std::vector<size_t> meshToGlobalMats;
|
||||
meshToGlobalMats.reserve(mesh.materialSets[0].size());
|
||||
|
||||
for (const Material& mat : mesh.materialSets[0])
|
||||
{
|
||||
bool newMat;
|
||||
size_t idx = matPool.addMaterial(mat, newMat);
|
||||
meshToGlobalMats.push_back(idx);
|
||||
if (!newMat)
|
||||
continue;
|
||||
|
||||
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().data(), mat.name.c_str());
|
||||
hecl::Frontend::IR matIR = FE.compileSource(mat.source, diagName);
|
||||
setBackends.emplace_back();
|
||||
hecl::Backend::GX& matGX = setBackends.back();
|
||||
matGX.reset(matIR, FE.getDiagnostics());
|
||||
|
||||
atUint32 groupIdx = -1;
|
||||
for (size_t i=0 ; i<setBackends.size()-1 ; ++i)
|
||||
{
|
||||
const hecl::Backend::GX& other = setBackends[i];
|
||||
if (matGX == other)
|
||||
{
|
||||
groupIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (groupIdx == -1)
|
||||
groupIdx = nextGroupIdx++;
|
||||
|
||||
auto lightmapped = mat.iprops.find("retro_lightmapped");
|
||||
bool lm = lightmapped != mat.iprops.cend() && lightmapped->second != 0;
|
||||
|
||||
matSet.materials.emplace_back(matGX, mat.iprops, mat.texs, texPaths,
|
||||
mesh.colorLayerCount, mesh.uvLayerCount,
|
||||
lm, false, groupIdx);
|
||||
|
||||
matSet.materials.back().binarySize(endOff);
|
||||
matSet.head.addMaterialEndOff(endOff);
|
||||
}
|
||||
|
||||
for (const Mesh::Surface& surf : mesh.surfaces)
|
||||
surfToGlobalMats.push_back(meshToGlobalMats[surf.materialIdx]);
|
||||
}
|
||||
}
|
||||
for (const hecl::ProjectPath& path : texPaths)
|
||||
matSet.head.addTexture(path);
|
||||
|
||||
size_t secSz = 0;
|
||||
matSet.binarySize(secSz);
|
||||
secsOut.emplace_back(secSz, 0);
|
||||
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
|
||||
matSet.write(w);
|
||||
}
|
||||
|
||||
/* Iterate meshes */
|
||||
auto matIt = surfToGlobalMats.cbegin();
|
||||
int meshIdx = 0;
|
||||
for (const Mesh& mesh : meshes)
|
||||
{
|
||||
zeus::CTransform meshXf(mesh.sceneXf.val);
|
||||
meshXf.basis.transpose();
|
||||
|
||||
/* Header */
|
||||
{
|
||||
MeshHeader meshHeader = {};
|
||||
meshHeader.visorFlags.setFromBlenderProps(mesh.customProps);
|
||||
memmove(meshHeader.xfMtx, &mesh.sceneXf, 48);
|
||||
|
||||
zeus::CAABox aabb(zeus::CVector3f(mesh.aabbMin), zeus::CVector3f(mesh.aabbMax));
|
||||
aabb = aabb.getTransformedAABox(meshXf);
|
||||
meshAABBs.push_back(aabb);
|
||||
fullAABB.accumulateBounds(aabb);
|
||||
meshHeader.aabb[0] = aabb.min;
|
||||
meshHeader.aabb[1] = aabb.max;
|
||||
|
||||
size_t secSz = 0;
|
||||
meshHeader.binarySize(secSz);
|
||||
secsOut.emplace_back(secSz, 0);
|
||||
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
|
||||
meshHeader.write(w);
|
||||
}
|
||||
|
||||
std::vector<size_t> surfEndOffs;
|
||||
surfEndOffs.reserve(mesh.surfaces.size());
|
||||
size_t endOff = 0;
|
||||
auto smatIt = matIt;
|
||||
for (const Mesh::Surface& surf : mesh.surfaces)
|
||||
{
|
||||
const typename MaterialSet::Material::VAFlags& vaFlags =
|
||||
matSet.materials.at(*smatIt++).getVAFlags();
|
||||
size_t vertSz = vaFlags.vertDLSize();
|
||||
|
||||
endOff += 96 + vertSz * surf.verts.size() + 4;
|
||||
endOff = ROUND_UP_32(endOff);
|
||||
surfEndOffs.push_back(endOff);
|
||||
}
|
||||
|
||||
/* Positions */
|
||||
{
|
||||
size_t secSz = ROUND_UP_32(mesh.pos.size() * 12);
|
||||
if (secSz == 0)
|
||||
secSz = 32;
|
||||
secsOut.emplace_back(secSz, 0);
|
||||
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
|
||||
for (const hecl::blender::Vector3f& v : mesh.pos)
|
||||
{
|
||||
zeus::CVector3f preXfPos = meshXf * zeus::CVector3f(v);
|
||||
w.writeVec3fBig(preXfPos);
|
||||
}
|
||||
}
|
||||
|
||||
/* Normals */
|
||||
{
|
||||
size_t secSz = ROUND_UP_32(mesh.norm.size() * 6);
|
||||
if (secSz == 0)
|
||||
secSz = 32;
|
||||
secsOut.emplace_back(secSz, 0);
|
||||
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
|
||||
for (const hecl::blender::Vector3f& v : mesh.norm)
|
||||
{
|
||||
zeus::CVector3f preXfNorm = (meshXf.basis * zeus::CVector3f(v)).normalized();
|
||||
for (int i=0 ; i<3 ; ++i)
|
||||
{
|
||||
int tmpV = int(preXfNorm[i] * 16834.f);
|
||||
tmpV = zeus::clamp(-32768, tmpV, 32767);
|
||||
w.writeInt16Big(atInt16(tmpV));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Colors */
|
||||
{
|
||||
size_t secSz = ROUND_UP_32(mesh.color.size() * 4);
|
||||
if (secSz == 0)
|
||||
secSz = 32;
|
||||
secsOut.emplace_back(secSz, 0);
|
||||
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
|
||||
for (const hecl::blender::Vector3f& v : mesh.color)
|
||||
{
|
||||
zeus::CColor col((zeus::CVector4f(zeus::CVector3f(v))));
|
||||
col.writeRGBA8(w);
|
||||
}
|
||||
}
|
||||
|
||||
/* UVs */
|
||||
{
|
||||
size_t secSz = ROUND_UP_32(mesh.uv.size() * 8);
|
||||
if (secSz == 0)
|
||||
secSz = 32;
|
||||
secsOut.emplace_back(secSz, 0);
|
||||
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
|
||||
for (const hecl::blender::Vector2f& v : mesh.uv)
|
||||
w.writeVec2fBig(v.val);
|
||||
}
|
||||
|
||||
/* LUVs */
|
||||
{
|
||||
size_t secSz = ROUND_UP_32(mesh.luv.size() * 4);
|
||||
if (secSz == 0)
|
||||
secSz = 32;
|
||||
secsOut.emplace_back(secSz, 0);
|
||||
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
|
||||
for (const hecl::blender::Vector2f& v : mesh.luv)
|
||||
{
|
||||
for (int i=0 ; i<2 ; ++i)
|
||||
{
|
||||
int tmpV = int(v.val.vec[i] * 32768.f);
|
||||
tmpV = zeus::clamp(-32768, tmpV, 32767);
|
||||
w.writeInt16Big(atInt16(tmpV));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Surface index */
|
||||
{
|
||||
secsOut.emplace_back((surfEndOffs.size() + 1) * 4, 0);
|
||||
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
|
||||
w.writeUint32Big(surfEndOffs.size());
|
||||
for (size_t off : surfEndOffs)
|
||||
w.writeUint32Big(off);
|
||||
}
|
||||
|
||||
/* Surfaces */
|
||||
GX::Primitive prim;
|
||||
if (mesh.topology == hecl::HMDLTopology::Triangles)
|
||||
prim = GX::TRIANGLES;
|
||||
else if (mesh.topology == hecl::HMDLTopology::TriStrips)
|
||||
prim = GX::TRIANGLESTRIP;
|
||||
else
|
||||
LogDNACommon.report(logvisor::Fatal, "unrecognized mesh output mode");
|
||||
for (const Mesh::Surface& surf : mesh.surfaces)
|
||||
{
|
||||
size_t matIdx = *matIt++;
|
||||
const typename MaterialSet::Material::VAFlags& vaFlags =
|
||||
matSet.materials.at(matIdx).getVAFlags();
|
||||
size_t vertSz = vaFlags.vertDLSize();
|
||||
|
||||
SurfaceHeader header;
|
||||
header.centroid = meshXf * zeus::CVector3f(surf.centroid);
|
||||
header.matIdx = matIdx;
|
||||
header.dlSize = ROUND_UP_32(4 + surf.verts.size() * vertSz);
|
||||
header.reflectionNormal = (meshXf.basis * zeus::CVector3f(surf.reflectionNormal)).normalized();
|
||||
header.aabbSz = 24;
|
||||
zeus::CAABox aabb(zeus::CVector3f(surf.aabbMin), zeus::CVector3f(surf.aabbMax));
|
||||
aabb = aabb.getTransformedAABox(meshXf);
|
||||
header.aabb[0] = aabb.min;
|
||||
header.aabb[1] = aabb.max;
|
||||
|
||||
size_t secSz = 0;
|
||||
header.binarySize(secSz);
|
||||
secSz += 4 + surf.verts.size() * vertSz;
|
||||
secSz = ROUND_UP_32(secSz);
|
||||
secsOut.emplace_back(secSz, 0);
|
||||
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
|
||||
header.write(w);
|
||||
|
||||
w.writeUByte(prim);
|
||||
w.writeUint16Big(surf.verts.size());
|
||||
|
||||
for (const Mesh::Surface::Vert& vert : surf.verts)
|
||||
{
|
||||
atUint32 skinIdx = vert.iBankSkin * 3;
|
||||
WriteDLVal(w, vaFlags.pnMatIdx(), skinIdx);
|
||||
WriteDLVal(w, vaFlags.tex0MatIdx(), skinIdx);
|
||||
WriteDLVal(w, vaFlags.tex1MatIdx(), skinIdx);
|
||||
WriteDLVal(w, vaFlags.tex2MatIdx(), skinIdx);
|
||||
WriteDLVal(w, vaFlags.tex3MatIdx(), skinIdx);
|
||||
WriteDLVal(w, vaFlags.tex4MatIdx(), skinIdx);
|
||||
WriteDLVal(w, vaFlags.tex5MatIdx(), skinIdx);
|
||||
WriteDLVal(w, vaFlags.tex6MatIdx(), skinIdx);
|
||||
WriteDLVal(w, vaFlags.position(), vert.iPos);
|
||||
WriteDLVal(w, vaFlags.normal(), vert.iNorm);
|
||||
WriteDLVal(w, vaFlags.color0(), vert.iColor[0]);
|
||||
WriteDLVal(w, vaFlags.color1(), vert.iColor[1]);
|
||||
WriteDLVal(w, vaFlags.tex0(), vert.iUv[0]);
|
||||
WriteDLVal(w, vaFlags.tex1(), vert.iUv[1]);
|
||||
WriteDLVal(w, vaFlags.tex2(), vert.iUv[2]);
|
||||
WriteDLVal(w, vaFlags.tex3(), vert.iUv[3]);
|
||||
WriteDLVal(w, vaFlags.tex4(), vert.iUv[4]);
|
||||
WriteDLVal(w, vaFlags.tex5(), vert.iUv[5]);
|
||||
WriteDLVal(w, vaFlags.tex6(), vert.iUv[6]);
|
||||
}
|
||||
|
||||
w.writeUByte(0);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool WriteMREASecs<DNAMP1::MaterialSet, DNACMDL::SurfaceHeader_1, DNAMP1::MREA::MeshHeader>
|
||||
(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
|
||||
const std::vector<Mesh>& meshes, zeus::CAABox& fullAABB, std::vector<zeus::CAABox>& meshAABBs);
|
||||
|
||||
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)
|
||||
|
@ -1663,24 +1972,7 @@ bool WriteHMDLMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::P
|
|||
/* Build material set */
|
||||
std::vector<size_t> surfToGlobalMats;
|
||||
{
|
||||
struct MaterialPool
|
||||
{
|
||||
std::vector<const Material*> materials;
|
||||
size_t addMaterial(const Material& mat, bool& newMat)
|
||||
{
|
||||
size_t ret = 0;
|
||||
newMat = false;
|
||||
for (const Material* testMat : materials)
|
||||
{
|
||||
if (mat == *testMat)
|
||||
return ret;
|
||||
++ret;
|
||||
}
|
||||
materials.push_back(&mat);
|
||||
newMat = true;
|
||||
return ret;
|
||||
}
|
||||
} matPool;
|
||||
MaterialPool matPool;
|
||||
|
||||
size_t surfCount = 0;
|
||||
for (const Mesh& mesh : meshes)
|
||||
|
|
|
@ -10,6 +10,9 @@ ThreadLocalPtr<SpecBase> g_curSpec;
|
|||
ThreadLocalPtr<PAKRouterBase> g_PakRouter;
|
||||
ThreadLocalPtr<hecl::blender::Token> g_ThreadBlenderToken;
|
||||
ThreadLocalPtr<hecl::Database::Project> UniqueIDBridge::s_Project;
|
||||
ThreadLocalPtr<IDRestorer<UniqueID32>> UniqueIDBridge::s_restorer32;
|
||||
ThreadLocalPtr<IDRestorer<UniqueID64>> UniqueIDBridge::s_restorer64;
|
||||
ThreadLocalPtr<IDRestorer<UniqueID128>> UniqueIDBridge::s_restorer128;
|
||||
UniqueID32 UniqueID32::kInvalidId;
|
||||
|
||||
template <class IDType>
|
||||
|
@ -38,11 +41,16 @@ hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const IDType& id, bool si
|
|||
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());
|
||||
|
@ -54,6 +62,8 @@ 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)
|
||||
|
@ -83,12 +93,21 @@ void UniqueIDBridge::TransformOldHashToNewHash(UniqueID32& id);
|
|||
template
|
||||
void UniqueIDBridge::TransformOldHashToNewHash(UniqueID64& id);
|
||||
|
||||
void UniqueIDBridge::setThreadProject(hecl::Database::Project& 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;
|
||||
}
|
||||
|
||||
template <>
|
||||
void UniqueID32::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
|
||||
{assign(reader.readUint32Big());}
|
||||
|
@ -164,7 +183,7 @@ void AuxiliaryID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& wr
|
|||
{
|
||||
if (!operator bool())
|
||||
return;
|
||||
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this, true);
|
||||
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath<UniqueID32>(*this, true);
|
||||
if (!path)
|
||||
path = UniqueIDBridge::TranslatePakIdToPath(m_baseId);
|
||||
if (!path)
|
||||
|
@ -177,6 +196,15 @@ void AuxiliaryID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& wr
|
|||
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
template <>
|
||||
void UniqueID64::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
|
||||
{assign(reader.readUint64Big());}
|
||||
|
@ -215,14 +243,14 @@ std::string UniqueID64::toString() const
|
|||
template <>
|
||||
void UniqueID128::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
|
||||
{
|
||||
m_id[0] = reader.readUint64Big();
|
||||
m_id[1] = reader.readUint64Big();
|
||||
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[0]);
|
||||
writer.writeUint64Big(m_id[1]);
|
||||
writer.writeUint64Big(m_id.id[0]);
|
||||
writer.writeUint64Big(m_id.id[1]);
|
||||
}
|
||||
template <>
|
||||
void UniqueID128::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader)
|
||||
|
@ -248,7 +276,7 @@ void UniqueID128::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s)
|
|||
std::string UniqueID128::toString() const
|
||||
{
|
||||
char buf[33];
|
||||
snprintf(buf, 33, "%016" PRIX64 "%016" PRIX64, m_id[0], m_id[1]);
|
||||
snprintf(buf, 33, "%016" PRIX64 "%016" PRIX64, m_id.id[0], m_id.id[1]);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
|
|
|
@ -123,6 +123,9 @@ class UniqueIDBridge
|
|||
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;
|
||||
public:
|
||||
template <class IDType>
|
||||
static hecl::ProjectPath TranslatePakIdToPath(const IDType& id, bool silenceWarnings=false);
|
||||
|
@ -131,19 +134,61 @@ public:
|
|||
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 <>
|
||||
inline IDRestorer<UniqueID32>* UniqueIDBridge::GetIDRestorer<UniqueID32>()
|
||||
{
|
||||
return s_restorer32.get();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void UniqueIDBridge::SetIDRestorer<UniqueID32>(IDRestorer<UniqueID32>* restorer)
|
||||
{
|
||||
s_restorer32.reset(restorer);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline IDRestorer<UniqueID64>* UniqueIDBridge::GetIDRestorer<UniqueID64>()
|
||||
{
|
||||
return s_restorer64.get();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void UniqueIDBridge::SetIDRestorer<UniqueID64>(IDRestorer<UniqueID64>* restorer)
|
||||
{
|
||||
s_restorer64.reset(restorer);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline IDRestorer<UniqueID128>* UniqueIDBridge::GetIDRestorer<UniqueID128>()
|
||||
{
|
||||
return s_restorer128.get();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void UniqueIDBridge::SetIDRestorer<UniqueID128>(IDRestorer<UniqueID128>* restorer)
|
||||
{
|
||||
s_restorer128.reset(restorer);
|
||||
}
|
||||
|
||||
/** PAK 32-bit Unique ID */
|
||||
class UniqueID32 : public BigDNA
|
||||
{
|
||||
protected:
|
||||
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) { m_id = id ? id : 0xffffffff; }
|
||||
void assign(uint32_t id, bool noOriginal = false);
|
||||
|
||||
UniqueID32& operator=(const hecl::ProjectPath& path)
|
||||
{assign(path.hash().val32()); return *this;}
|
||||
|
@ -157,7 +202,7 @@ public:
|
|||
void clear() {m_id = 0xffffffff;}
|
||||
|
||||
UniqueID32() = default;
|
||||
UniqueID32(uint32_t idin) {assign(idin);}
|
||||
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)
|
||||
|
@ -200,9 +245,10 @@ 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) { m_id = id ? id : 0xffffffffffffffff; }
|
||||
void assign(uint64_t id, bool noOriginal = false);
|
||||
|
||||
UniqueID64& operator=(const hecl::ProjectPath& path)
|
||||
{assign(path.hash().val64()); return *this;}
|
||||
|
@ -215,7 +261,7 @@ public:
|
|||
void clear() {m_id = 0xffffffffffffffff;}
|
||||
|
||||
UniqueID64() = default;
|
||||
UniqueID64(uint64_t idin) {assign(idin);}
|
||||
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)
|
||||
|
@ -247,23 +293,32 @@ public:
|
|||
/** PAK 128-bit Unique ID */
|
||||
class UniqueID128 : public BigDNA
|
||||
{
|
||||
union
|
||||
public:
|
||||
union Value
|
||||
{
|
||||
uint64_t m_id[2];
|
||||
uint64_t id[2];
|
||||
#if __SSE__
|
||||
__m128i m_id128;
|
||||
__m128i id128;
|
||||
#endif
|
||||
};
|
||||
private:
|
||||
Value m_id;
|
||||
public:
|
||||
using value_type = uint64_t;
|
||||
AT_DECL_EXPLICIT_DNA_YAML
|
||||
UniqueID128() {m_id[0]=0xffffffffffffffff; m_id[1]=0xffffffffffffffff;}
|
||||
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[0] != 0xffffffffffffffff && m_id[0] != 0 && m_id[1] != 0xffffffffffffffff && m_id[1] != 0;}
|
||||
{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[0] = path.hash().val64();
|
||||
m_id[1] = 0;
|
||||
m_id.id[0] = path.hash().val64();
|
||||
m_id.id[1] = 0;
|
||||
return *this;
|
||||
}
|
||||
UniqueID128(const hecl::ProjectPath& path) {*this = path;}
|
||||
|
@ -271,27 +326,27 @@ public:
|
|||
bool operator!=(const UniqueID128& other) const
|
||||
{
|
||||
#if __SSE__
|
||||
__m128i vcmp = _mm_cmpeq_epi32(m_id128, other.m_id128);
|
||||
__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[0] != other.m_id[0]) || (m_id[1] != other.m_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
|
||||
{
|
||||
#if __SSE__
|
||||
__m128i vcmp = _mm_cmpeq_epi32(m_id128, other.m_id128);
|
||||
__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[0] == other.m_id[0]) && (m_id[1] == other.m_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[0] = 0xffffffffffffffff; m_id[1] = 0xffffffffffffffff;}
|
||||
uint64_t toUint64() const {return m_id[0];}
|
||||
uint64_t toHighUint64() const {return m_id[0];}
|
||||
uint64_t toLowUint64() const {return m_id[1];}
|
||||
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;}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1271,6 +1271,126 @@ bool ANCS::CookCSKR(const hecl::ProjectPath& outPath,
|
|||
CINF cinf(arm, boneIdMap);
|
||||
}
|
||||
|
||||
const DNAANCS::Actor::Subtype* subtype = nullptr;
|
||||
for (const DNAANCS::Actor::Subtype& sub : actor.subtypes)
|
||||
{
|
||||
if (!sub.name.compare(subNameView.str()))
|
||||
{
|
||||
subtype = ⊂
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!subtype)
|
||||
Log.report(logvisor::Fatal, _S("unable to find subtype '%s'"), subName.c_str());
|
||||
|
||||
const hecl::ProjectPath* modelPath = nullptr;
|
||||
if (overName.empty())
|
||||
{
|
||||
modelPath = &subtype->mesh;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& overlay : subtype->overlayMeshes)
|
||||
if (!overlay.first.compare(overNameView.str()))
|
||||
{
|
||||
modelPath = &overlay.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!modelPath)
|
||||
Log.report(logvisor::Fatal, _S("unable to resolve model path of %s:%s"), subName.c_str(), overName.c_str());
|
||||
|
||||
if (!modelPath->isFile())
|
||||
Log.report(logvisor::Fatal, _S("unable to resolve '%s'"), modelPath->getRelativePath().data());
|
||||
|
||||
hecl::ProjectPath skinIntPath = modelPath->getCookedPath(SpecEntMP1).getWithExtension(_S(".skinint"));
|
||||
if (!skinIntPath.isFileOrGlob() || skinIntPath.getModtime() < modelPath->getModtime())
|
||||
if (!modelCookFunc(*modelPath))
|
||||
Log.report(logvisor::Fatal, _S("unable to cook '%s'"), modelPath->getRelativePath().data());
|
||||
|
||||
athena::io::FileReader skinIO(skinIntPath.getAbsolutePath(), 1024*32, false);
|
||||
if (skinIO.hasError())
|
||||
Log.report(logvisor::Fatal, _S("unable to open '%s'"), skinIntPath.getRelativePath().data());
|
||||
|
||||
std::vector<std::string> boneNames;
|
||||
uint32_t boneNameCount = skinIO.readUint32Big();
|
||||
boneNames.reserve(boneNameCount);
|
||||
for (uint32_t i=0 ; i<boneNameCount ; ++i)
|
||||
boneNames.push_back(skinIO.readString());
|
||||
|
||||
std::vector<std::pair<std::vector<std::pair<uint32_t, float>>, uint32_t>> skins;
|
||||
uint32_t skinCount = skinIO.readUint32Big();
|
||||
skins.resize(skinCount);
|
||||
for (uint32_t i=0 ; i<skinCount ; ++i)
|
||||
{
|
||||
std::pair<std::vector<std::pair<uint32_t, float>>, uint32_t>& virtualBone = skins[i];
|
||||
uint32_t bindCount = skinIO.readUint32Big();
|
||||
virtualBone.first.reserve(bindCount);
|
||||
for (uint32_t j=0 ; j<bindCount ; ++j)
|
||||
{
|
||||
uint32_t bIdx = skinIO.readUint32Big();
|
||||
float weight = skinIO.readFloatBig();
|
||||
const std::string& name = boneNames[bIdx];
|
||||
auto search = boneIdMap.find(name);
|
||||
if (search == boneIdMap.cend())
|
||||
Log.report(logvisor::Fatal, "unable to find bone '%s' in %s",
|
||||
name.c_str(), inPath.getRelativePathUTF8().data());
|
||||
virtualBone.first.emplace_back(search->second, weight);
|
||||
}
|
||||
virtualBone.second = skinIO.readUint32Big();
|
||||
}
|
||||
|
||||
uint32_t posCount = skinIO.readUint32Big();
|
||||
uint32_t normCount = skinIO.readUint32Big();
|
||||
|
||||
skinIO.close();
|
||||
|
||||
athena::io::TransactionalFileWriter skinOut(outPath.getAbsolutePath());
|
||||
|
||||
skinOut.writeUint32Big(skins.size());
|
||||
for (auto& virtuaBone : skins)
|
||||
{
|
||||
skinOut.writeUint32Big(virtuaBone.first.size());
|
||||
for (auto& bind : virtuaBone.first)
|
||||
{
|
||||
skinOut.writeUint32Big(bind.first);
|
||||
skinOut.writeFloatBig(bind.second);
|
||||
}
|
||||
skinOut.writeUint32Big(virtuaBone.second);
|
||||
}
|
||||
|
||||
skinOut.writeUint32Big(0xffffffff);
|
||||
skinOut.writeUint32Big(posCount);
|
||||
skinOut.writeUint32Big(0xffffffff);
|
||||
skinOut.writeUint32Big(normCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ANCS::CookCSKRPC(const hecl::ProjectPath& outPath,
|
||||
const hecl::ProjectPath& inPath,
|
||||
const DNAANCS::Actor& actor,
|
||||
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc)
|
||||
{
|
||||
hecl::SystemString subName(inPath.getAuxInfo().begin(),
|
||||
inPath.getAuxInfo().end() - 5);
|
||||
hecl::SystemString overName;
|
||||
auto dotPos = subName.rfind(_S('.'));
|
||||
if (dotPos != hecl::SystemString::npos)
|
||||
{
|
||||
overName = hecl::SystemString(subName.begin() + dotPos + 1, subName.end());
|
||||
subName = hecl::SystemString(subName.begin(), subName.begin() + dotPos);
|
||||
}
|
||||
hecl::SystemUTF8Conv subNameView(subName);
|
||||
hecl::SystemUTF8Conv overNameView(overName);
|
||||
|
||||
/* Build bone ID map */
|
||||
std::unordered_map<std::string, atInt32> boneIdMap;
|
||||
for (const DNAANCS::Armature& arm : actor.armatures)
|
||||
{
|
||||
CINF cinf(arm, boneIdMap);
|
||||
}
|
||||
|
||||
const DNAANCS::Actor::Subtype* subtype = nullptr;
|
||||
for (const DNAANCS::Actor::Subtype& sub : actor.subtypes)
|
||||
{
|
||||
|
|
|
@ -468,9 +468,9 @@ struct ANCS : BigDNA
|
|||
trans->enumeratePrimitives(func);
|
||||
}
|
||||
|
||||
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
|
||||
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut, int charIdx) const
|
||||
{
|
||||
for (const CharacterSet::CharacterInfo& ci : characterSet.characters)
|
||||
auto doCi = [&](const CharacterSet::CharacterInfo& ci)
|
||||
{
|
||||
for (const auto& id : ci.partResData.part)
|
||||
g_curSpec->flattenDependencies(id, pathsOut);
|
||||
|
@ -480,7 +480,12 @@ struct ANCS : BigDNA
|
|||
g_curSpec->flattenDependencies(id, pathsOut);
|
||||
for (const auto& id : ci.partResData.elsc)
|
||||
g_curSpec->flattenDependencies(id, pathsOut);
|
||||
}
|
||||
};
|
||||
if (charIdx < 0)
|
||||
for (const CharacterSet::CharacterInfo& ci : characterSet.characters)
|
||||
doCi(ci);
|
||||
else if (charIdx < characterSet.characters.size())
|
||||
doCi(characterSet.characters[charIdx]);
|
||||
}
|
||||
|
||||
static bool Extract(const SpecBase& dataSpec,
|
||||
|
@ -504,6 +509,10 @@ struct ANCS : BigDNA
|
|||
const hecl::ProjectPath& inPath,
|
||||
const DNAANCS::Actor& actor,
|
||||
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc);
|
||||
static bool CookCSKRPC(const hecl::ProjectPath& outPath,
|
||||
const hecl::ProjectPath& inPath,
|
||||
const DNAANCS::Actor& actor,
|
||||
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc);
|
||||
|
||||
static bool CookANIM(const hecl::ProjectPath& outPath,
|
||||
const hecl::ProjectPath& inPath,
|
||||
|
|
|
@ -74,6 +74,10 @@ bool CMDL::Cook(const hecl::ProjectPath& outPath,
|
|||
/* Output skinning intermediate */
|
||||
auto vertCountIt = skinMesh.contiguousSkinVertCounts.cbegin();
|
||||
athena::io::FileWriter writer(outPath.getWithExtension(_S(".skinint")).getAbsolutePath());
|
||||
writer.writeUint32Big(skinMesh.boneNames.size());
|
||||
for (const std::string& boneName : skinMesh.boneNames)
|
||||
writer.writeString(boneName);
|
||||
|
||||
writer.writeUint32Big(skinMesh.skins.size());
|
||||
for (const std::vector<DNACMDL::Mesh::SkinBind> skin : skinMesh.skins)
|
||||
{
|
||||
|
@ -86,9 +90,7 @@ bool CMDL::Cook(const hecl::ProjectPath& outPath,
|
|||
writer.writeUint32Big(*vertCountIt++);
|
||||
}
|
||||
writer.writeUint32Big(skinMesh.pos.size());
|
||||
writer.writeUint32Big(skinMesh.boneNames.size());
|
||||
for (const std::string& boneName : skinMesh.boneNames)
|
||||
writer.writeString(boneName);
|
||||
writer.writeUint32Big(skinMesh.norm.size());
|
||||
}
|
||||
else if (!DNACMDL::WriteCMDL<MaterialSet, DNACMDL::SurfaceHeader_1, 2>(outPath, inPath, mesh))
|
||||
return false;
|
||||
|
|
|
@ -60,6 +60,70 @@ bool MLVL::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl:
|
|||
return DNAMLVL::ReadMLVLToBlender(conn, mlvl, outPath, pakRouter, entry, force, fileChanged);
|
||||
}
|
||||
|
||||
struct BulkResources
|
||||
{
|
||||
std::unordered_map<hecl::Hash, size_t> addedBulkPaths;
|
||||
bool addBulkPath(const hecl::ProjectPath& path, size_t areaIdx)
|
||||
{
|
||||
auto search = addedBulkPaths.find(path.hash());
|
||||
if (search == addedBulkPaths.cend())
|
||||
{
|
||||
addedBulkPaths.insert(std::make_pair(path.hash(), areaIdx));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct LayerResources
|
||||
{
|
||||
BulkResources& bulkResources;
|
||||
std::unordered_map<hecl::Hash, std::pair<size_t, size_t>> addedPaths;
|
||||
std::vector<std::vector<hecl::ProjectPath>> layerPaths;
|
||||
std::unordered_set<hecl::Hash> addedSharedPaths;
|
||||
std::vector<hecl::ProjectPath> sharedPaths;
|
||||
LayerResources(BulkResources& bulkResources) : bulkResources(bulkResources) {}
|
||||
void beginLayer()
|
||||
{
|
||||
layerPaths.resize(layerPaths.size() + 1);
|
||||
}
|
||||
void addSharedPath(const hecl::ProjectPath& path)
|
||||
{
|
||||
auto search = addedSharedPaths.find(path.hash());
|
||||
if (search == addedSharedPaths.cend())
|
||||
{
|
||||
sharedPaths.push_back(path);
|
||||
addedSharedPaths.insert(path.hash());
|
||||
}
|
||||
}
|
||||
void addPath(const hecl::ProjectPath& path)
|
||||
{
|
||||
auto search = addedPaths.find(path.hash());
|
||||
if (search != addedPaths.cend())
|
||||
{
|
||||
if (search->second.first == layerPaths.size() - 1)
|
||||
return;
|
||||
else
|
||||
{
|
||||
hecl::ProjectPath& toMove = layerPaths[search->second.first][search->second.second];
|
||||
addSharedPath(toMove);
|
||||
toMove.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
layerPaths.back().push_back(path);
|
||||
addedPaths.insert(std::make_pair(path.hash(),
|
||||
std::make_pair(layerPaths.size() - 1, layerPaths.back().size() - 1)));
|
||||
}
|
||||
}
|
||||
void addBulkPath(const hecl::ProjectPath& path, size_t areaIdx)
|
||||
{
|
||||
if (bulkResources.addBulkPath(path, areaIdx))
|
||||
addPath(path);
|
||||
}
|
||||
};
|
||||
|
||||
bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const World& wld,
|
||||
hecl::blender::Token& btok)
|
||||
{
|
||||
|
@ -80,6 +144,7 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
|
||||
size_t areaIdx = 0;
|
||||
size_t nameOffset = 0;
|
||||
BulkResources bulkResources;
|
||||
for (const World::Area& area : wld.areas)
|
||||
{
|
||||
if (area.path.getPathType() != hecl::ProjectPath::Type::Directory)
|
||||
|
@ -110,6 +175,7 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
bool areaInit = false;
|
||||
|
||||
size_t layerIdx = 0;
|
||||
LayerResources layerResources(bulkResources);
|
||||
for (const hecl::DirectoryEnumerator::Entry& e : dEnum)
|
||||
{
|
||||
hecl::SystemString layerName;
|
||||
|
@ -139,6 +205,8 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
layer.read(reader);
|
||||
}
|
||||
|
||||
layerResources.beginLayer();
|
||||
|
||||
/* Set active flag state */
|
||||
hecl::ProjectPath defActivePath(area.path, e.m_name + _S("/!defaultactive"));
|
||||
bool active = defActivePath.isNone() ? false : true;
|
||||
|
@ -221,14 +289,11 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
areaInit = true;
|
||||
}
|
||||
|
||||
MLVL::Area& areaOut = mlvl.areas.back();
|
||||
areaOut.depLayers.push_back(areaOut.deps.size());
|
||||
|
||||
|
||||
/* Gather memory relays, scans, and dependencies */
|
||||
{
|
||||
g_ThreadBlenderToken.reset(&btok);
|
||||
std::vector<hecl::ProjectPath> depPaths;
|
||||
std::vector<hecl::ProjectPath> bulkPaths;
|
||||
for (std::unique_ptr<IScriptObject>& obj : layer.objects)
|
||||
{
|
||||
if (obj->type == int(urde::EScriptObjectType::MemoryRelay))
|
||||
|
@ -260,20 +325,14 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
}
|
||||
|
||||
obj->gatherDependencies(depPaths);
|
||||
obj->gatherBulkDependencies(bulkPaths);
|
||||
}
|
||||
|
||||
/* Cull duplicate paths and add typed hash to list */
|
||||
std::unordered_set<hecl::Hash> addedPaths;
|
||||
for (const hecl::ProjectPath& path : depPaths)
|
||||
{
|
||||
if (addedPaths.find(path.hash()) == addedPaths.cend())
|
||||
{
|
||||
addedPaths.insert(path.hash());
|
||||
urde::SObjectTag tag = g_curSpec->buildTagFromPath(path, btok);
|
||||
if (tag.id.IsValid())
|
||||
areaOut.deps.emplace_back(tag.id.Value(), tag.type);
|
||||
}
|
||||
}
|
||||
layerResources.addBulkPath(path, areaIdx);
|
||||
for (const hecl::ProjectPath& path : bulkPaths)
|
||||
layerResources.addBulkPath(path, areaIdx);
|
||||
}
|
||||
|
||||
hecl::SystemUTF8Conv layerU8(layerName);
|
||||
|
@ -288,6 +347,22 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
++layerIdx;
|
||||
}
|
||||
|
||||
/* Build deplist */
|
||||
MLVL::Area& areaOut = mlvl.areas.back();
|
||||
for (const std::vector<hecl::ProjectPath>& layer : layerResources.layerPaths)
|
||||
{
|
||||
areaOut.depLayers.push_back(areaOut.deps.size());
|
||||
for (const hecl::ProjectPath& path : layer)
|
||||
{
|
||||
if (path)
|
||||
{
|
||||
urde::SObjectTag tag = g_curSpec->buildTagFromPath(path, btok);
|
||||
if (tag.id.IsValid())
|
||||
areaOut.deps.emplace_back(tag.id.Value(), tag.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Append Memory Relays */
|
||||
mlvl.memRelayLinks.insert(mlvl.memRelayLinks.end(), memRelayLinks.begin(), memRelayLinks.end());
|
||||
|
||||
|
@ -295,33 +370,26 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||
auto& conn = btok.getBlenderConnection();
|
||||
if (conn.openBlend(areaPath))
|
||||
{
|
||||
MLVL::Area& areaOut = mlvl.areas.back();
|
||||
areaOut.depLayers.push_back(areaOut.deps.size());
|
||||
|
||||
auto ds = conn.beginData();
|
||||
std::vector<hecl::ProjectPath> texs = ds.getTextures();
|
||||
ds.close();
|
||||
|
||||
std::unordered_set<hecl::Hash> addedPaths;
|
||||
for (const hecl::ProjectPath& path : texs)
|
||||
layerResources.addSharedPath(path);
|
||||
|
||||
for (const hecl::ProjectPath& path : layerResources.sharedPaths)
|
||||
{
|
||||
if (addedPaths.find(path.hash()) == addedPaths.cend())
|
||||
{
|
||||
addedPaths.insert(path.hash());
|
||||
urde::SObjectTag tag = g_curSpec->buildTagFromPath(path, btok);
|
||||
if (tag.id.IsValid())
|
||||
areaOut.deps.emplace_back(tag.id.Value(), tag.type);
|
||||
}
|
||||
urde::SObjectTag tag = g_curSpec->buildTagFromPath(path, btok);
|
||||
if (tag.id.IsValid())
|
||||
areaOut.deps.emplace_back(tag.id.Value(), tag.type);
|
||||
}
|
||||
|
||||
hecl::ProjectPath pathPath(areaPath.getParentPath(), _S("!path.blend"));
|
||||
urde::SObjectTag pathTag = g_curSpec->buildTagFromPath(pathPath, btok);
|
||||
if (pathTag.id.IsValid())
|
||||
areaOut.deps.emplace_back(pathTag.id.Value(), pathTag.type);
|
||||
|
||||
urde::SObjectTag tag = g_curSpec->buildTagFromPath(areaPath, btok);
|
||||
if (tag.id.IsValid())
|
||||
areaOut.deps.emplace_back(tag.id.Value(), tag.type);
|
||||
}
|
||||
|
||||
++areaIdx;
|
||||
|
|
|
@ -421,17 +421,9 @@ bool MREA::Cook(const hecl::ProjectPath& outPath,
|
|||
const hecl::ProjectPath& inPath,
|
||||
const std::vector<DNACMDL::Mesh>& meshes,
|
||||
const ColMesh& cMesh,
|
||||
const std::vector<Light>& lights)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
||||
const hecl::ProjectPath& inPath,
|
||||
const std::vector<DNACMDL::Mesh>& meshes,
|
||||
const ColMesh& cMesh,
|
||||
const std::vector<Light>& lights,
|
||||
hecl::blender::Token& btok)
|
||||
const std::vector<Light>& lights,
|
||||
hecl::blender::Token& btok,
|
||||
bool pc)
|
||||
{
|
||||
/* Discover area layers */
|
||||
hecl::ProjectPath areaDirPath = inPath.getParentPath();
|
||||
|
@ -448,7 +440,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
|||
}
|
||||
}
|
||||
|
||||
size_t secCount = 1 + meshes.size() * 5; /* (materials, 5 fixed model secs) */
|
||||
size_t secCount = 1 + meshes.size() * (pc ? 5 : 7); /* (materials, 5/7 fixed model secs) */
|
||||
|
||||
/* tally up surfaces */
|
||||
for (const DNACMDL::Mesh& mesh : meshes)
|
||||
|
@ -457,7 +449,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
|||
/* Header */
|
||||
Header head = {};
|
||||
head.magic = 0xDEADBEEF;
|
||||
head.version = 0x1000F;
|
||||
head.version = pc ? 0x1000F : 0xF;
|
||||
head.localToWorldMtx[0].vec[0] = 1.f;
|
||||
head.localToWorldMtx[1].vec[1] = 1.f;
|
||||
head.localToWorldMtx[2].vec[2] = 1.f;
|
||||
|
@ -490,7 +482,6 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
|||
|
||||
/* Sizes section */
|
||||
secs.emplace_back();
|
||||
std::vector<uint8_t>& sizesSec = secs.back();
|
||||
|
||||
/* Pre-emptively build full AABB and mesh AABBs in world coords */
|
||||
zeus::CAABox fullAabb;
|
||||
|
@ -498,9 +489,18 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
|||
meshAabbs.reserve(meshes.size());
|
||||
|
||||
/* Models */
|
||||
if (!DNACMDL::WriteHMDLMREASecs<HMDLMaterialSet, DNACMDL::SurfaceHeader_2, MeshHeader>
|
||||
if (pc)
|
||||
{
|
||||
if (!DNACMDL::WriteHMDLMREASecs<HMDLMaterialSet, DNACMDL::SurfaceHeader_2, MeshHeader>
|
||||
(secs, inPath, meshes, fullAabb, meshAabbs))
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!DNACMDL::WriteMREASecs<MaterialSet, DNACMDL::SurfaceHeader_1, MeshHeader>
|
||||
(secs, inPath, meshes, fullAabb, meshAabbs))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* AROT */
|
||||
{
|
||||
|
@ -807,6 +807,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
|||
|
||||
/* Assemble sizes and add padding */
|
||||
{
|
||||
std::vector<uint8_t>& sizesSec = secs[1];
|
||||
sizesSec.assign((((head.secCount) + 7) & ~7) * 4, 0);
|
||||
athena::io::MemoryWriter w(sizesSec.data(), sizesSec.size());
|
||||
for (auto it = secs.begin() + 2 ; it != secs.end() ; ++it)
|
||||
|
|
|
@ -129,14 +129,9 @@ struct MREA
|
|||
const hecl::ProjectPath& inPath,
|
||||
const std::vector<DNACMDL::Mesh>& meshes,
|
||||
const ColMesh& cMesh,
|
||||
const std::vector<Light>& lights);
|
||||
|
||||
static bool PCCook(const hecl::ProjectPath& outPath,
|
||||
const hecl::ProjectPath& inPath,
|
||||
const std::vector<DNACMDL::Mesh>& meshes,
|
||||
const ColMesh& cMesh,
|
||||
const std::vector<Light>& lights,
|
||||
hecl::blender::Token& btok);
|
||||
const std::vector<Light>& lights,
|
||||
hecl::blender::Token& btok,
|
||||
bool pc);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -40,10 +40,14 @@ struct DoorArea : IScriptObject
|
|||
|
||||
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
|
||||
{
|
||||
animationParameters.depANCS(pathsOut);
|
||||
actorParameters.depIDs(pathsOut);
|
||||
}
|
||||
|
||||
void gatherBulkDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
|
||||
{
|
||||
animationParameters.depANCS(pathsOut);
|
||||
}
|
||||
|
||||
void gatherScans(std::vector<Scan>& scansOut) const
|
||||
{
|
||||
actorParameters.scanIDs(scansOut);
|
||||
|
|
|
@ -45,6 +45,7 @@ struct IScriptObject : BigDNAVYaml
|
|||
std::unordered_map<UniqueID32, std::pair<UniqueID32, UniqueID32>>&) const {}
|
||||
virtual void nameIDs(PAKRouter<PAKBridge>& pakRouter) const {}
|
||||
virtual void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const {}
|
||||
virtual void gatherBulkDependencies(std::vector<hecl::ProjectPath>& pathsOut) const {}
|
||||
virtual void gatherScans(std::vector<Scan>& scansOut) const {}
|
||||
virtual zeus::CAABox getVISIAABB(hecl::blender::Token& btok) const { return {}; }
|
||||
};
|
||||
|
|
|
@ -110,6 +110,11 @@ struct AnimationParameters : BigDNA
|
|||
}
|
||||
|
||||
void depANCS(std::vector<hecl::ProjectPath>& pathsOut) const
|
||||
{
|
||||
g_curSpec->flattenDependencies(animationCharacterSet, pathsOut, character);
|
||||
}
|
||||
|
||||
void depANCSAll(std::vector<hecl::ProjectPath>& pathsOut) const
|
||||
{
|
||||
g_curSpec->flattenDependencies(animationCharacterSet, pathsOut);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,11 @@ struct PlayerActor : IScriptObject
|
|||
actorParameters.depIDs(pathsOut);
|
||||
}
|
||||
|
||||
void gatherBulkDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
|
||||
{
|
||||
animationParameters.depANCSAll(pathsOut);
|
||||
}
|
||||
|
||||
void gatherScans(std::vector<Scan>& scansOut) const
|
||||
{
|
||||
actorParameters.scanIDs(scansOut);
|
||||
|
|
|
@ -39,12 +39,13 @@ static const hecl::SystemChar* MomErr[] =
|
|||
};
|
||||
|
||||
constexpr uint32_t MomErrCount = std::extent<decltype(MomErr)>::value;
|
||||
|
||||
SpecBase::SpecBase(const hecl::Database::DataSpecEntry* specEntry, hecl::Database::Project& project, bool pc)
|
||||
: hecl::Database::IDataSpec(specEntry), m_project(project), m_pc(pc),
|
||||
m_masterShader(project.getProjectWorkingPath(), ".hecl/RetroMasterShader.blend")
|
||||
{
|
||||
AssetNameMap::InitAssetNameMap();
|
||||
DataSpec::UniqueIDBridge::setThreadProject(m_project);
|
||||
SpecBase::setThreadProject();
|
||||
}
|
||||
|
||||
SpecBase::~SpecBase()
|
||||
|
@ -59,9 +60,75 @@ static const hecl::SystemString regP = _S("PAL");
|
|||
|
||||
void SpecBase::setThreadProject()
|
||||
{
|
||||
UniqueIDBridge::setThreadProject(m_project);
|
||||
UniqueIDBridge::SetThreadProject(m_project);
|
||||
}
|
||||
|
||||
template <typename IDType>
|
||||
IDRestorer<IDType>::IDRestorer(const hecl::ProjectPath& yamlPath, const hecl::Database::Project& project)
|
||||
{
|
||||
using ValType = typename IDType::value_type;
|
||||
if (!yamlPath.isFile())
|
||||
return;
|
||||
|
||||
athena::io::YAMLDocReader r;
|
||||
athena::io::FileReader fr(yamlPath.getAbsolutePath());
|
||||
if (!fr.isOpen() || !r.parse(&fr))
|
||||
return;
|
||||
|
||||
m_newToOrig.reserve(r.getRootNode()->m_mapChildren.size());
|
||||
m_origToNew.reserve(r.getRootNode()->m_mapChildren.size());
|
||||
for (const auto& node : r.getRootNode()->m_mapChildren)
|
||||
{
|
||||
char* end = const_cast<char*>(node.first.c_str());
|
||||
ValType id = strtoull(end, &end, 16);
|
||||
if (end != node.first.c_str() + sizeof(ValType) * 2)
|
||||
continue;
|
||||
|
||||
hecl::ProjectPath path(project.getProjectWorkingPath(), node.second->m_scalarString.c_str());
|
||||
m_newToOrig.push_back(std::make_pair(IDType{path.hash().valT<ValType>(), true}, IDType{id, true}));
|
||||
m_origToNew.push_back(std::make_pair(IDType{id, true}, IDType{path.hash().valT<ValType>(), true}));
|
||||
}
|
||||
|
||||
std::sort(m_newToOrig.begin(), m_newToOrig.end(),
|
||||
[](const std::pair<IDType, IDType>& a, const std::pair<IDType, IDType>& b) {
|
||||
return a.first < b.first;
|
||||
});
|
||||
std::sort(m_origToNew.begin(), m_origToNew.end(),
|
||||
[](const std::pair<IDType, IDType>& a, const std::pair<IDType, IDType>& b) {
|
||||
return a.first < b.first;
|
||||
});
|
||||
|
||||
Log.report(logvisor::Info, _S("Loaded Original IDs '%s'"), yamlPath.getRelativePath().data());
|
||||
}
|
||||
|
||||
template <typename IDType>
|
||||
IDType IDRestorer<IDType>::newToOriginal(IDType id) const
|
||||
{
|
||||
if (!id)
|
||||
return {};
|
||||
auto search = rstl::binary_find(m_newToOrig.cbegin(), m_newToOrig.cend(), id,
|
||||
[](const auto& id) { return id.first; });
|
||||
if (search == m_newToOrig.cend())
|
||||
return {};
|
||||
return search->second;
|
||||
}
|
||||
|
||||
template <typename IDType>
|
||||
IDType IDRestorer<IDType>::originalToNew(IDType id) const
|
||||
{
|
||||
if (!id)
|
||||
return {};
|
||||
auto search = rstl::binary_find(m_origToNew.cbegin(), m_origToNew.cend(), id,
|
||||
[](const auto& id) { return id.first; });
|
||||
if (search == m_origToNew.cend())
|
||||
return {};
|
||||
return search->second;
|
||||
}
|
||||
|
||||
template class IDRestorer<UniqueID32>;
|
||||
template class IDRestorer<UniqueID64>;
|
||||
template class IDRestorer<UniqueID128>;
|
||||
|
||||
bool SpecBase::canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps)
|
||||
{
|
||||
m_disc = nod::OpenDiscFromImage(info.srcpath, m_isWii);
|
||||
|
@ -340,9 +407,95 @@ void SpecBase::doCook(const hecl::ProjectPath& path, const hecl::ProjectPath& co
|
|||
}
|
||||
}
|
||||
|
||||
void SpecBase::flattenDependenciesBlend(const hecl::ProjectPath& in,
|
||||
std::vector<hecl::ProjectPath>& pathsOut,
|
||||
hecl::blender::Token& btok,
|
||||
int charIdx)
|
||||
{
|
||||
hecl::blender::Connection& conn = btok.getBlenderConnection();
|
||||
if (!conn.openBlend(in))
|
||||
return;
|
||||
switch (conn.getBlendType())
|
||||
{
|
||||
case hecl::blender::BlendType::Mesh:
|
||||
{
|
||||
hecl::blender::DataStream ds = conn.beginData();
|
||||
std::vector<hecl::ProjectPath> texs = ds.getTextures();
|
||||
for (const hecl::ProjectPath& tex : texs)
|
||||
pathsOut.push_back(tex);
|
||||
break;
|
||||
}
|
||||
case hecl::blender::BlendType::Actor:
|
||||
{
|
||||
hecl::ProjectPath asGlob = in.getWithExtension(_S(".*"), true);
|
||||
hecl::blender::DataStream ds = conn.beginData();
|
||||
hecl::blender::Actor actor = ds.compileActorCharacterOnly();
|
||||
|
||||
auto doSubtype = [&](Actor::Subtype& sub)
|
||||
{
|
||||
if (sub.armature >= 0)
|
||||
{
|
||||
pathsOut.push_back(sub.mesh);
|
||||
|
||||
hecl::SystemStringConv chSysName(sub.name);
|
||||
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(chSysName.sys_str()) + _S(".CSKR")));
|
||||
|
||||
const auto& arm = actor.armatures[sub.armature];
|
||||
hecl::SystemStringConv armSysName(arm.name);
|
||||
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(armSysName.sys_str()) + _S(".CINF")));
|
||||
for (const auto& overlay : sub.overlayMeshes)
|
||||
{
|
||||
hecl::SystemStringConv ovelaySys(overlay.first);
|
||||
pathsOut.push_back(overlay.second);
|
||||
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(chSysName.sys_str()) + _S('.') +
|
||||
ovelaySys.c_str() + _S(".CSKR")));
|
||||
}
|
||||
}
|
||||
};
|
||||
if (charIdx < 0)
|
||||
for (auto& sub : actor.subtypes)
|
||||
doSubtype(sub);
|
||||
else if (charIdx < actor.subtypes.size())
|
||||
doSubtype(actor.subtypes[charIdx]);
|
||||
|
||||
auto actNames = ds.getActionNames();
|
||||
for (const auto& act : actNames)
|
||||
{
|
||||
hecl::SystemStringConv actSysName(act);
|
||||
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(actSysName.sys_str()) + _S(".ANIM")));
|
||||
hecl::ProjectPath evntPath = asGlob.getWithExtension(
|
||||
hecl::SysFormat(_S(".%s.evnt.yaml"), actSysName.c_str()).c_str(), true);
|
||||
if (evntPath.isFile())
|
||||
pathsOut.push_back(evntPath);
|
||||
}
|
||||
ds.close();
|
||||
|
||||
hecl::ProjectPath yamlPath = asGlob.getWithExtension(_S(".yaml"), true);
|
||||
if (yamlPath.isFile())
|
||||
{
|
||||
athena::io::FileReader reader(yamlPath.getAbsolutePath());
|
||||
flattenDependenciesANCSYAML(reader, pathsOut, charIdx);
|
||||
}
|
||||
|
||||
pathsOut.push_back(asGlob);
|
||||
return;
|
||||
}
|
||||
case hecl::blender::BlendType::Area:
|
||||
{
|
||||
hecl::blender::DataStream ds = conn.beginData();
|
||||
std::vector<hecl::ProjectPath> texs = ds.getTextures();
|
||||
for (const hecl::ProjectPath& tex : texs)
|
||||
pathsOut.push_back(tex);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpecBase::flattenDependencies(const hecl::ProjectPath& path,
|
||||
std::vector<hecl::ProjectPath>& pathsOut,
|
||||
hecl::blender::Token& btok)
|
||||
hecl::blender::Token& btok,
|
||||
int charIdx)
|
||||
{
|
||||
DataSpec::g_curSpec.reset(this);
|
||||
g_ThreadBlenderToken.reset(&btok);
|
||||
|
@ -355,77 +508,7 @@ void SpecBase::flattenDependencies(const hecl::ProjectPath& path,
|
|||
|
||||
if (hecl::IsPathBlend(asBlend))
|
||||
{
|
||||
hecl::blender::Connection& conn = btok.getBlenderConnection();
|
||||
if (!conn.openBlend(asBlend))
|
||||
return;
|
||||
switch (conn.getBlendType())
|
||||
{
|
||||
case hecl::blender::BlendType::Mesh:
|
||||
{
|
||||
hecl::blender::DataStream ds = conn.beginData();
|
||||
std::vector<hecl::ProjectPath> texs = ds.getTextures();
|
||||
for (const hecl::ProjectPath& tex : texs)
|
||||
pathsOut.push_back(tex);
|
||||
break;
|
||||
}
|
||||
case hecl::blender::BlendType::Actor:
|
||||
{
|
||||
hecl::ProjectPath asGlob = path.getWithExtension(_S(".*"), true);
|
||||
hecl::blender::DataStream ds = conn.beginData();
|
||||
hecl::blender::Actor actor = ds.compileActorCharacterOnly();
|
||||
for (auto& sub : actor.subtypes)
|
||||
{
|
||||
if (sub.armature >= 0)
|
||||
{
|
||||
pathsOut.push_back(sub.mesh);
|
||||
|
||||
hecl::SystemStringConv chSysName(sub.name);
|
||||
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(chSysName.sys_str()) + _S(".CSKR")));
|
||||
|
||||
const auto& arm = actor.armatures[sub.armature];
|
||||
hecl::SystemStringConv armSysName(arm.name);
|
||||
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(armSysName.sys_str()) + _S(".CINF")));
|
||||
for (const auto& overlay : sub.overlayMeshes)
|
||||
{
|
||||
hecl::SystemStringConv ovelaySys(overlay.first);
|
||||
pathsOut.push_back(overlay.second);
|
||||
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(chSysName.sys_str()) + _S('.') +
|
||||
ovelaySys.c_str() + _S(".CSKR")));
|
||||
}
|
||||
}
|
||||
}
|
||||
auto actNames = ds.getActionNames();
|
||||
for (const auto& act : actNames)
|
||||
{
|
||||
hecl::SystemStringConv actSysName(act);
|
||||
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(actSysName.sys_str()) + _S(".ANIM")));
|
||||
hecl::ProjectPath evntPath = asGlob.getWithExtension(
|
||||
hecl::SysFormat(_S(".%s.evnt.yaml"), actSysName.c_str()).c_str(), true);
|
||||
if (evntPath.isFile())
|
||||
pathsOut.push_back(evntPath);
|
||||
}
|
||||
ds.close();
|
||||
|
||||
hecl::ProjectPath yamlPath = asGlob.getWithExtension(_S(".yaml"), true);
|
||||
if (yamlPath.isFile())
|
||||
{
|
||||
athena::io::FileReader reader(yamlPath.getAbsolutePath());
|
||||
flattenDependenciesANCSYAML(reader, pathsOut);
|
||||
}
|
||||
|
||||
pathsOut.push_back(asGlob);
|
||||
return;
|
||||
}
|
||||
case hecl::blender::BlendType::Area:
|
||||
{
|
||||
hecl::blender::DataStream ds = conn.beginData();
|
||||
std::vector<hecl::ProjectPath> texs = ds.getTextures();
|
||||
for (const hecl::ProjectPath& tex : texs)
|
||||
pathsOut.push_back(tex);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
flattenDependenciesBlend(asBlend, pathsOut, btok, charIdx);
|
||||
}
|
||||
else if (hecl::IsPathYAML(path))
|
||||
{
|
||||
|
@ -436,18 +519,18 @@ void SpecBase::flattenDependencies(const hecl::ProjectPath& path,
|
|||
pathsOut.push_back(path);
|
||||
}
|
||||
|
||||
void SpecBase::flattenDependencies(const UniqueID32& id, std::vector<hecl::ProjectPath>& pathsOut)
|
||||
void SpecBase::flattenDependencies(const UniqueID32& id, std::vector<hecl::ProjectPath>& pathsOut, int charIdx)
|
||||
{
|
||||
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
|
||||
if (path)
|
||||
flattenDependencies(path, pathsOut, *g_ThreadBlenderToken.get());
|
||||
flattenDependencies(path, pathsOut, *g_ThreadBlenderToken.get(), charIdx);
|
||||
}
|
||||
|
||||
void SpecBase::flattenDependencies(const UniqueID64& id, std::vector<hecl::ProjectPath>& pathsOut)
|
||||
void SpecBase::flattenDependencies(const UniqueID64& id, std::vector<hecl::ProjectPath>& pathsOut, int charIdx)
|
||||
{
|
||||
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
|
||||
if (path)
|
||||
flattenDependencies(path, pathsOut, *g_ThreadBlenderToken.get());
|
||||
flattenDependencies(path, pathsOut, *g_ThreadBlenderToken.get(), charIdx);
|
||||
}
|
||||
|
||||
bool SpecBase::canPackage(const hecl::ProjectPath& path)
|
||||
|
@ -550,8 +633,13 @@ void SpecBase::doPackage(const hecl::ProjectPath& path, const hecl::Database::Da
|
|||
auto components = path.getWithExtension(_S(""), true).getPathComponents();
|
||||
if (components.size() <= 1)
|
||||
return;
|
||||
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(),
|
||||
_S("out/") + components[0] + _S("/") + components[1] + _S(".upak"));
|
||||
hecl::ProjectPath outPath;
|
||||
if (hecl::ProjectPath(m_project.getProjectWorkingPath(), _S("out/files/") + components[0]).isDirectory())
|
||||
outPath.assign(m_project.getProjectWorkingPath(),
|
||||
_S("out/files/") + components[0] + _S("/") + components[1] + entry->m_pakExt.data());
|
||||
else
|
||||
outPath.assign(m_project.getProjectWorkingPath(),
|
||||
_S("out/files/") + components[1] + entry->m_pakExt.data());
|
||||
outPath.makeDirChain(false);
|
||||
|
||||
/* Output file */
|
||||
|
|
|
@ -23,6 +23,17 @@ class YAMLDocWriter;
|
|||
namespace DataSpec
|
||||
{
|
||||
|
||||
template <typename IDType>
|
||||
class IDRestorer
|
||||
{
|
||||
std::vector<std::pair<IDType, IDType>> m_newToOrig;
|
||||
std::vector<std::pair<IDType, IDType>> m_origToNew;
|
||||
public:
|
||||
IDRestorer(const hecl::ProjectPath& yamlPath, const hecl::Database::Project& project);
|
||||
IDType newToOriginal(IDType id) const;
|
||||
IDType originalToNew(IDType id) const;
|
||||
};
|
||||
|
||||
struct SpecBase : hecl::Database::IDataSpec
|
||||
{
|
||||
/* HECL Adaptors */
|
||||
|
@ -116,11 +127,18 @@ struct SpecBase : hecl::Database::IDataSpec
|
|||
/* Dependency flatteners */
|
||||
void flattenDependencies(const hecl::ProjectPath& in,
|
||||
std::vector<hecl::ProjectPath>& pathsOut,
|
||||
hecl::blender::Token& btok);
|
||||
void flattenDependencies(const class UniqueID32& id, std::vector<hecl::ProjectPath>& pathsOut);
|
||||
void flattenDependencies(const class UniqueID64& id, std::vector<hecl::ProjectPath>& pathsOut);
|
||||
hecl::blender::Token& btok,
|
||||
int charIdx = -1);
|
||||
void flattenDependencies(const class UniqueID32& id, std::vector<hecl::ProjectPath>& pathsOut, int charIdx = -1);
|
||||
void flattenDependencies(const class UniqueID64& id, std::vector<hecl::ProjectPath>& pathsOut, int charIdx = -1);
|
||||
void flattenDependenciesBlend(const hecl::ProjectPath& in,
|
||||
std::vector<hecl::ProjectPath>& pathsOut,
|
||||
hecl::blender::Token& btok,
|
||||
int charIdx = -1);
|
||||
virtual void flattenDependenciesYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut)=0;
|
||||
virtual void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut)=0;
|
||||
virtual void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin,
|
||||
std::vector<hecl::ProjectPath>& pathsOut,
|
||||
int charIdx = -1)=0;
|
||||
|
||||
virtual void buildWorldPakList(const hecl::ProjectPath& worldPath,
|
||||
const hecl::ProjectPath& worldPathCooked,
|
||||
|
@ -211,7 +229,7 @@ protected:
|
|||
bool fast, const hecl::MultiProgressPrinter& progress,
|
||||
athena::io::FileWriter& pakOut);
|
||||
|
||||
private:
|
||||
protected:
|
||||
std::unique_ptr<nod::DiscBase> m_disc;
|
||||
bool m_isWii;
|
||||
bool m_standalone;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "DNAMP1/CSNG.hpp"
|
||||
#include "DNAMP1/MAPA.hpp"
|
||||
#include "DNAMP1/PATH.hpp"
|
||||
#include "DNAMP1/FRME.hpp"
|
||||
#include "DNACommon/ATBL.hpp"
|
||||
#include "DNACommon/FONT.hpp"
|
||||
#include "DNACommon/PART.hpp"
|
||||
|
@ -135,7 +136,7 @@ struct OriginalIDs
|
|||
originalIDs.push_back(std::make_pair(id, path.hash().val32()));
|
||||
}
|
||||
std::sort(originalIDs.begin(), originalIDs.end(),
|
||||
[](const std::pair<UniqueID32, UniqueID32>& a, const std::pair<UniqueID32, UniqueID32>& b) -> bool {
|
||||
[](const std::pair<UniqueID32, UniqueID32>& a, const std::pair<UniqueID32, UniqueID32>& b) {
|
||||
return a.first < b.first;
|
||||
});
|
||||
|
||||
|
@ -148,7 +149,7 @@ struct OriginalIDs
|
|||
}
|
||||
|
||||
std::sort(originalIDs.begin(), originalIDs.end(),
|
||||
[](const std::pair<UniqueID32, UniqueID32>& a, const std::pair<UniqueID32, UniqueID32>& b) -> bool {
|
||||
[](const std::pair<UniqueID32, UniqueID32>& a, const std::pair<UniqueID32, UniqueID32>& b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
for (const auto& idPair : originalIDs)
|
||||
|
@ -176,12 +177,22 @@ struct SpecMP1 : SpecBase
|
|||
|
||||
std::unique_ptr<uint8_t[]> m_dolBuf;
|
||||
|
||||
IDRestorer<UniqueID32> m_idRestorer;
|
||||
|
||||
void setThreadProject()
|
||||
{
|
||||
SpecBase::setThreadProject();
|
||||
UniqueIDBridge::SetIDRestorer(&m_idRestorer);
|
||||
}
|
||||
|
||||
SpecMP1(const hecl::Database::DataSpecEntry* specEntry, hecl::Database::Project& project, bool pc)
|
||||
: SpecBase(specEntry, project, pc)
|
||||
, m_workPath(project.getProjectWorkingPath(), _S("MP1"))
|
||||
, m_cookPath(project.getProjectCookedPath(SpecEntMP1), _S("MP1"))
|
||||
, m_pakRouter(*this, m_workPath, m_cookPath)
|
||||
, m_idRestorer({project.getProjectWorkingPath(), "MP1/!original_ids.yaml"}, project)
|
||||
{
|
||||
setThreadProject();
|
||||
}
|
||||
|
||||
void buildPaks(nod::Node& root, const std::vector<hecl::SystemString>& args, ExtractReport& rep)
|
||||
|
@ -372,7 +383,8 @@ struct SpecMP1 : SpecBase
|
|||
|
||||
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
||||
outPath.makeDir();
|
||||
hecl::ProjectPath mp1OutPath(outPath, _S("MP1"));
|
||||
disc.getDataPartition()->extractSysFiles(outPath.getAbsolutePath(), ctx);
|
||||
hecl::ProjectPath mp1OutPath(outPath, m_standalone ? _S("files") : _S("files/MP1"));
|
||||
mp1OutPath.makeDir();
|
||||
|
||||
/* Extract non-pak files */
|
||||
|
@ -780,15 +792,22 @@ struct SpecMP1 : SpecBase
|
|||
{
|
||||
Actor actor = ds.compileActorCharacterOnly();
|
||||
ds.close();
|
||||
DNAMP1::ANCS::CookCSKR(out, in, actor, [&](const hecl::ProjectPath& modelPath) -> bool {
|
||||
hecl::ProjectPath cooked;
|
||||
if (m_pc)
|
||||
cooked = modelPath.getCookedPath(SpecEntMP1PC);
|
||||
else
|
||||
cooked = modelPath.getCookedPath(SpecEntMP1);
|
||||
doCook(modelPath, cooked, fast, btok, progress);
|
||||
return true;
|
||||
});
|
||||
if (m_pc)
|
||||
{
|
||||
DNAMP1::ANCS::CookCSKRPC(out, in, actor, [&](const hecl::ProjectPath& modelPath) {
|
||||
hecl::ProjectPath cooked = modelPath.getCookedPath(SpecEntMP1PC);
|
||||
doCook(modelPath, cooked, fast, btok, progress);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
DNAMP1::ANCS::CookCSKR(out, in, actor, [&](const hecl::ProjectPath& modelPath) {
|
||||
hecl::ProjectPath cooked = modelPath.getCookedPath(SpecEntMP1);
|
||||
doCook(modelPath, cooked, fast, btok, progress);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S(".ANIM")))
|
||||
{
|
||||
|
@ -821,7 +840,7 @@ struct SpecMP1 : SpecBase
|
|||
continue;
|
||||
}
|
||||
meshCompiles.push_back(ds.compileMesh(
|
||||
mesh, fast ? hecl::HMDLTopology::Triangles : hecl::HMDLTopology::TriStrips, -1,
|
||||
mesh, fast ? hecl::HMDLTopology::Triangles : hecl::HMDLTopology::TriStrips, -1, !m_pc,
|
||||
[&](int surfCount) { progress(hecl::SysFormat(_S("%s %d"), meshSys.c_str(), surfCount).c_str()); }));
|
||||
}
|
||||
|
||||
|
@ -832,10 +851,7 @@ struct SpecMP1 : SpecBase
|
|||
|
||||
ds.close();
|
||||
|
||||
if (m_pc)
|
||||
DNAMP1::MREA::PCCook(out, in, meshCompiles, *colMesh, lights, btok);
|
||||
else
|
||||
DNAMP1::MREA::Cook(out, in, meshCompiles, *colMesh, lights);
|
||||
DNAMP1::MREA::Cook(out, in, meshCompiles, *colMesh, lights, btok, m_pc);
|
||||
}
|
||||
|
||||
void cookWorld(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
|
||||
|
@ -864,7 +880,12 @@ struct SpecMP1 : SpecBase
|
|||
void cookGuiFrame(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds,
|
||||
hecl::blender::Token& btok, FCookProgress progress)
|
||||
{
|
||||
ds.compileGuiFrame(out.getAbsolutePathUTF8(), 0);
|
||||
auto data = ds.compileGuiFrame(0);
|
||||
athena::io::MemoryReader r(data.data(), data.size());
|
||||
DNAMP1::FRME frme;
|
||||
frme.read(r);
|
||||
athena::io::FileWriter w(out.getAbsolutePath());
|
||||
frme.write(w);
|
||||
}
|
||||
|
||||
void cookYAML(const hecl::ProjectPath& out, const hecl::ProjectPath& in, athena::io::IStreamReader& fin,
|
||||
|
@ -1131,7 +1152,9 @@ struct SpecMP1 : SpecBase
|
|||
}
|
||||
}
|
||||
|
||||
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut)
|
||||
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin,
|
||||
std::vector<hecl::ProjectPath>& pathsOut,
|
||||
int charIdx)
|
||||
{
|
||||
athena::io::YAMLDocReader reader;
|
||||
if (reader.parse(&fin))
|
||||
|
@ -1141,11 +1164,25 @@ struct SpecMP1 : SpecBase
|
|||
{
|
||||
DNAMP1::ANCS ancs;
|
||||
ancs.read(reader);
|
||||
ancs.gatherDependencies(pathsOut);
|
||||
ancs.gatherDependencies(pathsOut, charIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UniqueID32 newToOriginal(urde::CAssetId id) const
|
||||
{
|
||||
if (UniqueID32 origId = m_idRestorer.newToOriginal({uint32_t(id.Value()), true}))
|
||||
return {origId.toUint32(), true};
|
||||
return {uint32_t(id.Value()), true};
|
||||
}
|
||||
|
||||
urde::CAssetId originalToNew(UniqueID32 id) const
|
||||
{
|
||||
if (UniqueID32 newId = m_idRestorer.originalToNew(id))
|
||||
return newId.toUint32();
|
||||
return id.toUint32();
|
||||
}
|
||||
|
||||
void buildWorldPakList(const hecl::ProjectPath& worldPath,
|
||||
const hecl::ProjectPath& worldPathCooked,
|
||||
hecl::blender::Token& btok,
|
||||
|
@ -1169,32 +1206,35 @@ struct SpecMP1 : SpecBase
|
|||
|
||||
urde::SObjectTag worldTag = tagFromPath(worldPath.getWithExtension(_S(".*"), true), btok);
|
||||
|
||||
w.writeUint32Big(0x80030005);
|
||||
w.writeUint32Big(m_pc ? 0x80030005 : 0x00030005);
|
||||
w.writeUint32Big(0);
|
||||
|
||||
w.writeUint32Big(1);
|
||||
DNAMP1::PAK::NameEntry nameEnt;
|
||||
hecl::ProjectPath parentDir = worldPath.getParentPath();
|
||||
nameEnt.type = worldTag.type;
|
||||
nameEnt.id = atUint32(worldTag.id.Value());
|
||||
nameEnt.id = newToOriginal(worldTag.id);
|
||||
nameEnt.nameLen = atUint32(parentDir.getLastComponent().size());
|
||||
nameEnt.name = parentDir.getLastComponentUTF8();
|
||||
nameEnt.write(w);
|
||||
|
||||
for (const auto& area : mlvl.areas)
|
||||
{
|
||||
urde::SObjectTag nameTag(FOURCC('STRG'), area.areaNameId.toUint32());
|
||||
urde::SObjectTag nameTag(FOURCC('STRG'), originalToNew(area.areaNameId));
|
||||
if (nameTag)
|
||||
listOut.push_back(nameTag);
|
||||
for (const auto& dep : area.deps)
|
||||
listOut.push_back({dep.type, dep.id.toUint32()});
|
||||
listOut.push_back({dep.type, originalToNew(dep.id)});
|
||||
urde::SObjectTag areaTag(FOURCC('MREA'), originalToNew(area.areaMREAId));
|
||||
if (areaTag)
|
||||
listOut.push_back(areaTag);
|
||||
}
|
||||
|
||||
urde::SObjectTag nameTag(FOURCC('STRG'), mlvl.worldNameId.toUint32());
|
||||
urde::SObjectTag nameTag(FOURCC('STRG'), originalToNew(mlvl.worldNameId));
|
||||
if (nameTag)
|
||||
listOut.push_back(nameTag);
|
||||
|
||||
urde::SObjectTag savwTag(FOURCC('SAVW'), mlvl.saveWorldId.toUint32());
|
||||
urde::SObjectTag savwTag(FOURCC('SAVW'), originalToNew(mlvl.saveWorldId));
|
||||
if (savwTag)
|
||||
{
|
||||
if (hecl::ProjectPath savwPath = pathFromTag(savwTag))
|
||||
|
@ -1202,7 +1242,7 @@ struct SpecMP1 : SpecBase
|
|||
listOut.push_back(savwTag);
|
||||
}
|
||||
|
||||
urde::SObjectTag mapTag(FOURCC('MAPW'), mlvl.worldMap.toUint32());
|
||||
urde::SObjectTag mapTag(FOURCC('MAPW'), originalToNew(mlvl.worldMap));
|
||||
if (mapTag)
|
||||
{
|
||||
if (hecl::ProjectPath mapPath = pathFromTag(mapTag))
|
||||
|
@ -1222,14 +1262,14 @@ struct SpecMP1 : SpecBase
|
|||
{
|
||||
UniqueID32 id;
|
||||
id.read(r);
|
||||
listOut.push_back({FOURCC('MAPA'), id.toUint32()});
|
||||
listOut.push_back({FOURCC('MAPA'), originalToNew(id)});
|
||||
}
|
||||
}
|
||||
}
|
||||
listOut.push_back(mapTag);
|
||||
}
|
||||
|
||||
urde::SObjectTag skyboxTag(FOURCC('CMDL'), mlvl.worldSkyboxId.toUint32());
|
||||
urde::SObjectTag skyboxTag(FOURCC('CMDL'), originalToNew(mlvl.worldSkyboxId));
|
||||
if (skyboxTag)
|
||||
{
|
||||
listOut.push_back(skyboxTag);
|
||||
|
@ -1257,7 +1297,7 @@ struct SpecMP1 : SpecBase
|
|||
DNAMP1::PAK::Entry ent;
|
||||
ent.compressed = 0;
|
||||
ent.type = item.type;
|
||||
ent.id = atUint32(item.id.Value());
|
||||
ent.id = newToOriginal(item.id.Value());
|
||||
ent.size = 0;
|
||||
ent.offset = 0;
|
||||
ent.write(w);
|
||||
|
@ -1270,7 +1310,7 @@ struct SpecMP1 : SpecBase
|
|||
const std::vector<std::pair<urde::SObjectTag, std::string>>& nameList,
|
||||
atUint64& resTableOffset)
|
||||
{
|
||||
w.writeUint32Big(0x80030005);
|
||||
w.writeUint32Big(m_pc ? 0x80030005 : 0x00030005);
|
||||
w.writeUint32Big(0);
|
||||
|
||||
w.writeUint32Big(atUint32(nameList.size()));
|
||||
|
@ -1278,7 +1318,7 @@ struct SpecMP1 : SpecBase
|
|||
{
|
||||
DNAMP1::PAK::NameEntry nameEnt;
|
||||
nameEnt.type = item.first.type;
|
||||
nameEnt.id = atUint32(item.first.id.Value());
|
||||
nameEnt.id = newToOriginal(item.first.id);
|
||||
nameEnt.nameLen = atUint32(item.second.size());
|
||||
nameEnt.name = item.second;
|
||||
nameEnt.write(w);
|
||||
|
@ -1291,7 +1331,7 @@ struct SpecMP1 : SpecBase
|
|||
DNAMP1::PAK::Entry ent;
|
||||
ent.compressed = 0;
|
||||
ent.type = item.type;
|
||||
ent.id = atUint32(item.id.Value());
|
||||
ent.id = newToOriginal(item.id);
|
||||
ent.size = 0;
|
||||
ent.offset = 0;
|
||||
ent.write(w);
|
||||
|
@ -1312,7 +1352,7 @@ struct SpecMP1 : SpecBase
|
|||
DNAMP1::PAK::Entry ent;
|
||||
ent.compressed = atUint32(std::get<2>(item));
|
||||
ent.type = tag.type;
|
||||
ent.id = atUint32(tag.id.Value());
|
||||
ent.id = newToOriginal(tag.id);
|
||||
ent.size = atUint32(std::get<1>(item));
|
||||
ent.offset = atUint32(std::get<0>(item));
|
||||
ent.write(w);
|
||||
|
@ -1350,7 +1390,7 @@ struct SpecMP1 : SpecBase
|
|||
uLong destLen = compressBound(len);
|
||||
std::pair<std::unique_ptr<uint8_t[]>, size_t> ret;
|
||||
ret.first.reset(new uint8_t[destLen]);
|
||||
compress(ret.first.get(), &destLen, data, len);
|
||||
compress2(ret.first.get(), &destLen, data, len, Z_BEST_COMPRESSION);
|
||||
ret.second = destLen;
|
||||
return ret;
|
||||
};
|
||||
|
@ -1389,19 +1429,19 @@ struct SpecMP1 : SpecBase
|
|||
};
|
||||
|
||||
hecl::Database::DataSpecEntry SpecEntMP1 = {
|
||||
_S("MP1"sv), _S("Data specification for original Metroid Prime engine"sv),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool) -> hecl::Database::IDataSpec* {
|
||||
return new struct SpecMP1(&SpecEntMP1, project, false);
|
||||
_S("MP1"sv), _S("Data specification for original Metroid Prime engine"sv), _S(".pak"sv),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool) -> std::unique_ptr<hecl::Database::IDataSpec> {
|
||||
return std::make_unique<SpecMP1>(&SpecEntMP1, project, false);
|
||||
}};
|
||||
|
||||
hecl::Database::DataSpecEntry SpecEntMP1PC = {
|
||||
_S("MP1-PC"sv), _S("Data specification for PC-optimized Metroid Prime engine"sv),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool) -> hecl::Database::IDataSpec* {
|
||||
_S("MP1-PC"sv), _S("Data specification for PC-optimized Metroid Prime engine"sv), _S(".upak"sv),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool) -> std::unique_ptr<hecl::Database::IDataSpec> {
|
||||
if (tool != hecl::Database::DataSpecTool::Extract)
|
||||
return new struct SpecMP1(&SpecEntMP1PC, project, true);
|
||||
return nullptr;
|
||||
return std::make_unique<SpecMP1>(&SpecEntMP1PC, project, true);
|
||||
return {};
|
||||
}};
|
||||
|
||||
hecl::Database::DataSpecEntry SpecEntMP1ORIG = {
|
||||
_S("MP1-ORIG"sv), _S("Data specification for unmodified Metroid Prime resources"sv), {}};
|
||||
_S("MP1-ORIG"sv), _S("Data specification for unmodified Metroid Prime resources"sv), {}, {}};
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ struct SpecMP2 : SpecBase
|
|||
return true;
|
||||
}
|
||||
|
||||
bool extractFromDisc(nod::DiscBase&, bool force, const hecl::MultiProgressPrinter& progress)
|
||||
bool extractFromDisc(nod::DiscBase& disc, bool force, const hecl::MultiProgressPrinter& progress)
|
||||
{
|
||||
nod::ExtractionContext ctx = {force, nullptr};
|
||||
|
||||
|
@ -239,7 +239,8 @@ struct SpecMP2 : SpecBase
|
|||
|
||||
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
||||
outPath.makeDir();
|
||||
hecl::ProjectPath mp2OutPath(outPath, _S("MP2"));
|
||||
disc.getDataPartition()->extractSysFiles(outPath.getAbsolutePath(), ctx);
|
||||
hecl::ProjectPath mp2OutPath(outPath, m_standalone ? _S("files") : _S("files/MP2"));
|
||||
mp2OutPath.makeDir();
|
||||
progress.startNewLine();
|
||||
progress.print(_S("MP2 Root"), _S(""), 0.0);
|
||||
|
@ -375,7 +376,7 @@ struct SpecMP2 : SpecBase
|
|||
{
|
||||
}
|
||||
|
||||
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut)
|
||||
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut, int charIdx)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -417,21 +418,21 @@ struct SpecMP2 : SpecBase
|
|||
hecl::Database::DataSpecEntry SpecEntMP2
|
||||
(
|
||||
_S("MP2"sv),
|
||||
_S("Data specification for original Metroid Prime 2 engine"sv),
|
||||
_S("Data specification for original Metroid Prime 2 engine"sv), _S(".pak"sv),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool)
|
||||
-> hecl::Database::IDataSpec* {return new struct SpecMP2(&SpecEntMP2, project, false);}
|
||||
-> std::unique_ptr<hecl::Database::IDataSpec> {return std::make_unique<SpecMP2>(&SpecEntMP2, project, false);}
|
||||
);
|
||||
|
||||
hecl::Database::DataSpecEntry SpecEntMP2PC =
|
||||
{
|
||||
_S("MP2-PC"sv),
|
||||
_S("Data specification for PC-optimized Metroid Prime 2 engine"sv),
|
||||
_S("Data specification for PC-optimized Metroid Prime 2 engine"sv), _S(".upak"sv),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool)
|
||||
-> hecl::Database::IDataSpec*
|
||||
-> std::unique_ptr<hecl::Database::IDataSpec>
|
||||
{
|
||||
if (tool != hecl::Database::DataSpecTool::Extract)
|
||||
return new struct SpecMP2(&SpecEntMP2PC, project, true);
|
||||
return nullptr;
|
||||
return std::make_unique<SpecMP2>(&SpecEntMP2PC, project, true);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -439,7 +440,7 @@ hecl::Database::DataSpecEntry SpecEntMP2ORIG =
|
|||
{
|
||||
_S("MP2-ORIG"sv),
|
||||
_S("Data specification for unmodified Metroid Prime 2 resources"sv),
|
||||
{}
|
||||
{}, {}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -352,7 +352,7 @@ struct SpecMP3 : SpecBase
|
|||
return doMP3 || doMPTFE;
|
||||
}
|
||||
|
||||
bool extractFromDisc(nod::DiscBase&, bool force, const hecl::MultiProgressPrinter& progress)
|
||||
bool extractFromDisc(nod::DiscBase& disc, bool force, const hecl::MultiProgressPrinter& progress)
|
||||
{
|
||||
hecl::SystemString currentTarget = _S("");
|
||||
size_t nodeCount = 0;
|
||||
|
@ -378,7 +378,8 @@ struct SpecMP3 : SpecBase
|
|||
|
||||
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
||||
outPath.makeDir();
|
||||
hecl::ProjectPath mp3OutPath(outPath, _S("MP3"));
|
||||
disc.getDataPartition()->extractSysFiles(outPath.getAbsolutePath(), ctx);
|
||||
hecl::ProjectPath mp3OutPath(outPath, m_standalone ? _S("files") : _S("files/MP3"));
|
||||
mp3OutPath.makeDir();
|
||||
currentTarget = _S("MP3 Root");
|
||||
progress.print(currentTarget.c_str(), _S(""), 0.0);
|
||||
|
@ -436,7 +437,8 @@ struct SpecMP3 : SpecBase
|
|||
|
||||
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
||||
outPath.makeDir();
|
||||
hecl::ProjectPath feOutPath(outPath, _S("fe"));
|
||||
disc.getDataPartition()->extractSysFiles(outPath.getAbsolutePath(), ctx);
|
||||
hecl::ProjectPath feOutPath(outPath, m_standalone ? _S("files") : _S("files/fe"));
|
||||
feOutPath.makeDir();
|
||||
currentTarget = _S("fe Root");
|
||||
progress.print(currentTarget.c_str(), _S(""), 0.0);
|
||||
|
@ -566,7 +568,7 @@ struct SpecMP3 : SpecBase
|
|||
{
|
||||
}
|
||||
|
||||
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut)
|
||||
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut, int charIdx)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -600,20 +602,20 @@ struct SpecMP3 : SpecBase
|
|||
hecl::Database::DataSpecEntry SpecEntMP3
|
||||
(
|
||||
_S("MP3"sv),
|
||||
_S("Data specification for original Metroid Prime 3 engine"sv),
|
||||
_S("Data specification for original Metroid Prime 3 engine"sv), _S(".pak"sv),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool)
|
||||
-> hecl::Database::IDataSpec* {return new struct SpecMP3(&SpecEntMP3, project, false);}
|
||||
-> std::unique_ptr<hecl::Database::IDataSpec> {return std::make_unique<SpecMP3>(&SpecEntMP3, project, false);}
|
||||
);
|
||||
|
||||
hecl::Database::DataSpecEntry SpecEntMP3PC =
|
||||
{
|
||||
_S("MP3-PC"sv),
|
||||
_S("Data specification for PC-optimized Metroid Prime 3 engine"sv),
|
||||
_S("Data specification for PC-optimized Metroid Prime 3 engine"sv), _S(".upak"sv),
|
||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool)
|
||||
-> hecl::Database::IDataSpec*
|
||||
-> std::unique_ptr<hecl::Database::IDataSpec>
|
||||
{
|
||||
if (tool != hecl::Database::DataSpecTool::Extract)
|
||||
return new struct SpecMP3(&SpecEntMP3PC, project, true);
|
||||
return std::make_unique<SpecMP3>(&SpecEntMP3PC, project, true);
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
@ -622,7 +624,7 @@ hecl::Database::DataSpecEntry SpecEntMP3ORIG =
|
|||
{
|
||||
_S("MP3-ORIG"sv),
|
||||
_S("Data specification for unmodified Metroid Prime 3 resources"sv),
|
||||
{}
|
||||
{}, {}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ void ProjectResourceFactoryBase::BeginBackgroundIndex
|
|||
m_proj = &proj;
|
||||
m_origSpec = &origSpec;
|
||||
m_pcSpec = &pcSpec;
|
||||
m_cookSpec.reset(pcSpec.m_factory(proj, hecl::Database::DataSpecTool::Cook));
|
||||
m_cookSpec = pcSpec.m_factory(proj, hecl::Database::DataSpecTool::Cook);
|
||||
return static_cast<DataSpec::SpecBase&>(*m_cookSpec).beginBackgroundIndex();
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ void ProjectResourceFactoryBase::AsyncTask::EnsurePath(const urde::SObjectTag& t
|
|||
{
|
||||
/* Start a background cook here */
|
||||
m_cookTransaction = m_parent.m_clientProc.
|
||||
addCookTransaction(path, m_parent.m_cookSpec.get(), false, false);
|
||||
addCookTransaction(path, false, false, m_parent.m_cookSpec.get());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ void ViewManager::RootSpaceViewBuilt(specter::View *view)
|
|||
void ViewManager::ProjectChanged(hecl::Database::Project& proj)
|
||||
{
|
||||
CDvdFile::Shutdown();
|
||||
CDvdFile::Initialize(hecl::ProjectPath(proj.getProjectWorkingPath(), _S("out/MP1")));
|
||||
CDvdFile::Initialize(hecl::ProjectPath(proj.getProjectWorkingPath(), _S("out/files")));
|
||||
}
|
||||
|
||||
void ViewManager::SetupEditorView()
|
||||
|
|
|
@ -117,17 +117,21 @@ void CResFactory::CancelBuild(const SObjectTag& tag)
|
|||
|
||||
void CResFactory::LoadOriginalIDs(CSimplePool& sp)
|
||||
{
|
||||
m_origIds = sp.GetObj("MP1OriginalIDs");
|
||||
//m_origIds = sp.GetObj("MP1OriginalIDs");
|
||||
}
|
||||
|
||||
CAssetId CResFactory::TranslateOriginalToNew(CAssetId id) const
|
||||
{
|
||||
return m_origIds->TranslateOriginalToNew(id);
|
||||
/* The packager will have restored these ahead of time */
|
||||
return id;
|
||||
//return m_origIds->TranslateOriginalToNew(id);
|
||||
}
|
||||
|
||||
CAssetId CResFactory::TranslateNewToOriginal(CAssetId id) const
|
||||
{
|
||||
return m_origIds->TranslateNewToOriginal(id);
|
||||
/* The packager will have restored these ahead of time */
|
||||
return id;
|
||||
//return m_origIds->TranslateNewToOriginal(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class CResFactory : public IFactory
|
|||
{
|
||||
CResLoader x4_loader;
|
||||
CFactoryMgr x5c_factoryMgr;
|
||||
TLockedToken<MP1OriginalIDs> m_origIds;
|
||||
//TLockedToken<MP1OriginalIDs> m_origIds;
|
||||
|
||||
public:
|
||||
struct SLoadingData
|
||||
|
|
|
@ -50,8 +50,8 @@ public:
|
|||
virtual std::unique_ptr<u8[]> LoadNewResourcePartSync(const urde::SObjectTag& tag, u32 off, u32 size)=0;
|
||||
virtual void GetTagListForFile(const char* pakName, std::vector<SObjectTag>& out) const {}
|
||||
|
||||
virtual CAssetId TranslateOriginalToNew(CAssetId id) const { return -1; }
|
||||
virtual CAssetId TranslateNewToOriginal(CAssetId id) const { return -1; }
|
||||
virtual CAssetId TranslateOriginalToNew(CAssetId id) const { return {}; }
|
||||
virtual CAssetId TranslateNewToOriginal(CAssetId id) const { return {}; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
2
hecl
2
hecl
|
@ -1 +1 @@
|
|||
Subproject commit 1c7c56bc4405db1398a2246e010966e6fe7bde34
|
||||
Subproject commit e7c678ff572d941fa648ef99c92d90624a582761
|
2
nod
2
nod
|
@ -1 +1 @@
|
|||
Subproject commit bab7aab6fa7a82123f827475c1471f641ed2bf67
|
||||
Subproject commit 274a63bb306a77cd78527e4fca13d4c69cb5b56e
|
2
specter
2
specter
|
@ -1 +1 @@
|
|||
Subproject commit 8ff49e190761583b120b0510b0de3dda13fd68c0
|
||||
Subproject commit fb20084230cba3c54eabf340f3612f890c8522c3
|
Loading…
Reference in New Issue