Initial work on GameCube package targeting

This commit is contained in:
Jack Andersen 2018-03-27 22:09:41 -10:00
parent 7c0bf75f7a
commit 7a2fbfc582
27 changed files with 1891 additions and 283 deletions

View File

@ -1199,7 +1199,8 @@ template void NameCMDL<PAKRouter<DNAMP1::PAKBridge>, DNAMP1::MaterialSet>
PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
const SpecBase& dataspec);
static void WriteDLVal(athena::io::FileWriter& writer, GX::AttrType type, atUint32 val)
template <typename W>
static void WriteDLVal(W& writer, GX::AttrType type, atUint32 val)
{
switch (type)
{
@ -1356,7 +1357,7 @@ bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath
size_t vertSz = matSets.at(0).materials.at(surf.materialIdx).getVAFlags().vertDLSize();
if (surf.verts.size() > 65536)
LogDNACommon.report(logvisor::Fatal, "GX DisplayList overflow");
size_t secSz = 67 + surf.verts.size() * vertSz;
size_t secSz = 68 + surf.verts.size() * vertSz;
secSz32 = ROUND_UP_32(secSz);
if (secSz32 == 0)
secSz32 = 32;
@ -1430,7 +1431,7 @@ bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath
SurfaceHeader header;
header.centroid = surf.centroid;
header.matIdx = surf.materialIdx;
header.dlSize = 3 + surf.verts.size() * vertSz;
header.dlSize = ROUND_UP_32(4 + surf.verts.size() * vertSz);
header.reflectionNormal = surf.reflectionNormal;
header.write(writer);
@ -1461,6 +1462,8 @@ bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath
WriteDLVal(writer, vaFlags.tex6(), vert.iUv[6]);
}
writer.writeUByte(0);
writer.fill(atUint8(0), *padIt);
++padIt;
}
@ -1649,13 +1652,319 @@ template bool WriteHMDLCMDL<DNAMP1::HMDLMaterialSet, DNACMDL::SurfaceHeader_2, 2
(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh,
hecl::blender::PoolSkinIndex& poolSkinIndex);
struct MaterialPool
{
std::vector<const Material*> materials;
size_t addMaterial(const Material& mat, bool& newMat)
{
size_t ret = 0;
newMat = false;
for (const Material* testMat : materials)
{
if (mat == *testMat)
return ret;
++ret;
}
materials.push_back(&mat);
newMat = true;
return ret;
}
};
template <class MaterialSet, class SurfaceHeader, class MeshHeader>
bool WriteMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
const std::vector<Mesh>& meshes, zeus::CAABox& fullAABB, std::vector<zeus::CAABox>& meshAABBs)
{
return false;
/* Build material set */
std::vector<size_t> surfToGlobalMats;
MaterialSet matSet;
{
MaterialPool matPool;
size_t surfCount = 0;
for (const Mesh& mesh : meshes)
surfCount += mesh.surfaces.size();
surfToGlobalMats.reserve(surfCount);
hecl::Frontend::Frontend FE;
size_t endOff = 0;
std::vector<hecl::ProjectPath> texPaths;
std::vector<hecl::Backend::GX> setBackends;
atUint32 nextGroupIdx = 0;
for (const Mesh& mesh : meshes)
{
if (mesh.materialSets.size())
{
std::vector<size_t> meshToGlobalMats;
meshToGlobalMats.reserve(mesh.materialSets[0].size());
for (const Material& mat : mesh.materialSets[0])
{
bool newMat;
size_t idx = matPool.addMaterial(mat, newMat);
meshToGlobalMats.push_back(idx);
if (!newMat)
continue;
for (const hecl::ProjectPath& path : mat.texs)
{
bool found = false;
for (const hecl::ProjectPath& ePath : texPaths)
{
if (path == ePath)
{
found = true;
break;
}
}
if (!found)
texPaths.push_back(path);
}
std::string diagName = hecl::Format("%s:%s", inPath.getLastComponentUTF8().data(), mat.name.c_str());
hecl::Frontend::IR matIR = FE.compileSource(mat.source, diagName);
setBackends.emplace_back();
hecl::Backend::GX& matGX = setBackends.back();
matGX.reset(matIR, FE.getDiagnostics());
atUint32 groupIdx = -1;
for (size_t i=0 ; i<setBackends.size()-1 ; ++i)
{
const hecl::Backend::GX& other = setBackends[i];
if (matGX == other)
{
groupIdx = i;
break;
}
}
if (groupIdx == -1)
groupIdx = nextGroupIdx++;
auto lightmapped = mat.iprops.find("retro_lightmapped");
bool lm = lightmapped != mat.iprops.cend() && lightmapped->second != 0;
matSet.materials.emplace_back(matGX, mat.iprops, mat.texs, texPaths,
mesh.colorLayerCount, mesh.uvLayerCount,
lm, false, groupIdx);
matSet.materials.back().binarySize(endOff);
matSet.head.addMaterialEndOff(endOff);
}
for (const Mesh::Surface& surf : mesh.surfaces)
surfToGlobalMats.push_back(meshToGlobalMats[surf.materialIdx]);
}
}
for (const hecl::ProjectPath& path : texPaths)
matSet.head.addTexture(path);
size_t secSz = 0;
matSet.binarySize(secSz);
secsOut.emplace_back(secSz, 0);
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
matSet.write(w);
}
/* Iterate meshes */
auto matIt = surfToGlobalMats.cbegin();
int meshIdx = 0;
for (const Mesh& mesh : meshes)
{
zeus::CTransform meshXf(mesh.sceneXf.val);
meshXf.basis.transpose();
/* Header */
{
MeshHeader meshHeader = {};
meshHeader.visorFlags.setFromBlenderProps(mesh.customProps);
memmove(meshHeader.xfMtx, &mesh.sceneXf, 48);
zeus::CAABox aabb(zeus::CVector3f(mesh.aabbMin), zeus::CVector3f(mesh.aabbMax));
aabb = aabb.getTransformedAABox(meshXf);
meshAABBs.push_back(aabb);
fullAABB.accumulateBounds(aabb);
meshHeader.aabb[0] = aabb.min;
meshHeader.aabb[1] = aabb.max;
size_t secSz = 0;
meshHeader.binarySize(secSz);
secsOut.emplace_back(secSz, 0);
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
meshHeader.write(w);
}
std::vector<size_t> surfEndOffs;
surfEndOffs.reserve(mesh.surfaces.size());
size_t endOff = 0;
auto smatIt = matIt;
for (const Mesh::Surface& surf : mesh.surfaces)
{
const typename MaterialSet::Material::VAFlags& vaFlags =
matSet.materials.at(*smatIt++).getVAFlags();
size_t vertSz = vaFlags.vertDLSize();
endOff += 96 + vertSz * surf.verts.size() + 4;
endOff = ROUND_UP_32(endOff);
surfEndOffs.push_back(endOff);
}
/* Positions */
{
size_t secSz = ROUND_UP_32(mesh.pos.size() * 12);
if (secSz == 0)
secSz = 32;
secsOut.emplace_back(secSz, 0);
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
for (const hecl::blender::Vector3f& v : mesh.pos)
{
zeus::CVector3f preXfPos = meshXf * zeus::CVector3f(v);
w.writeVec3fBig(preXfPos);
}
}
/* Normals */
{
size_t secSz = ROUND_UP_32(mesh.norm.size() * 6);
if (secSz == 0)
secSz = 32;
secsOut.emplace_back(secSz, 0);
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
for (const hecl::blender::Vector3f& v : mesh.norm)
{
zeus::CVector3f preXfNorm = (meshXf.basis * zeus::CVector3f(v)).normalized();
for (int i=0 ; i<3 ; ++i)
{
int tmpV = int(preXfNorm[i] * 16834.f);
tmpV = zeus::clamp(-32768, tmpV, 32767);
w.writeInt16Big(atInt16(tmpV));
}
}
}
/* Colors */
{
size_t secSz = ROUND_UP_32(mesh.color.size() * 4);
if (secSz == 0)
secSz = 32;
secsOut.emplace_back(secSz, 0);
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
for (const hecl::blender::Vector3f& v : mesh.color)
{
zeus::CColor col((zeus::CVector4f(zeus::CVector3f(v))));
col.writeRGBA8(w);
}
}
/* UVs */
{
size_t secSz = ROUND_UP_32(mesh.uv.size() * 8);
if (secSz == 0)
secSz = 32;
secsOut.emplace_back(secSz, 0);
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
for (const hecl::blender::Vector2f& v : mesh.uv)
w.writeVec2fBig(v.val);
}
/* LUVs */
{
size_t secSz = ROUND_UP_32(mesh.luv.size() * 4);
if (secSz == 0)
secSz = 32;
secsOut.emplace_back(secSz, 0);
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
for (const hecl::blender::Vector2f& v : mesh.luv)
{
for (int i=0 ; i<2 ; ++i)
{
int tmpV = int(v.val.vec[i] * 32768.f);
tmpV = zeus::clamp(-32768, tmpV, 32767);
w.writeInt16Big(atInt16(tmpV));
}
}
}
/* Surface index */
{
secsOut.emplace_back((surfEndOffs.size() + 1) * 4, 0);
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
w.writeUint32Big(surfEndOffs.size());
for (size_t off : surfEndOffs)
w.writeUint32Big(off);
}
/* Surfaces */
GX::Primitive prim;
if (mesh.topology == hecl::HMDLTopology::Triangles)
prim = GX::TRIANGLES;
else if (mesh.topology == hecl::HMDLTopology::TriStrips)
prim = GX::TRIANGLESTRIP;
else
LogDNACommon.report(logvisor::Fatal, "unrecognized mesh output mode");
for (const Mesh::Surface& surf : mesh.surfaces)
{
size_t matIdx = *matIt++;
const typename MaterialSet::Material::VAFlags& vaFlags =
matSet.materials.at(matIdx).getVAFlags();
size_t vertSz = vaFlags.vertDLSize();
SurfaceHeader header;
header.centroid = meshXf * zeus::CVector3f(surf.centroid);
header.matIdx = matIdx;
header.dlSize = ROUND_UP_32(4 + surf.verts.size() * vertSz);
header.reflectionNormal = (meshXf.basis * zeus::CVector3f(surf.reflectionNormal)).normalized();
header.aabbSz = 24;
zeus::CAABox aabb(zeus::CVector3f(surf.aabbMin), zeus::CVector3f(surf.aabbMax));
aabb = aabb.getTransformedAABox(meshXf);
header.aabb[0] = aabb.min;
header.aabb[1] = aabb.max;
size_t secSz = 0;
header.binarySize(secSz);
secSz += 4 + surf.verts.size() * vertSz;
secSz = ROUND_UP_32(secSz);
secsOut.emplace_back(secSz, 0);
athena::io::MemoryWriter w(secsOut.back().data(), secsOut.back().size());
header.write(w);
w.writeUByte(prim);
w.writeUint16Big(surf.verts.size());
for (const Mesh::Surface::Vert& vert : surf.verts)
{
atUint32 skinIdx = vert.iBankSkin * 3;
WriteDLVal(w, vaFlags.pnMatIdx(), skinIdx);
WriteDLVal(w, vaFlags.tex0MatIdx(), skinIdx);
WriteDLVal(w, vaFlags.tex1MatIdx(), skinIdx);
WriteDLVal(w, vaFlags.tex2MatIdx(), skinIdx);
WriteDLVal(w, vaFlags.tex3MatIdx(), skinIdx);
WriteDLVal(w, vaFlags.tex4MatIdx(), skinIdx);
WriteDLVal(w, vaFlags.tex5MatIdx(), skinIdx);
WriteDLVal(w, vaFlags.tex6MatIdx(), skinIdx);
WriteDLVal(w, vaFlags.position(), vert.iPos);
WriteDLVal(w, vaFlags.normal(), vert.iNorm);
WriteDLVal(w, vaFlags.color0(), vert.iColor[0]);
WriteDLVal(w, vaFlags.color1(), vert.iColor[1]);
WriteDLVal(w, vaFlags.tex0(), vert.iUv[0]);
WriteDLVal(w, vaFlags.tex1(), vert.iUv[1]);
WriteDLVal(w, vaFlags.tex2(), vert.iUv[2]);
WriteDLVal(w, vaFlags.tex3(), vert.iUv[3]);
WriteDLVal(w, vaFlags.tex4(), vert.iUv[4]);
WriteDLVal(w, vaFlags.tex5(), vert.iUv[5]);
WriteDLVal(w, vaFlags.tex6(), vert.iUv[6]);
}
w.writeUByte(0);
}
}
return true;
}
template bool WriteMREASecs<DNAMP1::MaterialSet, DNACMDL::SurfaceHeader_1, DNAMP1::MREA::MeshHeader>
(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
const std::vector<Mesh>& meshes, zeus::CAABox& fullAABB, std::vector<zeus::CAABox>& meshAABBs);
template <class MaterialSet, class SurfaceHeader, class MeshHeader>
bool WriteHMDLMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::ProjectPath& inPath,
const std::vector<Mesh>& meshes, zeus::CAABox& fullAABB, std::vector<zeus::CAABox>& meshAABBs)
@ -1663,24 +1972,7 @@ bool WriteHMDLMREASecs(std::vector<std::vector<uint8_t>>& secsOut, const hecl::P
/* Build material set */
std::vector<size_t> surfToGlobalMats;
{
struct MaterialPool
{
std::vector<const Material*> materials;
size_t addMaterial(const Material& mat, bool& newMat)
{
size_t ret = 0;
newMat = false;
for (const Material* testMat : materials)
{
if (mat == *testMat)
return ret;
++ret;
}
materials.push_back(&mat);
newMat = true;
return ret;
}
} matPool;
MaterialPool matPool;
size_t surfCount = 0;
for (const Mesh& mesh : meshes)

View File

@ -10,6 +10,9 @@ ThreadLocalPtr<SpecBase> g_curSpec;
ThreadLocalPtr<PAKRouterBase> g_PakRouter;
ThreadLocalPtr<hecl::blender::Token> g_ThreadBlenderToken;
ThreadLocalPtr<hecl::Database::Project> UniqueIDBridge::s_Project;
ThreadLocalPtr<IDRestorer<UniqueID32>> UniqueIDBridge::s_restorer32;
ThreadLocalPtr<IDRestorer<UniqueID64>> UniqueIDBridge::s_restorer64;
ThreadLocalPtr<IDRestorer<UniqueID128>> UniqueIDBridge::s_restorer128;
UniqueID32 UniqueID32::kInvalidId;
template <class IDType>
@ -38,11 +41,16 @@ hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const IDType& id, bool si
LogDNACommon.report(logvisor::Fatal,
"g_PakRouter or s_Project must be set to non-null before "
"calling UniqueIDBridge::TranslatePakIdToPath");
return {};
}
const hecl::ProjectPath* search = project->lookupBridgePath(id.toUint64());
if (!search)
{
if (IDRestorer<IDType>* restorer = GetIDRestorer<IDType>())
if (IDType newId = restorer->originalToNew(id))
if (const hecl::ProjectPath* newSearch = project->lookupBridgePath(newId.toUint64()))
return *newSearch;
if (hecl::VerbosityLevel >= 1 && !silenceWarnings && id)
LogDNACommon.report(logvisor::Warning,
"unable to translate %s to path", id.toString().c_str());
@ -54,6 +62,8 @@ template
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID32& id, bool silenceWarnings);
template
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID64& id, bool silenceWarnings);
template
hecl::ProjectPath UniqueIDBridge::TranslatePakIdToPath(const UniqueID128& id, bool silenceWarnings);
template <class IDType>
hecl::ProjectPath UniqueIDBridge::MakePathFromString(std::string_view str)
@ -83,12 +93,21 @@ void UniqueIDBridge::TransformOldHashToNewHash(UniqueID32& id);
template
void UniqueIDBridge::TransformOldHashToNewHash(UniqueID64& id);
void UniqueIDBridge::setThreadProject(hecl::Database::Project& project)
void UniqueIDBridge::SetThreadProject(hecl::Database::Project& project)
{
s_Project.reset(&project);
}
/** PAK 32-bit Unique ID */
void UniqueID32::assign(uint32_t id, bool noOriginal)
{
m_id = id ? id : 0xffffffff;
if (!noOriginal)
if (IDRestorer<UniqueID32>* restorer = UniqueIDBridge::GetIDRestorer<UniqueID32>())
if (UniqueID32 origId = restorer->newToOriginal(*this))
*this = origId;
}
template <>
void UniqueID32::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
{assign(reader.readUint32Big());}
@ -164,7 +183,7 @@ void AuxiliaryID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& wr
{
if (!operator bool())
return;
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(*this, true);
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath<UniqueID32>(*this, true);
if (!path)
path = UniqueIDBridge::TranslatePakIdToPath(m_baseId);
if (!path)
@ -177,6 +196,15 @@ void AuxiliaryID32::Enumerate<BigDNA::WriteYaml>(typename WriteYaml::StreamT& wr
/** PAK 64-bit Unique ID */
void UniqueID64::assign(uint64_t id, bool noOriginal)
{
m_id = id ? id : 0xffffffffffffffff;
if (!noOriginal)
if (IDRestorer<UniqueID64>* restorer = UniqueIDBridge::GetIDRestorer<UniqueID64>())
if (UniqueID64 origId = restorer->newToOriginal(*this))
*this = origId;
}
template <>
void UniqueID64::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
{assign(reader.readUint64Big());}
@ -215,14 +243,14 @@ std::string UniqueID64::toString() const
template <>
void UniqueID128::Enumerate<BigDNA::Read>(typename Read::StreamT& reader)
{
m_id[0] = reader.readUint64Big();
m_id[1] = reader.readUint64Big();
m_id.id[0] = reader.readUint64Big();
m_id.id[1] = reader.readUint64Big();
}
template <>
void UniqueID128::Enumerate<BigDNA::Write>(typename Write::StreamT& writer)
{
writer.writeUint64Big(m_id[0]);
writer.writeUint64Big(m_id[1]);
writer.writeUint64Big(m_id.id[0]);
writer.writeUint64Big(m_id.id[1]);
}
template <>
void UniqueID128::Enumerate<BigDNA::ReadYaml>(typename ReadYaml::StreamT& reader)
@ -248,7 +276,7 @@ void UniqueID128::Enumerate<BigDNA::BinarySize>(typename BinarySize::StreamT& s)
std::string UniqueID128::toString() const
{
char buf[33];
snprintf(buf, 33, "%016" PRIX64 "%016" PRIX64, m_id[0], m_id[1]);
snprintf(buf, 33, "%016" PRIX64 "%016" PRIX64, m_id.id[0], m_id.id[1]);
return std::string(buf);
}

View File

@ -123,6 +123,9 @@ class UniqueIDBridge
friend class UniqueID64;
static ThreadLocalPtr<hecl::Database::Project> s_Project;
static ThreadLocalPtr<IDRestorer<UniqueID32>> s_restorer32;
static ThreadLocalPtr<IDRestorer<UniqueID64>> s_restorer64;
static ThreadLocalPtr<IDRestorer<UniqueID128>> s_restorer128;
public:
template <class IDType>
static hecl::ProjectPath TranslatePakIdToPath(const IDType& id, bool silenceWarnings=false);
@ -131,19 +134,61 @@ public:
template <class IDType>
static void TransformOldHashToNewHash(IDType& id);
static void setThreadProject(hecl::Database::Project& project);
static void SetThreadProject(hecl::Database::Project& project);
template <class IDType>
static IDRestorer<IDType>* GetIDRestorer();
template <class IDType>
static void SetIDRestorer(IDRestorer<IDType>* restorer);
};
template <>
inline IDRestorer<UniqueID32>* UniqueIDBridge::GetIDRestorer<UniqueID32>()
{
return s_restorer32.get();
}
template <>
inline void UniqueIDBridge::SetIDRestorer<UniqueID32>(IDRestorer<UniqueID32>* restorer)
{
s_restorer32.reset(restorer);
}
template <>
inline IDRestorer<UniqueID64>* UniqueIDBridge::GetIDRestorer<UniqueID64>()
{
return s_restorer64.get();
}
template <>
inline void UniqueIDBridge::SetIDRestorer<UniqueID64>(IDRestorer<UniqueID64>* restorer)
{
s_restorer64.reset(restorer);
}
template <>
inline IDRestorer<UniqueID128>* UniqueIDBridge::GetIDRestorer<UniqueID128>()
{
return s_restorer128.get();
}
template <>
inline void UniqueIDBridge::SetIDRestorer<UniqueID128>(IDRestorer<UniqueID128>* restorer)
{
s_restorer128.reset(restorer);
}
/** PAK 32-bit Unique ID */
class UniqueID32 : public BigDNA
{
protected:
uint32_t m_id = 0xffffffff;
public:
using value_type = uint32_t;
static UniqueID32 kInvalidId;
AT_DECL_EXPLICIT_DNA_YAML
operator bool() const {return m_id != 0xffffffff && m_id != 0;}
void assign(uint32_t id) { m_id = id ? id : 0xffffffff; }
void assign(uint32_t id, bool noOriginal = false);
UniqueID32& operator=(const hecl::ProjectPath& path)
{assign(path.hash().val32()); return *this;}
@ -157,7 +202,7 @@ public:
void clear() {m_id = 0xffffffff;}
UniqueID32() = default;
UniqueID32(uint32_t idin) {assign(idin);}
UniqueID32(uint32_t idin, bool noOriginal = false) {assign(idin, noOriginal);}
UniqueID32(athena::io::IStreamReader& reader) {read(reader);}
UniqueID32(const hecl::ProjectPath& path) {*this = path;}
UniqueID32(const char* hexStr)
@ -200,9 +245,10 @@ class UniqueID64 : public BigDNA
{
uint64_t m_id = 0xffffffffffffffff;
public:
using value_type = uint64_t;
AT_DECL_EXPLICIT_DNA_YAML
operator bool() const {return m_id != 0xffffffffffffffff && m_id != 0;}
void assign(uint64_t id) { m_id = id ? id : 0xffffffffffffffff; }
void assign(uint64_t id, bool noOriginal = false);
UniqueID64& operator=(const hecl::ProjectPath& path)
{assign(path.hash().val64()); return *this;}
@ -215,7 +261,7 @@ public:
void clear() {m_id = 0xffffffffffffffff;}
UniqueID64() = default;
UniqueID64(uint64_t idin) {assign(idin);}
UniqueID64(uint64_t idin, bool noOriginal = false) {assign(idin, noOriginal);}
UniqueID64(athena::io::IStreamReader& reader) {read(reader);}
UniqueID64(const hecl::ProjectPath& path) {*this = path;}
UniqueID64(const char* hexStr)
@ -247,23 +293,32 @@ public:
/** PAK 128-bit Unique ID */
class UniqueID128 : public BigDNA
{
union
public:
union Value
{
uint64_t m_id[2];
uint64_t id[2];
#if __SSE__
__m128i m_id128;
__m128i id128;
#endif
};
private:
Value m_id;
public:
using value_type = uint64_t;
AT_DECL_EXPLICIT_DNA_YAML
UniqueID128() {m_id[0]=0xffffffffffffffff; m_id[1]=0xffffffffffffffff;}
UniqueID128() {m_id.id[0]=0xffffffffffffffff; m_id.id[1]=0xffffffffffffffff;}
UniqueID128(uint64_t idin, bool noOriginal = false)
{
m_id.id[0] = idin;
m_id.id[1] = 0;
}
operator bool() const
{return m_id[0] != 0xffffffffffffffff && m_id[0] != 0 && m_id[1] != 0xffffffffffffffff && m_id[1] != 0;}
{return m_id.id[0] != 0xffffffffffffffff && m_id.id[0] != 0 && m_id.id[1] != 0xffffffffffffffff && m_id.id[1] != 0;}
UniqueID128& operator=(const hecl::ProjectPath& path)
{
m_id[0] = path.hash().val64();
m_id[1] = 0;
m_id.id[0] = path.hash().val64();
m_id.id[1] = 0;
return *this;
}
UniqueID128(const hecl::ProjectPath& path) {*this = path;}
@ -271,27 +326,27 @@ public:
bool operator!=(const UniqueID128& other) const
{
#if __SSE__
__m128i vcmp = _mm_cmpeq_epi32(m_id128, other.m_id128);
__m128i vcmp = _mm_cmpeq_epi32(m_id.id128, other.m_id.id128);
int vmask = _mm_movemask_epi8(vcmp);
return vmask != 0xffff;
#else
return (m_id[0] != other.m_id[0]) || (m_id[1] != other.m_id[1]);
return (m_id.id[0] != other.m_id.id[0]) || (m_id.id[1] != other.m_id.id[1]);
#endif
}
bool operator==(const UniqueID128& other) const
{
#if __SSE__
__m128i vcmp = _mm_cmpeq_epi32(m_id128, other.m_id128);
__m128i vcmp = _mm_cmpeq_epi32(m_id.id128, other.m_id.id128);
int vmask = _mm_movemask_epi8(vcmp);
return vmask == 0xffff;
#else
return (m_id[0] == other.m_id[0]) && (m_id[1] == other.m_id[1]);
return (m_id.id[0] == other.m_id.id[0]) && (m_id.id[1] == other.m_id.id[1]);
#endif
}
void clear() {m_id[0] = 0xffffffffffffffff; m_id[1] = 0xffffffffffffffff;}
uint64_t toUint64() const {return m_id[0];}
uint64_t toHighUint64() const {return m_id[0];}
uint64_t toLowUint64() const {return m_id[1];}
void clear() {m_id.id[0] = 0xffffffffffffffff; m_id.id[1] = 0xffffffffffffffff;}
uint64_t toUint64() const {return m_id.id[0];}
uint64_t toHighUint64() const {return m_id.id[0];}
uint64_t toLowUint64() const {return m_id.id[1];}
std::string toString() const;
static constexpr size_t BinarySize() {return 16;}

File diff suppressed because it is too large Load Diff

View File

@ -1271,6 +1271,126 @@ bool ANCS::CookCSKR(const hecl::ProjectPath& outPath,
CINF cinf(arm, boneIdMap);
}
const DNAANCS::Actor::Subtype* subtype = nullptr;
for (const DNAANCS::Actor::Subtype& sub : actor.subtypes)
{
if (!sub.name.compare(subNameView.str()))
{
subtype = &sub;
break;
}
}
if (!subtype)
Log.report(logvisor::Fatal, _S("unable to find subtype '%s'"), subName.c_str());
const hecl::ProjectPath* modelPath = nullptr;
if (overName.empty())
{
modelPath = &subtype->mesh;
}
else
{
for (const auto& overlay : subtype->overlayMeshes)
if (!overlay.first.compare(overNameView.str()))
{
modelPath = &overlay.second;
break;
}
}
if (!modelPath)
Log.report(logvisor::Fatal, _S("unable to resolve model path of %s:%s"), subName.c_str(), overName.c_str());
if (!modelPath->isFile())
Log.report(logvisor::Fatal, _S("unable to resolve '%s'"), modelPath->getRelativePath().data());
hecl::ProjectPath skinIntPath = modelPath->getCookedPath(SpecEntMP1).getWithExtension(_S(".skinint"));
if (!skinIntPath.isFileOrGlob() || skinIntPath.getModtime() < modelPath->getModtime())
if (!modelCookFunc(*modelPath))
Log.report(logvisor::Fatal, _S("unable to cook '%s'"), modelPath->getRelativePath().data());
athena::io::FileReader skinIO(skinIntPath.getAbsolutePath(), 1024*32, false);
if (skinIO.hasError())
Log.report(logvisor::Fatal, _S("unable to open '%s'"), skinIntPath.getRelativePath().data());
std::vector<std::string> boneNames;
uint32_t boneNameCount = skinIO.readUint32Big();
boneNames.reserve(boneNameCount);
for (uint32_t i=0 ; i<boneNameCount ; ++i)
boneNames.push_back(skinIO.readString());
std::vector<std::pair<std::vector<std::pair<uint32_t, float>>, uint32_t>> skins;
uint32_t skinCount = skinIO.readUint32Big();
skins.resize(skinCount);
for (uint32_t i=0 ; i<skinCount ; ++i)
{
std::pair<std::vector<std::pair<uint32_t, float>>, uint32_t>& virtualBone = skins[i];
uint32_t bindCount = skinIO.readUint32Big();
virtualBone.first.reserve(bindCount);
for (uint32_t j=0 ; j<bindCount ; ++j)
{
uint32_t bIdx = skinIO.readUint32Big();
float weight = skinIO.readFloatBig();
const std::string& name = boneNames[bIdx];
auto search = boneIdMap.find(name);
if (search == boneIdMap.cend())
Log.report(logvisor::Fatal, "unable to find bone '%s' in %s",
name.c_str(), inPath.getRelativePathUTF8().data());
virtualBone.first.emplace_back(search->second, weight);
}
virtualBone.second = skinIO.readUint32Big();
}
uint32_t posCount = skinIO.readUint32Big();
uint32_t normCount = skinIO.readUint32Big();
skinIO.close();
athena::io::TransactionalFileWriter skinOut(outPath.getAbsolutePath());
skinOut.writeUint32Big(skins.size());
for (auto& virtuaBone : skins)
{
skinOut.writeUint32Big(virtuaBone.first.size());
for (auto& bind : virtuaBone.first)
{
skinOut.writeUint32Big(bind.first);
skinOut.writeFloatBig(bind.second);
}
skinOut.writeUint32Big(virtuaBone.second);
}
skinOut.writeUint32Big(0xffffffff);
skinOut.writeUint32Big(posCount);
skinOut.writeUint32Big(0xffffffff);
skinOut.writeUint32Big(normCount);
return true;
}
bool ANCS::CookCSKRPC(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc)
{
hecl::SystemString subName(inPath.getAuxInfo().begin(),
inPath.getAuxInfo().end() - 5);
hecl::SystemString overName;
auto dotPos = subName.rfind(_S('.'));
if (dotPos != hecl::SystemString::npos)
{
overName = hecl::SystemString(subName.begin() + dotPos + 1, subName.end());
subName = hecl::SystemString(subName.begin(), subName.begin() + dotPos);
}
hecl::SystemUTF8Conv subNameView(subName);
hecl::SystemUTF8Conv overNameView(overName);
/* Build bone ID map */
std::unordered_map<std::string, atInt32> boneIdMap;
for (const DNAANCS::Armature& arm : actor.armatures)
{
CINF cinf(arm, boneIdMap);
}
const DNAANCS::Actor::Subtype* subtype = nullptr;
for (const DNAANCS::Actor::Subtype& sub : actor.subtypes)
{

View File

@ -468,9 +468,9 @@ struct ANCS : BigDNA
trans->enumeratePrimitives(func);
}
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut, int charIdx) const
{
for (const CharacterSet::CharacterInfo& ci : characterSet.characters)
auto doCi = [&](const CharacterSet::CharacterInfo& ci)
{
for (const auto& id : ci.partResData.part)
g_curSpec->flattenDependencies(id, pathsOut);
@ -480,7 +480,12 @@ struct ANCS : BigDNA
g_curSpec->flattenDependencies(id, pathsOut);
for (const auto& id : ci.partResData.elsc)
g_curSpec->flattenDependencies(id, pathsOut);
}
};
if (charIdx < 0)
for (const CharacterSet::CharacterInfo& ci : characterSet.characters)
doCi(ci);
else if (charIdx < characterSet.characters.size())
doCi(characterSet.characters[charIdx]);
}
static bool Extract(const SpecBase& dataSpec,
@ -504,6 +509,10 @@ struct ANCS : BigDNA
const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc);
static bool CookCSKRPC(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc);
static bool CookANIM(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,

View File

@ -74,6 +74,10 @@ bool CMDL::Cook(const hecl::ProjectPath& outPath,
/* Output skinning intermediate */
auto vertCountIt = skinMesh.contiguousSkinVertCounts.cbegin();
athena::io::FileWriter writer(outPath.getWithExtension(_S(".skinint")).getAbsolutePath());
writer.writeUint32Big(skinMesh.boneNames.size());
for (const std::string& boneName : skinMesh.boneNames)
writer.writeString(boneName);
writer.writeUint32Big(skinMesh.skins.size());
for (const std::vector<DNACMDL::Mesh::SkinBind> skin : skinMesh.skins)
{
@ -86,9 +90,7 @@ bool CMDL::Cook(const hecl::ProjectPath& outPath,
writer.writeUint32Big(*vertCountIt++);
}
writer.writeUint32Big(skinMesh.pos.size());
writer.writeUint32Big(skinMesh.boneNames.size());
for (const std::string& boneName : skinMesh.boneNames)
writer.writeString(boneName);
writer.writeUint32Big(skinMesh.norm.size());
}
else if (!DNACMDL::WriteCMDL<MaterialSet, DNACMDL::SurfaceHeader_1, 2>(outPath, inPath, mesh))
return false;

View File

@ -60,6 +60,70 @@ bool MLVL::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl:
return DNAMLVL::ReadMLVLToBlender(conn, mlvl, outPath, pakRouter, entry, force, fileChanged);
}
struct BulkResources
{
std::unordered_map<hecl::Hash, size_t> addedBulkPaths;
bool addBulkPath(const hecl::ProjectPath& path, size_t areaIdx)
{
auto search = addedBulkPaths.find(path.hash());
if (search == addedBulkPaths.cend())
{
addedBulkPaths.insert(std::make_pair(path.hash(), areaIdx));
return true;
}
return false;
}
};
struct LayerResources
{
BulkResources& bulkResources;
std::unordered_map<hecl::Hash, std::pair<size_t, size_t>> addedPaths;
std::vector<std::vector<hecl::ProjectPath>> layerPaths;
std::unordered_set<hecl::Hash> addedSharedPaths;
std::vector<hecl::ProjectPath> sharedPaths;
LayerResources(BulkResources& bulkResources) : bulkResources(bulkResources) {}
void beginLayer()
{
layerPaths.resize(layerPaths.size() + 1);
}
void addSharedPath(const hecl::ProjectPath& path)
{
auto search = addedSharedPaths.find(path.hash());
if (search == addedSharedPaths.cend())
{
sharedPaths.push_back(path);
addedSharedPaths.insert(path.hash());
}
}
void addPath(const hecl::ProjectPath& path)
{
auto search = addedPaths.find(path.hash());
if (search != addedPaths.cend())
{
if (search->second.first == layerPaths.size() - 1)
return;
else
{
hecl::ProjectPath& toMove = layerPaths[search->second.first][search->second.second];
addSharedPath(toMove);
toMove.clear();
}
}
else
{
layerPaths.back().push_back(path);
addedPaths.insert(std::make_pair(path.hash(),
std::make_pair(layerPaths.size() - 1, layerPaths.back().size() - 1)));
}
}
void addBulkPath(const hecl::ProjectPath& path, size_t areaIdx)
{
if (bulkResources.addBulkPath(path, areaIdx))
addPath(path);
}
};
bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const World& wld,
hecl::blender::Token& btok)
{
@ -80,6 +144,7 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
size_t areaIdx = 0;
size_t nameOffset = 0;
BulkResources bulkResources;
for (const World::Area& area : wld.areas)
{
if (area.path.getPathType() != hecl::ProjectPath::Type::Directory)
@ -110,6 +175,7 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
bool areaInit = false;
size_t layerIdx = 0;
LayerResources layerResources(bulkResources);
for (const hecl::DirectoryEnumerator::Entry& e : dEnum)
{
hecl::SystemString layerName;
@ -139,6 +205,8 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
layer.read(reader);
}
layerResources.beginLayer();
/* Set active flag state */
hecl::ProjectPath defActivePath(area.path, e.m_name + _S("/!defaultactive"));
bool active = defActivePath.isNone() ? false : true;
@ -221,14 +289,11 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
areaInit = true;
}
MLVL::Area& areaOut = mlvl.areas.back();
areaOut.depLayers.push_back(areaOut.deps.size());
/* Gather memory relays, scans, and dependencies */
{
g_ThreadBlenderToken.reset(&btok);
std::vector<hecl::ProjectPath> depPaths;
std::vector<hecl::ProjectPath> bulkPaths;
for (std::unique_ptr<IScriptObject>& obj : layer.objects)
{
if (obj->type == int(urde::EScriptObjectType::MemoryRelay))
@ -260,20 +325,14 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
}
obj->gatherDependencies(depPaths);
obj->gatherBulkDependencies(bulkPaths);
}
/* Cull duplicate paths and add typed hash to list */
std::unordered_set<hecl::Hash> addedPaths;
for (const hecl::ProjectPath& path : depPaths)
{
if (addedPaths.find(path.hash()) == addedPaths.cend())
{
addedPaths.insert(path.hash());
urde::SObjectTag tag = g_curSpec->buildTagFromPath(path, btok);
if (tag.id.IsValid())
areaOut.deps.emplace_back(tag.id.Value(), tag.type);
}
}
layerResources.addBulkPath(path, areaIdx);
for (const hecl::ProjectPath& path : bulkPaths)
layerResources.addBulkPath(path, areaIdx);
}
hecl::SystemUTF8Conv layerU8(layerName);
@ -288,6 +347,22 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
++layerIdx;
}
/* Build deplist */
MLVL::Area& areaOut = mlvl.areas.back();
for (const std::vector<hecl::ProjectPath>& layer : layerResources.layerPaths)
{
areaOut.depLayers.push_back(areaOut.deps.size());
for (const hecl::ProjectPath& path : layer)
{
if (path)
{
urde::SObjectTag tag = g_curSpec->buildTagFromPath(path, btok);
if (tag.id.IsValid())
areaOut.deps.emplace_back(tag.id.Value(), tag.type);
}
}
}
/* Append Memory Relays */
mlvl.memRelayLinks.insert(mlvl.memRelayLinks.end(), memRelayLinks.begin(), memRelayLinks.end());
@ -295,33 +370,26 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
auto& conn = btok.getBlenderConnection();
if (conn.openBlend(areaPath))
{
MLVL::Area& areaOut = mlvl.areas.back();
areaOut.depLayers.push_back(areaOut.deps.size());
auto ds = conn.beginData();
std::vector<hecl::ProjectPath> texs = ds.getTextures();
ds.close();
std::unordered_set<hecl::Hash> addedPaths;
for (const hecl::ProjectPath& path : texs)
layerResources.addSharedPath(path);
for (const hecl::ProjectPath& path : layerResources.sharedPaths)
{
if (addedPaths.find(path.hash()) == addedPaths.cend())
{
addedPaths.insert(path.hash());
urde::SObjectTag tag = g_curSpec->buildTagFromPath(path, btok);
if (tag.id.IsValid())
areaOut.deps.emplace_back(tag.id.Value(), tag.type);
}
urde::SObjectTag tag = g_curSpec->buildTagFromPath(path, btok);
if (tag.id.IsValid())
areaOut.deps.emplace_back(tag.id.Value(), tag.type);
}
hecl::ProjectPath pathPath(areaPath.getParentPath(), _S("!path.blend"));
urde::SObjectTag pathTag = g_curSpec->buildTagFromPath(pathPath, btok);
if (pathTag.id.IsValid())
areaOut.deps.emplace_back(pathTag.id.Value(), pathTag.type);
urde::SObjectTag tag = g_curSpec->buildTagFromPath(areaPath, btok);
if (tag.id.IsValid())
areaOut.deps.emplace_back(tag.id.Value(), tag.type);
}
++areaIdx;

View File

@ -421,17 +421,9 @@ bool MREA::Cook(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const std::vector<DNACMDL::Mesh>& meshes,
const ColMesh& cMesh,
const std::vector<Light>& lights)
{
return false;
}
bool MREA::PCCook(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const std::vector<DNACMDL::Mesh>& meshes,
const ColMesh& cMesh,
const std::vector<Light>& lights,
hecl::blender::Token& btok)
const std::vector<Light>& lights,
hecl::blender::Token& btok,
bool pc)
{
/* Discover area layers */
hecl::ProjectPath areaDirPath = inPath.getParentPath();
@ -448,7 +440,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
}
}
size_t secCount = 1 + meshes.size() * 5; /* (materials, 5 fixed model secs) */
size_t secCount = 1 + meshes.size() * (pc ? 5 : 7); /* (materials, 5/7 fixed model secs) */
/* tally up surfaces */
for (const DNACMDL::Mesh& mesh : meshes)
@ -457,7 +449,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
/* Header */
Header head = {};
head.magic = 0xDEADBEEF;
head.version = 0x1000F;
head.version = pc ? 0x1000F : 0xF;
head.localToWorldMtx[0].vec[0] = 1.f;
head.localToWorldMtx[1].vec[1] = 1.f;
head.localToWorldMtx[2].vec[2] = 1.f;
@ -490,7 +482,6 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
/* Sizes section */
secs.emplace_back();
std::vector<uint8_t>& sizesSec = secs.back();
/* Pre-emptively build full AABB and mesh AABBs in world coords */
zeus::CAABox fullAabb;
@ -498,9 +489,18 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
meshAabbs.reserve(meshes.size());
/* Models */
if (!DNACMDL::WriteHMDLMREASecs<HMDLMaterialSet, DNACMDL::SurfaceHeader_2, MeshHeader>
if (pc)
{
if (!DNACMDL::WriteHMDLMREASecs<HMDLMaterialSet, DNACMDL::SurfaceHeader_2, MeshHeader>
(secs, inPath, meshes, fullAabb, meshAabbs))
return false;
return false;
}
else
{
if (!DNACMDL::WriteMREASecs<MaterialSet, DNACMDL::SurfaceHeader_1, MeshHeader>
(secs, inPath, meshes, fullAabb, meshAabbs))
return false;
}
/* AROT */
{
@ -807,6 +807,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
/* Assemble sizes and add padding */
{
std::vector<uint8_t>& sizesSec = secs[1];
sizesSec.assign((((head.secCount) + 7) & ~7) * 4, 0);
athena::io::MemoryWriter w(sizesSec.data(), sizesSec.size());
for (auto it = secs.begin() + 2 ; it != secs.end() ; ++it)

View File

@ -129,14 +129,9 @@ struct MREA
const hecl::ProjectPath& inPath,
const std::vector<DNACMDL::Mesh>& meshes,
const ColMesh& cMesh,
const std::vector<Light>& lights);
static bool PCCook(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const std::vector<DNACMDL::Mesh>& meshes,
const ColMesh& cMesh,
const std::vector<Light>& lights,
hecl::blender::Token& btok);
const std::vector<Light>& lights,
hecl::blender::Token& btok,
bool pc);
};
}

