#pragma once #include <cstddef> #include <cstdint> #include <vector> #include "DataSpec/DNACommon/GX.hpp" #include "DataSpec/DNACommon/TXTR.hpp" #include <athena/DNA.hpp> #include <athena/Types.hpp> #include <hecl/Blender/Connection.hpp> namespace hecl { class ProjectPath; } namespace zeus { class CAABox; } namespace DataSpec::DNACMDL { using Mesh = hecl::blender::Mesh; using Material = hecl::blender::Material; struct Header : BigDNA { AT_DECL_DNA Value<atUint32> magic; Value<atUint32> version; struct Flags : BigDNA { AT_DECL_DNA Value<atUint32> flags = 0; bool skinned() const { return (flags & 0x1) != 0; } void setSkinned(bool val) { flags &= ~0x1; flags |= val; } bool shortNormals() const { return (flags & 0x2) != 0; } void setShortNormals(bool val) { flags &= ~0x2; flags |= val << 1; } bool shortUVs() const { return (flags & 0x4) != 0; } void setShortUVs(bool val) { flags &= ~0x4; flags |= val << 2; } } flags; Value<atVec3f> aabbMin; Value<atVec3f> aabbMax; Value<atUint32> secCount; Value<atUint32> matSetCount; Vector<atUint32, AT_DNA_COUNT(secCount)> secSizes; Align<32> align; }; struct SurfaceHeader_1 : BigDNA { AT_DECL_EXPLICIT_DNA Value<atVec3f> centroid; Value<atUint32> matIdx = 0; Value<atUint32> dlSize = 0; Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */ Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */ Value<atUint32> aabbSz = 0; Value<atVec3f> reflectionNormal; Value<atVec3f> aabb[2]; Align<32> align; static constexpr bool UseMatrixSkinning() { return false; } static constexpr atInt16 skinMatrixBankIdx() { return -1; } }; struct SurfaceHeader_2 : BigDNA { AT_DECL_EXPLICIT_DNA Value<atVec3f> centroid; Value<atUint32> matIdx = 0; Value<atUint32> dlSize = 0; Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */ Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */ Value<atUint32> aabbSz = 0; Value<atVec3f> reflectionNormal; Value<atInt16> skinMtxBankIdx; Value<atUint16> surfaceGroup; Value<atVec3f> aabb[2]; Align<32> align; static constexpr bool UseMatrixSkinning() { return false; } atInt16 skinMatrixBankIdx() const { return skinMtxBankIdx; } }; struct SurfaceHeader_3 : BigDNA { AT_DECL_EXPLICIT_DNA Value<atVec3f> centroid; Value<atUint32> matIdx = 0; Value<atUint32> dlSize = 0; Value<atUint32> idxStart = 0; /* Actually used by game to stash CCubeModel pointer */ Value<atUint32> idxCount = 0; /* Actually used by game to stash next CCubeSurface pointer */ Value<atUint32> aabbSz = 0; Value<atVec3f> reflectionNormal; Value<atInt16> skinMtxBankIdx; Value<atUint16> surfaceGroup; Value<atVec3f> aabb[2]; Value<atUint8> unk3; Align<32> align; static constexpr bool UseMatrixSkinning() { return true; } atInt16 skinMatrixBankIdx() const { return skinMtxBankIdx; } }; struct VertexAttributes { GX::AttrType pos = GX::NONE; GX::AttrType norm = GX::NONE; GX::AttrType color0 = GX::NONE; GX::AttrType color1 = GX::NONE; unsigned uvCount = 0; GX::AttrType uvs[7] = {GX::NONE}; GX::AttrType pnMtxIdx = GX::NONE; unsigned texMtxIdxCount = 0; GX::AttrType texMtxIdx[7] = {GX::NONE}; bool shortUVs; }; template <class MaterialSet> void GetVertexAttributes(const MaterialSet& matSet, std::vector<VertexAttributes>& attributesOut); template <class PAKRouter, class MaterialSet> void ReadMaterialSetToBlender_1_2(hecl::blender::PyOutStream& os, const MaterialSet& matSet, const PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, unsigned setIdx); template <class PAKRouter, class MaterialSet> void ReadMaterialSetToBlender_3(hecl::blender::PyOutStream& os, const MaterialSet& matSet, const PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, unsigned setIdx); void InitGeomBlenderContext(hecl::blender::PyOutStream& os, const hecl::ProjectPath& masterShaderPath); void FinishBlenderMesh(hecl::blender::PyOutStream& os, unsigned matSetCount, int meshIdx); template <class PAKRouter, class MaterialSet, class RigPair, class SurfaceHeader> atUint32 ReadGeomSectionsToBlender(hecl::blender::PyOutStream& os, athena::io::IStreamReader& reader, PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const RigPair& rp, bool shortNormals, bool shortUVs, std::vector<VertexAttributes>& vertAttribs, int meshIdx, atUint32 secCount, atUint32 matSetCount, const atUint32* secSizes, atUint32 surfaceCount = 0); template <class PAKRouter, class MaterialSet, class RigPair, class SurfaceHeader, atUint32 Version> bool ReadCMDLToBlender(hecl::blender::Connection& conn, athena::io::IStreamReader& reader, PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const SpecBase& dataspec, const RigPair& rp); template <class PAKRouter, class MaterialSet> void NameCMDL(athena::io::IStreamReader& reader, PAKRouter& pakRouter, typename PAKRouter::EntryType& entry, const SpecBase& dataspec); template <class MaterialSet, class SurfaceHeader, atUint32 Version> bool WriteCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh); template <class MaterialSet, class SurfaceHeader, atUint32 Version> bool WriteHMDLCMDL(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const Mesh& mesh, hecl::blender::PoolSkinIndex& poolSkinIndex); 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); 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); } // namespace DataSpec::DNACMDL