Merge pull request #53 from SHADE-DP/SP3-13-Assets-Manager

SP3-13 Assets Management
Asset Manager Integration
Load fbx files into meshes
Load dds into memory
This commit is contained in:
XiaoQiDigipen 2022-09-26 14:43:04 +08:00 committed by GitHub
commit 0c8fdb4985
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1179 additions and 10 deletions

Binary file not shown.

Binary file not shown.

BIN
Assets/racoon.fbx Normal file

Binary file not shown.

View File

@ -18,10 +18,11 @@ echo "K - RTTR"
echo "L - yamlcpp" echo "L - yamlcpp"
echo "M - SDL" echo "M - SDL"
echo "N - dotnet" echo "N - dotnet"
echo "O - tinyddsloader"
echo --------------------------------------------------- echo ---------------------------------------------------
echo. echo.
choice /C ABCDEFGHIJKLMN /T 10 /D A choice /C ABCDEFGHIJKLMNO /T 10 /D A
set _e=%ERRORLEVEL% set _e=%ERRORLEVEL%
if %_e%==1 goto VMA if %_e%==1 goto VMA
@ -38,6 +39,7 @@ if %_e%==11 goto RTTR
if %_e%==12 goto yamlcpp if %_e%==12 goto yamlcpp
if %_e%==13 goto SDL if %_e%==13 goto SDL
if %_e%==14 goto dotnet if %_e%==14 goto dotnet
if %_e%==15 goto tinyddsloader
:VMA :VMA
echo -----------------------VMA---------------------------- echo -----------------------VMA----------------------------
@ -136,6 +138,13 @@ robocopy "Dependencies/dotnet/tmp/shared/Microsoft.NETCore.App/6.0.8/" "Dependen
rmdir "Dependencies/dotnet/tmp/" /s /q rmdir "Dependencies/dotnet/tmp/" /s /q
del "Dependencies/dotnet/dotnet.zip" del "Dependencies/dotnet/dotnet.zip"
powershell -Command "& {Remove-Item "Dependencies/dotnet/dotnet.zip"}" powershell -Command "& {Remove-Item "Dependencies/dotnet/dotnet.zip"}"
if %_e%==14 (goto :done) else (goto :tinyddsloader)
:tinyddsloader
echo --------------------tinyddsloader-------------------------
rmdir "Dependencies/tinyddsloader" /S /Q
git clone https://github.com/benikabocha/tinyddsloader.git "Dependencies/tinyddsloader"
:done :done
echo DONE! echo DONE!

View File

@ -14,3 +14,4 @@ IncludeDir["reactphysics3d"] = "%{wks.location}\\Dependencies\\reactphysics3d"
IncludeDir["SDL"] = "%{wks.location}\\Dependencies\\SDL" IncludeDir["SDL"] = "%{wks.location}\\Dependencies\\SDL"
IncludeDir["VULKAN"] = "$(VULKAN_SDK)" IncludeDir["VULKAN"] = "$(VULKAN_SDK)"
IncludeDir["dotnet"] = "%{wks.location}\\Dependencies\\dotnet" IncludeDir["dotnet"] = "%{wks.location}\\Dependencies\\dotnet"
IncludeDir["tinyddsloader"] = "%{wks.location}\\Dependencies\\tinyddsloader"

View File

@ -33,7 +33,8 @@ project "SHADE_Application"
"%{IncludeDir.spdlog}/include", "%{IncludeDir.spdlog}/include",
"%{IncludeDir.VULKAN}/include", "%{IncludeDir.VULKAN}/include",
"%{IncludeDir.VMA}/include", "%{IncludeDir.VMA}/include",
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect" "%{IncludeDir.VULKAN}/Source/SPIRV-Reflect",
"%{IncludeDir.tinyddsloader}"
} }
externalwarnings "Off" externalwarnings "Off"

View File

@ -28,6 +28,8 @@
#include "Scenes/SBTestScene.h" #include "Scenes/SBTestScene.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Assets/SHAssetManager.h"
using namespace SHADE; using namespace SHADE;
namespace Sandbox namespace Sandbox
@ -76,6 +78,12 @@ namespace Sandbox
SHADE::SHSystemManager::RegisterRoutine<SHADE::SHInputManagerSystem, SHADE::SHInputManagerSystem::InputManagerRoutine>(); SHADE::SHSystemManager::RegisterRoutine<SHADE::SHInputManagerSystem, SHADE::SHInputManagerSystem::InputManagerRoutine>();
//TODO: REMOVE AFTER PRESENTATION
SHADE::SHAssetManager::LoadDataTemp("../../Assets/racoon.fbx");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds");
SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds");
//TODO: REMOVE AFTER PRESENTATION
// Set up graphics system and windows // Set up graphics system and windows
graphicsSystem->SetWindow(&window); graphicsSystem->SetWindow(&window);
sdlWindow = SDL_CreateWindowFrom(window.GetHWND()); sdlWindow = SDL_CreateWindowFrom(window.GetHWND());