View File

@ -40,10 +40,14 @@ struct DoorArea : IScriptObject
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
{
animationParameters.depANCS(pathsOut);
actorParameters.depIDs(pathsOut);
}
void gatherBulkDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
{
animationParameters.depANCS(pathsOut);
}
void gatherScans(std::vector<Scan>& scansOut) const
{
actorParameters.scanIDs(scansOut);

View File

@ -45,6 +45,7 @@ struct IScriptObject : BigDNAVYaml
std::unordered_map<UniqueID32, std::pair<UniqueID32, UniqueID32>>&) const {}
virtual void nameIDs(PAKRouter<PAKBridge>& pakRouter) const {}
virtual void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const {}
virtual void gatherBulkDependencies(std::vector<hecl::ProjectPath>& pathsOut) const {}
virtual void gatherScans(std::vector<Scan>& scansOut) const {}
virtual zeus::CAABox getVISIAABB(hecl::blender::Token& btok) const { return {}; }
};

View File

@ -110,6 +110,11 @@ struct AnimationParameters : BigDNA
}
void depANCS(std::vector<hecl::ProjectPath>& pathsOut) const
{
g_curSpec->flattenDependencies(animationCharacterSet, pathsOut, character);
}
void depANCSAll(std::vector<hecl::ProjectPath>& pathsOut) const
{
g_curSpec->flattenDependencies(animationCharacterSet, pathsOut);
}

