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
24 changed files with 1210 additions and 2964 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -73,7 +73,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
Handle<SHRig::Node> SHRig::recurseCreateNode(const SHRigAsset& asset, const RigNode* sourceNode) Handle<SHRig::Node> SHRig::recurseCreateNode(const SHRigAsset& asset, const SHRigNode* sourceNode)
{ {
// Construct the node // Construct the node
auto newNode = nodeStore.Create(); auto newNode = nodeStore.Create();

View File

@ -27,7 +27,7 @@ namespace SHADE
/* Forward Declarations */ /* Forward Declarations */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
struct SHRigAsset; struct SHRigAsset;
struct RigNode; struct SHRigNode;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -99,6 +99,6 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Handle<Node> recurseCreateNode(const SHRigAsset& asset, const RigNode* sourceNode); Handle<Node> recurseCreateNode(const SHRigAsset& asset, const SHRigNode* sourceNode);
}; };
} }

View File

@ -24,7 +24,6 @@ namespace SHADE
uint32_t indexCount; uint32_t indexCount;
uint32_t charCount; uint32_t charCount;
uint32_t boneCount; uint32_t boneCount;
std::string name;
}; };
struct MeshBoneInfo struct MeshBoneInfo
@ -48,7 +47,7 @@ namespace SHADE
struct SH_API SHMeshAsset : SHAssetData struct SH_API SHMeshAsset : SHAssetData
{ {
SHMeshDataHeader header; std::string name;
std::vector<SHVec3> VertexPositions; std::vector<SHVec3> VertexPositions;
std::vector<SHVec3> VertexTangents; std::vector<SHVec3> VertexTangents;
std::vector<SHVec3> VertexNormals; std::vector<SHVec3> VertexNormals;

View File

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

View File

@ -0,0 +1,31 @@
#include "SHpch.h"
#include "SHRigAsset.h"
#include <queue>
namespace SHADE
{
SHRigAsset::~SHRigAsset()
{
if (root == nullptr)
{
return;
}
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 namespace SHADE
{ {
struct RigDataHeader struct SHRigDataHeader
{ {
uint32_t nodeCount; uint32_t nodeCount;
std::vector<uint32_t> charCounts; std::vector<uint32_t> charCounts;
}; };
struct RigNodeData struct SHRigNodeData
{ {
std::string name; std::string name;
SHMatrix transform; SHMatrix transform;
}; };
struct RigNode struct SHRigNode
{ {
uint32_t idRef; uint32_t idRef;
std::vector<RigNode*> children; std::vector<SHRigNode*> children;
}; };
struct SH_API SHRigAsset : SHAssetData struct SH_API SHRigAsset : SHAssetData
{ {
~SHRigAsset() ~SHRigAsset();
{
delete root;
}
std::map<uint32_t, RigNodeData> nodeDataCollection; SHRigDataHeader header;
RigNode* root; std::vector<SHRigNodeData> nodeDataCollection;
SHRigNode* root;
}; };
} }

View File

@ -13,74 +13,268 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHModelLoader.h" #include "SHModelLoader.h"
#include <fstream> #include <fstream>
#include <queue>
namespace SHADE namespace SHADE
{ {
void SHModelLoader::ReadHeader(std::ifstream& file, SHMeshLoaderHeader& header) noexcept void SHModelLoader::ReadHeaders(FileReference file, SHModelAsset& asset)
{ {
file.read( file.read(
reinterpret_cast<char*>(&header), reinterpret_cast<char*>(&asset.header),
sizeof(SHMeshLoaderHeader) sizeof(asset.header)
);
if (asset.header.meshCount > 0)
{
asset.meshHeaders.resize(asset.header.meshCount);
file.read(
reinterpret_cast<char*>(asset.meshHeaders.data()),
asset.header.meshCount * sizeof(SHMeshDataHeader)
);
}
if (asset.header.animCount > 0)
{
asset.animHeaders.resize(asset.header.animCount);
for (auto i {0}; i < asset.header.animCount; ++i)
{
auto& animHeader = asset.animHeaders[i];
file.read(
reinterpret_cast<char*>(&animHeader.charCount),
sizeof(uint32_t)
);
file.read(
reinterpret_cast<char*>(&animHeader.animNodeCount),
sizeof(uint32_t)
);
animHeader.nodeHeaders.resize(animHeader.animNodeCount);
for (auto j {0}; j < animHeader.animNodeCount; ++j)
{
auto& nodeHeader = animHeader.nodeHeaders[j];
file.read(
reinterpret_cast<char*>(&nodeHeader),
sizeof(SHAnimNodeInfo)
);
}
}
}
}
void SHModelLoader::ReadData(FileReference file, SHModelAsset& asset)
{
ReadMeshData(file, asset.meshHeaders, asset.meshes);
ReadAnimData(file, asset.animHeaders, asset.anims);
// 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::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::ReadData(std::ifstream& file, SHMeshLoaderHeader const& header, SHMeshAsset& data) noexcept void SHModelLoader::ReadRigHeader(FileReference file, SHRigDataHeader& header)
{ {
auto const vertexVec3Byte{ sizeof(SHVec3) * header.vertexCount }; file.read(
auto const vertexVec2Byte{ sizeof(SHVec2) * header.vertexCount }; reinterpret_cast<char*>(&header.nodeCount),
sizeof(uint32_t)
);
data.VertexPositions.resize(header.vertexCount); header.charCounts.resize(header.nodeCount);
data.VertexTangents.resize(header.vertexCount); file.read(
data.VertexNormals.resize(header.vertexCount); reinterpret_cast<char*>(header.charCounts.data()),
data.VertexTexCoords.resize(header.vertexCount); sizeof(uint32_t) * header.nodeCount
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;
} }
void SHModelLoader::LoadSHMesh(AssetPath path, SHModelAsset& model) noexcept 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;
animAsset.name.resize(header.charCount);
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 }; std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open()) if (!file.is_open())
{ {
SHLOG_ERROR("[Model Loader] Unable to open SHModel File: {}", path.string()); SHLOG_ERROR("[Model Loader] Unable to open SHModel File: {}", path.string());
return; return nullptr;
} }
file.seekg(0); ReadHeaders(file, *result);
ReadData(file, *result);
//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)
);
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(); file.close();
}
SHAssetData* SHModelLoader::Load(AssetPath path)
{
auto result = new SHModelAsset();
LoadSHMesh(path, *result);
return result; return result;
} }

View File

@ -18,19 +18,20 @@ namespace SHADE
{ {
class SHModelLoader : public SHAssetLoader class SHModelLoader : public SHAssetLoader
{ {
struct SHMeshLoaderHeader using FileReference = std::ifstream&;
{
uint32_t vertexCount;
uint32_t indexCount;
uint32_t charCount;
};
void ReadAnimNode(FileReference file, SHAnimNodeInfo const& info, SHAnimData& data);
void ReadHeader(std::ifstream& file, SHMeshLoaderHeader& header) noexcept; void ReadRigHeader(FileReference file, SHRigDataHeader& header);
void ReadData(std::ifstream& file, SHMeshLoaderHeader const& header, SHMeshAsset& data) noexcept; 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 ReadHeaders(FileReference file, SHModelAsset& asset);
void ReadData(FileReference file, SHModelAsset& asset);
public: public:
void LoadSHMesh(AssetPath path, SHModelAsset& model) noexcept;
SHAssetData* Load(AssetPath path) override; SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override; void Write(SHAssetData const* data, AssetPath path) override;
}; };

View File

@ -437,7 +437,7 @@ namespace SHADE
return; return;
} }
if (genMeta) if (true)
{ {
GenerateNewMeta(newPath); GenerateNewMeta(newPath);
} }
@ -492,8 +492,8 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Load() noexcept void SHAssetManager::Load() noexcept
{ {
BuildAssetCollection();
InitLoaders(); InitLoaders();
BuildAssetCollection();
//CompileAll(); //CompileAll();
//LoadAllData(); //LoadAllData();
} }
@ -610,7 +610,7 @@ namespace SHADE
for(auto const& subMesh : data->meshes) for(auto const& subMesh : data->meshes)
{ {
SHAsset subAsset{ SHAsset subAsset{
.name = subMesh->header.name, .name = subMesh->name,
.id = GenerateAssetID(AssetType::MESH), .id = GenerateAssetID(AssetType::MESH),
.type = AssetType::MESH, .type = AssetType::MESH,
.isSubAsset = true, .isSubAsset = true,

View File

@ -6,6 +6,11 @@ namespace SHADE
template<typename T> template<typename T>
std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T* const> SHAssetManager::GetData(AssetID id) noexcept std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T* const> SHAssetManager::GetData(AssetID id) noexcept
{ {
if (id == 0)
{
return nullptr;
}
if (!assetData.contains(id)) if (!assetData.contains(id))
{ {
for (auto const& asset : std::ranges::views::values(assetCollection)) for (auto const& asset : std::ranges::views::values(assetCollection))