diff --git a/src/Libraries/MeshCompiler.cpp b/src/Libraries/MeshCompiler.cpp index 9c233a2..5bf674c 100644 --- a/src/Libraries/MeshCompiler.cpp +++ b/src/Libraries/MeshCompiler.cpp @@ -148,17 +148,42 @@ namespace SH_COMP void MeshCompiler::BuildHeaders(ModelAsset& asset) noexcept { - for (auto const& mesh : asset.meshes) + // Mesh Headers + asset.meshHeaders.resize(asset.meshes.size()); + asset.header.meshCount = asset.meshes.size(); + for (auto i{0}; i < asset.header.meshCount; ++i) { - asset.headers.emplace_back(); - auto& head = asset.headers.back(); + auto const& mesh = asset.meshes[i]; + auto& head = asset.meshHeaders[i]; head.charCount = mesh.name.size(); head.indexCount = mesh.indices.size(); head.vertexCount = mesh.vertexPosition.size(); head.boneCount = mesh.bonesInfo.size(); + } - asset.header.meshCount++; + // Anim Headers + asset.animHeaders.resize(asset.anims.size()); + asset.header.animCount = asset.anims.size(); + for (auto i{0}; i < asset.header.animCount; ++i) + { + auto const& anim = asset.anims[i]; + auto& head = asset.animHeaders[i]; + + head.charCount = anim.name.size(); + head.animNodeCount = anim.nodeChannels.size(); + head.nodeHeaders.resize(head.animNodeCount); + + for (auto j{0}; i < head.animNodeCount; ++j) + { + auto const& animNode = anim.nodeChannels[j]; + auto& nodeHeader = head.nodeHeaders[j]; + + nodeHeader.charCount = animNode.name.size(); + nodeHeader.posKeyCount = animNode.positionKeys.size(); + nodeHeader.rotKeyCount = animNode.rotationKeys.size(); + nodeHeader.scaKeyCount = animNode.scaleKeys.size(); + } } } @@ -206,89 +231,25 @@ namespace SH_COMP ); } - void MeshCompiler::LoadFromFile(AssetPath path, ModelAsset& asset) noexcept + void MeshCompiler::WriteAnimHeader(FileReference file, AnimDataHeader const& header) { - const aiScene* scene = aiImporter.ReadFile(path.string().c_str(), - aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons - | aiProcess_GenUVCoords // Convert any type of mapping to uv mapping - | aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...) - | aiProcess_FindInstances // search for instanced meshes and remove them by references to one master - | aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible - | aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing - | aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors - | aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs - | aiProcess_ValidateDataStructure - ); - - if (!scene || !scene->HasMeshes()) - { - std::cout << "ERROR in GLTF::ASSIMP: " << aiImporter.GetErrorString() << "\nFile: " << path.string() << std::endl; - return; - } - - std::vector anims; - - ParseAnimations(*scene, anims); - - ProcessNode(*scene->mRootNode, *scene, asset.meshes, asset.rig.root); - - aiImporter.FreeScene(); } - void MeshCompiler::CompileMeshBinary(AssetPath path, ModelAsset const& asset) noexcept + void MeshCompiler::WriteAnimData(FileReference file, AnimDataHeader const& header, AnimData& data) { - std::string newPath{ path.string().substr(0, path.string().find_last_of('.')) }; - newPath += MODEL_EXTENSION; - - std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc }; - if (!file.is_open()) - { - std::cout << "Unable to open file for write: " << newPath << std::endl; - return; - } - - file.write( - reinterpret_cast(&asset.header), - sizeof(asset.header) - ); - - for (auto i {0}; i < asset.headers.size(); ++i) - { - WriteMeshHeader(file, asset.headers[i]); - WriteMeshData(file, asset.headers[i], asset.meshes[i]); - } - - file.close(); } - void MeshCompiler::BuildArmature(aiNode const& baseNode, RigNode*& root) noexcept + void MeshCompiler::WriteHeaders(FileReference file, ModelConstRef asset) { - RigNode* start = new RigNode(); - - CopyNode(baseNode, start); - - root = start->children[0]; } - void MeshCompiler::CopyNode(aiNode const& source, RigNode* parent) noexcept + void MeshCompiler::WriteData(FileReference file, ModelConstRef asset) { - RigNode* current = new RigNode(); - current->name = source.mName.C_Str(); - std::memcpy(¤t->transform, &source.mTransformation, sizeof(SHMat4)); - - for (auto i {0}; i < source.mNumChildren; ++i) - { - CopyNode(*source.mChildren[i], current); - } - - if (parent) - { - parent->children.push_back(current); - } } - void MeshCompiler::ParseAnimations(aiScene const& scene, std::vector& anims) noexcept + void MeshCompiler::ParseAnimations(aiScene const& scene, std::vector& anims) noexcept { + // Size and read for number of animation clips anims.resize(scene.mNumAnimations); for (auto i {0}; i < scene.mNumAnimations; ++i) @@ -352,6 +313,86 @@ namespace SH_COMP } } + void MeshCompiler::LoadFromFile(AssetPath path, ModelAsset& asset) noexcept + { + const aiScene* scene = aiImporter.ReadFile(path.string().c_str(), + aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons + | aiProcess_GenUVCoords // Convert any type of mapping to uv mapping + | aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...) + | aiProcess_FindInstances // search for instanced meshes and remove them by references to one master + | aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible + | aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing + | aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors + | aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs + | aiProcess_ValidateDataStructure + ); + + if (!scene || !scene->HasMeshes()) + { + std::cout << "ERROR in GLTF::ASSIMP: " << aiImporter.GetErrorString() << "\nFile: " << path.string() << std::endl; + return; + } + + ParseAnimations(*scene, asset.anims); + + ProcessNode(*scene->mRootNode, *scene, asset.meshes, asset.rig.root); + + aiImporter.FreeScene(); + } + + void MeshCompiler::CompileMeshBinary(AssetPath path, ModelAsset const& asset) noexcept + { + std::string newPath{ path.string().substr(0, path.string().find_last_of('.')) }; + newPath += MODEL_EXTENSION; + + std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc }; + if (!file.is_open()) + { + std::cout << "Unable to open file for write: " << newPath << std::endl; + return; + } + + file.write( + reinterpret_cast(&asset.header), + sizeof(asset.header) + ); + + // Write Meshes + for (auto i {0}; i < asset.meshHeaders.size(); ++i) + { + WriteMeshHeader(file, asset.meshHeaders[i]); + WriteMeshData(file, asset.meshHeaders[i], asset.meshes[i]); + } + + file.close(); + } + + void MeshCompiler::BuildArmature(aiNode const& baseNode, RigNode*& root) noexcept + { + RigNode* start = new RigNode(); + + CopyNode(baseNode, start); + + root = start->children[0]; + } + + void MeshCompiler::CopyNode(aiNode const& source, RigNode* parent) noexcept + { + RigNode* current = new RigNode(); + current->name = source.mName.C_Str(); + std::memcpy(¤t->transform, &source.mTransformation, sizeof(SHMat4)); + + for (auto i {0}; i < source.mNumChildren; ++i) + { + CopyNode(*source.mChildren[i], current); + } + + if (parent) + { + parent->children.push_back(current); + } + } + void MeshCompiler::LoadAndCompile(AssetPath path) noexcept { auto const asset = new ModelAsset(); diff --git a/src/Libraries/MeshCompiler.h b/src/Libraries/MeshCompiler.h index 13e3fa9..4ba0955 100644 --- a/src/Libraries/MeshCompiler.h +++ b/src/Libraries/MeshCompiler.h @@ -26,25 +26,35 @@ namespace SH_COMP { using MeshVectorRef = std::vector&; - using AnimVectorRef = std::vector&; + using AnimVectorRef = std::vector&; + + using FileReference = std::ofstream&; + using ModelConstRef = ModelAsset const&; + using ModelRef = ModelAsset&; static Assimp::Importer aiImporter; static void ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes, RigNode*& root) noexcept; //static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept; static void GetMesh(aiMesh const& mesh, MeshData& meshData) noexcept; - static void BuildHeaders(ModelAsset& asset) noexcept; + static void BuildHeaders(ModelRef asset) noexcept; - static void WriteMeshHeader(std::ofstream& file, MeshDataHeader const& header); - static void WriteMeshData(std::ofstream& file, MeshDataHeader const& header, MeshData const& asset); + static void WriteMeshHeader(FileReference file, MeshDataHeader const& header); + static void WriteMeshData(FileReference file, MeshDataHeader const& header, MeshData const& asset); - static void LoadFromFile(AssetPath path, ModelAsset& asset) noexcept; - static void CompileMeshBinary(AssetPath path, ModelAsset const& asset) noexcept; + static void WriteAnimHeader(FileReference file, AnimDataHeader const& header); + static void WriteAnimData(FileReference file, AnimDataHeader const& header, AnimData cosnt& data); + + static void WriteHeaders(FileReference file, ModelConstRef asset); + static void WriteData(FileReference file, ModelConstRef asset); + + static void LoadFromFile(AssetPath path, ModelRef asset) noexcept; + static void CompileMeshBinary(AssetPath path, ModelConstRef asset) noexcept; static void BuildArmature(aiNode const& node, RigNode*& root) noexcept; static void CopyNode(aiNode const& source, RigNode* parent) noexcept; - static void ParseAnimations(aiScene const& scene, std::vector& anims) noexcept; + static void ParseAnimations(aiScene const& scene, std::vector& anims) noexcept; public: static void LoadAndCompile(AssetPath path) noexcept; }; diff --git a/src/Types/AnimationAsset.h b/src/Types/AnimationAsset.h index a8ea4a1..b69f907 100644 --- a/src/Types/AnimationAsset.h +++ b/src/Types/AnimationAsset.h @@ -16,24 +16,66 @@ namespace SH_COMP { - struct AnimationKey + enum class AnimationBehaviour : uint8_t + { + DEFAULT = 0x0, + CONSTNAT = 0x1, + LINEAR = 0x2, + REPEAT = 0x3 + }; + + // Smallest data containers + struct PositionKey + { + float time; + SHVec3 value; + }; + + struct RotationKey { float time; SHVec4 value; }; - struct AnimationNode + + struct ScaleKey { - std::string name; - std::vector positionKeys; - std::vector rotationKeys; - std::vector scaleKeys; + float time; + SHVec3 value; }; - struct AnimationAsset + // Headers for read/write + struct AnimNodeInfo + { + uint32_t charCount; + uint32_t posKeyCount; + uint32_t rotKeyCount; + uint32_t scaKeyCount; + }; + + struct AnimDataHeader + { + uint32_t charCount; + uint32_t animNodeCount; + std::vector nodeHeaders; + }; + + // Main data containers + struct AnimNode + { + std::string name; + std::vector positionKeys; + std::vector rotationKeys; + std::vector scaleKeys; + + AnimationBehaviour pre; + AnimationBehaviour post; + }; + + struct AnimData { std::string name; - std::vector nodeChannels; + std::vector nodeChannels; //std::vector meshChannels; //std::vector morphMeshChannels; diff --git a/src/Types/ModelAsset.h b/src/Types/ModelAsset.h index 9c09b66..d0e5dcc 100644 --- a/src/Types/ModelAsset.h +++ b/src/Types/ModelAsset.h @@ -16,6 +16,7 @@ #include #include "MeshAsset.h" +#include "AnimationAsset.h" namespace SH_COMP { @@ -35,13 +36,18 @@ namespace SH_COMP struct ModelAssetHeader { size_t meshCount; + size_t animCount; }; struct ModelAsset { ModelAssetHeader header; RigData rig; - std::vector headers; + + std::vector meshHeaders; + std::vector animHeaders; + std::vector meshes; + std::vector anims; }; } \ No newline at end of file