diff --git a/SHADE_Engine/SHAnimationAsset.h b/SHADE_Engine/SHAnimationAsset.h new file mode 100644 index 00000000..d8d0ffb1 --- /dev/null +++ b/SHADE_Engine/SHAnimationAsset.h @@ -0,0 +1,30 @@ +/*************************************************************************//** + * \file SHAnimationAsset.h + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once + +#include +#include +#include "SH_API.power h" + +namespace SHADE +{ + struct SH_API SHAnimationAsset + { + std::string name; + + std::vector nodeChannels; + std::vector meshChannels; + std::vector morphMeshChannels; + + double duration; + double ticksPerSecond; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h new file mode 100644 index 00000000..76f4c0ac --- /dev/null +++ b/SHADE_Engine/src/Assets/Asset Types/SHAnimationAsset.h @@ -0,0 +1,30 @@ +/*************************************************************************//** + * \file SHAnimationAsset.h + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#pragma once + +#include +#include +#include "SH_API.h" + +namespace SHADE +{ + struct SH_API SHAnimationAsset + { + std::string name; + + std::vector nodeChannels; + std::vector meshChannels; + std::vector morphMeshChannels; + + double duration; + double ticksPerSecond; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp new file mode 100644 index 00000000..feea9f35 --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.cpp @@ -0,0 +1,143 @@ +/*************************************************************************//** + * \file SHAssimpLibrary.cpp + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ +#include "SHpch.h" +#include "SHAssimpLibrary.h" +#include + +namespace SHADE +{ + Assimp::Importer SHAssimpLibrary::aiImporter; + + void SHAssimpLibrary::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept + { + for (size_t i {0}; i < node.mNumMeshes; ++i) + { + aiMesh* mesh = scene.mMeshes[node.mMeshes[i]]; + meshes.push_back(ProcessMesh(*mesh)); + } + + for (size_t i{ 0 }; i < node.mNumChildren; ++i) + { + ProcessNode(*node.mChildren[i], scene, meshes); + } + } + + void SHAssimpLibrary::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept + { + if (scene.HasAnimations()) + { + std::vector anims(scene.mNumAnimations); + for (auto i{0}; i < scene.mNumAnimations; ++i) + { + auto const& anim {*scene.mAnimations[i]}; + + anims[i].name = anim.mName.C_Str(); + + anims[i].duration = anim.mDuration; + anims[i].ticksPerSecond = anim.mTicksPerSecond; + + std::copy_n(anim.mChannels, anim.mNumChannels, anims[i].nodeChannels.data()); + std::copy_n(anim.mMeshChannels, anim.mNumMeshChannels, anims[i].meshChannels.data()); + std::copy_n(anim.mMorphMeshChannels, anim.mNumMorphMeshChannels, anims[i].morphMeshChannels.data()); + } + } + } + + SHMeshAsset SHAssimpLibrary::ProcessMesh(aiMesh const& mesh) noexcept + { + SHMeshAsset result + { + .compiled { false}, + .changed { false } + }; + + for (size_t i{0}; i < mesh.mNumVertices; ++i) + { + // Vertex position + SHVec3 vertex; + vertex.x = mesh.mVertices[i].x; + vertex.y = mesh.mVertices[i].y; + vertex.z = mesh.mVertices[i].z; + result.vertexPosition.push_back(vertex); + + // Tex coords + SHVec2 texCoord{0.f, 0.f}; + if (mesh.mTextureCoords[0]) + { + texCoord.x = mesh.mTextureCoords[0][i].x; + texCoord.y = mesh.mTextureCoords[0][i].y; + } + result.texCoords.push_back(texCoord); + + // Normals + SHVec3 normal{0.f, 0.f, 0.f}; + if (mesh.mNormals) + { + normal.x = mesh.mNormals[i].x; + normal.y = mesh.mNormals[i].y; + normal.z = mesh.mNormals[i].z; + } + result.vertexNormal.push_back(normal); + + // Tangent + SHVec3 tangent{0.f, 0.f, 0.f}; + if (mesh.mTangents) + { + tangent.x = mesh.mTangents[i].x; + tangent.y = mesh.mTangents[i].y; + tangent.z = mesh.mTangents[i].z; + } + result.vertexTangent.push_back(tangent); + } + + for (size_t i {0}; i < mesh.mNumFaces; ++i) + { + aiFace face = mesh.mFaces[i]; + for (size_t j{0}; j < face.mNumIndices; ++j) + { + result.indices.push_back(face.mIndices[j]); + } + } + + result.header.vertexCount = static_cast(result.vertexPosition.size()); + result.header.indexCount = static_cast(result.indices.size()); + result.header.meshName = mesh.mName.C_Str(); + + return result; + } + + void SHAssimpLibrary::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) 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_RemoveRedundantMaterials // remove redundant materials + | aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors + | aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs + ); + + if (!scene || !scene->HasMeshes()) + { + SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string()); + return; + } + + ExtractAnimations(*scene, anims); + + ProcessNode(*scene->mRootNode, *scene, meshes); + + aiImporter.FreeScene(); + } +} diff --git a/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h new file mode 100644 index 00000000..a4a0447a --- /dev/null +++ b/SHADE_Engine/src/Assets/Libraries/SHAssimpLibrary.h @@ -0,0 +1,36 @@ +/*************************************************************************//** + * \file SHAssimpLibrary.h + * \author Loh Xiao Qi + * \date October 2022 + * \brief + * + * Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or + * disclosure of this file or its contents without the prior written consent + * of DigiPen Institute of Technology is prohibited. + *****************************************************************************/ + +#pragma once +#include +#include +#include +#include "../SHAssetMacros.h" +#include "../Asset Types/SHMeshAsset.h" +#include "../Asset Types/SHAnimationAsset.h" + +namespace SHADE +{ + class SHAssimpLibrary + { + private: + using MeshVectorRef = std::vector&; + using AnimVectorRef = std::vector&; + + static Assimp::Importer aiImporter; + static void ProcessNode(aiNode const& node, aiScene const& scene,MeshVectorRef meshes) noexcept; + static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept; + static SHMeshAsset ProcessMesh(aiMesh const& mesh) noexcept; + + public: + static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp index 4bfa2d9b..73fed1fb 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.cpp @@ -12,128 +12,10 @@ *****************************************************************************/ #include "SHpch.h" #include "SHMeshLoader.h" -#include #include namespace SHADE { - Assimp::Importer SHMeshLoader::aiImporter; - - void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector& meshes) noexcept - { - for (size_t i {0}; i < node.mNumMeshes; ++i) - { - aiMesh* mesh = scene.mMeshes[node.mMeshes[i]]; - meshes.push_back(ProcessMesh(*mesh, scene)); - } - - for (size_t i{ 0 }; i < node.mNumChildren; ++i) - { - ProcessNode(*node.mChildren[i], scene, meshes); - } - } - - SHMeshAsset SHMeshLoader::ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept - { - (void)scene; - - SHMeshAsset result - { - .compiled { false}, - .changed { false } - }; - - for (size_t i{0}; i < mesh.mNumVertices; ++i) - { - // Vertex position - SHVec3 vertex; - vertex.x = mesh.mVertices[i].x; - vertex.y = mesh.mVertices[i].y; - vertex.z = mesh.mVertices[i].z; - result.vertexPosition.push_back(vertex); - - // Tex coords - SHVec2 texCoord{0.f, 0.f}; - if (mesh.mTextureCoords[0]) - { - texCoord.x = mesh.mTextureCoords[0][i].x; - texCoord.y = mesh.mTextureCoords[0][i].y; - } - result.texCoords.push_back(texCoord); - - // Normals - SHVec3 normal{0.f, 0.f, 0.f}; - if (mesh.mNormals) - { - normal.x = mesh.mNormals[i].x; - normal.y = mesh.mNormals[i].y; - normal.z = mesh.mNormals[i].z; - } - result.vertexNormal.push_back(normal); - - // Tangent - SHVec3 tangent{0.f, 0.f, 0.f}; - if (mesh.mTangents) - { - tangent.x = mesh.mTangents[i].x; - tangent.y = mesh.mTangents[i].y; - tangent.z = mesh.mTangents[i].z; - } - result.vertexTangent.push_back(tangent); - } - - for (size_t i {0}; i < mesh.mNumFaces; ++i) - { - aiFace face = mesh.mFaces[i]; - for (size_t j{0}; j < face.mNumIndices; ++j) - { - result.indices.push_back(face.mIndices[j]); - } - } - - result.header.vertexCount = static_cast(result.vertexPosition.size()); - result.header.indexCount = static_cast(result.indices.size()); - result.header.meshName = mesh.mName.C_Str(); - - return result; - } - - void SHMeshLoader::LoadExternal(std::vector& meshes, AssetPath path) 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_RemoveRedundantMaterials // remove redundant materials - | aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors - | aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs - ); - - if (!scene || !scene->HasMeshes()) - { - SHLOG_ERROR("ERROR in GLTF::ASSIMP: {}\nFile: {}", aiImporter.GetErrorString(), path.string()); - return; - } - - //TODO MATERIALS FROM MESHES - //if (scene->HasMaterials()) - //{ - // for (int i{0}; i < scene->mNumMaterials; ++i) - // { - // if (scene->mMaterials[i]->mNumProperties > 0) - // { - // for (int j{0}; j < scene->mMaterials[i]->mProperties[j].) - // } - //std::cout << scene->mMaterials[i]->; - // } - //} - - ProcessNode(*scene->mRootNode, *scene, meshes); - } - void SHMeshLoader::LoadSHMesh(SHMeshAsset& mesh, AssetPath path) noexcept { std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; @@ -168,38 +50,6 @@ namespace SHADE file.read(reinterpret_cast(vertNorm.data()), vertexVec3Byte); file.read(reinterpret_cast(texCoord.data()), vertexVec2Byte); file.read(reinterpret_cast(indices.data()), sizeof(uint32_t) * indexCount); - - //for (auto i{ 0 }; i < vertCount; ++i) - //{ - // file >> vertPos[i].x; - // file >> vertPos[i].y; - // file >> vertPos[i].z; - //} - // - //for (auto i{ 0 }; i < vertCount; ++i) - //{ - // file >> vertTan[i].x; - // file >> vertTan[i].y; - // file >> vertTan[i].z; - //} - - //for (auto i{ 0 }; i < vertCount; ++i) - //{ - // file >> vertNorm[i].x; - // file >> vertNorm[i].y; - // file >> vertNorm[i].z; - //} - - //for (auto i{ 0 }; i < vertCount; ++i) - //{ - // file >> texCoord[i].x; - // file >> texCoord[i].y; - //} - - //for (auto i{ 0 }; i < indexCount; ++i) - //{ - // file >> indices[i]; - //} mesh.compiled = true; mesh.changed = false; @@ -216,16 +66,4 @@ namespace SHADE file.close(); } - - void SHMeshLoader::LoadMesh(std::vector& meshes, AssetPath path) noexcept - { - if (path.extension().string() == GLTF_EXTENSION) - { - LoadExternal(meshes, path); - return; - } - - meshes.emplace_back(); - LoadSHMesh(meshes.back(), path); - } } diff --git a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h index a27d63ea..f01b942a 100644 --- a/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h +++ b/SHADE_Engine/src/Assets/Libraries/SHMeshLoader.h @@ -10,27 +10,13 @@ * of DigiPen Institute of Technology is prohibited. *****************************************************************************/ #pragma once -#include -#include #include "../SHAssetMacros.h" #include "../Asset Types/SHMeshAsset.h" -#include namespace SHADE { - class SHMeshLoader + struct SHMeshLoader { - private: - static Assimp::Importer aiImporter; - - static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector& meshes) noexcept; - - static SHMeshAsset ProcessMesh(aiMesh const& mesh, aiScene const& scene) noexcept; - - static void LoadExternal(std::vector& meshes, AssetPath path) noexcept; - - public: - static void LoadMesh(std::vector& meshes, AssetPath path) noexcept; static void LoadSHMesh(SHMeshAsset& meshes, AssetPath path) noexcept; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp index aa9772dd..faca24b2 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.cpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp @@ -14,6 +14,7 @@ #include "SHAssetMetaHandler.h" #include "Filesystem/SHFileSystem.h" +#include "Libraries/SHAssimpLibrary.h" #include "Libraries/SHMeshLoader.h" #include "Libraries/SHTextureLoader.h" @@ -200,38 +201,38 @@ namespace SHADE } - void SHAssetManager::LoadDataTemp(std::string p) noexcept - { - AssetPath path{ p }; + //void SHAssetManager::LoadDataTemp(std::string p) noexcept + //{ + // AssetPath path{ p }; - if (path.extension().string() == FBX_EXTENSION - || path.extension().string() == GLTF_EXTENSION - || path.extension().string() == MESH_EXTENSION) - { - LoadGLTF( - { - .name {path.filename().string()}, - .id {0}, - .type {AssetType::MESH}, - .path {path}, - .location {0} - } - ); - } - else if (path.extension().string() == DDS_EXTENSION - || path.extension().string() == TEXTURE_EXTENSION) - { - LoadDDS( - { - .name {path.filename().string()}, - .id {0}, - .type {AssetType::DDS}, - .path {path}, - .location {0} - } - ); - } - } + // if (path.extension().string() == FBX_EXTENSION + // || path.extension().string() == GLTF_EXTENSION + // || path.extension().string() == MESH_EXTENSION) + // { + // LoadGLTF( + // { + // .name {path.filename().string()}, + // .id {0}, + // .type {AssetType::MESH}, + // .path {path}, + // .location {0} + // } + // ); + // } + // else if (path.extension().string() == DDS_EXTENSION + // || path.extension().string() == TEXTURE_EXTENSION) + // { + // LoadDDS( + // { + // .name {path.filename().string()}, + // .id {0}, + // .type {AssetType::DDS}, + // .path {path}, + // .location {0} + // } + // ); + // } + //} std::vector SHAssetManager::GetAllMeshes() noexcept { @@ -319,11 +320,12 @@ namespace SHADE return false; } - void SHAssetManager::LoadGLTF(SHAsset asset) noexcept + void SHAssetManager::LoadGLTF(AssetPath path) noexcept { std::vector meshes; - - SHMeshLoader::LoadMesh(meshes, asset.path); + std::vector anims; + + SHAssimpLibrary::LoadFromFile(path, meshes, anims); for (auto const& mesh : meshes) { @@ -333,7 +335,7 @@ namespace SHADE AssetPath path; if (!mesh.compiled) { - path = SHMeshCompiler::CompileMeshBinary(mesh, asset.path); + path = SHMeshCompiler::CompileMeshBinary(mesh, path); } assetCollection.emplace_back( @@ -344,6 +346,11 @@ namespace SHADE 0 ); } + + for (auto const& anim : anims) + { + //TODO Register anim resource and compile into binary + } } void SHAssetManager::LoadDDS(SHAsset asset) noexcept diff --git a/SHADE_Engine/src/Assets/SHAssetManager.h b/SHADE_Engine/src/Assets/SHAssetManager.h index 50549e01..b2c4216b 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.h +++ b/SHADE_Engine/src/Assets/SHAssetManager.h @@ -71,12 +71,16 @@ namespace SHADE // -------------------------------------------------------------------------/ //TODO: TEMPORARY FOR TESTING GLTF & DDS - static void LoadDataTemp(std::string path) noexcept; + //static void LoadDataTemp(std::string path) noexcept; static std::vector GetAllMeshes() noexcept; static std::vector GetAllTextures() noexcept; static SHMeshAsset const* GetMesh(AssetID id) noexcept; static SHTextureAsset const* GetTexture(AssetID id) noexcept; + + // Specialised load calls + static void LoadGLTF(AssetPath path) noexcept; + static void LoadDDS(SHAsset asset) noexcept; private: /**************************************************************************** * \brief Load resource data into memory @@ -118,9 +122,6 @@ namespace SHADE static bool IsRecognised(char const*) noexcept; - // Specialised load calls - static void LoadGLTF(SHAsset asset) noexcept; - static void LoadDDS(SHAsset asset) noexcept; static FMOD::System* audioSystem; static std::unordered_map* audioSoundList;