View File

@ -10,6 +10,8 @@
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Assets/SHAssetManager.h"
using namespace SHADE; using namespace SHADE;
namespace Sandbox namespace Sandbox
@ -33,6 +35,23 @@ namespace Sandbox
SHADE::SHGraphicsSystem* graphicsSystem = static_cast<SHADE::SHGraphicsSystem*>(SHADE::SHSystemManager::GetSystem<SHADE::SHGraphicsSystem>()); SHADE::SHGraphicsSystem* graphicsSystem = static_cast<SHADE::SHGraphicsSystem*>(SHADE::SHSystemManager::GetSystem<SHADE::SHGraphicsSystem>());
// Create temp meshes // Create temp meshes
const auto CUBE_MESH = SHADE::SHPrimitiveGenerator::Cube(*graphicsSystem); const auto CUBE_MESH = SHADE::SHPrimitiveGenerator::Cube(*graphicsSystem);
//graphicsSystem->BuildMeshBuffers();
//Test Racoon mesh
auto meshes = SHADE::SHAssetManager::GetAllMeshes();
std::vector<Handle<SHMesh>> handles;
for (auto const& mesh : meshes)
{
handles.push_back(graphicsSystem->AddMesh(
mesh.header.vertexCount,
mesh.vertexPosition.data(),
mesh.texCoords.data(),
mesh.vertexTangent.data(),
mesh.vertexNormal.data(),
mesh.header.indexCount,
mesh.indices.data()
));
}
graphicsSystem->BuildMeshBuffers(); graphicsSystem->BuildMeshBuffers();
// Create Materials // Create Materials
@ -44,22 +63,33 @@ namespace Sandbox
constexpr int NUM_COLS = 1; constexpr int NUM_COLS = 1;
static const SHVec3 TEST_OBJ_SPACING = { 1.0f, 1.0f, 1.0f }; static const SHVec3 TEST_OBJ_SPACING = { 1.0f, 1.0f, 1.0f };
static const SHVec3 TEST_OBJ_START_POS = { - (NUM_COLS / 2 * TEST_OBJ_SPACING.x ), 0.0f, 0.0f }; static const SHVec3 TEST_OBJ_START_POS = { - (NUM_COLS / 2 * TEST_OBJ_SPACING.x ), 0.0f, 0.0f };
for (int z = 0; z < NUM_ROWS; ++z) //for (int z = 0; z < NUM_ROWS; ++z)
for (int x = 0; x < NUM_COLS; ++x) //for (int x = 0; x < NUM_COLS; ++x)
{ //{
// auto entity = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
// auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(entity);
// auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(entity);
// renderable.Mesh = handles.front();
// renderable.SetMaterial(matInst);
// // Set initial positions
// transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, 0.0f, z * TEST_OBJ_SPACING.z });
// //transform.SetLocalScale(TEST_OBJ_SCALE);
// stressTestObjects.emplace_back(entity);
//}
auto entity = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>(); auto entity = SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(entity); auto& renderable = *SHComponentManager::GetComponent_s<SHRenderable>(entity);
auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(entity); auto& transform = *SHComponentManager::GetComponent_s<SHTransformComponent>(entity);
renderable.Mesh = CUBE_MESH; renderable.Mesh = handles.front();
renderable.SetMaterial(matInst); renderable.SetMaterial(matInst);
// Set initial positions
transform.SetWorldPosition(TEST_OBJ_START_POS + SHVec3{ x * TEST_OBJ_SPACING.x, 0.0f, z * TEST_OBJ_SPACING.z });
//transform.SetLocalScale(TEST_OBJ_SCALE); //transform.SetLocalScale(TEST_OBJ_SCALE);
stressTestObjects.emplace_back(entity); stressTestObjects.emplace_back(entity);
}
// Create blank entity with a script // Create blank entity with a script
testObj = SHADE::SHEntityManager::CreateEntity(); testObj = SHADE::SHEntityManager::CreateEntity();

