From 70b6045453741916d7d17c4f18a9c07908926a2d Mon Sep 17 00:00:00 2001 From: Xiao Qi Date: Wed, 19 Oct 2022 18:37:27 +0800 Subject: [PATCH] Ported all mesh and animation asset related file into repo Created premake to build solution and project Changed loader and compiler to be self contained and take in paths relative to "local" --- .gitignore | 10 ++ Assimp Compile Application/main.cpp | 47 ++++++ Assimp Compile Application/premake5.lua | 60 +++++++ .../src/Libraries/SHAssimpLibrary.cpp | 148 ++++++++++++++++++ .../src/Libraries/SHAssimpLibrary.h | 39 +++++ .../src/Libraries/SHMeshCompiler.cpp | 70 +++++++++ .../src/Libraries/SHMeshCompiler.h | 26 +++ .../src/SHAssetMacros.h | 105 +++++++++++++ .../src/Types/SHAnimationAsset.h | 29 ++++ .../src/Types/SHMeshAsset.h | 52 ++++++ Dependencies.bat | 2 + generate.bat | 5 + premake5.lua | 22 +++ 13 files changed, 615 insertions(+) create mode 100644 Assimp Compile Application/main.cpp create mode 100644 Assimp Compile Application/premake5.lua create mode 100644 Assimp Compile Application/src/Libraries/SHAssimpLibrary.cpp create mode 100644 Assimp Compile Application/src/Libraries/SHAssimpLibrary.h create mode 100644 Assimp Compile Application/src/Libraries/SHMeshCompiler.cpp create mode 100644 Assimp Compile Application/src/Libraries/SHMeshCompiler.h create mode 100644 Assimp Compile Application/src/SHAssetMacros.h create mode 100644 Assimp Compile Application/src/Types/SHAnimationAsset.h create mode 100644 Assimp Compile Application/src/Types/SHMeshAsset.h create mode 100644 Dependencies.bat create mode 100644 generate.bat create mode 100644 premake5.lua diff --git a/.gitignore b/.gitignore index dfcfd56..d104d42 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,13 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ + +*.vcxproj + +*.filters + +Premake/ + +Dependencies/assimp + +*.sln diff --git a/Assimp Compile Application/main.cpp b/Assimp Compile Application/main.cpp new file mode 100644 index 0000000..c1ca2fd --- /dev/null +++ b/Assimp Compile Application/main.cpp @@ -0,0 +1,47 @@ +#include "Types/SHAnimationAsset.h" +#include "Types/SHMeshAsset.h" + +#include "Libraries/SHAssimpLibrary.h" +#include "Libraries/SHMeshCompiler.h" + +#include +#include + +int main(int argc, char* argv[]) +{ + SHADE::MeshVector meshes; + SHADE::AnimVector anims; + + std::vector paths; + + if (argc == 1) + { + + for (auto const& dir : std::filesystem::recursive_directory_iterator{"./Assets/"}) + { + if (dir.path().extension().string() == GLTF_EXTENSION) + { + paths.push_back(dir.path().string()); + } + } + } + else if (argc > 1) + { + for (int i { 1 }; i < argc; ++i) + { + paths.emplace_back(argv[i]); + } + } + + for (auto const& path : paths) + { + SHADE::SHAssimpLibrary::LoadFromFile(path, meshes, anims); + } + + for (auto const& mesh : meshes) + { + SHADE::SHMeshCompiler::CompileMeshBinary(mesh); + } + + return 0; +} diff --git a/Assimp Compile Application/premake5.lua b/Assimp Compile Application/premake5.lua new file mode 100644 index 0000000..f6ffd32 --- /dev/null +++ b/Assimp Compile Application/premake5.lua @@ -0,0 +1,60 @@ +project "Assimp Compile Library" + kind "ConsoleApp" + language "C++" + cppdialect "C++20" + targetdir (outputdir) + objdir (interdir) + systemversion "latest" + + files + { + "%{prj.location}/src/**.h", + "%{prj.location}/src/**.cpp", + } + + externalincludedirs + { + "%{IncludeDir.assimp}\\include" + } + + includedirs + { + "%{prj.location}/src", + } + + externalwarnings "Off" + + libdirs + { + "%{IncludeDir.assimp}/lib/Debug", + "%{IncludeDir.assimp}/lib/Release" + } + + flags + { + "MultiProcessorCompile" + } + + filter "configurations:Debug" + postbuildcommands + { + "xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Debug\\assimp-vc142-mtd.dll\" \"$(OutDir)\"" + } + + filter "configurations:Release" + postbuildcommands + { + "xcopy /r /y /q \"%{IncludeDir.assimp}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\"" + } + + warnings 'Extra' + + filter "configurations:Debug" + symbols "On" + defines {"_DEBUG", "SHEDITOR"} + links{"assimp-vc142-mtd.lib"} + + filter "configurations:Release" + optimize "On" + defines{"_RELEASE", "SHEDITOR"} + links{"assimp-vc142-mt.lib"} \ No newline at end of file diff --git a/Assimp Compile Application/src/Libraries/SHAssimpLibrary.cpp b/Assimp Compile Application/src/Libraries/SHAssimpLibrary.cpp new file mode 100644 index 0000000..b0b2d67 --- /dev/null +++ b/Assimp Compile Application/src/Libraries/SHAssimpLibrary.cpp @@ -0,0 +1,148 @@ +/*************************************************************************//** + * \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 "SHAssimpLibrary.h" +#include +#include +#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.emplace_back(); + ProcessMesh(*mesh, meshes.back()); + } + + 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()); + } + } + } + + void SHAssimpLibrary::ProcessMesh(aiMesh const& mesh, SHMeshAsset& meshDest) noexcept + { + meshDest.compiled = false; + meshDest.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; + meshDest.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; + } + meshDest.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; + } + meshDest.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; + } + meshDest.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) + { + meshDest.indices.push_back(face.mIndices[j]); + } + } + + meshDest.header.vertexCount = static_cast(meshDest.vertexPosition.size()); + meshDest.header.indexCount = static_cast(meshDest.indices.size()); + meshDest.header.meshName = mesh.mName.C_Str(); + } + + 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()) + { + std::cout << "ERROR in GLTF::ASSIMP: " << aiImporter.GetErrorString() << "\nFile: " << path.string() << std::endl; + return; + } + + ExtractAnimations(*scene, anims); + + MeshVector localMesh(scene->mNumMeshes); + ProcessNode(*scene->mRootNode, *scene, localMesh); + + for (auto& mesh : localMesh) + { + mesh.parentPath = path.parent_path().string(); + } + + std::ranges::move(localMesh.begin(), localMesh.end(), meshes.end()); + + aiImporter.FreeScene(); + } +} diff --git a/Assimp Compile Application/src/Libraries/SHAssimpLibrary.h b/Assimp Compile Application/src/Libraries/SHAssimpLibrary.h new file mode 100644 index 0000000..c779e6c --- /dev/null +++ b/Assimp Compile Application/src/Libraries/SHAssimpLibrary.h @@ -0,0 +1,39 @@ +/*************************************************************************//** + * \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 "../Types/SHMeshAsset.h" +#include "../Types/SHAnimationAsset.h" + +namespace SHADE +{ + using MeshVector = std::vector; + using AnimVector = std::vector; + + 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 void ProcessMesh(aiMesh const& mesh, SHMeshAsset& meshDest) noexcept; + + public: + static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept; + }; +} \ No newline at end of file diff --git a/Assimp Compile Application/src/Libraries/SHMeshCompiler.cpp b/Assimp Compile Application/src/Libraries/SHMeshCompiler.cpp new file mode 100644 index 0000000..06cc0e9 --- /dev/null +++ b/Assimp Compile Application/src/Libraries/SHMeshCompiler.cpp @@ -0,0 +1,70 @@ +/*************************************************************************//** + * \file SHMeshCompiler.cpp + * \author Loh Xiao Qi + * \date 30 September 2022 + * \brief Library to write data in SHMeshAsset into binary file for faster + * loading in the future + * + * + * 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 "SHMeshCompiler.h" + +#include +#include + +std::string SHADE::SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset) noexcept +{ + std::string newPath{ asset.parentPath }; + newPath += asset.header.meshName + MESH_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 writing mesh file: " << asset.parentPath << std::endl; + } + + file.write( + reinterpret_cast(&(asset.header.vertexCount)), + sizeof(uint32_t) + ); + + file.write( + reinterpret_cast(&(asset.header.indexCount)), + sizeof(uint32_t) + ); + + auto const vertexVec3Byte {sizeof(SHVec3) * asset.header.vertexCount}; + auto const vertexVec2Byte {sizeof(SHVec2) * asset.header.vertexCount}; + + file.write( + reinterpret_cast(asset.vertexPosition.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.vertexTangent.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.vertexNormal.data()), + vertexVec3Byte + ); + + file.write( + reinterpret_cast(asset.texCoords.data()), + vertexVec2Byte + ); + + file.write( + reinterpret_cast(asset.indices.data()), + sizeof(uint32_t) * asset.header.indexCount + ); + + file.close(); + + return newPath; +} diff --git a/Assimp Compile Application/src/Libraries/SHMeshCompiler.h b/Assimp Compile Application/src/Libraries/SHMeshCompiler.h new file mode 100644 index 0000000..41c1d57 --- /dev/null +++ b/Assimp Compile Application/src/Libraries/SHMeshCompiler.h @@ -0,0 +1,26 @@ +/*************************************************************************//** + * \file SHMeshCompiler.h + * \author Loh Xiao Qi + * \date 30 September 2022 + * \brief Library to write data in SHMeshAsset into binary file for faster + * loading in the future + * + * + * 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 "../Types/SHMeshAsset.h" +#include "../SHAssetMacros.h" + +namespace SHADE +{ + class SHMeshCompiler + { + private: + public: + static std::string CompileMeshBinary(SHMeshAsset const& asset) noexcept; + }; +} \ No newline at end of file diff --git a/Assimp Compile Application/src/SHAssetMacros.h b/Assimp Compile Application/src/SHAssetMacros.h new file mode 100644 index 0000000..61c5879 --- /dev/null +++ b/Assimp Compile Application/src/SHAssetMacros.h @@ -0,0 +1,105 @@ +/****************************************************************************** + * \file SHAssetMacros.h + * \author Loh Xiao Qi + * \brief Macros and typedefs for assets + * + * \copyright 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 + ******************************************************************************/ +#ifndef SH_ASSET_MACROS_H +#define SH_ASSET_MACROS_H + +#include +#include +#include + +// FMOD Fwd Declare +namespace FMOD +{ + class Sound; + class System; + class ChannelGroup; + class Channel; +} +enum FMOD_RESULT : int; +enum FMOD_SPEAKERMODE : int; + +// Typedefs +typedef uint32_t AssetID; +typedef std::string AssetName; +typedef std::filesystem::path AssetPath; +typedef unsigned char* AssetData; +typedef std::string AssetMetaVersion; +typedef std::string AssetExtension; +typedef unsigned char AssetTypeMeta; + +typedef FMOD::Sound* SHSound; + +// Asset Meta Version +#define ASSET_META_VER "1.0" + +// Asset type enum +enum class AssetType : AssetTypeMeta +{ + INVALID = 0, + AUDIO = 1, + SHADER, + MATERIAL, + IMAGE, + TEXTURE, + MESH, + SCRIPT, + SCENE, + PREFAB, + AUDIO_WAV, + DDS +}; + +//Directory +#ifdef _PUBLISH +#define ASSET_ROOT "Assets" +#else +#define ASSET_ROOT "../../Assets" +#endif + + +// ASSET EXTENSIONS +#define META_EXTENSION ".shmeta" +#define IMAGE_EXTENSION ".png" +#define AUDIO_EXTENSION ".ogg" +#define AUDIO_WAV_EXTENSION ".wav" +#define SHADER_EXTENSION ".glsl" +#define SCRIPT_EXTENSION ".cs" +#define SCENE_EXTENSION ".SHADE" +#define PREFAB_EXTENSION ".SHPrefab" +#define MATERIAL_EXTENSION ".SHMat" +#define TEXTURE_EXTENSION ".shtex" +#define DDS_EXTENSION ".dds" +#define FBX_EXTENSION ".fbx" +#define GLTF_EXTENSION ".gltf" +#define MESH_EXTENSION ".shmesh" + +std::string const EXTENSIONS[] = { + AUDIO_EXTENSION, + SHADER_EXTENSION, + MATERIAL_EXTENSION, + IMAGE_EXTENSION, + TEXTURE_EXTENSION, + DDS_EXTENSION, + MESH_EXTENSION, + SCRIPT_EXTENSION, + SCENE_EXTENSION, + PREFAB_EXTENSION, + AUDIO_WAV_EXTENSION, + FBX_EXTENSION, + GLTF_EXTENSION +}; + +// Error flags +#define FILE_NOT_FOUND_ERR "FILE NOT FOUND" +#define META_NOT_FOUND_ERR "META NOT FOUND" +#define ASSET_NOT_FOUND_ERR "ASSET NOT FOUND" +#define EXT_DOES_NOT_EXIST "TYPE DOES NOT HAVE EXTENSION DEFINED" + +#endif // !SH_ASSET_MACROS_H diff --git a/Assimp Compile Application/src/Types/SHAnimationAsset.h b/Assimp Compile Application/src/Types/SHAnimationAsset.h new file mode 100644 index 0000000..38b2e11 --- /dev/null +++ b/Assimp Compile Application/src/Types/SHAnimationAsset.h @@ -0,0 +1,29 @@ +/*************************************************************************//** + * \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 + +namespace SHADE +{ + struct 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/Assimp Compile Application/src/Types/SHMeshAsset.h b/Assimp Compile Application/src/Types/SHMeshAsset.h new file mode 100644 index 0000000..051d9dc --- /dev/null +++ b/Assimp Compile Application/src/Types/SHMeshAsset.h @@ -0,0 +1,52 @@ +/*************************************************************************//** + * \file SHMeshAsset.h + * \author Loh Xiao Qi + * \date 30 September 2022 + * \brief Struct to contain ready data for loading into GPU. Also used for + * compilation into binary files + * + * + * 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 + +namespace SHADE +{ + struct SHVec3 + { + float x, y, z; + }; + + struct SHVec2 + { + float x, y; + }; + + struct SHMeshAssetHeader + { + uint32_t vertexCount; + uint32_t indexCount; + std::string meshName; + }; + + struct SHMeshAsset + { + std::string parentPath; + bool compiled; + bool changed; + + SHMeshAssetHeader header; + + std::vector vertexPosition; + std::vector vertexTangent; + std::vector vertexNormal; + std::vector texCoords; + std::vector indices; + }; +} \ No newline at end of file diff --git a/Dependencies.bat b/Dependencies.bat new file mode 100644 index 0000000..8bba20c --- /dev/null +++ b/Dependencies.bat @@ -0,0 +1,2 @@ +rmdir "Dependencies/assimp" /S /Q +git clone https://github.com/SHADE-DP/assimp.git "Dependencies/assimp" \ No newline at end of file diff --git a/generate.bat b/generate.bat new file mode 100644 index 0000000..b81fce8 --- /dev/null +++ b/generate.bat @@ -0,0 +1,5 @@ +erase /s /q *.vcxproj +erase /s /q *.vcxproj.filters + +call Premake\premake5 vs2019 +PAUSE \ No newline at end of file diff --git a/premake5.lua b/premake5.lua new file mode 100644 index 0000000..e69c37e --- /dev/null +++ b/premake5.lua @@ -0,0 +1,22 @@ +IncludeDir = {} +IncludeDir["assimp"] = "%{wks.location}\\Dependencies\\assimp" + +workspace "Assimp Compile Library" + architecture "x64" + startproject "Assimp Compile Application" + + configurations + { + "Debug", + "Release" + } + + flags + { + "MultiProcessorCompile" + } + + outputdir = "%{wks.location}/bin/%{cfg.buildcfg}" + interdir = "%{wks.location}/bin_int" + + include "Assimp Compile Application" \ No newline at end of file