Initial CMDL cooking in place

This commit is contained in:
Jack Andersen 2015-10-18 17:28:47 -10:00
parent 58c0fd5ad2
commit bf8a007514
6 changed files with 280 additions and 22 deletions

View File

@ -24,7 +24,7 @@ struct Header : BigDNA
struct Flags : BigDNA struct Flags : BigDNA
{ {
DECL_DNA DECL_DNA
Value<atUint32> flags; Value<atUint32> flags = 0;
bool shortNormals() const {return (flags & 0x2) != 0;} bool shortNormals() const {return (flags & 0x2) != 0;}
void setShortNormals(bool val) {flags &= ~0x2; flags |= val << 1;} void setShortNormals(bool val) {flags &= ~0x2; flags |= val << 1;}
bool shortUVs() const {return (flags & 0x4) != 0;} bool shortUVs() const {return (flags & 0x4) != 0;}
@ -42,12 +42,12 @@ struct SurfaceHeader_1_2 : BigDNA
{ {
DECL_DNA DECL_DNA
Value<atVec3f> centroid; Value<atVec3f> centroid;
Value<atUint32> matIdx; Value<atUint32> matIdx = 0;
Value<atInt16> qDiv; Value<atUint16> qDiv = 0x8000;
Value<atUint16> dlSize; Value<atUint16> dlSize = 0;
Value<atUint32> unk1; Value<atUint32> unk1 = 0;
Value<atUint32> unk2; Value<atUint32> unk2 = 0;
Value<atUint32> aabbSz; Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal; Value<atVec3f> reflectionNormal;
Seek<DNA_COUNT(aabbSz), Athena::Current> seek2; Seek<DNA_COUNT(aabbSz), Athena::Current> seek2;
Align<32> align; Align<32> align;
@ -60,12 +60,12 @@ struct SurfaceHeader_3 : BigDNA
{ {
DECL_DNA DECL_DNA
Value<atVec3f> centroid; Value<atVec3f> centroid;
Value<atUint32> matIdx; Value<atUint32> matIdx = 0;
Value<atInt16> qDiv; Value<atUint16> qDiv = 0x8000;
Value<atUint16> dlSize; Value<atUint16> dlSize = 0;
Value<atUint32> unk1; Value<atUint32> unk1 = 0;
Value<atUint32> unk2; Value<atUint32> unk2 = 0;
Value<atUint32> aabbSz; Value<atUint32> aabbSz = 0;
Value<atVec3f> reflectionNormal; Value<atVec3f> reflectionNormal;
Value<atInt16> skinMtxBankIdx; Value<atInt16> skinMtxBankIdx;
Value<atUint16> unk3; Value<atUint16> unk3;
@ -1024,21 +1024,39 @@ bool ReadCMDLToBlender(HECL::BlenderConnection& conn,
return true; 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> template <class MaterialSet, class SurfaceHeader, atUint32 Version>
bool WriteCMDL(const HECL::ProjectPath& outPath, const HECL::ProjectPath& inPath, const Mesh& mesh) 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; Header head;
head.magic = 0xDEADBABE; head.magic = 0xDEADBABE;
head.version = Version; head.version = Version;
head.flags.flags = 0;
head.aabbMin = mesh.aabbMin.val; head.aabbMin = mesh.aabbMin.val;
head.aabbMax = mesh.aabbMax.val; head.aabbMax = mesh.aabbMax.val;
head.matSetCount = mesh.materialSets.size(); head.matSetCount = mesh.materialSets.size();
head.secCount = head.matSetCount + 5 + mesh.surfaces.size(); head.secCount = head.matSetCount + 5 + mesh.surfaces.size();
head.secSizes.reserve(head.secCount); head.secSizes.reserve(head.secCount);
/* Lengths of padding to insert while writing */
std::vector<size_t> paddingSizes;
paddingSizes.reserve(head.secCount);
/* Build material sets */ /* Build material sets */
std::vector<MaterialSet> matSets; std::vector<MaterialSet> matSets;
matSets.reserve(mesh.materialSets.size()); matSets.reserve(mesh.materialSets.size());
@ -1049,23 +1067,213 @@ bool WriteCMDL(const HECL::ProjectPath& outPath, const HECL::ProjectPath& inPath
matSets.emplace_back(); matSets.emplace_back();
MaterialSet& targetMSet = matSets.back(); MaterialSet& targetMSet = matSets.back();
std::vector<HECL::ProjectPath> texPaths; 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) for (const Mesh::Material& mat : mset)
{ {
std::string diagName = HECL::Format("%s:%s", inPath.getLastComponentUTF8(), mat.name.c_str()); std::string diagName = HECL::Format("%s:%s", inPath.getLastComponentUTF8(), mat.name.c_str());
HECL::Frontend::IR matIR = FE.compileSource(mat.source, diagName); 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()); 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, targetMSet.materials.emplace_back(matGX, mat.iprops, mat.texs, texPaths,
mesh.colorLayerCount, mesh.uvLayerCount, 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; return true;
} }

View File

@ -71,6 +71,15 @@ public:
snprintf(buf, 9, "%08X", m_id); snprintf(buf, 9, "%08X", m_id);
return std::string(buf); 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 */ /* PAK 64-bit Unique ID */
@ -100,6 +109,15 @@ public:
snprintf(buf, 17, "%016" PRIX64, m_id); snprintf(buf, 17, "%016" PRIX64, m_id);
return std::string(buf); 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 */ /* PAK 128-bit Unique ID */

View File

@ -20,11 +20,13 @@ struct MaterialSet : BigDNA
struct MaterialSetHead : BigDNA struct MaterialSetHead : BigDNA
{ {
DECL_DNA DECL_DNA
Value<atUint32> textureCount; Value<atUint32> textureCount = 0;
Vector<UniqueID32, DNA_COUNT(textureCount)> textureIDs; Vector<UniqueID32, DNA_COUNT(textureCount)> textureIDs;
Value<atUint32> materialCount; Value<atUint32> materialCount = 0;
Vector<atUint32, DNA_COUNT(materialCount)> materialEndOffs; Vector<atUint32, DNA_COUNT(materialCount)> materialEndOffs;
} head; } 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 struct Material : BigDNA
{ {
@ -102,6 +104,32 @@ struct MaterialSet : BigDNA
void setTex5MatIdx(GX::AttrType val) {vaFlags &= ~0x40000000; vaFlags |= atUint32(val & 0x1) << 30;} void setTex5MatIdx(GX::AttrType val) {vaFlags &= ~0x40000000; vaFlags |= atUint32(val & 0x1) << 30;}
GX::AttrType tex6MatIdx() const {return GX::AttrType(vaFlags >> 31 & 0x1);} GX::AttrType tex6MatIdx() const {return GX::AttrType(vaFlags >> 31 & 0x1);}
void setTex6MatIdx(GX::AttrType val) {vaFlags &= ~0x80000000; vaFlags |= atUint32(val & 0x1) << 31;} 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; } vaFlags;
const VAFlags& getVAFlags() const {return vaFlags;} const VAFlags& getVAFlags() const {return vaFlags;}
Value<atUint32> groupIdx; Value<atUint32> groupIdx;

View File

@ -18,6 +18,10 @@ struct MaterialSet : BigDNA
DECL_DNA DECL_DNA
Value<atUint32> materialCount; Value<atUint32> materialCount;
/* Dummy methods from MP1/2 */
void addTexture(const UniqueID32&) {}
void addMaterialEndOff(atUint32) {++materialCount;}
struct Material : BigDNA struct Material : BigDNA
{ {
Delete expl; Delete expl;

View File

@ -282,7 +282,7 @@ struct SpecMP1 : SpecBase
void cookMesh(const HECL::ProjectPath& out, const HECL::ProjectPath& in, BlendStream& ds) const 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); DNAMP1::CMDL::Cook(out, in, mesh);
} }

2
hecl

@ -1 +1 @@
Subproject commit 7dac1ffef13697a8fe2478c1f29292cd2c95e67d Subproject commit ad061af83e93d766aab3bd0985a7984f9cbea5bf