Updated Loading of .shmodel files and updated original models #303

Merged
XiaoQiDigipen merged 9 commits from Model-Loader-Update into SP3-17-animation-system 2023-01-08 12:40:01 +08:00
6 changed files with 263 additions and 67 deletions
Showing only changes of commit ab766d9304 - Show all commits

View File

@ -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<SHVec3> VertexPositions;
std::vector<SHVec3> VertexTangents;
std::vector<SHVec3> VertexNormals;

View File

@ -29,9 +29,11 @@ namespace SHADE
struct SH_API SHModelAsset : SHAssetData
{
SHModelAssetHeader header;
SHRigAsset rig;
std::vector<SHMeshDataHeader> meshHeaders;
std::vector<SHAnimDataHeader> animHeaders;
std::vector<SHMeshAsset*> meshes;
std::vector<SHAnimAsset*> anims;
};

View File

@ -0,0 +1,26 @@
#include "SHpch.h"
#include "SHRigAsset.h"
#include <queue>
namespace SHADE
{
SHRigAsset::~SHRigAsset()
{
std::queue<SHRigNode*> nodeQueue;
nodeQueue.push(root);
while(!nodeQueue.empty())
{
auto curr = nodeQueue.front();
nodeQueue.pop();
for (auto child : curr->children)
{
nodeQueue.push(child);
}
delete curr;
}
}
}

View File

@ -17,32 +17,30 @@
namespace SHADE
{
struct RigDataHeader
struct SHRigDataHeader
{
uint32_t nodeCount;
std::vector<uint32_t> charCounts;
};
struct RigNodeData
struct SHRigNodeData
{
std::string name;
SHMatrix transform;
};
struct RigNode
struct SHRigNode
{
uint32_t idRef;
std::vector<RigNode*> children;
std::vector<SHRigNode*> children;
};
struct SH_API SHRigAsset : SHAssetData
{
~SHRigAsset()
{
delete root;
}
~SHRigAsset();
std::map<uint32_t, RigNodeData> nodeDataCollection;
RigNode* root;
SHRigDataHeader header;
std::vector<SHRigNodeData> nodeDataCollection;
SHRigNode* root;
};
}

View File

@ -13,42 +13,231 @@
#include "SHpch.h"
#include "SHModelLoader.h"
#include <fstream>
#include <queue>
namespace SHADE
{
void SHModelLoader::ReadHeader(std::ifstream& file, SHMeshLoaderHeader& header) noexcept
void SHModelLoader::ReadHeaders(FileReference file, SHModelAsset& asset)
{
file.read(
reinterpret_cast<char*>(&header),
sizeof(SHMeshLoaderHeader)
reinterpret_cast<char*>(&asset.header),
sizeof(asset.header)
);
asset.meshHeaders.resize(asset.header.meshCount);
asset.animHeaders.resize(asset.header.animCount);
file.read(
reinterpret_cast<char*>(asset.meshHeaders.data()),
sizeof(asset.header.meshCount) * sizeof(SHMeshDataHeader)
);
file.read(
reinterpret_cast<char*>(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<char*>(data.VertexPositions.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexTangents.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexNormals.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexTexCoords.data()), vertexVec2Byte);
file.read(reinterpret_cast<char*>(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<char*>(&data.pre),
sizeof(SHAnimationBehaviour)
);
file.read(
reinterpret_cast<char*>(&data.post),
sizeof(SHAnimationBehaviour)
);
uint32_t keySize {0};
file.read(
reinterpret_cast<char*>(&keySize),
sizeof(uint32_t)
);
data.positionKeys.resize(keySize);
data.rotationKeys.resize(keySize);
data.scaleKeys.resize(keySize);
file.read(
reinterpret_cast<char*>(data.positionKeys.data()),
sizeof(PositionKey) * keySize
);
file.read(
reinterpret_cast<char*>(data.rotationKeys.data()),
sizeof(RotationKey) * keySize
);
file.read(
reinterpret_cast<char*>(data.scaleKeys.data()),
sizeof(ScaleKey) * keySize
);
}
void SHModelLoader::ReadRigHeader(FileReference file, SHRigDataHeader& header)
{
file.read(
reinterpret_cast<char*>(&header.nodeCount),
sizeof(uint32_t)
);
header.charCounts.resize(header.nodeCount);
file.read(
reinterpret_cast<char*>(header.charCounts.data()),
sizeof(uint32_t) * header.nodeCount
);
}
void SHModelLoader::ReadRigData(FileReference file, SHRigDataHeader const& header, std::vector<SHRigNodeData>& 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<char*>(&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<char*>(dst),
sizeof(NodeTemp) * header.nodeCount
);
// Build and populate tree
SHRigNode* nodePool = new SHRigNode[header.nodeCount];
root = nodePool;
std::queue<std::pair<SHRigNode*, NodeTemp*>> 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<SHMeshDataHeader> const& headers,
std::vector<SHMeshAsset*>& 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<char*>(data.VertexPositions.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexTangents.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexNormals.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexTexCoords.data()), vertexVec2Byte);
file.read(reinterpret_cast<char*>(data.Indices.data()), sizeof(uint32_t) * header.indexCount);
meshes[i] = &data;
}
}
void SHModelLoader::ReadAnimData(FileReference file, std::vector<SHAnimDataHeader> const& headers,
std::vector<SHAnimAsset*>& 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<char*>(&animAsset.duration),
sizeof(double)
);
file.read(
reinterpret_cast<char*>(&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<char*>(&model.header.meshCount),
sizeof(model.header.meshCount)
);
ReadHeaders(file, *result);
ReadData(file, *result);
std::vector<SHMeshLoaderHeader> 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;
}

View File

@ -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<SHRigNodeData>& data);
void ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNode* root);
void ReadMeshData(FileReference file, std::vector<SHMeshDataHeader> const& headers, std::vector<SHMeshAsset*>& meshes);
void ReadAnimData(FileReference file, std::vector<SHAnimDataHeader> const& headers, std::vector<SHAnimAsset*>& 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;
};