View File

@ -55,6 +55,11 @@ struct PlayerActor : IScriptObject
actorParameters.depIDs(pathsOut);
}
void gatherBulkDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
{
animationParameters.depANCSAll(pathsOut);
}
void gatherScans(std::vector<Scan>& scansOut) const
{
actorParameters.scanIDs(scansOut);

View File

@ -39,12 +39,13 @@ static const hecl::SystemChar* MomErr[] =
};
constexpr uint32_t MomErrCount = std::extent<decltype(MomErr)>::value;
SpecBase::SpecBase(const hecl::Database::DataSpecEntry* specEntry, hecl::Database::Project& project, bool pc)
: hecl::Database::IDataSpec(specEntry), m_project(project), m_pc(pc),
m_masterShader(project.getProjectWorkingPath(), ".hecl/RetroMasterShader.blend")
{
AssetNameMap::InitAssetNameMap();
DataSpec::UniqueIDBridge::setThreadProject(m_project);
SpecBase::setThreadProject();
}
SpecBase::~SpecBase()
@ -59,9 +60,75 @@ static const hecl::SystemString regP = _S("PAL");
void SpecBase::setThreadProject()
{
UniqueIDBridge::setThreadProject(m_project);
UniqueIDBridge::SetThreadProject(m_project);
}
template <typename IDType>
IDRestorer<IDType>::IDRestorer(const hecl::ProjectPath& yamlPath, const hecl::Database::Project& project)
{
using ValType = typename IDType::value_type;
if (!yamlPath.isFile())
return;
athena::io::YAMLDocReader r;
athena::io::FileReader fr(yamlPath.getAbsolutePath());
if (!fr.isOpen() || !r.parse(&fr))
return;
m_newToOrig.reserve(r.getRootNode()->m_mapChildren.size());
m_origToNew.reserve(r.getRootNode()->m_mapChildren.size());
for (const auto& node : r.getRootNode()->m_mapChildren)
{
char* end = const_cast<char*>(node.first.c_str());
ValType id = strtoull(end, &end, 16);
if (end != node.first.c_str() + sizeof(ValType) * 2)
continue;
hecl::ProjectPath path(project.getProjectWorkingPath(), node.second->m_scalarString.c_str());
m_newToOrig.push_back(std::make_pair(IDType{path.hash().valT<ValType>(), true}, IDType{id, true}));
m_origToNew.push_back(std::make_pair(IDType{id, true}, IDType{path.hash().valT<ValType>(), true}));
}
std::sort(m_newToOrig.begin(), m_newToOrig.end(),
[](const std::pair<IDType, IDType>& a, const std::pair<IDType, IDType>& b) {
return a.first < b.first;
});
std::sort(m_origToNew.begin(), m_origToNew.end(),
[](const std::pair<IDType, IDType>& a, const std::pair<IDType, IDType>& b) {
return a.first < b.first;
});
Log.report(logvisor::Info, _S("Loaded Original IDs '%s'"), yamlPath.getRelativePath().data());
}
template <typename IDType>
IDType IDRestorer<IDType>::newToOriginal(IDType id) const
{
if (!id)
return {};
auto search = rstl::binary_find(m_newToOrig.cbegin(), m_newToOrig.cend(), id,
[](const auto& id) { return id.first; });
if (search == m_newToOrig.cend())
return {};
return search->second;
}
template <typename IDType>
IDType IDRestorer<IDType>::originalToNew(IDType id) const
{
if (!id)
return {};
auto search = rstl::binary_find(m_origToNew.cbegin(), m_origToNew.cend(), id,
[](const auto& id) { return id.first; });
if (search == m_origToNew.cend())
return {};
return search->second;
}
template class IDRestorer<UniqueID32>;
template class IDRestorer<UniqueID64>;
template class IDRestorer<UniqueID128>;
bool SpecBase::canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps)
{
m_disc = nod::OpenDiscFromImage(info.srcpath, m_isWii);
@ -340,9 +407,95 @@ void SpecBase::doCook(const hecl::ProjectPath& path, const hecl::ProjectPath& co
}
}
void SpecBase::flattenDependenciesBlend(const hecl::ProjectPath& in,
std::vector<hecl::ProjectPath>& pathsOut,
hecl::blender::Token& btok,
int charIdx)
{
hecl::blender::Connection& conn = btok.getBlenderConnection();
if (!conn.openBlend(in))
return;
switch (conn.getBlendType())
{
case hecl::blender::BlendType::Mesh:
{
hecl::blender::DataStream ds = conn.beginData();
std::vector<hecl::ProjectPath> texs = ds.getTextures();
for (const hecl::ProjectPath& tex : texs)
pathsOut.push_back(tex);
break;
}
case hecl::blender::BlendType::Actor:
{
hecl::ProjectPath asGlob = in.getWithExtension(_S(".*"), true);
hecl::blender::DataStream ds = conn.beginData();
hecl::blender::Actor actor = ds.compileActorCharacterOnly();
auto doSubtype = [&](Actor::Subtype& sub)
{
if (sub.armature >= 0)
{
pathsOut.push_back(sub.mesh);
hecl::SystemStringConv chSysName(sub.name);
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(chSysName.sys_str()) + _S(".CSKR")));
const auto& arm = actor.armatures[sub.armature];
hecl::SystemStringConv armSysName(arm.name);
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(armSysName.sys_str()) + _S(".CINF")));
for (const auto& overlay : sub.overlayMeshes)
{
hecl::SystemStringConv ovelaySys(overlay.first);
pathsOut.push_back(overlay.second);
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(chSysName.sys_str()) + _S('.') +
ovelaySys.c_str() + _S(".CSKR")));
}
}
};
if (charIdx < 0)
for (auto& sub : actor.subtypes)
doSubtype(sub);
else if (charIdx < actor.subtypes.size())
doSubtype(actor.subtypes[charIdx]);
auto actNames = ds.getActionNames();
for (const auto& act : actNames)
{
hecl::SystemStringConv actSysName(act);
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(actSysName.sys_str()) + _S(".ANIM")));
hecl::ProjectPath evntPath = asGlob.getWithExtension(
hecl::SysFormat(_S(".%s.evnt.yaml"), actSysName.c_str()).c_str(), true);
if (evntPath.isFile())
pathsOut.push_back(evntPath);
}
ds.close();
hecl::ProjectPath yamlPath = asGlob.getWithExtension(_S(".yaml"), true);
if (yamlPath.isFile())
{
athena::io::FileReader reader(yamlPath.getAbsolutePath());
flattenDependenciesANCSYAML(reader, pathsOut, charIdx);
}
pathsOut.push_back(asGlob);
return;
}
case hecl::blender::BlendType::Area:
{
hecl::blender::DataStream ds = conn.beginData();
std::vector<hecl::ProjectPath> texs = ds.getTextures();
for (const hecl::ProjectPath& tex : texs)
pathsOut.push_back(tex);
break;
}
default: break;
}
}
void SpecBase::flattenDependencies(const hecl::ProjectPath& path,
std::vector<hecl::ProjectPath>& pathsOut,
hecl::blender::Token& btok)
hecl::blender::Token& btok,
int charIdx)
{
DataSpec::g_curSpec.reset(this);
g_ThreadBlenderToken.reset(&btok);
@ -355,77 +508,7 @@ void SpecBase::flattenDependencies(const hecl::ProjectPath& path,
if (hecl::IsPathBlend(asBlend))
{
hecl::blender::Connection& conn = btok.getBlenderConnection();
if (!conn.openBlend(asBlend))
return;
switch (conn.getBlendType())
{
case hecl::blender::BlendType::Mesh:
{
hecl::blender::DataStream ds = conn.beginData();
std::vector<hecl::ProjectPath> texs = ds.getTextures();
for (const hecl::ProjectPath& tex : texs)
pathsOut.push_back(tex);
break;
}
case hecl::blender::BlendType::Actor:
{
hecl::ProjectPath asGlob = path.getWithExtension(_S(".*"), true);
hecl::blender::DataStream ds = conn.beginData();
hecl::blender::Actor actor = ds.compileActorCharacterOnly();
for (auto& sub : actor.subtypes)
{
if (sub.armature >= 0)
{
pathsOut.push_back(sub.mesh);
hecl::SystemStringConv chSysName(sub.name);
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(chSysName.sys_str()) + _S(".CSKR")));
const auto& arm = actor.armatures[sub.armature];
hecl::SystemStringConv armSysName(arm.name);
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(armSysName.sys_str()) + _S(".CINF")));
for (const auto& overlay : sub.overlayMeshes)
{
hecl::SystemStringConv ovelaySys(overlay.first);
pathsOut.push_back(overlay.second);
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(chSysName.sys_str()) + _S('.') +
ovelaySys.c_str() + _S(".CSKR")));
}
}
}
auto actNames = ds.getActionNames();
for (const auto& act : actNames)
{
hecl::SystemStringConv actSysName(act);
pathsOut.push_back(asGlob.ensureAuxInfo(hecl::SystemString(actSysName.sys_str()) + _S(".ANIM")));
hecl::ProjectPath evntPath = asGlob.getWithExtension(
hecl::SysFormat(_S(".%s.evnt.yaml"), actSysName.c_str()).c_str(), true);
if (evntPath.isFile())
pathsOut.push_back(evntPath);
}
ds.close();
hecl::ProjectPath yamlPath = asGlob.getWithExtension(_S(".yaml"), true);
if (yamlPath.isFile())
{
athena::io::FileReader reader(yamlPath.getAbsolutePath());
flattenDependenciesANCSYAML(reader, pathsOut);
}
pathsOut.push_back(asGlob);
return;
}
case hecl::blender::BlendType::Area:
{
hecl::blender::DataStream ds = conn.beginData();
std::vector<hecl::ProjectPath> texs = ds.getTextures();
for (const hecl::ProjectPath& tex : texs)
pathsOut.push_back(tex);
break;
}
default: break;
}
flattenDependenciesBlend(asBlend, pathsOut, btok, charIdx);
}
else if (hecl::IsPathYAML(path))
{
@ -436,18 +519,18 @@ void SpecBase::flattenDependencies(const hecl::ProjectPath& path,
pathsOut.push_back(path);
}
void SpecBase::flattenDependencies(const UniqueID32& id, std::vector<hecl::ProjectPath>& pathsOut)
void SpecBase::flattenDependencies(const UniqueID32& id, std::vector<hecl::ProjectPath>& pathsOut, int charIdx)
{
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
if (path)
flattenDependencies(path, pathsOut, *g_ThreadBlenderToken.get());
flattenDependencies(path, pathsOut, *g_ThreadBlenderToken.get(), charIdx);
}
void SpecBase::flattenDependencies(const UniqueID64& id, std::vector<hecl::ProjectPath>& pathsOut)
void SpecBase::flattenDependencies(const UniqueID64& id, std::vector<hecl::ProjectPath>& pathsOut, int charIdx)
{
hecl::ProjectPath path = UniqueIDBridge::TranslatePakIdToPath(id);
if (path)
flattenDependencies(path, pathsOut, *g_ThreadBlenderToken.get());
flattenDependencies(path, pathsOut, *g_ThreadBlenderToken.get(), charIdx);
}
bool SpecBase::canPackage(const hecl::ProjectPath& path)
@ -550,8 +633,13 @@ void SpecBase::doPackage(const hecl::ProjectPath& path, const hecl::Database::Da
auto components = path.getWithExtension(_S(""), true).getPathComponents();
if (components.size() <= 1)
return;
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(),
_S("out/") + components[0] + _S("/") + components[1] + _S(".upak"));
hecl::ProjectPath outPath;
if (hecl::ProjectPath(m_project.getProjectWorkingPath(), _S("out/files/") + components[0]).isDirectory())
outPath.assign(m_project.getProjectWorkingPath(),
_S("out/files/") + components[0] + _S("/") + components[1] + entry->m_pakExt.data());
else
outPath.assign(m_project.getProjectWorkingPath(),
_S("out/files/") + components[1] + entry->m_pakExt.data());
outPath.makeDirChain(false);
/* Output file */

View File

@ -23,6 +23,17 @@ class YAMLDocWriter;
namespace DataSpec
{
template <typename IDType>
class IDRestorer
{
std::vector<std::pair<IDType, IDType>> m_newToOrig;
std::vector<std::pair<IDType, IDType>> m_origToNew;
public:
IDRestorer(const hecl::ProjectPath& yamlPath, const hecl::Database::Project& project);
IDType newToOriginal(IDType id) const;
IDType originalToNew(IDType id) const;
};
struct SpecBase : hecl::Database::IDataSpec
{
/* HECL Adaptors */
@ -116,11 +127,18 @@ struct SpecBase : hecl::Database::IDataSpec
/* Dependency flatteners */
void flattenDependencies(const hecl::ProjectPath& in,
std::vector<hecl::ProjectPath>& pathsOut,
hecl::blender::Token& btok);
void flattenDependencies(const class UniqueID32& id, std::vector<hecl::ProjectPath>& pathsOut);
void flattenDependencies(const class UniqueID64& id, std::vector<hecl::ProjectPath>& pathsOut);
hecl::blender::Token& btok,
int charIdx = -1);
void flattenDependencies(const class UniqueID32& id, std::vector<hecl::ProjectPath>& pathsOut, int charIdx = -1);
void flattenDependencies(const class UniqueID64& id, std::vector<hecl::ProjectPath>& pathsOut, int charIdx = -1);
void flattenDependenciesBlend(const hecl::ProjectPath& in,
std::vector<hecl::ProjectPath>& pathsOut,
hecl::blender::Token& btok,
int charIdx = -1);
virtual void flattenDependenciesYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut)=0;
virtual void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut)=0;
virtual void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin,
std::vector<hecl::ProjectPath>& pathsOut,
int charIdx = -1)=0;
virtual void buildWorldPakList(const hecl::ProjectPath& worldPath,
const hecl::ProjectPath& worldPathCooked,
@ -211,7 +229,7 @@ protected:
bool fast, const hecl::MultiProgressPrinter& progress,
athena::io::FileWriter& pakOut);
private:
protected:
std::unique_ptr<nod::DiscBase> m_disc;
bool m_isWii;
bool m_standalone;

