diff --git a/SHADE_Engine/src/Assets/SHAsset.h b/SHADE_Engine/src/Assets/SHAsset.h index a4e9847c..29f43e0c 100644 --- a/SHADE_Engine/src/Assets/SHAsset.h +++ b/SHADE_Engine/src/Assets/SHAsset.h @@ -21,6 +21,11 @@ namespace SHADE AssetName name; AssetID id; AssetType type; - AssetPath path; + AssetPath path; + bool isSubAsset; + + std::vector subAssets; + + AssetID parent; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Assets/SHAssetMacros.h b/SHADE_Engine/src/Assets/SHAssetMacros.h index 52e5cb80..6253ee6d 100644 --- a/SHADE_Engine/src/Assets/SHAssetMacros.h +++ b/SHADE_Engine/src/Assets/SHAssetMacros.h @@ -46,10 +46,11 @@ enum class AssetType : AssetTypeMeta SHADER, SHADER_BUILT_IN, TEXTURE, - MESH, + MODEL, SCENE, PREFAB, MATERIAL, + MESH, MAX_COUNT }; constexpr size_t TYPE_COUNT{ static_cast(AssetType::MAX_COUNT) }; @@ -83,7 +84,7 @@ constexpr std::string_view SCENE_EXTENSION {".shade"}; constexpr std::string_view PREFAB_EXTENSION {".shprefab"}; constexpr std::string_view MATERIAL_EXTENSION {".shmat"}; constexpr std::string_view TEXTURE_EXTENSION {".shtex"}; -constexpr std::string_view MESH_EXTENSION {".shmesh"}; +constexpr std::string_view MODEL_EXTENSION {".shmodel"}; constexpr std::string_view EXTENSIONS[] = { AUDIO_EXTENSION, @@ -91,7 +92,7 @@ constexpr std::string_view EXTENSIONS[] = { SHADER_BUILT_IN_EXTENSION, MATERIAL_EXTENSION, TEXTURE_EXTENSION, - MESH_EXTENSION, + MODEL_EXTENSION, SCRIPT_EXTENSION, SCENE_EXTENSION, PREFAB_EXTENSION, diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp index 29e00075..689276b1 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.cpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp @@ -16,7 +16,7 @@ #include "SHAssetManager.h" #include "SHAssetMetaHandler.h" -#include "Libraries/Loaders/SHMeshLoader.h" +#include "Libraries/Loaders/SHModelLoader.h" #include "Libraries/Loaders/SHTextureLoader.h" #include "Libraries/Loaders/SHShaderSourceLoader.h" #include "Libraries/Loaders/SHTextBasedLoader.h" @@ -178,7 +178,8 @@ namespace SHADE name, id, type, - newPath + newPath, + false }; assetCollection.insert({ @@ -187,7 +188,8 @@ namespace SHADE name, id, type, - newPath + newPath, + false ) }); @@ -324,25 +326,32 @@ namespace SHADE return result; } - AssetID SHAssetManager::CompileAsset(AssetPath const& path) noexcept + void SHAssetManager::CompileAsset(AssetPath const& path) noexcept { - SHAsset newAsset - { - .name = path.stem().string() - }; - + if (!std::filesystem::exists(path)) + { + SHLOG_ERROR("Path provided does not point to a file: {}", path.string()); + return; + } + AssetPath newPath; auto const ext{ path.extension().string() }; if (ext == GLSL_EXTENSION.data()) { - newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); - newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN); - newAsset.type = AssetType::SHADER_BUILT_IN; + newPath = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); } + else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data()) + { + std::string command = MODEL_COMPILER_EXE.data(); + command += " " + path.string(); + std::system(command.c_str()); - assetCollection.insert({ newAsset.id, newAsset }); - SHAssetMetaHandler::WriteMetaData(newAsset); + std::string modelPath = path.string().substr(0, path.string().find_last_of('.')); + modelPath += MODEL_EXTENSION; + newPath = modelPath; + + GenerateNewMeta(newPath); + } - return newAsset.id; } FolderPointer SHAssetManager::GetRootFolder() noexcept @@ -395,23 +404,15 @@ namespace SHADE for (auto const& path : paths) { - SHAsset newAsset - { - .name = path.stem().string() - }; - + AssetPath newPath; auto const ext{ path.extension().string() }; if (ext == GLSL_EXTENSION.data()) { - newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); - newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN); - newAsset.type = AssetType::SHADER_BUILT_IN; + newPath = SHShaderSourceCompiler::LoadAndCompileShader(path).value(); } else if (ext == DDS_EXTENSION.data()) { - newAsset.path = SHTextureCompiler::CompileTextureAsset(path).value(); - newAsset.id = GenerateAssetID(AssetType::TEXTURE); - newAsset.type = AssetType::TEXTURE; + newPath = SHTextureCompiler::CompileTextureAsset(path).value(); } else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data()) { @@ -419,15 +420,12 @@ namespace SHADE command += " " + path.string(); std::system(command.c_str()); - std::string newPath = path.string().substr(0, path.string().find_last_of('.')); - newPath += MESH_EXTENSION; - newAsset.path = newPath; - newAsset.id = GenerateAssetID(AssetType::MESH); - newAsset.type = AssetType::MESH; + std::string modelPath = path.string().substr(0, path.string().find_last_of('.')); + modelPath += MODEL_EXTENSION; + newPath = modelPath; } - assetCollection.insert({ newAsset.id, newAsset }); - SHAssetMetaHandler::WriteMetaData(newAsset); + GenerateNewMeta(newPath); } } @@ -442,10 +440,11 @@ namespace SHADE loaders[static_cast(AssetType::SHADER)] = dynamic_cast(new SHShaderSourceLoader()); loaders[static_cast(AssetType::SHADER_BUILT_IN)] = loaders[static_cast(AssetType::SHADER)]; loaders[static_cast(AssetType::TEXTURE)] = dynamic_cast(new SHTextureLoader()); - loaders[static_cast(AssetType::MESH)] = dynamic_cast(new SHMeshLoader()); + loaders[static_cast(AssetType::MODEL)] = dynamic_cast(new SHModelLoader()); loaders[static_cast(AssetType::SCENE)] = dynamic_cast(new SHTextBasedLoader()); loaders[static_cast(AssetType::PREFAB)] = loaders[static_cast(AssetType::SCENE)]; loaders[static_cast(AssetType::MATERIAL)] = loaders[static_cast(AssetType::SCENE)]; + loaders[static_cast(AssetType::MESH)] = nullptr; } /**************************************************************************** @@ -453,9 +452,9 @@ namespace SHADE ****************************************************************************/ void SHAssetManager::Load() noexcept { - //CompileAll(); BuildAssetCollection(); InitLoaders(); + //CompileAll(); //LoadAllData(); } @@ -473,8 +472,12 @@ namespace SHADE SHAssetData* SHAssetManager::LoadData(SHAsset const& asset) noexcept { - SHAssetData* data = loaders[static_cast(asset.type)]->Load(asset.path); + if (asset.isSubAsset) + { + return LoadSubData(asset); + } + SHAssetData* data = loaders[static_cast(asset.type)]->Load(asset.path); if (data == nullptr) { SHLOG_ERROR("Unable to load asset into memory: {}\n", asset.path.string()); @@ -487,13 +490,120 @@ namespace SHADE return data; } - void SHAssetManager::LoadDataFromScratch(AssetPath path) noexcept + SHAssetData* SHAssetManager::LoadSubData(SHAsset const& asset) noexcept { + auto const& parent = assetCollection[asset.parent]; + auto parentData = loaders[static_cast(parent.type)]->Load(parent.path); + if (parentData == nullptr) + { + SHLOG_ERROR("Unable to load asset into memory: {}\n", parent.path.string()); + } + else + { + assetData.emplace(parent.id, parentData); + if (parent.type == AssetType::MODEL) + { + auto parentModel = reinterpret_cast(parentData); + for (auto i {0}; i < parent.subAssets.size(); ++i) + { + assetData.emplace( + parent.subAssets[i]->id, + parentModel->subMeshes[i] + ); + } + } + + return assetData[asset.id]; + } + + return parentData; + } + + void SHAssetManager::LoadNewData(AssetPath path) noexcept + { + } + + void SHAssetManager::GenerateNewMeta(AssetPath path) noexcept + { + auto const ext = path.extension().string(); + if (ext == SHADER_BUILT_IN_EXTENSION.data()) + { + SHAsset newAsset{ + path.stem().string(), + GenerateAssetID(AssetType::SHADER_BUILT_IN), + AssetType::SHADER_BUILT_IN, + path, + false + }; + + assetCollection.emplace(newAsset.id, newAsset); + SHAssetMetaHandler::WriteMetaData(newAsset); + } + else if (ext == TEXTURE_EXTENSION.data()) + { + SHAsset newAsset{ + path.stem().string(), + GenerateAssetID(AssetType::SHADER_BUILT_IN), + AssetType::SHADER_BUILT_IN, + path, + false + }; + + assetCollection.emplace(newAsset.id, newAsset); + SHAssetMetaHandler::WriteMetaData(newAsset); + } + else if (ext == MODEL_EXTENSION) + { + SHAsset newAsset{ + path.stem().string(), + GenerateAssetID(AssetType::MODEL), + AssetType::MODEL, + path, + false + }; + + assetCollection.emplace(newAsset.id, newAsset); + + SHModelAsset* const data = reinterpret_cast(LoadData(newAsset)); + assetData.emplace(newAsset.id, data); + for(auto const& subMesh : data->subMeshes) + { + SHAsset subAsset{ + .name = subMesh->header.name, + .id = GenerateAssetID(AssetType::MESH), + .type = AssetType::MESH, + .isSubAsset = true, + .parent = newAsset.id + }; + + assetCollection.emplace(subAsset.id, subAsset); + assetCollection[newAsset.id].subAssets.push_back(&assetCollection[subAsset.id]); + + assetData.emplace(subAsset.id, subMesh); + } + + SHAssetMetaHandler::WriteMetaData(assetCollection[newAsset.id]); + } } void SHAssetManager::BuildAssetCollection() noexcept { SHFileSystem::BuildDirectory(ASSET_ROOT.data(), folderRoot, assetCollection); + + for (auto& asset : std::ranges::views::values(assetCollection)) + { + if (!asset.subAssets.empty()) + { + // Add subasset data into map, replace pointer and free heap memory + for (auto i{ 0 }; i < asset.subAssets.size(); ++i) + { + auto const id = asset.subAssets[i]->id; + assetCollection[id] = *asset.subAssets[i]; + delete asset.subAssets[i]; + asset.subAssets[i] = &assetCollection[id]; + } + } + } } } diff --git a/SHADE_Engine/src/Assets/SHAssetManager.h b/SHADE_Engine/src/Assets/SHAssetManager.h index 4daeb536..ba10d84f 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.h +++ b/SHADE_Engine/src/Assets/SHAssetManager.h @@ -87,7 +87,7 @@ namespace SHADE static std::vector GetAllDataOfType(AssetType type) noexcept; static std::vector GetAllRecordOfType(AssetType type) noexcept; - static AssetID CompileAsset(AssetPath const& path) noexcept; + static void CompileAsset(AssetPath const& path) noexcept; static FolderPointer GetRootFolder() noexcept; @@ -95,8 +95,11 @@ namespace SHADE static void InitLoaders() noexcept; static void LoadAllData() noexcept; - static SHAssetData* LoadData(SHAsset const& asset) noexcept; - static void LoadDataFromScratch(AssetPath path) noexcept; + static SHAssetData* LoadData(SHAsset const& asset) noexcept; + static SHAssetData* LoadSubData(SHAsset const& asset) noexcept; + static void LoadNewData(AssetPath path) noexcept; + static void GenerateNewMeta(AssetPath path) noexcept; + inline static void BuildAssetCollection() noexcept; static bool IsRecognised(char const*) noexcept; diff --git a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp index 1bfec00d..9ae8cde2 100644 --- a/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp +++ b/SHADE_Engine/src/Assets/SHAssetMetaHandler.cpp @@ -9,7 +9,6 @@ ******************************************************************************/ #include "SHpch.h" #include "SHAssetMetaHandler.h" -#include #include namespace SHADE @@ -21,11 +20,15 @@ namespace SHADE * \brief Helper function to retrieve field value from meta data file * for processing ****************************************************************************/ - void GetFieldValue(std::ifstream& file, std::string& line) noexcept + bool GetFieldValue(std::ifstream& file, std::string& line) noexcept { line = ""; - std::getline(file, line); - line = line.substr(line.find_last_of(':') + 2, line.length()); + if (std::getline(file, line)) + { + line = line.substr(line.find_last_of(':') + 2, line.length()); + return true; + } + return false; } /**************************************************************************** @@ -66,7 +69,8 @@ namespace SHADE std::ifstream metaFile{ path.string(), std::ios_base::in }; if (!metaFile.is_open()) { - // Error unable to open + SHLOG_ERROR("Unable to open meta file: {}", path.string()); + return {}; } std::string line; @@ -92,6 +96,43 @@ namespace SHADE AssetTypeMeta type; typeStream >> type; meta.type = static_cast(type); + + meta.isSubAsset = false; + + // Burn Line + if (std::getline(metaFile, line)) + { + // Name Line + while(GetFieldValue(metaFile, line)) + { + auto subAsset = new SHAsset(); + + // Get resource name + std::stringstream nameStream{ line }; + AssetName name; + nameStream >> name; + subAsset->name = name; + + // Get resource id + GetFieldValue(metaFile, line); + std::stringstream idStream{ line }; + AssetID id; + idStream >> id; + subAsset->id = id; + + // Get resource type + GetFieldValue(metaFile, line); + std::stringstream typeStream{ line }; + AssetTypeMeta type; + typeStream >> type; + subAsset->type = static_cast(type); + + subAsset->isSubAsset = true; + subAsset->parent = meta.id; + + meta.subAssets.push_back(subAsset); + } + } metaFile.close(); @@ -108,6 +149,12 @@ namespace SHADE ****************************************************************************/ void SHAssetMetaHandler::WriteMetaData(SHAsset const& meta) noexcept { + if (meta.isSubAsset) + { + SHLOG_WARNING("Cannot write subasset meta: {}", meta.name); + return; + } + //TODO: Write into binary eventually std::string path{ meta.path.string() }; path.append(META_EXTENSION); @@ -124,7 +171,23 @@ namespace SHADE metaFile << "ID: " << meta.id << "\n"; metaFile << "Type: " << static_cast(meta.type) << std::endl; + if (!meta.subAssets.empty()) + { + metaFile << "Sub Assets:\n"; + + for (auto const& subAsset : meta.subAssets) + { + WriteSubAssetMeta(metaFile, *subAsset); + } + } + metaFile.close(); } + void SHAssetMetaHandler::WriteSubAssetMeta(std::ofstream& metaFile, SHAsset const& subAsset) noexcept + { + metaFile << "Name: " << subAsset.name << "\n"; + metaFile << "ID: " << subAsset.id << "\n"; + metaFile << "Type: " << static_cast(subAsset.type) << std::endl; + } } diff --git a/SHADE_Engine/src/Assets/SHAssetMetaHandler.h b/SHADE_Engine/src/Assets/SHAssetMetaHandler.h index 88b5329d..ffa965aa 100644 --- a/SHADE_Engine/src/Assets/SHAssetMetaHandler.h +++ b/SHADE_Engine/src/Assets/SHAssetMetaHandler.h @@ -12,6 +12,7 @@ #include "SHAssetMacros.h" #include "SHAsset.h" +#include namespace SHADE { @@ -45,6 +46,8 @@ namespace SHADE * \brief Writes meta data into text file ****************************************************************************/ static void WriteMetaData(SHAsset const&) noexcept; + + static void WriteSubAssetMeta(std::ofstream&, SHAsset const&) noexcept; }; }