mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-07-03 10:35:51 +00:00
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,
|
PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
|
||||||
const SpecBase& dataspec);
|
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)
|
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();
|
size_t vertSz = matSets.at(0).materials.at(surf.materialIdx).getVAFlags().vertDLSize();
|
||||||
if (surf.verts.size() > 65536)
|
if (surf.verts.size() > 65536)
|
||||||
LogDNACommon.report(logvisor::Fatal, "GX DisplayList overflow");
|
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);
|
secSz32 = ROUND_UP_32(secSz);
|
||||||
if (secSz32 == 0)
|
if (secSz32 == 0)
|
||||||
secSz32 = 32;
|
secSz32 = 32;
|
||||||
@ -1430,7 +1431,7 @@ bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath
|
|||||||
SurfaceHeader header;
|
SurfaceHeader header;
|
||||||
header.centroid = surf.centroid;
|
header.centroid = surf.centroid;
|
||||||
header.matIdx = surf.materialIdx;
|
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.reflectionNormal = surf.reflectionNormal;
|
||||||
header.write(writer);
|
header.write(writer);
|
||||||
|
|
||||||
@ -1461,6 +1462,8 @@ bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath
|
|||||||
WriteDLVal(writer, vaFlags.tex6(), vert.iUv[6]);
|
WriteDLVal(writer, vaFlags.tex6(), vert.iUv[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writer.writeUByte(0);
|
||||||
|
|
||||||
writer.fill(atUint8(0), *padIt);
|
writer.fill(atUint8(0), *padIt);
|
||||||
++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,
|
(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh,
|
||||||
hecl::blender::PoolSkinIndex& poolSkinIndex);
|
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>
|
template <class MaterialSet, class SurfaceHeader, class MeshHeader>
|
||||||
bool WriteMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
|
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)
|
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>
|
template <class MaterialSet, class SurfaceHeader, class MeshHeader>
|
||||||
bool WriteHMDLMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
|
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)
|
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 */
|
/* Build material set */
|
||||||
std::vector<size_t> surfToGlobalMats;
|
std::vector<size_t> surfToGlobalMats;
|
||||||
{
|
{
|
||||||
struct MaterialPool
|
MaterialPool matPool;
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
size_t surfCount = 0;
|
size_t surfCount = 0;
|
||||||
for (const Mesh& mesh : meshes)
|
for (const Mesh& mesh : meshes)
|
||||||
|
@ -10,6 +10,9 @@ ThreadLocalPtr<SpecBase> g_curSpec;
|
|||||||
ThreadLocalPtr<PAKRouterBase> g_PakRouter;
|
ThreadLocalPtr<PAKRouterBase> g_PakRouter;
|
||||||
ThreadLocalPtr<hecl::blender::Token> g_ThreadBlenderToken;
|
ThreadLocalPtr<hecl::blender::Token> g_ThreadBlenderToken;
|
||||||
ThreadLocalPtr<hecl::Database::Project> UniqueIDBridge::s_Project;
|
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;
|
UniqueID32 UniqueID32::kInvalidId;
|
||||||
|
|
||||||
template <class IDType>
|
template <class IDType>
|
||||||
@ -38,11 +41,16 @@ hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const IDType& id, bool si
|
|||||||
LogDNACommon.report(logvisor::Fatal,
|
LogDNACommon.report(logvisor::Fatal,
|
||||||
"g_PakRouter or s_Project must be set to non-null before "
|
"g_PakRouter or s_Project must be set to non-null before "
|
||||||
"calling UniqueIDBridge::TranslatePakIdToPath");
|
"calling UniqueIDBridge::TranslatePakIdToPath");
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const hecl::ProjectPath* search = project->lookupBridgePath(id.toUint64());
|
const hecl::ProjectPath* search = project->lookupBridgePath(id.toUint64());
|
||||||
if (!search)
|
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)
|
if (hecl::VerbosityLevel >= 1 && !silenceWarnings && id)
|
||||||
LogDNACommon.report(logvisor::Warning,
|
LogDNACommon.report(logvisor::Warning,
|
||||||
"unable to translate %s to path", id.toString().c_str());
|
"unable to translate %s to path", id.toString().c_str());
|
||||||
@ -54,6 +62,8 @@ template
|
|||||||
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID32& id, bool silenceWarnings);
|
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID32& id, bool silenceWarnings);
|
||||||
template
|
template
|
||||||
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID64& id, bool silenceWarnings);
|
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID64& id, bool silenceWarnings);
|
||||||
|
template
|
||||||
|
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID128& id, bool silenceWarnings);
|
||||||
|
|
||||||
template <class IDType>
|
template <class IDType>
|
||||||
hecl::ProjectPath UniqueIDBridge::MakePathFromString(std::string_view str)
|
hecl::ProjectPath UniqueIDBridge::MakePathFromString(std::string_view str)
|
||||||
@ -83,12 +93,21 @@ void UniqueIDBridge::TransformOldHashToNewHash(UniqueID32& id);
|
|||||||
template
|
template
|
||||||
void UniqueIDBridge::TransformOldHashToNewHash(UniqueID64& id);
|
void UniqueIDBridge::TransformOldHashToNewHash(UniqueID64& id);
|
||||||
|
|
||||||
void UniqueIDBridge::setThreadProject(hecl::Database::Project& project)
|
void UniqueIDBridge::SetThreadProject(hecl::Database::Project& project)
|
||||||
{
|
{
|
||||||
s_Project.reset(&project);
|
s_Project.reset(&project);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** PAK 32-bit Unique ID */
|
/** 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 <>
|
template <>
|
||||||
void UniqueID32::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
|
void UniqueID32::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
|
||||||
{assign(reader.readUint32Big());}
|
{assign(reader.readUint32Big());}
|
||||||
@ -164,7 +183,7 @@ void AuxiliaryID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& wr
|
|||||||
{
|
{
|
||||||
if (!operator bool())
|
if (!operator bool())
|
||||||
return;
|
return;
|
||||||
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this, true);
|
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath<UniqueID32>(*this, true);
|
||||||
if (!path)
|
if (!path)
|
||||||
path = UniqueIDBridge::TranslatePakIdToPath(m_baseId);
|
path = UniqueIDBridge::TranslatePakIdToPath(m_baseId);
|
||||||
if (!path)
|
if (!path)
|
||||||
@ -177,6 +196,15 @@ void AuxiliaryID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& wr
|
|||||||
|
|
||||||
|
|
||||||
/** PAK 64-bit Unique ID */
|
/** 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 <>
|
template <>
|
||||||
void UniqueID64::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
|
void UniqueID64::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
|
||||||
{assign(reader.readUint64Big());}
|
{assign(reader.readUint64Big());}
|
||||||
@ -215,14 +243,14 @@ std::string UniqueID64::toString() const
|
|||||||
template <>
|
template <>
|
||||||
void UniqueID128::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
|
void UniqueID128::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
|
||||||
{
|
{
|
||||||
m_id[0] = reader.readUint64Big();
|
m_id.id[0] = reader.readUint64Big();
|
||||||
m_id[1] = reader.readUint64Big();
|
m_id.id[1] = reader.readUint64Big();
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
void UniqueID128::Enumerate<BigDNA::Write>(typename Write::StreamT& writer)
|
void UniqueID128::Enumerate<BigDNA::Write>(typename Write::StreamT& writer)
|
||||||
{
|
{
|
||||||
writer.writeUint64Big(m_id[0]);
|
writer.writeUint64Big(m_id.id[0]);
|
||||||
writer.writeUint64Big(m_id[1]);
|
writer.writeUint64Big(m_id.id[1]);
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
void UniqueID128::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader)
|
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
|
std::string UniqueID128::toString() const
|
||||||
{
|
{
|
||||||
char buf[33];
|
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);
|
return std::string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +123,9 @@ class UniqueIDBridge
|
|||||||
friend class UniqueID64;
|
friend class UniqueID64;
|
||||||
|
|
||||||
static ThreadLocalPtr<hecl::Database::Project> s_Project;
|
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:
|
public:
|
||||||
template <class IDType>
|
template <class IDType>
|
||||||
static hecl::ProjectPath TranslatePakIdToPath(const IDType& id, bool silenceWarnings=false);
|
static hecl::ProjectPath TranslatePakIdToPath(const IDType& id, bool silenceWarnings=false);
|
||||||
@ -131,19 +134,61 @@ public:
|
|||||||
template <class IDType>
|
template <class IDType>
|
||||||
static void TransformOldHashToNewHash(IDType& id);
|
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 */
|
/** PAK 32-bit Unique ID */
|
||||||
class UniqueID32 : public BigDNA
|
class UniqueID32 : public BigDNA
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
uint32_t m_id = 0xffffffff;
|
uint32_t m_id = 0xffffffff;
|
||||||
public:
|
public:
|
||||||
|
using value_type = uint32_t;
|
||||||
static UniqueID32 kInvalidId;
|
static UniqueID32 kInvalidId;
|
||||||
AT_DECL_EXPLICIT_DNA_YAML
|
AT_DECL_EXPLICIT_DNA_YAML
|
||||||
operator bool() const {return m_id != 0xffffffff && m_id != 0;}
|
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)
|
UniqueID32& operator=(const hecl::ProjectPath& path)
|
||||||
{assign(path.hash().val32()); return *this;}
|
{assign(path.hash().val32()); return *this;}
|
||||||
@ -157,7 +202,7 @@ public:
|
|||||||
void clear() {m_id = 0xffffffff;}
|
void clear() {m_id = 0xffffffff;}
|
||||||
|
|
||||||
UniqueID32() = default;
|
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(athena::io::IStreamReader& reader) {read(reader);}
|
||||||
UniqueID32(const hecl::ProjectPath& path) {*this = path;}
|
UniqueID32(const hecl::ProjectPath& path) {*this = path;}
|
||||||
UniqueID32(const char* hexStr)
|
UniqueID32(const char* hexStr)
|
||||||
@ -200,9 +245,10 @@ class UniqueID64 : public BigDNA
|
|||||||
{
|
{
|
||||||
uint64_t m_id = 0xffffffffffffffff;
|
uint64_t m_id = 0xffffffffffffffff;
|
||||||
public:
|
public:
|
||||||
|
using value_type = uint64_t;
|
||||||
AT_DECL_EXPLICIT_DNA_YAML
|
AT_DECL_EXPLICIT_DNA_YAML
|
||||||
operator bool() const {return m_id != 0xffffffffffffffff && m_id != 0;}
|
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)
|
UniqueID64& operator=(const hecl::ProjectPath& path)
|
||||||
{assign(path.hash().val64()); return *this;}
|
{assign(path.hash().val64()); return *this;}
|
||||||
@ -215,7 +261,7 @@ public:
|
|||||||
void clear() {m_id = 0xffffffffffffffff;}
|
void clear() {m_id = 0xffffffffffffffff;}
|
||||||
|
|
||||||
UniqueID64() = default;
|
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(athena::io::IStreamReader& reader) {read(reader);}
|
||||||
UniqueID64(const hecl::ProjectPath& path) {*this = path;}
|
UniqueID64(const hecl::ProjectPath& path) {*this = path;}
|
||||||
UniqueID64(const char* hexStr)
|
UniqueID64(const char* hexStr)
|
||||||
@ -247,23 +293,32 @@ public:
|
|||||||
/** PAK 128-bit Unique ID */
|
/** PAK 128-bit Unique ID */
|
||||||
class UniqueID128 : public BigDNA
|
class UniqueID128 : public BigDNA
|
||||||
{
|
{
|
||||||
union
|
public:
|
||||||
|
union Value
|
||||||
{
|
{
|
||||||
uint64_t m_id[2];
|
uint64_t id[2];
|
||||||
#if __SSE__
|
#if __SSE__
|
||||||
__m128i m_id128;
|
__m128i id128;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
private:
|
||||||
|
Value m_id;
|
||||||
public:
|
public:
|
||||||
|
using value_type = uint64_t;
|
||||||
AT_DECL_EXPLICIT_DNA_YAML
|
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
|
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)
|
UniqueID128& operator=(const hecl::ProjectPath& path)
|
||||||
{
|
{
|
||||||
m_id[0] = path.hash().val64();
|
m_id.id[0] = path.hash().val64();
|
||||||
m_id[1] = 0;
|
m_id.id[1] = 0;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
UniqueID128(const hecl::ProjectPath& path) {*this = path;}
|
UniqueID128(const hecl::ProjectPath& path) {*this = path;}
|
||||||
@ -271,27 +326,27 @@ public:
|
|||||||
bool operator!=(const UniqueID128& other) const
|
bool operator!=(const UniqueID128& other) const
|
||||||
{
|
{
|
||||||
#if __SSE__
|
#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);
|
int vmask = _mm_movemask_epi8(vcmp);
|
||||||
return vmask != 0xffff;
|
return vmask != 0xffff;
|
||||||
#else
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
bool operator==(const UniqueID128& other) const
|
bool operator==(const UniqueID128& other) const
|
||||||
{
|
{
|
||||||
#if __SSE__
|
#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);
|
int vmask = _mm_movemask_epi8(vcmp);
|
||||||
return vmask == 0xffff;
|
return vmask == 0xffff;
|
||||||
#else
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
void clear() {m_id[0] = 0xffffffffffffffff; m_id[1] = 0xffffffffffffffff;}
|
void clear() {m_id.id[0] = 0xffffffffffffffff; m_id.id[1] = 0xffffffffffffffff;}
|
||||||
uint64_t toUint64() const {return m_id[0];}
|
uint64_t toUint64() const {return m_id.id[0];}
|
||||||
uint64_t toHighUint64() const {return m_id[0];}
|
uint64_t toHighUint64() const {return m_id.id[0];}
|
||||||
uint64_t toLowUint64() const {return m_id[1];}
|
uint64_t toLowUint64() const {return m_id.id[1];}
|
||||||
std::string toString() const;
|
std::string toString() const;
|
||||||
|
|
||||||
static constexpr size_t BinarySize() {return 16;}
|
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);
|
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;
|
const DNAANCS::Actor::Subtype* subtype = nullptr;
|
||||||
for (const DNAANCS::Actor::Subtype& sub : actor.subtypes)
|
for (const DNAANCS::Actor::Subtype& sub : actor.subtypes)
|
||||||
{
|
{
|
||||||
|
@ -468,9 +468,9 @@ struct ANCS : BigDNA
|
|||||||
trans->enumeratePrimitives(func);
|
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)
|
for (const auto& id : ci.partResData.part)
|
||||||
g_curSpec->flattenDependencies(id, pathsOut);
|
g_curSpec->flattenDependencies(id, pathsOut);
|
||||||
@ -480,7 +480,12 @@ struct ANCS : BigDNA
|
|||||||
g_curSpec->flattenDependencies(id, pathsOut);
|
g_curSpec->flattenDependencies(id, pathsOut);
|
||||||
for (const auto& id : ci.partResData.elsc)
|
for (const auto& id : ci.partResData.elsc)
|
||||||
g_curSpec->flattenDependencies(id, pathsOut);
|
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,
|
static bool Extract(const SpecBase& dataSpec,
|
||||||
@ -504,6 +509,10 @@ struct ANCS : BigDNA
|
|||||||
const hecl::ProjectPath& inPath,
|
const hecl::ProjectPath& inPath,
|
||||||
const DNAANCS::Actor& actor,
|
const DNAANCS::Actor& actor,
|
||||||
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc);
|
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,
|
static bool CookANIM(const hecl::ProjectPath& outPath,
|
||||||
const hecl::ProjectPath& inPath,
|
const hecl::ProjectPath& inPath,
|
||||||
|
@ -74,6 +74,10 @@ bool CMDL::Cook(const hecl::ProjectPath& outPath,
|
|||||||
/* Output skinning intermediate */
|
/* Output skinning intermediate */
|
||||||
auto vertCountIt = skinMesh.contiguousSkinVertCounts.cbegin();
|
auto vertCountIt = skinMesh.contiguousSkinVertCounts.cbegin();
|
||||||
athena::io::FileWriter writer(outPath.getWithExtension(_S(".skinint")).getAbsolutePath());
|
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());
|
writer.writeUint32Big(skinMesh.skins.size());
|
||||||
for (const std::vector<DNACMDL::Mesh::SkinBind> skin : skinMesh.skins)
|
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(*vertCountIt++);
|
||||||
}
|
}
|
||||||
writer.writeUint32Big(skinMesh.pos.size());
|
writer.writeUint32Big(skinMesh.pos.size());
|
||||||
writer.writeUint32Big(skinMesh.boneNames.size());
|
writer.writeUint32Big(skinMesh.norm.size());
|
||||||
for (const std::string& boneName : skinMesh.boneNames)
|
|
||||||
writer.writeString(boneName);
|
|
||||||
}
|
}
|
||||||
else if (!DNACMDL::WriteCMDL<MaterialSet, DNACMDL::SurfaceHeader_1, 2>(outPath, inPath, mesh))
|
else if (!DNACMDL::WriteCMDL<MaterialSet, DNACMDL::SurfaceHeader_1, 2>(outPath, inPath, mesh))
|
||||||
return false;
|
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);
|
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,
|
bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const World& wld,
|
||||||
hecl::blender::Token& btok)
|
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 areaIdx = 0;
|
||||||
size_t nameOffset = 0;
|
size_t nameOffset = 0;
|
||||||
|
BulkResources bulkResources;
|
||||||
for (const World::Area& area : wld.areas)
|
for (const World::Area& area : wld.areas)
|
||||||
{
|
{
|
||||||
if (area.path.getPathType() != hecl::ProjectPath::Type::Directory)
|
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;
|
bool areaInit = false;
|
||||||
|
|
||||||
size_t layerIdx = 0;
|
size_t layerIdx = 0;
|
||||||
|
LayerResources layerResources(bulkResources);
|
||||||
for (const hecl::DirectoryEnumerator::Entry& e : dEnum)
|
for (const hecl::DirectoryEnumerator::Entry& e : dEnum)
|
||||||
{
|
{
|
||||||
hecl::SystemString layerName;
|
hecl::SystemString layerName;
|
||||||
@ -139,6 +205,8 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||||||
layer.read(reader);
|
layer.read(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layerResources.beginLayer();
|
||||||
|
|
||||||
/* Set active flag state */
|
/* Set active flag state */
|
||||||
hecl::ProjectPath defActivePath(area.path, e.m_name + _S("/!defaultactive"));
|
hecl::ProjectPath defActivePath(area.path, e.m_name + _S("/!defaultactive"));
|
||||||
bool active = defActivePath.isNone() ? false : true;
|
bool active = defActivePath.isNone() ? false : true;
|
||||||
@ -221,14 +289,11 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||||||
areaInit = true;
|
areaInit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MLVL::Area& areaOut = mlvl.areas.back();
|
|
||||||
areaOut.depLayers.push_back(areaOut.deps.size());
|
|
||||||
|
|
||||||
|
|
||||||
/* Gather memory relays, scans, and dependencies */
|
/* Gather memory relays, scans, and dependencies */
|
||||||
{
|
{
|
||||||
g_ThreadBlenderToken.reset(&btok);
|
g_ThreadBlenderToken.reset(&btok);
|
||||||
std::vector<hecl::ProjectPath> depPaths;
|
std::vector<hecl::ProjectPath> depPaths;
|
||||||
|
std::vector<hecl::ProjectPath> bulkPaths;
|
||||||
for (std::unique_ptr<IScriptObject>& obj : layer.objects)
|
for (std::unique_ptr<IScriptObject>& obj : layer.objects)
|
||||||
{
|
{
|
||||||
if (obj->type == int(urde::EScriptObjectType::MemoryRelay))
|
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->gatherDependencies(depPaths);
|
||||||
|
obj->gatherBulkDependencies(bulkPaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cull duplicate paths and add typed hash to list */
|
/* Cull duplicate paths and add typed hash to list */
|
||||||
std::unordered_set<hecl::Hash> addedPaths;
|
|
||||||
for (const hecl::ProjectPath& path : depPaths)
|
for (const hecl::ProjectPath& path : depPaths)
|
||||||
{
|
layerResources.addBulkPath(path, areaIdx);
|
||||||
if (addedPaths.find(path.hash()) == addedPaths.cend())
|
for (const hecl::ProjectPath& path : bulkPaths)
|
||||||
{
|
layerResources.addBulkPath(path, areaIdx);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hecl::SystemUTF8Conv layerU8(layerName);
|
hecl::SystemUTF8Conv layerU8(layerName);
|
||||||
@ -288,6 +347,22 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
|
|||||||
++layerIdx;
|
++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 */
|
/* Append Memory Relays */
|
||||||
mlvl.memRelayLinks.insert(mlvl.memRelayLinks.end(), memRelayLinks.begin(), memRelayLinks.end());
|
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();
|
auto& conn = btok.getBlenderConnection();
|
||||||
if (conn.openBlend(areaPath))
|
if (conn.openBlend(areaPath))
|
||||||
{
|
{
|
||||||
MLVL::Area& areaOut = mlvl.areas.back();
|
|
||||||
areaOut.depLayers.push_back(areaOut.deps.size());
|
areaOut.depLayers.push_back(areaOut.deps.size());
|
||||||
|
|
||||||
auto ds = conn.beginData();
|
auto ds = conn.beginData();
|
||||||
std::vector<hecl::ProjectPath> texs = ds.getTextures();
|
std::vector<hecl::ProjectPath> texs = ds.getTextures();
|
||||||
ds.close();
|
ds.close();
|
||||||
|
|
||||||
std::unordered_set<hecl::Hash> addedPaths;
|
|
||||||
for (const hecl::ProjectPath& path : texs)
|
for (const hecl::ProjectPath& path : texs)
|
||||||
|
layerResources.addSharedPath(path);
|
||||||
|
|
||||||
|
for (const hecl::ProjectPath& path : layerResources.sharedPaths)
|
||||||
{
|
{
|
||||||
if (addedPaths.find(path.hash()) == addedPaths.cend())
|
urde::SObjectTag tag = g_curSpec->buildTagFromPath(path, btok);
|
||||||
{
|
if (tag.id.IsValid())
|
||||||
addedPaths.insert(path.hash());
|
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"));
|
hecl::ProjectPath pathPath(areaPath.getParentPath(), _S("!path.blend"));
|
||||||
urde::SObjectTag pathTag = g_curSpec->buildTagFromPath(pathPath, btok);
|
urde::SObjectTag pathTag = g_curSpec->buildTagFromPath(pathPath, btok);
|
||||||
if (pathTag.id.IsValid())
|
if (pathTag.id.IsValid())
|
||||||
areaOut.deps.emplace_back(pathTag.id.Value(), pathTag.type);
|
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;
|
++areaIdx;
|
||||||
|
@ -421,17 +421,9 @@ bool MREA::Cook(const hecl::ProjectPath& outPath,
|
|||||||
const hecl::ProjectPath& inPath,
|
const hecl::ProjectPath& inPath,
|
||||||
const std::vector<DNACMDL::Mesh>& meshes,
|
const std::vector<DNACMDL::Mesh>& meshes,
|
||||||
const ColMesh& cMesh,
|
const ColMesh& cMesh,
|
||||||
const std::vector<Light>& lights)
|
const std::vector<Light>& lights,
|
||||||
{
|
hecl::blender::Token& btok,
|
||||||
return false;
|
bool pc)
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
/* Discover area layers */
|
/* Discover area layers */
|
||||||
hecl::ProjectPath areaDirPath = inPath.getParentPath();
|
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 */
|
/* tally up surfaces */
|
||||||
for (const DNACMDL::Mesh& mesh : meshes)
|
for (const DNACMDL::Mesh& mesh : meshes)
|
||||||
@ -457,7 +449,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
|||||||
/* Header */
|
/* Header */
|
||||||
Header head = {};
|
Header head = {};
|
||||||
head.magic = 0xDEADBEEF;
|
head.magic = 0xDEADBEEF;
|
||||||
head.version = 0x1000F;
|
head.version = pc ? 0x1000F : 0xF;
|
||||||
head.localToWorldMtx[0].vec[0] = 1.f;
|
head.localToWorldMtx[0].vec[0] = 1.f;
|
||||||
head.localToWorldMtx[1].vec[1] = 1.f;
|
head.localToWorldMtx[1].vec[1] = 1.f;
|
||||||
head.localToWorldMtx[2].vec[2] = 1.f;
|
head.localToWorldMtx[2].vec[2] = 1.f;
|
||||||
@ -490,7 +482,6 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
|||||||
|
|
||||||
/* Sizes section */
|
/* Sizes section */
|
||||||
secs.emplace_back();
|
secs.emplace_back();
|
||||||
std::vector<uint8_t>& sizesSec = secs.back();
|
|
||||||
|
|
||||||
/* Pre-emptively build full AABB and mesh AABBs in world coords */
|
/* Pre-emptively build full AABB and mesh AABBs in world coords */
|
||||||
zeus::CAABox fullAabb;
|
zeus::CAABox fullAabb;
|
||||||
@ -498,9 +489,18 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
|||||||
meshAabbs.reserve(meshes.size());
|
meshAabbs.reserve(meshes.size());
|
||||||
|
|
||||||
/* Models */
|
/* Models */
|
||||||
if (!DNACMDL::WriteHMDLMREASecs<HMDLMaterialSet, DNACMDL::SurfaceHeader_2, MeshHeader>
|
if (pc)
|
||||||
|
{
|
||||||
|
if (!DNACMDL::WriteHMDLMREASecs<HMDLMaterialSet, DNACMDL::SurfaceHeader_2, MeshHeader>
|
||||||
(secs, inPath, meshes, fullAabb, meshAabbs))
|
(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 */
|
/* AROT */
|
||||||
{
|
{
|
||||||
@ -807,6 +807,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
|
|||||||
|
|
||||||
/* Assemble sizes and add padding */
|
/* Assemble sizes and add padding */
|
||||||
{
|
{
|
||||||
|
std::vector<uint8_t>& sizesSec = secs[1];
|
||||||
sizesSec.assign((((head.secCount) + 7) & ~7) * 4, 0);
|
sizesSec.assign((((head.secCount) + 7) & ~7) * 4, 0);
|
||||||
athena::io::MemoryWriter w(sizesSec.data(), sizesSec.size());
|
athena::io::MemoryWriter w(sizesSec.data(), sizesSec.size());
|
||||||
for (auto it = secs.begin() + 2 ; it != secs.end() ; ++it)
|
for (auto it = secs.begin() + 2 ; it != secs.end() ; ++it)
|
||||||
|
@ -129,14 +129,9 @@ struct MREA
|
|||||||
const hecl::ProjectPath& inPath,
|
const hecl::ProjectPath& inPath,
|
||||||
const std::vector<DNACMDL::Mesh>& meshes,
|
const std::vector<DNACMDL::Mesh>& meshes,
|
||||||
const ColMesh& cMesh,
|
const ColMesh& cMesh,
|
||||||
const std::vector<Light>& lights);
|
const std::vector<Light>& lights,
|
||||||
|
hecl::blender::Token& btok,
|
||||||
static bool PCCook(const hecl::ProjectPath& outPath,
|
bool pc);
|
||||||
const hecl::ProjectPath& inPath,
|
|
||||||
const std::vector<DNACMDL::Mesh>& meshes,
|
|
||||||
const ColMesh& cMesh,
|
|
||||||
const std::vector<Light>& lights,
|
|
||||||
hecl::blender::Token& btok);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,10 +40,14 @@ struct DoorArea : IScriptObject
|
|||||||
|
|
||||||
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
|
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
|
||||||
{
|
{
|
||||||
animationParameters.depANCS(pathsOut);
|
|
||||||
actorParameters.depIDs(pathsOut);
|
actorParameters.depIDs(pathsOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gatherBulkDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
|
||||||
|
{
|
||||||
|
animationParameters.depANCS(pathsOut);
|
||||||
|
}
|
||||||
|
|
||||||
void gatherScans(std::vector<Scan>& scansOut) const
|
void gatherScans(std::vector<Scan>& scansOut) const
|
||||||
{
|
{
|
||||||
actorParameters.scanIDs(scansOut);
|
actorParameters.scanIDs(scansOut);
|
||||||
|
@ -45,6 +45,7 @@ struct IScriptObject : BigDNAVYaml
|
|||||||
std::unordered_map<UniqueID32, std::pair<UniqueID32, UniqueID32>>&) const {}
|
std::unordered_map<UniqueID32, std::pair<UniqueID32, UniqueID32>>&) const {}
|
||||||
virtual void nameIDs(PAKRouter<PAKBridge>& pakRouter) const {}
|
virtual void nameIDs(PAKRouter<PAKBridge>& pakRouter) const {}
|
||||||
virtual void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) 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 void gatherScans(std::vector<Scan>& scansOut) const {}
|
||||||
virtual zeus::CAABox getVISIAABB(hecl::blender::Token& btok) const { return {}; }
|
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
|
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);
|
g_curSpec->flattenDependencies(animationCharacterSet, pathsOut);
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,11 @@ struct PlayerActor : IScriptObject
|
|||||||
actorParameters.depIDs(pathsOut);
|
actorParameters.depIDs(pathsOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gatherBulkDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
|
||||||
|
{
|
||||||
|
animationParameters.depANCSAll(pathsOut);
|
||||||
|
}
|
||||||
|
|
||||||
void gatherScans(std::vector<Scan>& scansOut) const
|
void gatherScans(std::vector<Scan>& scansOut) const
|
||||||
{
|
{
|
||||||
actorParameters.scanIDs(scansOut);
|
actorParameters.scanIDs(scansOut);
|
||||||
|
@ -39,12 +39,13 @@ static const hecl::SystemChar* MomErr[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr uint32_t MomErrCount = std::extent<decltype(MomErr)>::value;
|
constexpr uint32_t MomErrCount = std::extent<decltype(MomErr)>::value;
|
||||||
|
|
||||||
SpecBase::SpecBase(const hecl::Database::DataSpecEntry* specEntry, hecl::Database::Project& project, bool pc)
|
SpecBase::SpecBase(const hecl::Database::DataSpecEntry* specEntry, hecl::Database::Project& project, bool pc)
|
||||||
: hecl::Database::IDataSpec(specEntry), m_project(project), m_pc(pc),
|
: hecl::Database::IDataSpec(specEntry), m_project(project), m_pc(pc),
|
||||||
m_masterShader(project.getProjectWorkingPath(), ".hecl/RetroMasterShader.blend")
|
m_masterShader(project.getProjectWorkingPath(), ".hecl/RetroMasterShader.blend")
|
||||||
{
|
{
|
||||||
AssetNameMap::InitAssetNameMap();
|
AssetNameMap::InitAssetNameMap();
|
||||||
DataSpec::UniqueIDBridge::setThreadProject(m_project);
|
SpecBase::setThreadProject();
|
||||||
}
|
}
|
||||||
|
|
||||||
SpecBase::~SpecBase()
|
SpecBase::~SpecBase()
|
||||||
@ -59,9 +60,75 @@ static const hecl::SystemString regP = _S("PAL");
|
|||||||
|
|
||||||
void SpecBase::setThreadProject()
|
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)
|
bool SpecBase::canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps)
|
||||||
{
|
{
|
||||||
m_disc = nod::OpenDiscFromImage(info.srcpath, m_isWii);
|
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,
|
void SpecBase::flattenDependencies(const hecl::ProjectPath& path,
|
||||||
std::vector<hecl::ProjectPath>& pathsOut,
|
std::vector<hecl::ProjectPath>& pathsOut,
|
||||||
hecl::blender::Token& btok)
|
hecl::blender::Token& btok,
|
||||||
|
int charIdx)
|
||||||
{
|
{
|
||||||
DataSpec::g_curSpec.reset(this);
|
DataSpec::g_curSpec.reset(this);
|
||||||
g_ThreadBlenderToken.reset(&btok);
|
g_ThreadBlenderToken.reset(&btok);
|
||||||
@ -355,77 +508,7 @@ void SpecBase::flattenDependencies(const hecl::ProjectPath& path,
|
|||||||
|
|
||||||
if (hecl::IsPathBlend(asBlend))
|
if (hecl::IsPathBlend(asBlend))
|
||||||
{
|
{
|
||||||
hecl::blender::Connection& conn = btok.getBlenderConnection();
|
flattenDependenciesBlend(asBlend, pathsOut, btok, charIdx);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (hecl::IsPathYAML(path))
|
else if (hecl::IsPathYAML(path))
|
||||||
{
|
{
|
||||||
@ -436,18 +519,18 @@ void SpecBase::flattenDependencies(const hecl::ProjectPath& path,
|
|||||||
pathsOut.push_back(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);
|
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
|
||||||
if (path)
|
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);
|
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
|
||||||
if (path)
|
if (path)
|
||||||
flattenDependencies(path, pathsOut, *g_ThreadBlenderToken.get());
|
flattenDependencies(path, pathsOut, *g_ThreadBlenderToken.get(), charIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpecBase::canPackage(const hecl::ProjectPath& path)
|
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();
|
auto components = path.getWithExtension(_S(""), true).getPathComponents();
|
||||||
if (components.size() <= 1)
|
if (components.size() <= 1)
|
||||||
return;
|
return;
|
||||||
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(),
|
hecl::ProjectPath outPath;
|
||||||
_S("out/") + components[0] + _S("/") + components[1] + _S(".upak"));
|
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);
|
outPath.makeDirChain(false);
|
||||||
|
|
||||||
/* Output file */
|
/* Output file */
|
||||||
|
@ -23,6 +23,17 @@ class YAMLDocWriter;
|
|||||||
namespace DataSpec
|
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
|
struct SpecBase : hecl::Database::IDataSpec
|
||||||
{
|
{
|
||||||
/* HECL Adaptors */
|
/* HECL Adaptors */
|
||||||
@ -116,11 +127,18 @@ struct SpecBase : hecl::Database::IDataSpec
|
|||||||
/* Dependency flatteners */
|
/* Dependency flatteners */
|
||||||
void flattenDependencies(const hecl::ProjectPath& in,
|
void flattenDependencies(const hecl::ProjectPath& in,
|
||||||
std::vector<hecl::ProjectPath>& pathsOut,
|
std::vector<hecl::ProjectPath>& pathsOut,
|
||||||
hecl::blender::Token& btok);
|
hecl::blender::Token& btok,
|
||||||
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);
|
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 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,
|
virtual void buildWorldPakList(const hecl::ProjectPath& worldPath,
|
||||||
const hecl::ProjectPath& worldPathCooked,
|
const hecl::ProjectPath& worldPathCooked,
|
||||||
@ -211,7 +229,7 @@ protected:
|
|||||||
bool fast, const hecl::MultiProgressPrinter& progress,
|
bool fast, const hecl::MultiProgressPrinter& progress,
|
||||||
athena::io::FileWriter& pakOut);
|
athena::io::FileWriter& pakOut);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
std::unique_ptr<nod::DiscBase> m_disc;
|
std::unique_ptr<nod::DiscBase> m_disc;
|
||||||
bool m_isWii;
|
bool m_isWii;
|
||||||
bool m_standalone;
|
bool m_standalone;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "DNAMP1/CSNG.hpp"
|
#include "DNAMP1/CSNG.hpp"
|
||||||
#include "DNAMP1/MAPA.hpp"
|
#include "DNAMP1/MAPA.hpp"
|
||||||
#include "DNAMP1/PATH.hpp"
|
#include "DNAMP1/PATH.hpp"
|
||||||
|
#include "DNAMP1/FRME.hpp"
|
||||||
#include "DNACommon/ATBL.hpp"
|
#include "DNACommon/ATBL.hpp"
|
||||||
#include "DNACommon/FONT.hpp"
|
#include "DNACommon/FONT.hpp"
|
||||||
#include "DNACommon/PART.hpp"
|
#include "DNACommon/PART.hpp"
|
||||||
@ -135,7 +136,7 @@ struct OriginalIDs
|
|||||||
originalIDs.push_back(std::make_pair(id, path.hash().val32()));
|
originalIDs.push_back(std::make_pair(id, path.hash().val32()));
|
||||||
}
|
}
|
||||||
std::sort(originalIDs.begin(), originalIDs.end(),
|
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;
|
return a.first < b.first;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -148,7 +149,7 @@ struct OriginalIDs
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::sort(originalIDs.begin(), originalIDs.end(),
|
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;
|
return a.second < b.second;
|
||||||
});
|
});
|
||||||
for (const auto& idPair : originalIDs)
|
for (const auto& idPair : originalIDs)
|
||||||
@ -176,12 +177,22 @@ struct SpecMP1 : SpecBase
|
|||||||
|
|
||||||
std::unique_ptr<uint8_t[]> m_dolBuf;
|
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)
|
SpecMP1(const hecl::Database::DataSpecEntry* specEntry, hecl::Database::Project& project, bool pc)
|
||||||
: SpecBase(specEntry, project, pc)
|
: SpecBase(specEntry, project, pc)
|
||||||
, m_workPath(project.getProjectWorkingPath(), _S("MP1"))
|
, m_workPath(project.getProjectWorkingPath(), _S("MP1"))
|
||||||
, m_cookPath(project.getProjectCookedPath(SpecEntMP1), _S("MP1"))
|
, m_cookPath(project.getProjectCookedPath(SpecEntMP1), _S("MP1"))
|
||||||
, m_pakRouter(*this, m_workPath, m_cookPath)
|
, 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)
|
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"));
|
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
||||||
outPath.makeDir();
|
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();
|
mp1OutPath.makeDir();
|
||||||
|
|
||||||
/* Extract non-pak files */
|
/* Extract non-pak files */
|
||||||
@ -780,15 +792,22 @@ struct SpecMP1 : SpecBase
|
|||||||
{
|
{
|
||||||
Actor actor = ds.compileActorCharacterOnly();
|
Actor actor = ds.compileActorCharacterOnly();
|
||||||
ds.close();
|
ds.close();
|
||||||
DNAMP1::ANCS::CookCSKR(out, in, actor, [&](const hecl::ProjectPath& modelPath) -> bool {
|
if (m_pc)
|
||||||
hecl::ProjectPath cooked;
|
{
|
||||||
if (m_pc)
|
DNAMP1::ANCS::CookCSKRPC(out, in, actor, [&](const hecl::ProjectPath& modelPath) {
|
||||||
cooked = modelPath.getCookedPath(SpecEntMP1PC);
|
hecl::ProjectPath cooked = modelPath.getCookedPath(SpecEntMP1PC);
|
||||||
else
|
doCook(modelPath, cooked, fast, btok, progress);
|
||||||
cooked = modelPath.getCookedPath(SpecEntMP1);
|
return true;
|
||||||
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")))
|
else if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S(".ANIM")))
|
||||||
{
|
{
|
||||||
@ -821,7 +840,7 @@ struct SpecMP1 : SpecBase
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
meshCompiles.push_back(ds.compileMesh(
|
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()); }));
|
[&](int surfCount) { progress(hecl::SysFormat(_S("%s %d"), meshSys.c_str(), surfCount).c_str()); }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -832,10 +851,7 @@ struct SpecMP1 : SpecBase
|
|||||||
|
|
||||||
ds.close();
|
ds.close();
|
||||||
|
|
||||||
if (m_pc)
|
DNAMP1::MREA::Cook(out, in, meshCompiles, *colMesh, lights, btok, m_pc);
|
||||||
DNAMP1::MREA::PCCook(out, in, meshCompiles, *colMesh, lights, btok);
|
|
||||||
else
|
|
||||||
DNAMP1::MREA::Cook(out, in, meshCompiles, *colMesh, lights);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cookWorld(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
|
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,
|
void cookGuiFrame(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds,
|
||||||
hecl::blender::Token& btok, FCookProgress progress)
|
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,
|
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;
|
athena::io::YAMLDocReader reader;
|
||||||
if (reader.parse(&fin))
|
if (reader.parse(&fin))
|
||||||
@ -1141,11 +1164,25 @@ struct SpecMP1 : SpecBase
|
|||||||
{
|
{
|
||||||
DNAMP1::ANCS ancs;
|
DNAMP1::ANCS ancs;
|
||||||
ancs.read(reader);
|
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,
|
void buildWorldPakList(const hecl::ProjectPath& worldPath,
|
||||||
const hecl::ProjectPath& worldPathCooked,
|
const hecl::ProjectPath& worldPathCooked,
|
||||||
hecl::blender::Token& btok,
|
hecl::blender::Token& btok,
|
||||||
@ -1169,32 +1206,35 @@ struct SpecMP1 : SpecBase
|
|||||||
|
|
||||||
urde::SObjectTag worldTag = tagFromPath(worldPath.getWithExtension(_S(".*"), true), btok);
|
urde::SObjectTag worldTag = tagFromPath(worldPath.getWithExtension(_S(".*"), true), btok);
|
||||||
|
|
||||||
w.writeUint32Big(0x80030005);
|
w.writeUint32Big(m_pc ? 0x80030005 : 0x00030005);
|
||||||
w.writeUint32Big(0);
|
w.writeUint32Big(0);
|
||||||
|
|
||||||
w.writeUint32Big(1);
|
w.writeUint32Big(1);
|
||||||
DNAMP1::PAK::NameEntry nameEnt;
|
DNAMP1::PAK::NameEntry nameEnt;
|
||||||
hecl::ProjectPath parentDir = worldPath.getParentPath();
|
hecl::ProjectPath parentDir = worldPath.getParentPath();
|
||||||
nameEnt.type = worldTag.type;
|
nameEnt.type = worldTag.type;
|
||||||
nameEnt.id = atUint32(worldTag.id.Value());
|
nameEnt.id = newToOriginal(worldTag.id);
|
||||||
nameEnt.nameLen = atUint32(parentDir.getLastComponent().size());
|
nameEnt.nameLen = atUint32(parentDir.getLastComponent().size());
|
||||||
nameEnt.name = parentDir.getLastComponentUTF8();
|
nameEnt.name = parentDir.getLastComponentUTF8();
|
||||||
nameEnt.write(w);
|
nameEnt.write(w);
|
||||||
|
|
||||||
for (const auto& area : mlvl.areas)
|
for (const auto& area : mlvl.areas)
|
||||||
{
|
{
|
||||||
urde::SObjectTag nameTag(FOURCC('STRG'), area.areaNameId.toUint32());
|
urde::SObjectTag nameTag(FOURCC('STRG'), originalToNew(area.areaNameId));
|
||||||
if (nameTag)
|
if (nameTag)
|
||||||
listOut.push_back(nameTag);
|
listOut.push_back(nameTag);
|
||||||
for (const auto& dep : area.deps)
|
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)
|
if (nameTag)
|
||||||
listOut.push_back(nameTag);
|
listOut.push_back(nameTag);
|
||||||
|
|
||||||
urde::SObjectTag savwTag(FOURCC('SAVW'), mlvl.saveWorldId.toUint32());
|
urde::SObjectTag savwTag(FOURCC('SAVW'), originalToNew(mlvl.saveWorldId));
|
||||||
if (savwTag)
|
if (savwTag)
|
||||||
{
|
{
|
||||||
if (hecl::ProjectPath savwPath = pathFromTag(savwTag))
|
if (hecl::ProjectPath savwPath = pathFromTag(savwTag))
|
||||||
@ -1202,7 +1242,7 @@ struct SpecMP1 : SpecBase
|
|||||||
listOut.push_back(savwTag);
|
listOut.push_back(savwTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
urde::SObjectTag mapTag(FOURCC('MAPW'), mlvl.worldMap.toUint32());
|
urde::SObjectTag mapTag(FOURCC('MAPW'), originalToNew(mlvl.worldMap));
|
||||||
if (mapTag)
|
if (mapTag)
|
||||||
{
|
{
|
||||||
if (hecl::ProjectPath mapPath = pathFromTag(mapTag))
|
if (hecl::ProjectPath mapPath = pathFromTag(mapTag))
|
||||||
@ -1222,14 +1262,14 @@ struct SpecMP1 : SpecBase
|
|||||||
{
|
{
|
||||||
UniqueID32 id;
|
UniqueID32 id;
|
||||||
id.read(r);
|
id.read(r);
|
||||||
listOut.push_back({FOURCC('MAPA'), id.toUint32()});
|
listOut.push_back({FOURCC('MAPA'), originalToNew(id)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
listOut.push_back(mapTag);
|
listOut.push_back(mapTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
urde::SObjectTag skyboxTag(FOURCC('CMDL'), mlvl.worldSkyboxId.toUint32());
|
urde::SObjectTag skyboxTag(FOURCC('CMDL'), originalToNew(mlvl.worldSkyboxId));
|
||||||
if (skyboxTag)
|
if (skyboxTag)
|
||||||
{
|
{
|
||||||
listOut.push_back(skyboxTag);
|
listOut.push_back(skyboxTag);
|
||||||
@ -1257,7 +1297,7 @@ struct SpecMP1 : SpecBase
|
|||||||
DNAMP1::PAK::Entry ent;
|
DNAMP1::PAK::Entry ent;
|
||||||
ent.compressed = 0;
|
ent.compressed = 0;
|
||||||
ent.type = item.type;
|
ent.type = item.type;
|
||||||
ent.id = atUint32(item.id.Value());
|
ent.id = newToOriginal(item.id.Value());
|
||||||
ent.size = 0;
|
ent.size = 0;
|
||||||
ent.offset = 0;
|
ent.offset = 0;
|
||||||
ent.write(w);
|
ent.write(w);
|
||||||
@ -1270,7 +1310,7 @@ struct SpecMP1 : SpecBase
|
|||||||
const std::vector<std::pair<urde::SObjectTag, std::string>>& nameList,
|
const std::vector<std::pair<urde::SObjectTag, std::string>>& nameList,
|
||||||
atUint64& resTableOffset)
|
atUint64& resTableOffset)
|
||||||
{
|
{
|
||||||
w.writeUint32Big(0x80030005);
|
w.writeUint32Big(m_pc ? 0x80030005 : 0x00030005);
|
||||||
w.writeUint32Big(0);
|
w.writeUint32Big(0);
|
||||||
|
|
||||||
w.writeUint32Big(atUint32(nameList.size()));
|
w.writeUint32Big(atUint32(nameList.size()));
|
||||||
@ -1278,7 +1318,7 @@ struct SpecMP1 : SpecBase
|
|||||||
{
|
{
|
||||||
DNAMP1::PAK::NameEntry nameEnt;
|
DNAMP1::PAK::NameEntry nameEnt;
|
||||||
nameEnt.type = item.first.type;
|
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.nameLen = atUint32(item.second.size());
|
||||||
nameEnt.name = item.second;
|
nameEnt.name = item.second;
|
||||||
nameEnt.write(w);
|
nameEnt.write(w);
|
||||||
@ -1291,7 +1331,7 @@ struct SpecMP1 : SpecBase
|
|||||||
DNAMP1::PAK::Entry ent;
|
DNAMP1::PAK::Entry ent;
|
||||||
ent.compressed = 0;
|
ent.compressed = 0;
|
||||||
ent.type = item.type;
|
ent.type = item.type;
|
||||||
ent.id = atUint32(item.id.Value());
|
ent.id = newToOriginal(item.id);
|
||||||
ent.size = 0;
|
ent.size = 0;
|
||||||
ent.offset = 0;
|
ent.offset = 0;
|
||||||
ent.write(w);
|
ent.write(w);
|
||||||
@ -1312,7 +1352,7 @@ struct SpecMP1 : SpecBase
|
|||||||
DNAMP1::PAK::Entry ent;
|
DNAMP1::PAK::Entry ent;
|
||||||
ent.compressed = atUint32(std::get<2>(item));
|
ent.compressed = atUint32(std::get<2>(item));
|
||||||
ent.type = tag.type;
|
ent.type = tag.type;
|
||||||
ent.id = atUint32(tag.id.Value());
|
ent.id = newToOriginal(tag.id);
|
||||||
ent.size = atUint32(std::get<1>(item));
|
ent.size = atUint32(std::get<1>(item));
|
||||||
ent.offset = atUint32(std::get<0>(item));
|
ent.offset = atUint32(std::get<0>(item));
|
||||||
ent.write(w);
|
ent.write(w);
|
||||||
@ -1350,7 +1390,7 @@ struct SpecMP1 : SpecBase
|
|||||||
uLong destLen = compressBound(len);
|
uLong destLen = compressBound(len);
|
||||||
std::pair<std::unique_ptr<uint8_t[]>, size_t> ret;
|
std::pair<std::unique_ptr<uint8_t[]>, size_t> ret;
|
||||||
ret.first.reset(new uint8_t[destLen]);
|
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;
|
ret.second = destLen;
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
@ -1389,19 +1429,19 @@ struct SpecMP1 : SpecBase
|
|||||||
};
|
};
|
||||||
|
|
||||||
hecl::Database::DataSpecEntry SpecEntMP1 = {
|
hecl::Database::DataSpecEntry SpecEntMP1 = {
|
||||||
_S("MP1"sv), _S("Data specification for original Metroid Prime engine"sv),
|
_S("MP1"sv), _S("Data specification for original Metroid Prime engine"sv), _S(".pak"sv),
|
||||||
[](hecl::Database::Project& project, hecl::Database::DataSpecTool) -> hecl::Database::IDataSpec* {
|
[](hecl::Database::Project& project, hecl::Database::DataSpecTool) -> std::unique_ptr<hecl::Database::IDataSpec> {
|
||||||
return new struct SpecMP1(&SpecEntMP1, project, false);
|
return std::make_unique<SpecMP1>(&SpecEntMP1, project, false);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
hecl::Database::DataSpecEntry SpecEntMP1PC = {
|
hecl::Database::DataSpecEntry SpecEntMP1PC = {
|
||||||
_S("MP1-PC"sv), _S("Data specification for PC-optimized Metroid Prime engine"sv),
|
_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) -> hecl::Database::IDataSpec* {
|
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool) -> std::unique_ptr<hecl::Database::IDataSpec> {
|
||||||
if (tool != hecl::Database::DataSpecTool::Extract)
|
if (tool != hecl::Database::DataSpecTool::Extract)
|
||||||
return new struct SpecMP1(&SpecEntMP1PC, project, true);
|
return std::make_unique<SpecMP1>(&SpecEntMP1PC, project, true);
|
||||||
return nullptr;
|
return {};
|
||||||
}};
|
}};
|
||||||
|
|
||||||
hecl::Database::DataSpecEntry SpecEntMP1ORIG = {
|
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;
|
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};
|
nod::ExtractionContext ctx = {force, nullptr};
|
||||||
|
|
||||||
@ -239,7 +239,8 @@ struct SpecMP2 : SpecBase
|
|||||||
|
|
||||||
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
||||||
outPath.makeDir();
|
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();
|
mp2OutPath.makeDir();
|
||||||
progress.startNewLine();
|
progress.startNewLine();
|
||||||
progress.print(_S("MP2 Root"), _S(""), 0.0);
|
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
|
hecl::Database::DataSpecEntry SpecEntMP2
|
||||||
(
|
(
|
||||||
_S("MP2"sv),
|
_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::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 =
|
hecl::Database::DataSpecEntry SpecEntMP2PC =
|
||||||
{
|
{
|
||||||
_S("MP2-PC"sv),
|
_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::Project& project, hecl::Database::DataSpecTool tool)
|
||||||
-> hecl::Database::IDataSpec*
|
-> std::unique_ptr<hecl::Database::IDataSpec>
|
||||||
{
|
{
|
||||||
if (tool != hecl::Database::DataSpecTool::Extract)
|
if (tool != hecl::Database::DataSpecTool::Extract)
|
||||||
return new struct SpecMP2(&SpecEntMP2PC, project, true);
|
return std::make_unique<SpecMP2>(&SpecEntMP2PC, project, true);
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -439,7 +440,7 @@ hecl::Database::DataSpecEntry SpecEntMP2ORIG =
|
|||||||
{
|
{
|
||||||
_S("MP2-ORIG"sv),
|
_S("MP2-ORIG"sv),
|
||||||
_S("Data specification for unmodified Metroid Prime 2 resources"sv),
|
_S("Data specification for unmodified Metroid Prime 2 resources"sv),
|
||||||
{}
|
{}, {}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -352,7 +352,7 @@ struct SpecMP3 : SpecBase
|
|||||||
return doMP3 || doMPTFE;
|
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("");
|
hecl::SystemString currentTarget = _S("");
|
||||||
size_t nodeCount = 0;
|
size_t nodeCount = 0;
|
||||||
@ -378,7 +378,8 @@ struct SpecMP3 : SpecBase
|
|||||||
|
|
||||||
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
||||||
outPath.makeDir();
|
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();
|
mp3OutPath.makeDir();
|
||||||
currentTarget = _S("MP3 Root");
|
currentTarget = _S("MP3 Root");
|
||||||
progress.print(currentTarget.c_str(), _S(""), 0.0);
|
progress.print(currentTarget.c_str(), _S(""), 0.0);
|
||||||
@ -436,7 +437,8 @@ struct SpecMP3 : SpecBase
|
|||||||
|
|
||||||
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
|
||||||
outPath.makeDir();
|
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();
|
feOutPath.makeDir();
|
||||||
currentTarget = _S("fe Root");
|
currentTarget = _S("fe Root");
|
||||||
progress.print(currentTarget.c_str(), _S(""), 0.0);
|
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
|
hecl::Database::DataSpecEntry SpecEntMP3
|
||||||
(
|
(
|
||||||
_S("MP3"sv),
|
_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::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 =
|
hecl::Database::DataSpecEntry SpecEntMP3PC =
|
||||||
{
|
{
|
||||||
_S("MP3-PC"sv),
|
_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::Project& project, hecl::Database::DataSpecTool tool)
|
||||||
-> hecl::Database::IDataSpec*
|
-> std::unique_ptr<hecl::Database::IDataSpec>
|
||||||
{
|
{
|
||||||
if (tool != hecl::Database::DataSpecTool::Extract)
|
if (tool != hecl::Database::DataSpecTool::Extract)
|
||||||
return new struct SpecMP3(&SpecEntMP3PC, project, true);
|
return std::make_unique<SpecMP3>(&SpecEntMP3PC, project, true);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -622,7 +624,7 @@ hecl::Database::DataSpecEntry SpecEntMP3ORIG =
|
|||||||
{
|
{
|
||||||
_S("MP3-ORIG"sv),
|
_S("MP3-ORIG"sv),
|
||||||
_S("Data specification for unmodified Metroid Prime 3 resources"sv),
|
_S("Data specification for unmodified Metroid Prime 3 resources"sv),
|
||||||
{}
|
{}, {}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ void ProjectResourceFactoryBase::BeginBackgroundIndex
|
|||||||
m_proj = &proj;
|
m_proj = &proj;
|
||||||
m_origSpec = &origSpec;
|
m_origSpec = &origSpec;
|
||||||
m_pcSpec = &pcSpec;
|
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();
|
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 */
|
/* Start a background cook here */
|
||||||
m_cookTransaction = m_parent.m_clientProc.
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ void ViewManager::RootSpaceViewBuilt(specter::View *view)
|
|||||||
void ViewManager::ProjectChanged(hecl::Database::Project& proj)
|
void ViewManager::ProjectChanged(hecl::Database::Project& proj)
|
||||||
{
|
{
|
||||||
CDvdFile::Shutdown();
|
CDvdFile::Shutdown();
|
||||||
CDvdFile::Initialize(hecl::ProjectPath(proj.getProjectWorkingPath(), _S("out/MP1")));
|
CDvdFile::Initialize(hecl::ProjectPath(proj.getProjectWorkingPath(), _S("out/files")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewManager::SetupEditorView()
|
void ViewManager::SetupEditorView()
|
||||||
|
@ -117,17 +117,21 @@ void CResFactory::CancelBuild(const SObjectTag& tag)
|
|||||||
|
|
||||||
void CResFactory::LoadOriginalIDs(CSimplePool& sp)
|
void CResFactory::LoadOriginalIDs(CSimplePool& sp)
|
||||||
{
|
{
|
||||||
m_origIds = sp.GetObj("MP1OriginalIDs");
|
//m_origIds = sp.GetObj("MP1OriginalIDs");
|
||||||
}
|
}
|
||||||
|
|
||||||
CAssetId CResFactory::TranslateOriginalToNew(CAssetId id) const
|
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
|
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;
|
CResLoader x4_loader;
|
||||||
CFactoryMgr x5c_factoryMgr;
|
CFactoryMgr x5c_factoryMgr;
|
||||||
TLockedToken<MP1OriginalIDs> m_origIds;
|
//TLockedToken<MP1OriginalIDs> m_origIds;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct SLoadingData
|
struct SLoadingData
|
||||||
|
@ -50,8 +50,8 @@ public:
|
|||||||
virtual std::unique_ptr<u8[]> LoadNewResourcePartSync(const urde::SObjectTag& tag, u32 off, u32 size)=0;
|
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 void GetTagListForFile(const char* pakName, std::vector<SObjectTag>& out) const {}
|
||||||
|
|
||||||
virtual CAssetId TranslateOriginalToNew(CAssetId id) const { return -1; }
|
virtual CAssetId TranslateOriginalToNew(CAssetId id) const { return {}; }
|
||||||
virtual CAssetId TranslateNewToOriginal(CAssetId id) const { return -1; }
|
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…
x
Reference in New Issue
Block a user