View File

@ -17,6 +17,7 @@
#include "DNAMP1/CSNG.hpp"
#include "DNAMP1/MAPA.hpp"
#include "DNAMP1/PATH.hpp"
#include "DNAMP1/FRME.hpp"
#include "DNACommon/ATBL.hpp"
#include "DNACommon/FONT.hpp"
#include "DNACommon/PART.hpp"
@ -135,7 +136,7 @@ struct OriginalIDs
originalIDs.push_back(std::make_pair(id, path.hash().val32()));
}
std::sort(originalIDs.begin(), originalIDs.end(),
[](const std::pair<UniqueID32, UniqueID32>& a, const std::pair<UniqueID32, UniqueID32>& b) -> bool {
[](const std::pair<UniqueID32, UniqueID32>& a, const std::pair<UniqueID32, UniqueID32>& b) {
return a.first < b.first;
});
@ -148,7 +149,7 @@ struct OriginalIDs
}
std::sort(originalIDs.begin(), originalIDs.end(),
[](const std::pair<UniqueID32, UniqueID32>& a, const std::pair<UniqueID32, UniqueID32>& b) -> bool {
[](const std::pair<UniqueID32, UniqueID32>& a, const std::pair<UniqueID32, UniqueID32>& b) {
return a.second < b.second;
});
for (const auto& idPair : originalIDs)
@ -176,12 +177,22 @@ struct SpecMP1 : SpecBase
std::unique_ptr<uint8_t[]> m_dolBuf;
IDRestorer<UniqueID32> m_idRestorer;
void setThreadProject()
{
SpecBase::setThreadProject();
UniqueIDBridge::SetIDRestorer(&m_idRestorer);
}
SpecMP1(const hecl::Database::DataSpecEntry* specEntry, hecl::Database::Project& project, bool pc)
: SpecBase(specEntry, project, pc)
, m_workPath(project.getProjectWorkingPath(), _S("MP1"))
, m_cookPath(project.getProjectCookedPath(SpecEntMP1), _S("MP1"))
, m_pakRouter(*this, m_workPath, m_cookPath)
, m_idRestorer({project.getProjectWorkingPath(), "MP1/!original_ids.yaml"}, project)
{
setThreadProject();
}
void buildPaks(nod::Node& root, const std::vector<hecl::SystemString>& args, ExtractReport& rep)
@ -372,7 +383,8 @@ struct SpecMP1 : SpecBase
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
outPath.makeDir();
hecl::ProjectPath mp1OutPath(outPath, _S("MP1"));
disc.getDataPartition()->extractSysFiles(outPath.getAbsolutePath(), ctx);
hecl::ProjectPath mp1OutPath(outPath, m_standalone ? _S("files") : _S("files/MP1"));
mp1OutPath.makeDir();
/* Extract non-pak files */
@ -780,15 +792,22 @@ struct SpecMP1 : SpecBase
{
Actor actor = ds.compileActorCharacterOnly();
ds.close();
DNAMP1::ANCS::CookCSKR(out, in, actor, [&](const hecl::ProjectPath& modelPath) -> bool {
hecl::ProjectPath cooked;
if (m_pc)
cooked = modelPath.getCookedPath(SpecEntMP1PC);
else
cooked = modelPath.getCookedPath(SpecEntMP1);
doCook(modelPath, cooked, fast, btok, progress);
return true;
});
if (m_pc)
{
DNAMP1::ANCS::CookCSKRPC(out, in, actor, [&](const hecl::ProjectPath& modelPath) {
hecl::ProjectPath cooked = modelPath.getCookedPath(SpecEntMP1PC);
doCook(modelPath, cooked, fast, btok, progress);
return true;
});
}
else
{
DNAMP1::ANCS::CookCSKR(out, in, actor, [&](const hecl::ProjectPath& modelPath) {
hecl::ProjectPath cooked = modelPath.getCookedPath(SpecEntMP1);
doCook(modelPath, cooked, fast, btok, progress);
return true;
});
}
}
else if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S(".ANIM")))
{
@ -821,7 +840,7 @@ struct SpecMP1 : SpecBase
continue;
}
meshCompiles.push_back(ds.compileMesh(
mesh, fast ? hecl::HMDLTopology::Triangles : hecl::HMDLTopology::TriStrips, -1,
mesh, fast ? hecl::HMDLTopology::Triangles : hecl::HMDLTopology::TriStrips, -1, !m_pc,
[&](int surfCount) { progress(hecl::SysFormat(_S("%s %d"), meshSys.c_str(), surfCount).c_str()); }));
}
@ -832,10 +851,7 @@ struct SpecMP1 : SpecBase
ds.close();
if (m_pc)
DNAMP1::MREA::PCCook(out, in, meshCompiles, *colMesh, lights, btok);
else
DNAMP1::MREA::Cook(out, in, meshCompiles, *colMesh, lights);
DNAMP1::MREA::Cook(out, in, meshCompiles, *colMesh, lights, btok, m_pc);
}
void cookWorld(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
@ -864,7 +880,12 @@ struct SpecMP1 : SpecBase
void cookGuiFrame(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds,
hecl::blender::Token& btok, FCookProgress progress)
{
ds.compileGuiFrame(out.getAbsolutePathUTF8(), 0);
auto data = ds.compileGuiFrame(0);
athena::io::MemoryReader r(data.data(), data.size());
DNAMP1::FRME frme;
frme.read(r);
athena::io::FileWriter w(out.getAbsolutePath());
frme.write(w);
}
void cookYAML(const hecl::ProjectPath& out, const hecl::ProjectPath& in, athena::io::IStreamReader& fin,
@ -1131,7 +1152,9 @@ struct SpecMP1 : SpecBase
}
}
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut)
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin,
std::vector<hecl::ProjectPath>& pathsOut,
int charIdx)
{
athena::io::YAMLDocReader reader;
if (reader.parse(&fin))
@ -1141,11 +1164,25 @@ struct SpecMP1 : SpecBase
{
DNAMP1::ANCS ancs;
ancs.read(reader);
ancs.gatherDependencies(pathsOut);
ancs.gatherDependencies(pathsOut, charIdx);
}
}
}
UniqueID32 newToOriginal(urde::CAssetId id) const
{
if (UniqueID32 origId = m_idRestorer.newToOriginal({uint32_t(id.Value()), true}))
return {origId.toUint32(), true};
return {uint32_t(id.Value()), true};
}
urde::CAssetId originalToNew(UniqueID32 id) const
{
if (UniqueID32 newId = m_idRestorer.originalToNew(id))
return newId.toUint32();
return id.toUint32();
}
void buildWorldPakList(const hecl::ProjectPath& worldPath,
const hecl::ProjectPath& worldPathCooked,
hecl::blender::Token& btok,
@ -1169,32 +1206,35 @@ struct SpecMP1 : SpecBase
urde::SObjectTag worldTag = tagFromPath(worldPath.getWithExtension(_S(".*"), true), btok);
w.writeUint32Big(0x80030005);
w.writeUint32Big(m_pc ? 0x80030005 : 0x00030005);
w.writeUint32Big(0);
w.writeUint32Big(1);
DNAMP1::PAK::NameEntry nameEnt;
hecl::ProjectPath parentDir = worldPath.getParentPath();
nameEnt.type = worldTag.type;
nameEnt.id = atUint32(worldTag.id.Value());
nameEnt.id = newToOriginal(worldTag.id);
nameEnt.nameLen = atUint32(parentDir.getLastComponent().size());
nameEnt.name = parentDir.getLastComponentUTF8();
nameEnt.write(w);
for (const auto& area : mlvl.areas)
{
urde::SObjectTag nameTag(FOURCC('STRG'), area.areaNameId.toUint32());
urde::SObjectTag nameTag(FOURCC('STRG'), originalToNew(area.areaNameId));
if (nameTag)
listOut.push_back(nameTag);
for (const auto& dep : area.deps)
listOut.push_back({dep.type, dep.id.toUint32()});
listOut.push_back({dep.type, originalToNew(dep.id)});
urde::SObjectTag areaTag(FOURCC('MREA'), originalToNew(area.areaMREAId));
if (areaTag)
listOut.push_back(areaTag);
}
urde::SObjectTag nameTag(FOURCC('STRG'), mlvl.worldNameId.toUint32());
urde::SObjectTag nameTag(FOURCC('STRG'), originalToNew(mlvl.worldNameId));
if (nameTag)
listOut.push_back(nameTag);
urde::SObjectTag savwTag(FOURCC('SAVW'), mlvl.saveWorldId.toUint32());
urde::SObjectTag savwTag(FOURCC('SAVW'), originalToNew(mlvl.saveWorldId));
if (savwTag)
{
if (hecl::ProjectPath savwPath = pathFromTag(savwTag))
@ -1202,7 +1242,7 @@ struct SpecMP1 : SpecBase
listOut.push_back(savwTag);
}
urde::SObjectTag mapTag(FOURCC('MAPW'), mlvl.worldMap.toUint32());
urde::SObjectTag mapTag(FOURCC('MAPW'), originalToNew(mlvl.worldMap));
if (mapTag)
{
if (hecl::ProjectPath mapPath = pathFromTag(mapTag))
@ -1222,14 +1262,14 @@ struct SpecMP1 : SpecBase
{
UniqueID32 id;
id.read(r);
listOut.push_back({FOURCC('MAPA'), id.toUint32()});
listOut.push_back({FOURCC('MAPA'), originalToNew(id)});
}
}
}
listOut.push_back(mapTag);
}
urde::SObjectTag skyboxTag(FOURCC('CMDL'), mlvl.worldSkyboxId.toUint32());
urde::SObjectTag skyboxTag(FOURCC('CMDL'), originalToNew(mlvl.worldSkyboxId));
if (skyboxTag)
{
listOut.push_back(skyboxTag);
@ -1257,7 +1297,7 @@ struct SpecMP1 : SpecBase
DNAMP1::PAK::Entry ent;
ent.compressed = 0;
ent.type = item.type;
ent.id = atUint32(item.id.Value());
ent.id = newToOriginal(item.id.Value());
ent.size = 0;
ent.offset = 0;
ent.write(w);
@ -1270,7 +1310,7 @@ struct SpecMP1 : SpecBase
const std::vector<std::pair<urde::SObjectTag, std::string>>& nameList,
atUint64& resTableOffset)
{
w.writeUint32Big(0x80030005);
w.writeUint32Big(m_pc ? 0x80030005 : 0x00030005);
w.writeUint32Big(0);
w.writeUint32Big(atUint32(nameList.size()));
@ -1278,7 +1318,7 @@ struct SpecMP1 : SpecBase
{
DNAMP1::PAK::NameEntry nameEnt;
nameEnt.type = item.first.type;
nameEnt.id = atUint32(item.first.id.Value());
nameEnt.id = newToOriginal(item.first.id);
nameEnt.nameLen = atUint32(item.second.size());
nameEnt.name = item.second;
nameEnt.write(w);
@ -1291,7 +1331,7 @@ struct SpecMP1 : SpecBase
DNAMP1::PAK::Entry ent;
ent.compressed = 0;
ent.type = item.type;
ent.id = atUint32(item.id.Value());
ent.id = newToOriginal(item.id);
ent.size = 0;
ent.offset = 0;
ent.write(w);
@ -1312,7 +1352,7 @@ struct SpecMP1 : SpecBase
DNAMP1::PAK::Entry ent;
ent.compressed = atUint32(std::get<2>(item));
ent.type = tag.type;
ent.id = atUint32(tag.id.Value());
ent.id = newToOriginal(tag.id);
ent.size = atUint32(std::get<1>(item));
ent.offset = atUint32(std::get<0>(item));
ent.write(w);
@ -1350,7 +1390,7 @@ struct SpecMP1 : SpecBase
uLong destLen = compressBound(len);
std::pair<std::unique_ptr<uint8_t[]>, size_t> ret;
ret.first.reset(new uint8_t[destLen]);
compress(ret.first.get(), &destLen, data, len);
compress2(ret.first.get(), &destLen, data, len, Z_BEST_COMPRESSION);
ret.second = destLen;
return ret;
};
@ -1389,19 +1429,19 @@ struct SpecMP1 : SpecBase
};
hecl::Database::DataSpecEntry SpecEntMP1 = {
_S("MP1"sv), _S("Data specification for original Metroid Prime engine"sv),
[](hecl::Database::Project& project, hecl::Database::DataSpecTool) -> hecl::Database::IDataSpec* {
return new struct SpecMP1(&SpecEntMP1, project, false);
_S("MP1"sv), _S("Data specification for original Metroid Prime engine"sv), _S(".pak"sv),
[](hecl::Database::Project& project, hecl::Database::DataSpecTool) -> std::unique_ptr<hecl::Database::IDataSpec> {
return std::make_unique<SpecMP1>(&SpecEntMP1, project, false);
}};
hecl::Database::DataSpecEntry SpecEntMP1PC = {
_S("MP1-PC"sv), _S("Data specification for PC-optimized Metroid Prime engine"sv),
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool) -> hecl::Database::IDataSpec* {
_S("MP1-PC"sv), _S("Data specification for PC-optimized Metroid Prime engine"sv), _S(".upak"sv),
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool) -> std::unique_ptr<hecl::Database::IDataSpec> {
if (tool != hecl::Database::DataSpecTool::Extract)
return new struct SpecMP1(&SpecEntMP1PC, project, true);
return nullptr;
return std::make_unique<SpecMP1>(&SpecEntMP1PC, project, true);
return {};
}};
hecl::Database::DataSpecEntry SpecEntMP1ORIG = {
_S("MP1-ORIG"sv), _S("Data specification for unmodified Metroid Prime resources"sv), {}};
_S("MP1-ORIG"sv), _S("Data specification for unmodified Metroid Prime resources"sv), {}, {}};
}

