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