View File

@ -42,6 +42,7 @@ project "SHADE_Engine"
"%{IncludeDir.VULKAN}\\include", "%{IncludeDir.VULKAN}\\include",
"%{IncludeDir.VULKAN}\\Source\\SPIRV-Reflect", "%{IncludeDir.VULKAN}\\Source\\SPIRV-Reflect",
"%{IncludeDir.dotnet}\\include", "%{IncludeDir.dotnet}\\include",
"%{IncludeDir.tinyddsloader}"
} }
externalwarnings "Off" externalwarnings "Off"
@ -106,6 +107,12 @@ project "SHADE_Engine"
"xcopy /s /r /y /q \"%{IncludeDir.dotnet}\\bin\" \"$(OutDir)\"" "xcopy /s /r /y /q \"%{IncludeDir.dotnet}\\bin\" \"$(OutDir)\""
} }
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' warnings 'Extra'
filter "configurations:Debug" filter "configurations:Debug"

View File

@ -0,0 +1,11 @@
#pragma once
#include "tinyddsloader.h"
namespace SHADE
{
struct SHDDSAsset
{
tinyddsloader::DDSFile image;
};
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <vector>
#include "Math/SHMath.h"
namespace SHADE
{
struct SHMeshAssetHeader
{
uint32_t vertexCount;
uint32_t indexCount;
};
struct SHMeshAsset
{
bool compiled;
bool changed;
SHMeshAssetHeader header;
std::string meshName;
std::vector<SHVec3> vertexPosition;
std::vector<SHVec2> texCoords;
std::vector<SHVec3> vertexTangent;
std::vector<SHVec3> vertexNormal;
std::vector<uint32_t> indices;
};
}

View File

@ -0,0 +1,38 @@
#include "SHpch.h"
#include "SHDDSLoader.h"
namespace SHADE
{
std::string SHDDSLoader::TinyDDSResultToString(tinyddsloader::Result value)
{
switch (value)
{
case tinyddsloader::Result::ErrorFileOpen:
return "File open err";
case tinyddsloader::Result::ErrorRead:
return "File read err";
case tinyddsloader::Result::ErrorMagicWord:
return "File header magicword err";
case tinyddsloader::Result::ErrorSize:
return "File size err";
case tinyddsloader::Result::ErrorVerify:
return "Pixel format err";
case tinyddsloader::Result::ErrorNotSupported:
return "Unsupported format";
case tinyddsloader::Result::ErrorInvalidData:
return "Invalid data";
default:
return "Unknown";
}
}
void SHDDSLoader::LoadImageAsset(AssetPath path, SHDDSAsset& asset)
{
tinyddsloader::Result loadResult = tinyddsloader::Result::Success;
loadResult = asset.image.Load(path.string().c_str());
if (loadResult != tinyddsloader::Result::Success)
{
SHLOG_ERROR("Unable to load DDS file: {} at {}", TinyDDSResultToString(loadResult), path.string());
}
}
}

View File

@ -0,0 +1,18 @@
#pragma once
#define TINYDDSLOADER_IMPLEMENTATION
#include "../SHAssetMacros.h"
#include "../Asset Types/SHDDSAsset.h"
#include "tinyddsloader.h"
#include <vector>
namespace SHADE
{
class SHDDSLoader
{
private:
static std::string TinyDDSResultToString(tinyddsloader::Result value);
public:
static void LoadImageAsset(AssetPath paths, SHDDSAsset& image);
};
}

View File

@ -0,0 +1,131 @@
#include "SHpch.h"
#include "SHMeshLoader.h"
#include <assimp/postprocess.h>
namespace SHADE
{
Assimp::Importer SHMeshLoader::aiImporter;
void SHMeshLoader::ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes)
{
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)
{
(void)scene;
SHMeshAsset result
{
.compiled { false},
.changed { false },
.meshName { mesh.mName.C_Str() }
};
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 = result.vertexPosition.size();
result.header.indexCount = result.indices.size();
return result;
}
bool SHMeshLoader::LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path)
{
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_PreTransformVertices // pre-transform all vertices
| 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 false;
}
//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);
return true;
}
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include "../SHAssetMacros.h"
#include "../Asset Types/SHMeshAsset.h"
#include <vector>
namespace SHADE
{
class SHMeshLoader
{
private:
static Assimp::Importer aiImporter;
static void ProcessNode(aiNode const& node, aiScene const& scene, std::vector<SHMeshAsset>& meshes);
static SHMeshAsset ProcessMesh(aiMesh const& mesh, aiScene const& scene);
public:
static bool LoadMesh(std::vector<SHMeshAsset>& meshes, AssetPath path);
};
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "Filesystem/SHFileSystem.h"
#include "SHAssetMacros.h"
namespace SHADE
{
struct SHAsset
{
AssetName name;
AssetID id;
AssetType type;
AssetPath path;
FolderLocation location;
};
}

View File

@ -0,0 +1,94 @@
/******************************************************************************
* \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 <cstdint>
#include <string>
#include <filesystem>
// 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 : uint8_t
{
INVALID = 0,
AUDIO = 1,
SHADER,
MATERIAL,
IMAGE,
TEXTURE,
MESH,
SCRIPT,
SCENE,
PREFAB,
AUDIO_WAV,
DDS
};
//Directory
#define ASSET_ROOT "./Assets/"
// 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 ".dds"
#define MESH_EXTENSION ".fbx"
std::string const EXTENSIONS[] = {
AUDIO_EXTENSION,
SHADER_EXTENSION,
MATERIAL_EXTENSION,
IMAGE_EXTENSION,
TEXTURE_EXTENSION,
MESH_EXTENSION,
SCRIPT_EXTENSION,
SCENE_EXTENSION,
PREFAB_EXTENSION,
AUDIO_WAV_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

View File

@ -0,0 +1,430 @@
/******************************************************************************
* \file SHAssetManager.cpp
* \author Loh Xiao Qi
* \brief Implementations for SHAssetManager.h
*
* \copyright Copyright (c) 2021 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 <random>
#include <chrono>
#include "SHAssetManager.h"
#include "SHAssetMetaHandler.h"
#include "Filesystem/SHFileSystem.h"
#include "Libraries/SHMeshLoader.h"
#include "Libraries/SHDDSLoader.h"
namespace SHADE
{
FMOD::System* SHAssetManager::audioSystem;
std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList;
std::vector<SHAsset> SHAssetManager::assetCollection;
std::unordered_map<AssetID, SHAsset> SHAssetManager::assetRegistry;
std::unordered_map<AssetID, SHMeshAsset> SHAssetManager::meshCollection;
std::unordered_map<AssetID, SHDDSAsset> SHAssetManager::ddsCollection;
/****************************************************************************
* \brief Static function to generate asset ID.
****************************************************************************/
AssetID SHAssetManager::GenerateAssetID(AssetType type) noexcept
{
std::default_random_engine randEngine{
static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count()) };
std::mt19937 idGen{ randEngine() };
AssetID result{ static_cast<AssetID>(type) << 24};
AssetID unique{ idGen() & ((1 << 24) - 1) };
result |= unique;
while (result == 0)
{
result = GenerateAssetID(type);
}
return result;
}
/****************************************************************************
* \brief Deallocate all memory used by asset data
****************************************************************************/
void SHAssetManager::Unload() noexcept
{
for (auto const& asset : assetCollection)
{
SHAssetMetaHandler::WriteMetaData(asset);
}
}
AssetPath SHAssetManager::GenerateLocalPath(AssetPath path) noexcept
{
if (!IsRecognised(path.extension().string().c_str()))
{
//TODO:ASSERT UNRECOGNISED FILE TYPE
return std::filesystem::path();
}
AssetType type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string().c_str());
std::string folder;
switch (type)
{
default:
//TODO:ASSERT UNSUPPORTED FILE TYPE
return std::filesystem::path();
}
return std::filesystem::path(ASSET_ROOT + folder + path.filename().string());
}
/****************************************************************************
* \brief Get record of all assets currently loaded with name and id.
*
* \return const& to unordered_map<AssetName, AssetID>
****************************************************************************/
std::vector<SHAsset> const& SHAssetManager::GetAllAssets() noexcept
{
return assetCollection;
}
/****************************************************************************
* \brief Create record for new asset. CAN ONLY CREATE FOR CUSTOM
* ASSETS CREATED BY THE ENGINE.
*
* \param type of asset
* \param name of asset
* \return asset id generated for new asset
****************************************************************************/
AssetID SHAssetManager::CreateNewAsset(AssetType type, AssetName name) noexcept
{
AssetID id{ GenerateAssetID(type) };
SHAsset meta;
meta.id = id;
meta.type = type;
std::string folder;
switch (type)
{
default:
folder = "";
break;
}
AssetPath path{ ASSET_ROOT + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
SHAssetMetaHandler::WriteMetaData(meta);
assetCollection.push_back(meta);
return id;
}
/****************************************************************************
* \brief Import new asset from outside editor window.
*
* \param path - c style string to full path
* \return asset if generated for new
****************************************************************************/
AssetID SHAssetManager::ImportNewAsset(char const* p) noexcept
{
std::filesystem::path const path{ p };
std::filesystem::path const newPath{ GenerateLocalPath(path) };
if (newPath.empty())
{
SHLOG_WARNING("Unsupported file format for asset: {}", path.string());
return 0;
}
std::filesystem::copy(path, newPath);
AssetID id{ RetrieveAsset(newPath.string().c_str()) };
if (id != 0)
{
LoadData(id);
}
return id;
}
/****************************************************************************
* \brief Search through assets folder for new unregistered assets.
* Takes in no params and returns nothing. Only updates internally.
****************************************************************************/
void SHAssetManager::RefreshAllAssets() noexcept
{
std::vector<AssetPath> metaFiles;
std::vector<AssetPath> AssetFiles;
//SHFileSystem::LoadAllFiles(metaFiles, AssetFiles);
//std::vector<AssetPath> AssetFilesVerified;
std::vector<AssetPath> AssetFilesNew;
for (auto const& asset : AssetFiles)
{
bool found = false;
for (auto it {metaFiles.begin()}; it != metaFiles.end(); ++it)
{
std::string fileExtCheck{ asset.filename().string() };
fileExtCheck += META_EXTENSION;
if (it->filename().string() == fileExtCheck)
{
metaFiles.erase(it);
found = true;
break;
}
}
if (!found && IsRecognised(asset.extension().string().c_str()))
{
AssetFilesNew.push_back(asset);
}
}
std::vector<SHAsset> newLoad;
newLoad.reserve(AssetFilesNew.size());
//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
for (auto const& file : AssetFilesNew)
{
newLoad.push_back(RegisterAssetNew(file));
}
//UpdateAllSpriteSets();
}
void SHAssetManager::LoadDataTemp(std::string p) noexcept
{
AssetPath path{ p };
if (path.extension().string() == MESH_EXTENSION)
{
LoadGLTF(
{
.name {path.filename().string()},
.id {0},
.type {AssetType::MESH},
.path {path},
.location {0}
}
);
}
else if (path.extension().string() == TEXTURE_EXTENSION)
{
LoadDDS(
{
.name {path.filename().string()},
.id {0},
.type {AssetType::DDS},
.path {path},
.location {0}
}
);
}
}
std::vector<SHMeshAsset> SHAssetManager::GetAllMeshes() noexcept
{
std::vector<SHMeshAsset> result;
for (auto const& mesh : meshCollection)
{
result.push_back(mesh.second);
}
return result;
}
/****************************************************************************
* \param Path for meta data file
* \param Path for asset file
* \brief Links meta data to asset in registries. Meta data should
* already exist
****************************************************************************/
void SHAssetManager::RegisterAsset(AssetPath const& metaPath, AssetPath const& path) noexcept
{
SHAsset const meta = SHAssetMetaHandler::RetrieveMetaData(metaPath);
assetCollection.push_back(meta);
}
/****************************************************************************
* \param Path for asset file
* \brief Creates new meta data for new asset.
****************************************************************************/
SHAsset SHAssetManager::RegisterAssetNew(AssetPath const& asset) noexcept
{
SHAsset meta;
meta.type = SHAssetMetaHandler::GetTypeFromExtension(asset.extension().string());
meta.id = GenerateAssetID(meta.type);
assetCollection.push_back(meta);
SHAssetMetaHandler::WriteMetaData(meta);
return assetCollection.back();
}
bool SHAssetManager::IsRecognised(char const* ext) noexcept
{
for (auto const& e : EXTENSIONS)
{
if (strcmp(ext, e.c_str()) == 0)
{
return true;
}
}
return false;
}
void SHAssetManager::LoadGLTF(SHAsset asset) noexcept
{
std::vector<SHMeshAsset> meshes;
SHMeshLoader::LoadMesh(meshes, asset.path);
for (auto const& mesh : meshes)
{
meshCollection.emplace(GenerateAssetID(AssetType::MESH), mesh);
}
}
void SHAssetManager::LoadDDS(SHAsset asset) noexcept
{
SHDDSAsset image;
SHDDSLoader::LoadImageAsset(asset.path, image);
ddsCollection.emplace(GenerateAssetID(AssetType::DDS), image);
}
/****************************************************************************
* \brief Load all assets that are in the folder
****************************************************************************/
void SHAssetManager::Load() noexcept
{
RetrieveAssets();
LoadAllData();
}
/****************************************************************************
* \brief Load asset data into memory
****************************************************************************/
void SHAssetManager::LoadAllData() noexcept
{
for (auto const& asset : assetCollection)
{
}
}
void SHAssetManager::LoadData(AssetID id) noexcept
{
(void)id;
}
/****************************************************************************
* \brief Retrieve all asset files and meta files from filesystem
****************************************************************************/
void SHAssetManager::RetrieveAssets() noexcept
{
std::vector<AssetPath> metaFiles;
std::vector<AssetPath> AssetFiles;
//TODO: Write new function for file manager to loop through all files
SHFileSystem::StartupFillDirectories(ASSET_ROOT);
FolderPointer rootFolder = SHFileSystem::GetRoot();
for (auto const& meta : metaFiles)
{
for (std::vector<AssetPath>::const_iterator it{ AssetFiles.cbegin() };
it != AssetFiles.cend();
++it)
{
// Asset exists for meta file
std::string fileExtCheck{ it->filename().string() };
fileExtCheck += META_EXTENSION;
if (meta.filename().string() == fileExtCheck)
{
RegisterAsset(meta, *it);
AssetFiles.erase(it);
break;
}
}
}
//TODO: Handle if meta does not match all assets (if meta exist and asset doesnt, vice versa)
for (auto const& file : AssetFiles)
{
if (IsRecognised(file.extension().string().c_str()))
{
SHAssetMetaHandler::WriteMetaData(RegisterAssetNew(file));
}
else
{
std::cout << "Unsupported File Format: " << file.filename() << "\n";
}
}
}
AssetID SHAssetManager::RetrieveAsset(char const* path) noexcept
{
std::filesystem::path p{ path };
if (IsRecognised(p.extension().string().c_str()))
{
SHAsset const& meta{ RegisterAssetNew(p) };
SHAssetMetaHandler::WriteMetaData(meta);
return meta.id;
}
else
{
std::cout << "Unsupported File Format: " << p.filename() << "\n";
}
// Assert that file imported is not recognised
return 0;
}
/****************************************************************************
* \param Full path of file
* \brief Extracts file name from path. Formats file name into readable
* with spaces and capitalises first letter of every word
****************************************************************************/
AssetName SHAssetManager::GetNameFromPath(AssetPath filepath) noexcept
{
std::string name{ filepath.filename().string() };
name = name.substr(0, name.find_last_of('.'));
//if (name[0] <= 122 && name[0] >= 97)
//{
// name[0] -= 32;
//}
//for (size_t i{ 1 }; i < name.length(); ++i)
//{
// // Replace all underscores with spaces
// if (name[i] == '_')
// {
// name[i] = ' ';
// continue;
// }
// if (name[i + 1] <= 'Z' && name[i + 1] >= 'A'
// && name[i] <= 'z' && name[i] >= 'a')
// {
// name.insert(i + 1, 1, ' ');
// continue;
// }
// if (name[i - 1] == ' ' && name[i] <= 'z' && name[i] >= 'a')
// {
// name[i] -= 32;
// }
//}
return name;
}
}