View File

@ -223,7 +223,7 @@ struct SpecMP2 : SpecBase
return true;
}
bool extractFromDisc(nod::DiscBase&, bool force, const hecl::MultiProgressPrinter& progress)
bool extractFromDisc(nod::DiscBase& disc, bool force, const hecl::MultiProgressPrinter& progress)
{
nod::ExtractionContext ctx = {force, nullptr};
@ -239,7 +239,8 @@ struct SpecMP2 : SpecBase
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
outPath.makeDir();
hecl::ProjectPath mp2OutPath(outPath, _S("MP2"));
disc.getDataPartition()->extractSysFiles(outPath.getAbsolutePath(), ctx);
hecl::ProjectPath mp2OutPath(outPath, m_standalone ? _S("files") : _S("files/MP2"));
mp2OutPath.makeDir();
progress.startNewLine();
progress.print(_S("MP2 Root"), _S(""), 0.0);
@ -375,7 +376,7 @@ struct SpecMP2 : SpecBase
{
}
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut)
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut, int charIdx)
{
}
@ -417,21 +418,21 @@ struct SpecMP2 : SpecBase
hecl::Database::DataSpecEntry SpecEntMP2
(
_S("MP2"sv),
_S("Data specification for original Metroid Prime 2 engine"sv),
_S("Data specification for original Metroid Prime 2 engine"sv), _S(".pak"sv),
[](hecl::Database::Project& project, hecl::Database::DataSpecTool)
-> hecl::Database::IDataSpec* {return new struct SpecMP2(&SpecEntMP2, project, false);}
-> std::unique_ptr<hecl::Database::IDataSpec> {return std::make_unique<SpecMP2>(&SpecEntMP2, project, false);}
);
hecl::Database::DataSpecEntry SpecEntMP2PC =
{
_S("MP2-PC"sv),
_S("Data specification for PC-optimized Metroid Prime 2 engine"sv),
_S("Data specification for PC-optimized Metroid Prime 2 engine"sv), _S(".upak"sv),
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool)
-> hecl::Database::IDataSpec*
-> std::unique_ptr<hecl::Database::IDataSpec>
{
if (tool != hecl::Database::DataSpecTool::Extract)
return new struct SpecMP2(&SpecEntMP2PC, project, true);
return nullptr;
return std::make_unique<SpecMP2>(&SpecEntMP2PC, project, true);
return {};
}
};
@ -439,7 +440,7 @@ hecl::Database::DataSpecEntry SpecEntMP2ORIG =
{
_S("MP2-ORIG"sv),
_S("Data specification for unmodified Metroid Prime 2 resources"sv),
{}
{}, {}
};
}

