diff --git a/SHADE_Engine/src/Assets/Asset Types/Models/SHMeshAsset.h b/SHADE_Engine/src/Assets/Asset Types/Models/SHMeshAsset.h index e8780669..c772f717 100644 --- a/SHADE_Engine/src/Assets/Asset Types/Models/SHMeshAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/Models/SHMeshAsset.h @@ -24,7 +24,6 @@ namespace SHADE uint32_t indexCount; uint32_t charCount; uint32_t boneCount; - std::string name; }; struct MeshBoneInfo @@ -48,7 +47,7 @@ namespace SHADE struct SH_API SHMeshAsset : SHAssetData { - SHMeshDataHeader header; + std::string name; std::vector VertexPositions; std::vector VertexTangents; std::vector VertexNormals; diff --git a/SHADE_Engine/src/Assets/Asset Types/Models/SHModelAsset.h b/SHADE_Engine/src/Assets/Asset Types/Models/SHModelAsset.h index 4425f555..2ddc6a5a 100644 --- a/SHADE_Engine/src/Assets/Asset Types/Models/SHModelAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/Models/SHModelAsset.h @@ -29,9 +29,11 @@ namespace SHADE struct SH_API SHModelAsset : SHAssetData { SHModelAssetHeader header; - SHRigAsset rig; + std::vector meshHeaders; + std::vector animHeaders; + std::vector meshes; std::vector anims; }; diff --git a/SHADE_Engine/src/Assets/Asset Types/Models/SHRigAsset.cpp b/SHADE_Engine/src/Assets/Asset Types/Models/SHRigAsset.cpp new file mode 100644 index 00000000..251fdc91 --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/Models/SHRigAsset.cpp @@ -0,0 +1,26 @@ +#include "SHpch.h" +#include "SHRigAsset.h" + +#include + +namespace SHADE +{ + SHRigAsset::~SHRigAsset() + { + std::queue nodeQueue; + nodeQueue.push(root); + + while(!nodeQueue.empty()) + { + auto curr = nodeQueue.front(); + nodeQueue.pop(); + + for (auto child : curr->children) + { + nodeQueue.push(child); + } + + delete curr; + } + } +} diff --git a/SHADE_Engine/src/Assets/Asset Types/Models/SHRigAsset.h b/SHADE_Engine/src/Assets/Asset Types/Models/SHRigAsset.h index 09ce5658..86b497ae 100644 --- a/SHADE_Engine/src/Assets/Asset Types/Models/SHRigAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/Models/SHRigAsset.h @@ -17,32 +17,30 @@ namespace SHADE { - struct RigDataHeader + struct SHRigDataHeader { uint32_t nodeCount; std::vector charCounts; }; - struct RigNodeData + struct SHRigNodeData { std::string name; SHMatrix transform; }; - struct RigNode + struct SHRigNode { uint32_t idRef; - std::vector children; + std::vector children; }; struct SH_API SHRigAsset : SHAssetData { - ~SHRigAsset() - { - delete root; - } + ~SHRigAsset(); - std::map nodeDataCollection; - RigNode* root; + SHRigDataHeader header; + std::vector nodeDataCollection; + SHRigNode* root; }; } diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHModelLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHModelLoader.cpp index e2d80821..fb809a66 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHModelLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHModelLoader.cpp @@ -13,42 +13,231 @@ #include "SHpch.h" #include "SHModelLoader.h" #include +#include namespace SHADE { - void SHModelLoader::ReadHeader(std::ifstream& file, SHMeshLoaderHeader& header) noexcept + void SHModelLoader::ReadHeaders(FileReference file, SHModelAsset& asset) { file.read( - reinterpret_cast(&header), - sizeof(SHMeshLoaderHeader) + reinterpret_cast(&asset.header), + sizeof(asset.header) + ); + + asset.meshHeaders.resize(asset.header.meshCount); + asset.animHeaders.resize(asset.header.animCount); + + file.read( + reinterpret_cast(asset.meshHeaders.data()), + sizeof(asset.header.meshCount) * sizeof(SHMeshDataHeader) + ); + + file.read( + reinterpret_cast(asset.animHeaders.data()), + sizeof(asset.header.animCount) * sizeof(SHAnimDataHeader) ); } - void SHModelLoader::ReadData(std::ifstream& file, SHMeshLoaderHeader const& header, SHMeshAsset& data) noexcept + void SHModelLoader::ReadData(FileReference file, SHModelAsset& asset) { - auto const vertexVec3Byte{ sizeof(SHVec3) * header.vertexCount }; - auto const vertexVec2Byte{ sizeof(SHVec2) * header.vertexCount }; + ReadMeshData(file, asset.meshHeaders, asset.meshes); + ReadAnimData(file, asset.animHeaders, asset.anims); - data.VertexPositions.resize(header.vertexCount); - data.VertexTangents.resize(header.vertexCount); - data.VertexNormals.resize(header.vertexCount); - data.VertexTexCoords.resize(header.vertexCount); - data.Indices.resize(header.indexCount); - data.header.name.resize(header.charCount); - - file.read(data.header.name.data(), header.charCount); - file.read(reinterpret_cast(data.VertexPositions.data()), vertexVec3Byte); - file.read(reinterpret_cast(data.VertexTangents.data()), vertexVec3Byte); - file.read(reinterpret_cast(data.VertexNormals.data()), vertexVec3Byte); - file.read(reinterpret_cast(data.VertexTexCoords.data()), vertexVec2Byte); - file.read(reinterpret_cast(data.Indices.data()), sizeof(uint32_t) * header.indexCount); - - data.header.vertexCount = header.vertexCount; - data.header.indexCount = header.indexCount; + // Not eof yet, animation exists + if (file.peek() != EOF) + { + ReadRigHeader(file, asset.rig.header); + ReadRigData(file, asset.rig.header, asset.rig.nodeDataCollection); + ReadRigTree(file, asset.rig.header, asset.rig.root); + } } - void SHModelLoader::LoadSHMesh(AssetPath path, SHModelAsset& model) noexcept + void SHModelLoader::ReadAnimNode(FileReference file, SHAnimNodeInfo const& info, SHAnimData& data) { + file.read( + data.name.data(), + info.charCount + ); + + file.read( + reinterpret_cast(&data.pre), + sizeof(SHAnimationBehaviour) + ); + + file.read( + reinterpret_cast(&data.post), + sizeof(SHAnimationBehaviour) + ); + + uint32_t keySize {0}; + file.read( + reinterpret_cast(&keySize), + sizeof(uint32_t) + ); + + data.positionKeys.resize(keySize); + data.rotationKeys.resize(keySize); + data.scaleKeys.resize(keySize); + + file.read( + reinterpret_cast(data.positionKeys.data()), + sizeof(PositionKey) * keySize + ); + + file.read( + reinterpret_cast(data.rotationKeys.data()), + sizeof(RotationKey) * keySize + ); + + file.read( + reinterpret_cast(data.scaleKeys.data()), + sizeof(ScaleKey) * keySize + ); + } + + void SHModelLoader::ReadRigHeader(FileReference file, SHRigDataHeader& header) + { + file.read( + reinterpret_cast(&header.nodeCount), + sizeof(uint32_t) + ); + + header.charCounts.resize(header.nodeCount); + file.read( + reinterpret_cast(header.charCounts.data()), + sizeof(uint32_t) * header.nodeCount + ); + } + + void SHModelLoader::ReadRigData(FileReference file, SHRigDataHeader const& header, std::vector& data) + { + data.resize(header.nodeCount); + + for (auto i {0}; i < header.nodeCount; ++i) + { + data[i].name.resize(header.charCounts[i]); + file.read( + data[i].name.data(), + header.charCounts[i] + ); + + file.read( + reinterpret_cast(&data[i].transform), + sizeof(SHMatrix) + ); + } + } + + void SHModelLoader::ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNode* root) + { + // Read All nodes into one contiguous data block + struct NodeTemp + { + uint32_t id, numChild; + }; + + NodeTemp* dst = new NodeTemp[header.nodeCount]; + + file.read( + reinterpret_cast(dst), + sizeof(NodeTemp) * header.nodeCount + ); + + // Build and populate tree + SHRigNode* nodePool = new SHRigNode[header.nodeCount]; + root = nodePool; + + std::queue> nodeQueue; + nodeQueue.emplace(std::make_pair(nodePool, dst)); + + auto depthPtr = nodePool + 1; + auto depthTempPtr = dst + 1; + + while(!nodeQueue.empty()) + { + auto currPair = nodeQueue.front(); + nodeQueue.pop(); + auto currNode = currPair.first; + auto currTemp = currPair.second; + + currNode->idRef = currTemp->id; + + for (auto i{0}; i < currTemp->numChild; ++i) + { + currNode->children.push_back(depthPtr); + nodeQueue.emplace(depthPtr++, depthTempPtr++); + } + } + } + + void SHModelLoader::ReadMeshData(FileReference file, std::vector const& headers, + std::vector& meshes) + { + meshes.resize(headers.size()); + for (auto i {0}; i < headers.size(); ++i) + { + auto const& header = headers[i]; + auto& data = *new SHMeshAsset; + + auto const vertexVec3Byte{ sizeof(SHVec3) * header.vertexCount }; + auto const vertexVec2Byte{ sizeof(SHVec2) * header.vertexCount }; + + data.name.resize(header.charCount); + data.VertexPositions.resize(header.vertexCount); + data.VertexTangents.resize(header.vertexCount); + data.VertexNormals.resize(header.vertexCount); + data.VertexTexCoords.resize(header.vertexCount); + data.Indices.resize(header.indexCount); + + file.read(data.name.data(), header.charCount); + file.read(reinterpret_cast(data.VertexPositions.data()), vertexVec3Byte); + file.read(reinterpret_cast(data.VertexTangents.data()), vertexVec3Byte); + file.read(reinterpret_cast(data.VertexNormals.data()), vertexVec3Byte); + file.read(reinterpret_cast(data.VertexTexCoords.data()), vertexVec2Byte); + file.read(reinterpret_cast(data.Indices.data()), sizeof(uint32_t) * header.indexCount); + + meshes[i] = &data; + } + } + + void SHModelLoader::ReadAnimData(FileReference file, std::vector const& headers, + std::vector& anims) + { + anims.resize(headers.size()); + for (auto i {0}; i < headers.size(); ++i) + { + auto const& header = headers[i]; + auto& animAsset = *new SHAnimAsset; + + file.read( + animAsset.name.data(), + header.charCount + ); + + file.read( + reinterpret_cast(&animAsset.duration), + sizeof(double) + ); + + file.read( + reinterpret_cast(&animAsset.ticksPerSecond), + sizeof(double) + ); + + animAsset.nodeChannels.resize(header.animNodeCount); + for (auto i {0}; i < header.animNodeCount; ++i) + { + ReadAnimNode(file, header.nodeHeaders[i], animAsset.nodeChannels[i]); + } + + anims[i] = &animAsset; + } + } + + SHAssetData* SHModelLoader::Load(AssetPath path) + { + auto result = new SHModelAsset(); + std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; if (!file.is_open()) { @@ -58,29 +247,10 @@ namespace SHADE file.seekg(0); - //TODO Update to new mesh header with anim count when animation saving is done - file.read( - reinterpret_cast(&model.header.meshCount), - sizeof(model.header.meshCount) - ); + ReadHeaders(file, *result); + ReadData(file, *result); - std::vector headers(model.header.meshCount); - model.meshes.resize(model.header.meshCount); - - for (auto i{ 0 }; i < model.header.meshCount; ++i) - { - model.meshes[i] = new SHMeshAsset(); - ReadHeader(file, headers[i]); - ReadData(file, headers[i], *model.meshes[i]); - } file.close(); - } - - SHAssetData* SHModelLoader::Load(AssetPath path) - { - auto result = new SHModelAsset(); - - LoadSHMesh(path, *result); return result; } diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHModelLoader.h b/SHADE_Engine/src/Assets/Libraries/Loaders/SHModelLoader.h index 2074169c..05e58b6c 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHModelLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHModelLoader.h @@ -18,19 +18,20 @@ namespace SHADE { class SHModelLoader : public SHAssetLoader { - struct SHMeshLoaderHeader - { - uint32_t vertexCount; - uint32_t indexCount; - uint32_t charCount; - }; + using FileReference = std::ifstream&; + + void ReadAnimNode(FileReference file, SHAnimNodeInfo const& info, SHAnimData& data); + void ReadRigHeader(FileReference file, SHRigDataHeader& header); + void ReadRigData(FileReference file, SHRigDataHeader const& header, std::vector& data); + void ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNode* root); + + void ReadMeshData(FileReference file, std::vector const& headers, std::vector& meshes); + void ReadAnimData(FileReference file, std::vector const& headers, std::vector& anims); - void ReadHeader(std::ifstream& file, SHMeshLoaderHeader& header) noexcept; - void ReadData(std::ifstream& file, SHMeshLoaderHeader const& header, SHMeshAsset& data) noexcept; - + void ReadHeaders(FileReference file, SHModelAsset& asset); + void ReadData(FileReference file, SHModelAsset& asset); public: - void LoadSHMesh(AssetPath path, SHModelAsset& model) noexcept; SHAssetData* Load(AssetPath path) override; void Write(SHAssetData const* data, AssetPath path) override; };