View File

@ -0,0 +1,132 @@
/******************************************************************************
* \file SHAssetManager.h
* \author Loh Xiao Qi
* \brief Interface for resource manager, to be used by engine side
* operations.
*
* \copyright Copyright (c) 2021 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 "tinyddsloader.h"
#include "SHAsset.h"
#include "Asset Types/SHMeshAsset.h"
#include "Asset Types/SHDDSAsset.h"
#include "SH_API.h"
namespace SHADE
{
class SH_API SHAssetManager
{
public:
/****************************************************************************
* \brief Static function to generate resource ID.
****************************************************************************/
static AssetID GenerateAssetID(AssetType type) noexcept;
static AssetPath GenerateLocalPath(AssetPath path) noexcept;
/****************************************************************************
* \brief Deallocate all memory used by resource data
****************************************************************************/
static void Unload() noexcept;
/****************************************************************************
* \brief Load all resources that are in the folder
****************************************************************************/
static void Load() noexcept;
/****************************************************************************
* \brief Get record of all resources currently loaded with name and id.
*
* \return const& to unordered_map<AssetName, AssetID>
****************************************************************************/
static std::vector<SHAsset> const& GetAllAssets() noexcept;
/****************************************************************************
* \brief Create record for new resource. CAN ONLY CREATE FOR CUSTOM
* RESOURCES CREATED BY THE ENGINE.
*
* \param type of resource
* \param name of resource
* \return resource id generated for new asset
****************************************************************************/
static AssetID CreateNewAsset(AssetType, AssetName) noexcept;
/****************************************************************************
* \brief Import new resource from outside editor window.
*
* \param path - c style string to full path
* \return resource if generated for new
****************************************************************************/
static AssetID ImportNewAsset(char const* path) noexcept;
/****************************************************************************
* \brief Search through resources folder for new unregistered assets.
* Takes in no params and returns nothing. Only updates internally.
****************************************************************************/
static void RefreshAllAssets() noexcept;
// -------------------------------------------------------------------------/
//TODO: TEMPORARY FOR TESTING GLTF & DDS
static void LoadDataTemp(std::string path) noexcept;
static std::vector<SHMeshAsset> GetAllMeshes() noexcept;
private:
/****************************************************************************
* \brief Load resource data into memory
****************************************************************************/
static void LoadAllData() noexcept;
static void LoadData(AssetID id) noexcept;
/****************************************************************************
* \brief Retrieve all resource files and meta files from filesystem
****************************************************************************/
static void RetrieveAssets() noexcept;
static AssetID RetrieveAsset(char const* path) noexcept;
/****************************************************************************
* \param Full path of file
* \brief Extracts file name from path. Formats file name into readable
* with spaces and capitalises first letter of every word
****************************************************************************/
static AssetName GetNameFromPath(AssetPath) noexcept;
/****************************************************************************
* \param Path for meta data file
* \param Path for resource file
* \brief Links meta data to resource in registries. Meta data should
* already exist
****************************************************************************/
static void RegisterAsset(AssetPath const&, AssetPath const&) noexcept;
/****************************************************************************
* \param Path for resource file
* \brief Creates new meta data for new resource.
****************************************************************************/
static SHAsset RegisterAssetNew(AssetPath const&) noexcept;
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<AssetID,SHSound>* audioSoundList;
// For all resources
static std::vector<SHAsset> assetCollection;
static std::unordered_map<AssetID, SHAsset> assetRegistry;
static std::unordered_map<AssetID, SHMeshAsset> meshCollection;
static std::unordered_map<AssetID, SHDDSAsset> ddsCollection;
};
}