View File

@ -352,7 +352,7 @@ struct SpecMP3 : SpecBase
return doMP3 || doMPTFE;
}
bool extractFromDisc(nod::DiscBase&, bool force, const hecl::MultiProgressPrinter& progress)
bool extractFromDisc(nod::DiscBase& disc, bool force, const hecl::MultiProgressPrinter& progress)
{
hecl::SystemString currentTarget = _S("");
size_t nodeCount = 0;
@ -378,7 +378,8 @@ struct SpecMP3 : SpecBase
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
outPath.makeDir();
hecl::ProjectPath mp3OutPath(outPath, _S("MP3"));
disc.getDataPartition()->extractSysFiles(outPath.getAbsolutePath(), ctx);
hecl::ProjectPath mp3OutPath(outPath, m_standalone ? _S("files") : _S("files/MP3"));
mp3OutPath.makeDir();
currentTarget = _S("MP3 Root");
progress.print(currentTarget.c_str(), _S(""), 0.0);
@ -436,7 +437,8 @@ struct SpecMP3 : SpecBase
hecl::ProjectPath outPath(m_project.getProjectWorkingPath(), _S("out"));
outPath.makeDir();
hecl::ProjectPath feOutPath(outPath, _S("fe"));
disc.getDataPartition()->extractSysFiles(outPath.getAbsolutePath(), ctx);
hecl::ProjectPath feOutPath(outPath, m_standalone ? _S("files") : _S("files/fe"));
feOutPath.makeDir();
currentTarget = _S("fe Root");
progress.print(currentTarget.c_str(), _S(""), 0.0);
@ -566,7 +568,7 @@ struct SpecMP3 : SpecBase
{
}
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut)
void flattenDependenciesANCSYAML(athena::io::IStreamReader& fin, std::vector<hecl::ProjectPath>& pathsOut, int charIdx)
{
}
@ -600,20 +602,20 @@ struct SpecMP3 : SpecBase
hecl::Database::DataSpecEntry SpecEntMP3
(
_S("MP3"sv),
_S("Data specification for original Metroid Prime 3 engine"sv),
_S("Data specification for original Metroid Prime 3 engine"sv), _S(".pak"sv),
[](hecl::Database::Project& project, hecl::Database::DataSpecTool)
-> hecl::Database::IDataSpec* {return new struct SpecMP3(&SpecEntMP3, project, false);}
-> std::unique_ptr<hecl::Database::IDataSpec> {return std::make_unique<SpecMP3>(&SpecEntMP3, project, false);}
);
hecl::Database::DataSpecEntry SpecEntMP3PC =
{
_S("MP3-PC"sv),
_S("Data specification for PC-optimized Metroid Prime 3 engine"sv),
_S("Data specification for PC-optimized Metroid Prime 3 engine"sv), _S(".upak"sv),
[](hecl::Database::Project& project, hecl::Database::DataSpecTool tool)
-> hecl::Database::IDataSpec*
-> std::unique_ptr<hecl::Database::IDataSpec>
{
if (tool != hecl::Database::DataSpecTool::Extract)
return new struct SpecMP3(&SpecEntMP3PC, project, true);
return std::make_unique<SpecMP3>(&SpecEntMP3PC, project, true);
return nullptr;
}
};
@ -622,7 +624,7 @@ hecl::Database::DataSpecEntry SpecEntMP3ORIG =
{
_S("MP3-ORIG"sv),
_S("Data specification for unmodified Metroid Prime 3 resources"sv),
{}
{}, {}
};
}

