mirror of https://github.com/AxioDL/metaforce.git
Initial CMDL cooking in place
This commit is contained in:
parent
58c0fd5ad2
commit
bf8a007514
|
@ -24,7 +24,7 @@ struct Header : BigDNA
|
|||
struct Flags : BigDNA
|
||||
{
|
||||
DECL_DNA
|
||||
Value<atUint32> flags;
|
||||
Value<atUint32> flags = 0;
|
||||
bool shortNormals() const {return (flags & 0x2) != 0;}
|
||||
void setShortNormals(bool val) {flags &= ~0x2; flags |= val << 1;}
|
||||
bool shortUVs() const {return (flags & 0x4) != 0;}
|
||||
|
@ -42,12 +42,12 @@ struct SurfaceHeader_1_2 : BigDNA
|
|||
{
|
||||
DECL_DNA
|
||||
Value<atVec3f> centroid;
|
||||
Value<atUint32> matIdx;
|
||||
Value<atInt16> qDiv;
|
||||
Value<atUint16> dlSize;
|
||||
Value<atUint32> unk1;
|
||||
Value<atUint32> unk2;
|
||||
Value<atUint32> aabbSz;
|
||||
Value<atUint32> matIdx = 0;
|
||||
Value<atUint16> qDiv = 0x8000;
|
||||
Value<atUint16> dlSize = 0;
|
||||
Value<atUint32> unk1 = 0;
|
||||
Value<atUint32> unk2 = 0;
|
||||
Value<atUint32> aabbSz = 0;
|
||||
Value<atVec3f> reflectionNormal;
|
||||
Seek<DNA_COUNT(aabbSz), Athena::Current> seek2;
|
||||
Align<32> align;
|
||||
|
@ -60,12 +60,12 @@ struct SurfaceHeader_3 : BigDNA
|
|||
{
|
||||
DECL_DNA
|
||||
Value<atVec3f> centroid;
|
||||
Value<atUint32> matIdx;
|
||||
Value<atInt16> qDiv;
|
||||
Value<atUint16> dlSize;
|
||||
Value<atUint32> unk1;
|
||||
Value<atUint32> unk2;
|
||||
Value<atUint32> aabbSz;
|
||||
Value<atUint32> matIdx = 0;
|
||||
Value<atUint16> qDiv = 0x8000;
|
||||
Value<atUint16> dlSize = 0;
|
||||
Value<atUint32> unk1 = 0;
|
||||
Value<atUint32> unk2 = 0;
|
||||
Value<atUint32> aabbSz = 0;
|
||||
Value<atVec3f> reflectionNormal;
|
||||
Value<atInt16> skinMtxBankIdx;
|
||||
Value<atUint16> unk3;
|
||||
|
@ -1024,21 +1024,39 @@ bool ReadCMDLToBlender(HECL::BlenderConnection& conn,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void WriteDLVal(Athena::io::FileWriter& writer, GX::AttrType type, atUint32 val)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GX::DIRECT:
|
||||
case GX::INDEX8:
|
||||
writer.writeUByte(atUint8(val));
|
||||
break;
|
||||
case GX::INDEX16:
|
||||
writer.writeUint16Big(atUint16(val));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
template <class MaterialSet, class SurfaceHeader, atUint32 Version>
|
||||
bool WriteCMDL(const HECL::ProjectPath& outPath, const HECL::ProjectPath& inPath, const Mesh& mesh)
|
||||
{
|
||||
//Athena::io::FileWriter writer(outPath.getAbsolutePath());
|
||||
Athena::io::FileWriter writer(outPath.getWithExtension(_S(".recook")).getAbsolutePath());
|
||||
|
||||
Header head;
|
||||
head.magic = 0xDEADBABE;
|
||||
head.version = Version;
|
||||
head.flags.flags = 0;
|
||||
head.aabbMin = mesh.aabbMin.val;
|
||||
head.aabbMax = mesh.aabbMax.val;
|
||||
head.matSetCount = mesh.materialSets.size();
|
||||
head.secCount = head.matSetCount + 5 + mesh.surfaces.size();
|
||||
head.secSizes.reserve(head.secCount);
|
||||
|
||||
/* Lengths of padding to insert while writing */
|
||||
std::vector<size_t> paddingSizes;
|
||||
paddingSizes.reserve(head.secCount);
|
||||
|
||||
/* Build material sets */
|
||||
std::vector<MaterialSet> matSets;
|
||||
matSets.reserve(mesh.materialSets.size());
|
||||
|
@ -1049,23 +1067,213 @@ bool WriteCMDL(const HECL::ProjectPath& outPath, const HECL::ProjectPath& inPath
|
|||
matSets.emplace_back();
|
||||
MaterialSet& targetMSet = matSets.back();
|
||||
std::vector<HECL::ProjectPath> texPaths;
|
||||
std::vector<HECL::Backend::GX> setBackends;
|
||||
setBackends.reserve(mset.size());
|
||||
|
||||
size_t endOff = 0;
|
||||
atUint32 nextGroupIdx = 0;
|
||||
for (const Mesh::Material& mat : mset)
|
||||
{
|
||||
std::string diagName = HECL::Format("%s:%s", inPath.getLastComponentUTF8(), mat.name.c_str());
|
||||
HECL::Frontend::IR matIR = FE.compileSource(mat.source, diagName);
|
||||
HECL::Backend::GX matGX;
|
||||
setBackends.emplace_back();
|
||||
HECL::Backend::GX& matGX = setBackends.back();
|
||||
matGX.reset(matIR, FE.getDiagnostics());
|
||||
|
||||
atUint32 groupIdx = -1;
|
||||
if (matSets.size() == 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++;
|
||||
}
|
||||
|
||||
targetMSet.materials.emplace_back(matGX, mat.iprops, mat.texs, texPaths,
|
||||
mesh.colorLayerCount, mesh.uvLayerCount,
|
||||
false, false, 0);
|
||||
false, false, groupIdx);
|
||||
|
||||
endOff = targetMSet.materials.back().binarySize(endOff);
|
||||
targetMSet.addMaterialEndOff(endOff);
|
||||
}
|
||||
|
||||
for (const HECL::ProjectPath& path : texPaths)
|
||||
{
|
||||
const HECL::SystemString& relPath = path.getRelativePath();
|
||||
|
||||
/* TODO: incorporate hecl hashes */
|
||||
size_t search = relPath.find("TXTR_");
|
||||
if (search != HECL::SystemString::npos)
|
||||
targetMSet.addTexture(relPath.c_str() + search + 5);
|
||||
else
|
||||
LogDNACommon.report(LogVisor::FatalError, "unable to get hash from path");
|
||||
}
|
||||
|
||||
size_t secSz = targetMSet.binarySize(0);
|
||||
size_t secSz32 = ROUND_UP_32(secSz);
|
||||
head.secSizes.push_back(secSz32);
|
||||
paddingSizes.push_back(secSz32 - secSz);
|
||||
}
|
||||
}
|
||||
|
||||
//head.write(writer);
|
||||
/* Vertex Positions */
|
||||
size_t secSz = mesh.pos.size() * 12;
|
||||
size_t secSz32 = ROUND_UP_32(secSz);
|
||||
if (secSz32 == 0)
|
||||
secSz32 = 32;
|
||||
head.secSizes.push_back(secSz32);
|
||||
paddingSizes.push_back(secSz32 - secSz);
|
||||
|
||||
/* Vertex Normals */
|
||||
secSz = mesh.norm.size() * 12;
|
||||
secSz32 = ROUND_UP_32(secSz);
|
||||
if (secSz32 == 0)
|
||||
secSz32 = 32;
|
||||
head.secSizes.push_back(secSz32);
|
||||
paddingSizes.push_back(secSz32 - secSz);
|
||||
|
||||
/* Vertex Colors */
|
||||
secSz = mesh.color.size() * 4;
|
||||
secSz32 = ROUND_UP_32(secSz);
|
||||
if (secSz32 == 0)
|
||||
secSz32 = 32;
|
||||
head.secSizes.push_back(secSz32);
|
||||
paddingSizes.push_back(secSz32 - secSz);
|
||||
|
||||
/* UV coords */
|
||||
secSz = mesh.uv.size() * 8;
|
||||
secSz32 = ROUND_UP_32(secSz);
|
||||
if (secSz32 == 0)
|
||||
secSz32 = 32;
|
||||
head.secSizes.push_back(secSz32);
|
||||
paddingSizes.push_back(secSz32 - secSz);
|
||||
|
||||
/* Surface index */
|
||||
std::vector<size_t> surfEndOffs;
|
||||
surfEndOffs.reserve(mesh.surfaces.size());
|
||||
secSz = mesh.surfaces.size() * 4 + 4;
|
||||
secSz32 = ROUND_UP_32(secSz);
|
||||
if (secSz32 == 0)
|
||||
secSz32 = 32;
|
||||
head.secSizes.push_back(secSz32);
|
||||
paddingSizes.push_back(secSz32 - secSz);
|
||||
|
||||
/* Surfaces */
|
||||
size_t endOff = 0;
|
||||
for (const Mesh::Surface& surf : mesh.surfaces)
|
||||
{
|
||||
size_t vertSz = matSets.at(0).materials.at(surf.materialIdx).getVAFlags().vertDLSize();
|
||||
if (surf.verts.size() > 65536)
|
||||
LogDNACommon.report(LogVisor::FatalError, "GX DisplayList overflow");
|
||||
size_t secSz = 67 + surf.verts.size() * vertSz;
|
||||
secSz32 = ROUND_UP_32(secSz);
|
||||
if (secSz32 == 0)
|
||||
secSz32 = 32;
|
||||
head.secSizes.push_back(secSz32);
|
||||
paddingSizes.push_back(secSz32 - secSz);
|
||||
endOff += secSz32;
|
||||
surfEndOffs.push_back(endOff);
|
||||
}
|
||||
|
||||
/* Write sections */
|
||||
head.write(writer);
|
||||
std::vector<size_t>::const_iterator padIt = paddingSizes.cbegin();
|
||||
|
||||
/* Material Sets */
|
||||
for (const MaterialSet& mset : matSets)
|
||||
{
|
||||
mset.write(writer);
|
||||
writer.fill(atUint8(0), *padIt);
|
||||
++padIt;
|
||||
}
|
||||
|
||||
/* Vertex Positions */
|
||||
for (const atVec3f& pos : mesh.pos)
|
||||
writer.writeVec3fBig(pos);
|
||||
writer.fill(atUint8(0), *padIt);
|
||||
++padIt;
|
||||
|
||||
/* Vertex Normals */
|
||||
for (const atVec3f& norm : mesh.norm)
|
||||
writer.writeVec3fBig(norm);
|
||||
writer.fill(atUint8(0), *padIt);
|
||||
++padIt;
|
||||
|
||||
/* Vertex Colors */
|
||||
for (const atVec3f& col : mesh.color)
|
||||
{
|
||||
GX::Color qCol(col);
|
||||
qCol.write(writer);
|
||||
}
|
||||
writer.fill(atUint8(0), *padIt);
|
||||
++padIt;
|
||||
|
||||
/* UV coords */
|
||||
for (const atVec2f& uv : mesh.uv)
|
||||
writer.writeVec2fBig(uv);
|
||||
writer.fill(atUint8(0), *padIt);
|
||||
++padIt;
|
||||
|
||||
/* Surface index */
|
||||
writer.writeUint32Big(surfEndOffs.size());
|
||||
for (size_t off : surfEndOffs)
|
||||
writer.writeUint32Big(off);
|
||||
writer.fill(atUint8(0), *padIt);
|
||||
++padIt;
|
||||
|
||||
/* Surfaces */
|
||||
for (const Mesh::Surface& surf : mesh.surfaces)
|
||||
{
|
||||
const typename MaterialSet::Material::VAFlags& vaFlags =
|
||||
matSets.at(0).materials.at(surf.materialIdx).getVAFlags();
|
||||
size_t vertSz = vaFlags.vertDLSize();
|
||||
|
||||
SurfaceHeader header;
|
||||
header.centroid = surf.centroid;
|
||||
header.matIdx = surf.materialIdx;
|
||||
header.dlSize = 3 + surf.verts.size() * vertSz;
|
||||
header.reflectionNormal = surf.reflectionNormal;
|
||||
header.write(writer);
|
||||
|
||||
writer.writeUByte(GX::TRIANGLESTRIP);
|
||||
writer.writeUint16Big(surf.verts.size());
|
||||
|
||||
for (const Mesh::Surface::Vert& vert : surf.verts)
|
||||
{
|
||||
atUint32 skinIdx = vert.iBankSkin * 3;
|
||||
WriteDLVal(writer, vaFlags.pnMatIdx(), skinIdx);
|
||||
WriteDLVal(writer, vaFlags.tex0MatIdx(), skinIdx);
|
||||
WriteDLVal(writer, vaFlags.tex1MatIdx(), skinIdx);
|
||||
WriteDLVal(writer, vaFlags.tex2MatIdx(), skinIdx);
|
||||
WriteDLVal(writer, vaFlags.tex3MatIdx(), skinIdx);
|
||||
WriteDLVal(writer, vaFlags.tex4MatIdx(), skinIdx);
|
||||
WriteDLVal(writer, vaFlags.tex5MatIdx(), skinIdx);
|
||||
WriteDLVal(writer, vaFlags.tex6MatIdx(), skinIdx);
|
||||
WriteDLVal(writer, vaFlags.position(), vert.iPos);
|
||||
WriteDLVal(writer, vaFlags.normal(), vert.iNorm);
|
||||
WriteDLVal(writer, vaFlags.color0(), vert.iColor[0]);
|
||||
WriteDLVal(writer, vaFlags.color1(), vert.iColor[1]);
|
||||
WriteDLVal(writer, vaFlags.tex0(), vert.iUv[0]);
|
||||
WriteDLVal(writer, vaFlags.tex1(), vert.iUv[1]);
|
||||
WriteDLVal(writer, vaFlags.tex2(), vert.iUv[2]);
|
||||
WriteDLVal(writer, vaFlags.tex3(), vert.iUv[3]);
|
||||
WriteDLVal(writer, vaFlags.tex4(), vert.iUv[4]);
|
||||
WriteDLVal(writer, vaFlags.tex5(), vert.iUv[5]);
|
||||
WriteDLVal(writer, vaFlags.tex6(), vert.iUv[6]);
|
||||
}
|
||||
|
||||
writer.fill(atUint8(0), *padIt);
|
||||
++padIt;
|
||||
}
|
||||
|
||||
writer.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,15 @@ public:
|
|||
snprintf(buf, 9, "%08X", m_id);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
UniqueID32() = default;
|
||||
UniqueID32(const char* hexStr)
|
||||
{
|
||||
char copy[9];
|
||||
strncpy(copy, hexStr, 8);
|
||||
copy[8] = '\0';
|
||||
m_id = strtoul(copy, nullptr, 16);
|
||||
}
|
||||
};
|
||||
|
||||
/* PAK 64-bit Unique ID */
|
||||
|
@ -100,6 +109,15 @@ public:
|
|||
snprintf(buf, 17, "%016" PRIX64, m_id);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
UniqueID64() = default;
|
||||
UniqueID64(const char* hexStr)
|
||||
{
|
||||
char copy[17];
|
||||
strncpy(copy, hexStr, 16);
|
||||
copy[16] = '\0';
|
||||
m_id = strtouq(copy, nullptr, 16);
|
||||
}
|
||||
};
|
||||
|
||||
/* PAK 128-bit Unique ID */
|
||||
|
|
|
@ -20,11 +20,13 @@ struct MaterialSet : BigDNA
|
|||
struct MaterialSetHead : BigDNA
|
||||
{
|
||||
DECL_DNA
|
||||
Value<atUint32> textureCount;
|
||||
Value<atUint32> textureCount = 0;
|
||||
Vector<UniqueID32, DNA_COUNT(textureCount)> textureIDs;
|
||||
Value<atUint32> materialCount;
|
||||
Value<atUint32> materialCount = 0;
|
||||
Vector<atUint32, DNA_COUNT(materialCount)> materialEndOffs;
|
||||
} head;
|
||||
void addTexture(const UniqueID32& id) {head.textureIDs.push_back(id); ++head.textureCount;}
|
||||
void addMaterialEndOff(atUint32 off) {head.materialEndOffs.push_back(off); ++head.materialCount;}
|
||||
|
||||
struct Material : BigDNA
|
||||
{
|
||||
|
@ -102,6 +104,32 @@ struct MaterialSet : BigDNA
|
|||
void setTex5MatIdx(GX::AttrType val) {vaFlags &= ~0x40000000; vaFlags |= atUint32(val & 0x1) << 30;}
|
||||
GX::AttrType tex6MatIdx() const {return GX::AttrType(vaFlags >> 31 & 0x1);}
|
||||
void setTex6MatIdx(GX::AttrType val) {vaFlags &= ~0x80000000; vaFlags |= atUint32(val & 0x1) << 31;}
|
||||
|
||||
size_t vertDLSize() const
|
||||
{
|
||||
static size_t ATTR_SZ[] = {0,1,1,2};
|
||||
size_t ret = 0;
|
||||
ret += ATTR_SZ[position()];
|
||||
ret += ATTR_SZ[normal()];
|
||||
ret += ATTR_SZ[color0()];
|
||||
ret += ATTR_SZ[color1()];
|
||||
ret += ATTR_SZ[tex0()];
|
||||
ret += ATTR_SZ[tex1()];
|
||||
ret += ATTR_SZ[tex2()];
|
||||
ret += ATTR_SZ[tex3()];
|
||||
ret += ATTR_SZ[tex4()];
|
||||
ret += ATTR_SZ[tex5()];
|
||||
ret += ATTR_SZ[tex6()];
|
||||
ret += ATTR_SZ[pnMatIdx()];
|
||||
ret += ATTR_SZ[tex0MatIdx()];
|
||||
ret += ATTR_SZ[tex1MatIdx()];
|
||||
ret += ATTR_SZ[tex2MatIdx()];
|
||||
ret += ATTR_SZ[tex3MatIdx()];
|
||||
ret += ATTR_SZ[tex4MatIdx()];
|
||||
ret += ATTR_SZ[tex5MatIdx()];
|
||||
ret += ATTR_SZ[tex6MatIdx()];
|
||||
return ret;
|
||||
}
|
||||
} vaFlags;
|
||||
const VAFlags& getVAFlags() const {return vaFlags;}
|
||||
Value<atUint32> groupIdx;
|
||||
|
|
|
@ -18,6 +18,10 @@ struct MaterialSet : BigDNA
|
|||
DECL_DNA
|
||||
Value<atUint32> materialCount;
|
||||
|
||||
/* Dummy methods from MP1/2 */
|
||||
void addTexture(const UniqueID32&) {}
|
||||
void addMaterialEndOff(atUint32) {++materialCount;}
|
||||
|
||||
struct Material : BigDNA
|
||||
{
|
||||
Delete expl;
|
||||
|
|
|
@ -282,7 +282,7 @@ struct SpecMP1 : SpecBase
|
|||
|
||||
void cookMesh(const HECL::ProjectPath& out, const HECL::ProjectPath& in, BlendStream& ds) const
|
||||
{
|
||||
Mesh mesh = ds.compileMesh();
|
||||
Mesh mesh = ds.compileMesh(-1);
|
||||
DNAMP1::CMDL::Cook(out, in, mesh);
|
||||
}
|
||||
|
||||
|
|
2
hecl
2
hecl
|
@ -1 +1 @@
|
|||
Subproject commit 7dac1ffef13697a8fe2478c1f29292cd2c95e67d
|
||||
Subproject commit ad061af83e93d766aab3bd0985a7984f9cbea5bf
|
Loading…
Reference in New Issue