View File

@ -0,0 +1,118 @@
/******************************************************************************
* \file SHAssetMetaHandler.cpp
* \author Loh Xiao Qi
* \brief Implementations for SHAssetMetaHandler.h
*
* \copyright Copyright (c) 2021 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 "SHAssetMetaHandler.h"
#include <fstream>
#include <sstream>
namespace SHADE
{
/****************************************************************************
* \param reference to ifstream file to read line from
* \param reference to string to store line into
* \brief Helper function to retrieve field value from meta data file
* for processing
****************************************************************************/
void GetFieldValue(std::ifstream& file, std::string& line) noexcept
{
line = "";
std::getline(file, line);
line = line.substr(line.find_last_of(':') + 2, line.length());
}
/****************************************************************************
* \param String containing extension of resource file
* \brief Get correct resource type from file extension of resource.
****************************************************************************/
AssetType SHAssetMetaHandler::GetTypeFromExtension(AssetExtension ext) noexcept
{
for (int i{0}; i < EXTENSIONS->size(); ++i)
{
if (ext == EXTENSIONS[i])
{
return static_cast<AssetType>(i);
}
}
return AssetType::INVALID;
}
/****************************************************************************
* \param String containing extension of resource file
* \brief Get correct resource type from file extension of resource.
****************************************************************************/
AssetExtension SHAssetMetaHandler::GetExtensionFromType(AssetType type) noexcept
{
return EXTENSIONS[static_cast<size_t>(type)];
}
/****************************************************************************
* \param Create class containing meta data from meta file
* \brief path to meta data file
****************************************************************************/
SHAsset SHAssetMetaHandler::RetrieveMetaData(AssetPath const& path) noexcept
{
std::ifstream metaFile{ path.string(), std::ios_base::in };
if (!metaFile.is_open())
{
// Error unable to open
}
std::string line;
SHAsset meta;
// Get resource id
GetFieldValue(metaFile, line);
std::stringstream idStream{ line };
AssetID id;
idStream >> id;
meta.id = id;
// Get resource type
GetFieldValue(metaFile, line);
std::stringstream typeStream{ line };
AssetTypeMeta type;
typeStream >> type;
meta.type = static_cast<AssetType>(type);
metaFile.close();
return meta;
}
/****************************************************************************
* \param Asset meta data to be written into
* \param Path to be written into
* \brief Writes meta data into text file
****************************************************************************/
void SHAssetMetaHandler::WriteMetaData(SHAsset const& meta) noexcept
{
std::string path{ meta.path.string() };
path.append(META_EXTENSION);
std::ofstream metaFile{ path, std::ios_base::out };
if (!metaFile.is_open())
{
SHLOG_ERROR("Asset write path is invalid: {}", path);
return;
}
metaFile << "ID: " << meta.id << "\n";
metaFile << "Type: " << static_cast<int>(meta.type) << std::endl;
metaFile.close();
}
}