View File

@ -17,7 +17,7 @@ void ProjectResourceFactoryBase::BeginBackgroundIndex
m_proj = &proj;
m_origSpec = &origSpec;
m_pcSpec = &pcSpec;
m_cookSpec.reset(pcSpec.m_factory(proj, hecl::Database::DataSpecTool::Cook));
m_cookSpec = pcSpec.m_factory(proj, hecl::Database::DataSpecTool::Cook);
return static_cast<DataSpec::SpecBase&>(*m_cookSpec).beginBackgroundIndex();
}
@ -99,7 +99,7 @@ void ProjectResourceFactoryBase::AsyncTask::EnsurePath(const urde::SObjectTag& t
{
/* Start a background cook here */
m_cookTransaction = m_parent.m_clientProc.
addCookTransaction(path, m_parent.m_cookSpec.get(), false, false);
addCookTransaction(path, false, false, m_parent.m_cookSpec.get());
return;
}
}

View File

@ -84,7 +84,7 @@ void ViewManager::RootSpaceViewBuilt(specter::View *view)
void ViewManager::ProjectChanged(hecl::Database::Project& proj)
{
CDvdFile::Shutdown();
CDvdFile::Initialize(hecl::ProjectPath(proj.getProjectWorkingPath(), _S("out/MP1")));
CDvdFile::Initialize(hecl::ProjectPath(proj.getProjectWorkingPath(), _S("out/files")));
}
void ViewManager::SetupEditorView()

View File

@ -117,17 +117,21 @@ void CResFactory::CancelBuild(const SObjectTag& tag)
void CResFactory::LoadOriginalIDs(CSimplePool& sp)
{
m_origIds = sp.GetObj("MP1OriginalIDs");
//m_origIds = sp.GetObj("MP1OriginalIDs");
}
CAssetId CResFactory::TranslateOriginalToNew(CAssetId id) const
{
return m_origIds->TranslateOriginalToNew(id);
/* The packager will have restored these ahead of time */
return id;
//return m_origIds->TranslateOriginalToNew(id);
}
CAssetId CResFactory::TranslateNewToOriginal(CAssetId id) const
{
return m_origIds->TranslateNewToOriginal(id);
/* The packager will have restored these ahead of time */
return id;
//return m_origIds->TranslateNewToOriginal(id);
}
}

View File

@ -17,7 +17,7 @@ class CResFactory : public IFactory
{
CResLoader x4_loader;
CFactoryMgr x5c_factoryMgr;
TLockedToken<MP1OriginalIDs> m_origIds;
//TLockedToken<MP1OriginalIDs> m_origIds;
public:
struct SLoadingData

View File

@ -50,8 +50,8 @@ public:
virtual std::unique_ptr<u8[]> LoadNewResourcePartSync(const urde::SObjectTag& tag, u32 off, u32 size)=0;
virtual void GetTagListForFile(const char* pakName, std::vector<SObjectTag>& out) const {}
virtual CAssetId TranslateOriginalToNew(CAssetId id) const { return -1; }
virtual CAssetId TranslateNewToOriginal(CAssetId id) const { return -1; }
virtual CAssetId TranslateOriginalToNew(CAssetId id) const { return {}; }
virtual CAssetId TranslateNewToOriginal(CAssetId id) const { return {}; }
};
}

2
hecl

@ -1 +1 @@
Subproject commit 1c7c56bc4405db1398a2246e010966e6fe7bde34
Subproject commit e7c678ff572d941fa648ef99c92d90624a582761

2
nod

@ -1 +1 @@
Subproject commit bab7aab6fa7a82123f827475c1471f641ed2bf67
Subproject commit 274a63bb306a77cd78527e4fca13d4c69cb5b56e

@ -1 +1 @@
Subproject commit 8ff49e190761583b120b0510b0de3dda13fd68c0
Subproject commit fb20084230cba3c54eabf340f3612f890c8522c3