View File

@ -0,0 +1,51 @@
/******************************************************************************
* \file SHAssetMetaHandler.h
* \author Loh Xiao Qi
* \brief Handler classes for meta data for all resources
*
* \copyright Copyright (c) 2021 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_RESOURCE_META_HANDLER_H
#define SH_RESOURCE_META_HANDLER_H
#include "SHAssetMacros.h"
#include "SHAsset.h"
namespace SHADE
{
struct SHAssetMetaHandler
{
/****************************************************************************
* \param String containing extension of resource file
* \brief Get correct resource type from file extension of resource.
****************************************************************************/
static AssetType GetTypeFromExtension(AssetExtension) noexcept;
/****************************************************************************
* \param String containing extension of resource file
* \brief Get correct resource type from file extension of resource.
****************************************************************************/
static AssetExtension GetExtensionFromType(AssetType) noexcept;
/****************************************************************************
* \param Create class containing meta data from meta file
* \brief path to meta data file
****************************************************************************/
static SHAsset RetrieveMetaData(AssetPath const&) noexcept;
/****************************************************************************
* \param Asset meta data to be written into
* \param Path to be written into
* \brief Writes meta data into text file
****************************************************************************/
static void WriteMetaData(SHAsset const&) noexcept;
};
}
#endif // !SH_RESOURCE_META_HANDLER_H

View File

@ -80,6 +80,12 @@ namespace SHADE
{ {
if (!dirEntry.is_directory()) if (!dirEntry.is_directory())
{ {
folder->files.emplace_back(
dirEntry.path().filename().string(),
dirEntry.path().string(),
dirEntry.path().extension().string()
);
continue; continue;
} }
@ -103,6 +109,11 @@ namespace SHADE
} }
} }
FolderPointer SHFileSystem::GetRoot() noexcept
{
return root;
}
FolderPointer SHFileSystem::CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept FolderPointer SHFileSystem::CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept
{ {
assert( assert(

View File

@ -14,12 +14,22 @@ namespace SHADE
typedef uint64_t FolderLocation; typedef uint64_t FolderLocation;
typedef uint64_t FolderHandle; typedef uint64_t FolderHandle;
typedef std::string FolderName; typedef std::string FolderName;
typedef std::string FileName;
typedef std::string FolderPath; typedef std::string FolderPath;
typedef std::string FilePath;
typedef std::string FileExt;
typedef SHFolder* FolderPointer; typedef SHFolder* FolderPointer;
constexpr char FOLDER_BIT_ALLOCATE{ 4 }; constexpr char FOLDER_BIT_ALLOCATE{ 4 };
constexpr char FOLDER_MAX_DEPTH{ 16 }; constexpr char FOLDER_MAX_DEPTH{ 16 };
struct SHFile
{
FileName name;
FilePath path;
FileExt ext;
};
class SHFolder class SHFolder
{ {
public: public:
@ -28,6 +38,7 @@ namespace SHADE
FolderHandle id; FolderHandle id;
FolderName name; FolderName name;
std::vector<FolderPointer> subFolders; std::vector<FolderPointer> subFolders;
std::vector<SHFile> files;
bool folded; bool folded;
@ -45,6 +56,8 @@ namespace SHADE
static void StartupFillDirectories(FolderPath path) noexcept; static void StartupFillDirectories(FolderPath path) noexcept;
static FolderPointer GetRoot() noexcept;
private: private:
static FolderPointer root; static FolderPointer root;