diff --git a/SHADE_Engine/SHADE_Engine.vcxproj b/SHADE_Engine/SHADE_Engine.vcxproj index 2613f1dc..ca421c40 100644 --- a/SHADE_Engine/SHADE_Engine.vcxproj +++ b/SHADE_Engine/SHADE_Engine.vcxproj @@ -71,7 +71,7 @@ Windows true - vulkan-1.lib;shlwapi.lib;assimp-vc142-mtd.lib;ktxd.lib;librttr_core_d.lib;%(AdditionalDependencies) + vulkan-1.lib;shaderc_shared.lib;shlwapi.lib;assimp-vc142-mtd.lib;ktxd.lib;librttr_core_d.lib;%(AdditionalDependencies) libs;$(VULKAN_SDK)\Lib;..\Dependencies\assimp\lib\Debug;..\Dependencies\assimp\lib\Release;..\Dependencies\RTTR\lib;..\Dependencies\ktx\lib\Debug;..\Dependencies\ktx\lib\Release;%(AdditionalLibraryDirectories) bin\Debug_x86_64\SHADE_Engine\SHADE_Engine.lib @@ -99,7 +99,7 @@ Windows true true - vulkan-1.lib;shlwapi.lib;assimp-vc142-mt.lib;ktx.lib;librttr_core.lib;%(AdditionalDependencies) + vulkan-1.lib;shaderc_shared.lib;shlwapi.lib;assimp-vc142-mt.lib;ktx.lib;librttr_core.lib;%(AdditionalDependencies) libs;$(VULKAN_SDK)\Lib;..\Dependencies\assimp\lib\Debug;..\Dependencies\assimp\lib\Release;..\Dependencies\RTTR\lib;..\Dependencies\ktx\lib\Debug;..\Dependencies\ktx\lib\Release;%(AdditionalLibraryDirectories) bin\Release_x86_64\SHADE_Engine\SHADE_Engine.lib @@ -108,20 +108,21 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -194,6 +195,7 @@ + @@ -207,13 +209,14 @@ - - - - - - + + + + + + + @@ -270,6 +273,7 @@ Create + diff --git a/SHADE_Engine/SHADE_Engine.vcxproj.filters b/SHADE_Engine/SHADE_Engine.vcxproj.filters index 67d6bec9..f9b4dee7 100644 --- a/SHADE_Engine/SHADE_Engine.vcxproj.filters +++ b/SHADE_Engine/SHADE_Engine.vcxproj.filters @@ -1,23 +1,26 @@ + + {1AB26817-067F-C322-2F98-B1CA1BC4F8B0} + + + {EFD23933-5B34-1741-E4A1-5DF350024E00} + + + {261D0942-92A8-7606-9BB9-F9FA07C4D206} + + + {07FEB307-F3F6-D259-1C29-B8DE0881B265} + + + {EE037863-5A8F-E527-63A0-681CCFAA4128} + {DBC7D3B0-C769-FE86-B024-12DB9C6585D7} - - {7FF59BF8-EB80-09BD-F491-8CB1609C65BD} - - - {340D0110-201D-ADE0-89D6-11FF75059C79} - - - {EBFC8BDC-D7F6-B42E-C063-4B3FACFC1A9B} - - - {6CD692F2-D80D-DB89-E117-3FAD4DCE0183} - - - {B3E3FAFD-9FDD-2350-884A-BA6074E389BC} + + {8A8E2B37-7646-6D84-DF4D-46E0CB240875} {1653CE33-0220-293F-2B39-17E717655ECD} @@ -117,48 +120,51 @@ - - Engine\ECS_Base\Components + + ECS_Base\Components - - Engine\ECS_Base\Components + + ECS_Base\Components - - Engine\ECS_Base\Entity + + ECS_Base\Entity - - Engine\ECS_Base\General + + ECS_Base\General - - Engine\ECS_Base\General + + ECS_Base\General - - Engine\ECS_Base\General + + ECS_Base\General - - Engine\ECS_Base\General + + ECS_Base\General - - Engine\ECS_Base\General + + ECS_Base\General - - Engine\ECS_Base + + ECS_Base - - Engine\ECS_Base\System + + ECS_Base\System - - Engine\ECS_Base\System + + ECS_Base\System - - Engine\ECS_Base\System + + ECS_Base\System - - Engine\ECS_Base\System + + ECS_Base\System Engine + + Filesystem + Graphics\Buffers @@ -373,6 +379,9 @@ Scene + + Scene + Scene @@ -408,27 +417,30 @@ - - Engine\ECS_Base\Components + + ECS_Base\Components - - Engine\ECS_Base\Components + + ECS_Base\Components - - Engine\ECS_Base\Entity + + ECS_Base\Entity - - Engine\ECS_Base\System + + ECS_Base\System - - Engine\ECS_Base\System + + ECS_Base\System - - Engine\ECS_Base\System + + ECS_Base\System Engine + + Filesystem + Graphics\Buffers @@ -589,6 +601,9 @@ Resource + + Scene + Scene diff --git a/SHADE_Engine/premake5.lua b/SHADE_Engine/premake5.lua index 83c3821b..39866d72 100644 --- a/SHADE_Engine/premake5.lua +++ b/SHADE_Engine/premake5.lua @@ -60,6 +60,7 @@ project "SHADE_Engine" "imgui", "spdlog", "vulkan-1.lib", + "shaderc_shared.lib", "shlwapi.lib" } diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp b/SHADE_Engine/src/ECS_Base/Components/SHComponent.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.cpp rename to SHADE_Engine/src/ECS_Base/Components/SHComponent.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h b/SHADE_Engine/src/ECS_Base/Components/SHComponent.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/Components/SHComponent.h rename to SHADE_Engine/src/ECS_Base/Components/SHComponent.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp b/SHADE_Engine/src/ECS_Base/Components/SHComponentGroup.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.cpp rename to SHADE_Engine/src/ECS_Base/Components/SHComponentGroup.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.h b/SHADE_Engine/src/ECS_Base/Components/SHComponentGroup.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/Components/SHComponentGroup.h rename to SHADE_Engine/src/ECS_Base/Components/SHComponentGroup.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.cpp rename to SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.h b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/Entity/SHEntity.h rename to SHADE_Engine/src/ECS_Base/Entity/SHEntity.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHFamily.h b/SHADE_Engine/src/ECS_Base/General/SHFamily.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/General/SHFamily.h rename to SHADE_Engine/src/ECS_Base/General/SHFamily.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHHandleGenerator.h b/SHADE_Engine/src/ECS_Base/General/SHHandleGenerator.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/General/SHHandleGenerator.h rename to SHADE_Engine/src/ECS_Base/General/SHHandleGenerator.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseBase.h b/SHADE_Engine/src/ECS_Base/General/SHSparseBase.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/General/SHSparseBase.h rename to SHADE_Engine/src/ECS_Base/General/SHSparseBase.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSet.h b/SHADE_Engine/src/ECS_Base/General/SHSparseSet.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSet.h rename to SHADE_Engine/src/ECS_Base/General/SHSparseSet.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSetContainer.h b/SHADE_Engine/src/ECS_Base/General/SHSparseSetContainer.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/General/SHSparseSetContainer.h rename to SHADE_Engine/src/ECS_Base/General/SHSparseSetContainer.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/SHECSMacros.h b/SHADE_Engine/src/ECS_Base/SHECSMacros.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/SHECSMacros.h rename to SHADE_Engine/src/ECS_Base/SHECSMacros.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp b/SHADE_Engine/src/ECS_Base/System/SHComponentManager.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.cpp rename to SHADE_Engine/src/ECS_Base/System/SHComponentManager.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.h b/SHADE_Engine/src/ECS_Base/System/SHComponentManager.h similarity index 99% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.h rename to SHADE_Engine/src/ECS_Base/System/SHComponentManager.h index 05a3d1ee..2f6ff504 100644 --- a/SHADE_Engine/src/Engine/ECS_Base/System/SHComponentManager.h +++ b/SHADE_Engine/src/ECS_Base/System/SHComponentManager.h @@ -34,7 +34,7 @@ namespace SHADE //The Container of all Componentgroups static std::vector componentGroups; - friend class SHSceneNode; + friend struct SHSceneNode; diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp b/SHADE_Engine/src/ECS_Base/System/SHEntityManager.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.cpp rename to SHADE_Engine/src/ECS_Base/System/SHEntityManager.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.h b/SHADE_Engine/src/ECS_Base/System/SHEntityManager.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHEntityManager.h rename to SHADE_Engine/src/ECS_Base/System/SHEntityManager.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystem.h b/SHADE_Engine/src/ECS_Base/System/SHSystem.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHSystem.h rename to SHADE_Engine/src/ECS_Base/System/SHSystem.h diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp b/SHADE_Engine/src/ECS_Base/System/SHSystemManager.cpp similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.cpp rename to SHADE_Engine/src/ECS_Base/System/SHSystemManager.cpp diff --git a/SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.h b/SHADE_Engine/src/ECS_Base/System/SHSystemManager.h similarity index 100% rename from SHADE_Engine/src/Engine/ECS_Base/System/SHSystemManager.h rename to SHADE_Engine/src/ECS_Base/System/SHSystemManager.h diff --git a/SHADE_Engine/src/Filesystem/SHFileSystem.cpp b/SHADE_Engine/src/Filesystem/SHFileSystem.cpp new file mode 100644 index 00000000..5663dadd --- /dev/null +++ b/SHADE_Engine/src/Filesystem/SHFileSystem.cpp @@ -0,0 +1,135 @@ +#include "SHpch.h" +#include "SHFileSystem.h" +#include "fileapi.h" +#include +#include +#include + +namespace SHADE +{ + char const FOLDER_MAX_COUNT {15}; + + std::unordered_map> SHFileSystem::folders; + FolderPointer SHFileSystem::root {nullptr}; + + SHFolder::SHFolder(FolderHandle id, FolderName name) + :id{ id }, name{ name }, subFolders(0), folded{ false }, path{""} + { + } + + FolderLocation SHFileSystem::CreateNewFolderHere(FolderName name, FolderLocation here) noexcept + { + if (here == 0) + { + if (!folders.contains(0)) + { + folders[0] = std::make_unique(0, "root"); + } + + auto const count = static_cast(folders[here]->subFolders.size()); + + assert(count < FOLDER_MAX_COUNT, "Max subfolders reached\n"); + + auto const location = static_cast(count); + + CreateFolder(folders[0]->path, here, location, name); + + return location; + } + + assert(folders.contains(here), "Folder creation location does not exist/invalid\n"); + + auto const count = static_cast(folders[here]->subFolders.size()); + + FolderHandle location = here; + location <<= FOLDER_BIT_ALLOCATE; + location |= count; + + assert(count < FOLDER_MAX_COUNT, "Max subfolders reached\n"); + CreateFolder(folders[0]->path, here, location, name); + + return location; + } + + bool SHFileSystem::DeleteFolder(FolderPointer location) noexcept + { + assert(folders.contains(location->id), "Delete target does not exist/invalid.\n"); + + for (auto const& subFolder : folders[location->id]->subFolders) + { + DeleteFolder(subFolder); + } + + RemoveDirectoryA(folders[location->id]->path.c_str()); + return true; + } + + void SHFileSystem::StartupFillDirectories(FolderPath path) noexcept + { + std::queue folderQueue; + + folderQueue.push(RegisterFolder(path, 0, 0, "Root")); + + while (!folderQueue.empty()) + { + auto folder = folderQueue.front(); + folderQueue.pop(); + FolderCounter count = 0; + + for (auto const& dirEntry : std::filesystem::directory_iterator(folder->path)) + { + if (!dirEntry.is_directory()) + { + continue; + } + + FolderLocation location = folder->id; + location <<= FOLDER_BIT_ALLOCATE; + location |= ++count; + + std::string name = dirEntry.path().string(); + name = name.substr(name.find_last_of('/') + 1, name.length() - name.find_last_of('/')); + + FolderPointer newFolder{ RegisterFolder( + dirEntry.path().string(), + folder->id, + location, + name) + }; + + folderQueue.push(newFolder); + folder->subFolders.push_back(newFolder); + } + } + } + + FolderPointer SHFileSystem::CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept + { + assert( + CreateDirectoryA(path.c_str(), nullptr), + "Failed to create folder\n" + ); + + folders[location] = std::make_unique(location, name); + folders[location]->path = path; + folders[parent]->subFolders.push_back(folders[location].get()); + + return FolderMakeHelper(path, parent, location, name); + } + + FolderPointer SHFileSystem::RegisterFolder(FolderPath path, FolderLocation parent, FolderHandle location, + FolderName name) noexcept + { + return FolderMakeHelper(path, parent, location, name); + } + + FolderPointer SHFileSystem::FolderMakeHelper(FolderPath path, FolderLocation parent, FolderHandle location, + FolderName name) noexcept + { + folders[location] = std::make_unique(location, name); + folders[location]->path = path; + folders[parent]->subFolders.push_back(folders[location].get()); + + return folders[location].get(); + } +} diff --git a/SHADE_Engine/src/Filesystem/SHFileSystem.h b/SHADE_Engine/src/Filesystem/SHFileSystem.h new file mode 100644 index 00000000..9b8b94a2 --- /dev/null +++ b/SHADE_Engine/src/Filesystem/SHFileSystem.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include +#include + +namespace SHADE +{ + class SHFolder; + + typedef unsigned char FolderCounter; + typedef unsigned char FileCounter; + typedef uint64_t FolderLocation; + typedef uint64_t FolderHandle; + typedef std::string FolderName; + typedef std::string FolderPath; + typedef SHFolder* FolderPointer; + + constexpr char FOLDER_BIT_ALLOCATE{ 4 }; + constexpr char FOLDER_MAX_DEPTH{ 16 }; + + class SHFolder + { + public: + SHFolder(FolderHandle id, FolderName name); + + FolderHandle id; + FolderName name; + std::vector subFolders; + + bool folded; + + private: + FolderPath path; + friend class SHFileSystem; + }; + + class SHFileSystem + { + public: + static FolderLocation CreateNewFolderHere(FolderName name, FolderLocation here = 0) noexcept; + + static bool DeleteFolder(FolderPointer location) noexcept; + + static void StartupFillDirectories(FolderPath path) noexcept; + + private: + static FolderPointer root; + + static std::unordered_map> folders; + + static FolderPointer CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept; + static FolderPointer RegisterFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept; + static FolderPointer FolderMakeHelper(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/SHpch.h b/SHADE_Engine/src/SHpch.h index b54a8a5b..0342eedb 100644 --- a/SHADE_Engine/src/SHpch.h +++ b/SHADE_Engine/src/SHpch.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp new file mode 100644 index 00000000..9c99fb5a --- /dev/null +++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp @@ -0,0 +1,475 @@ +/**************************************************************************************** + * \file SHSceneGraph.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Scene Graph & Scene Nodes. + * + * \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. +****************************************************************************************/ + +#include + +// Primary Header +#include "SHSceneGraph.h" + +// Project Headers +#include "ECS_Base/System/SHEntityManager.h" +#include "Tools/SHLogger.h" +#include "Tools/SHException.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHSceneNode::SHSceneNode(EntityID eid, SHSceneNode* parent) noexcept + : isActive { true } + , entityID { eid } + , parent { parent } + {} + + + SHSceneNode::SHSceneNode(const SHSceneNode& rhs) noexcept + : isActive { rhs.isActive } + , entityID { rhs.entityID } + , parent { rhs.parent } + { + std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children)); + } + + SHSceneNode::SHSceneNode(SHSceneNode&& rhs) noexcept + : isActive { rhs.isActive } + , entityID { rhs.entityID } + , parent { rhs.parent } + { + std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children)); + } + + SHSceneNode& SHSceneNode::operator=(const SHSceneNode& rhs) noexcept + { + if (this == &rhs) + return *this; + + isActive = rhs.isActive; + entityID = rhs.entityID; + parent = rhs.parent; + + children.clear(); + std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children)); + + return *this; + } + + SHSceneNode& SHSceneNode::operator=(SHSceneNode&& rhs) noexcept + { + isActive = rhs.isActive; + entityID = rhs.entityID; + parent = rhs.parent; + + children.clear(); + std::ranges::copy(rhs.children.begin(), rhs.children.end(), std::back_inserter(children)); + + return *this; + } + + SHSceneGraph::SHSceneGraph() noexcept + : root { nullptr } + {} + + SHSceneGraph::~SHSceneGraph() noexcept + { + SHASSERT(root != nullptr, "Unable to destroy a Scene without a root node!") + + #ifdef _DEBUG + SHLOG_INFO("Destroying Scene Graph...") + #endif + + // Go through the map and release all the nodes + for (auto* node : entityNodeMap | std::views::values) + ReleaseNode(node); + + #ifdef _DEBUG + SHLOG_INFO("Scene Graph Destroyed Successfully!") + #endif + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHSceneNode* SHSceneNode::GetChild(EntityID childID) const noexcept + { + // Error handling + { + if (!SHEntityManager::IsValidEID(childID)) + { + SHLOG_ERROR("Child Entity {} is invalid! Unable to get child from Entity {}", childID, entityID) + return nullptr; + } + + if (children.empty()) + { + SHLOG_WARNING("Entity {} has no children!", entityID) + return nullptr; + } + } + + // Find child + const auto ENTITY_MATCH = [&](const SHSceneNode* node) { return node->GetEntityID() == childID; }; + + const auto CHILD_ITER = std::ranges::find_if(children.begin(), children.end(),ENTITY_MATCH); + if (CHILD_ITER == children.end()) + { + SHLOG_WARNING("Entity {} is not a child of Entity {}! Unable to retrieve child node!", childID, entityID) + return nullptr; + } + + return *CHILD_ITER; + } + + SHSceneNode* SHSceneGraph::GetRoot() const noexcept + { + if (root != nullptr) + return root; + + SHLOG_WARNING("Scene has no root object!") + return nullptr; + } + + SHSceneNode* SHSceneGraph::GetNode(EntityID entityID) const noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid! Unable to Get Scene node!", entityID) + return nullptr; + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to Get Scene node!", entityID) + return nullptr; + } + + return NODE_ITER->second; + } + + SHSceneNode* SHSceneGraph::GetParent(EntityID entityID) const noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid! Unable to get Parent node!", entityID) + return nullptr; + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to get Parent node!", entityID) + return nullptr; + } + + return NODE_ITER->second->GetParent(); + } + + SHSceneNode* SHSceneGraph::GetChild(EntityID entityID, SHSceneNode* childNode) const noexcept + { + // Error Handling + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return nullptr; + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) + return nullptr; + } + + const auto& children = NODE_ITER->second->GetChildren(); + if (children.empty()) + { + SHLOG_WARNING("Entity {} has no children!", entityID) + return nullptr; + } + + const auto CHILD_ITER = std::ranges::find(children.begin(), children.end(), childNode); + if (CHILD_ITER == children.end()) + { + SHLOG_WARNING("Entity {} is not a child of Entity {}!", childNode->GetEntityID(), entityID) + return nullptr; + } + + return *CHILD_ITER; + } + + SHSceneNode* SHSceneGraph::GetChild(EntityID entityID, EntityID childEntityID) const noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return nullptr; + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) + return nullptr; + } + + return NODE_ITER->second->GetChild(childEntityID); + } + + const std::vector& SHSceneGraph::GetChildren(EntityID entityID) const noexcept + { + // TODO(Diren): Discuss with team best way to handle this + + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return root->GetChildren(); + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) + return root->GetChildren(); + } + + return NODE_ITER->second->GetChildren(); + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHSceneNode::SetParent(SHSceneNode* parentNode) noexcept + { + if (parentNode == nullptr) + SHLOG_WARNING("Removing Entity {}'s parent", entityID) + + if (parentNode == parent) + return; + + parent = parentNode; + // Update parent's children + parent->AddChild(this); + } + + void SHSceneGraph::SetParent(EntityID entityID, SHSceneNode* parent) const noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return; + } + + const auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) + return; + } + + NODE_ITER->second->SetParent(parent); + } + + void SHSceneGraph::SetParent(EntityID entityID, EntityID parent) const noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid! Unable to set parent of an invalid entity!", entityID) + return; + } + + if (!SHEntityManager::IsValidEID(parent)) + { + SHLOG_ERROR("Parent Entity {} is invalid! Unable to set Entity {}'s parent!", parent, entityID) + return; + } + + auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to set parent!", entityID) + return; + } + + auto PARENT_ITER = entityNodeMap.find(entityID); + if (PARENT_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to parent to Entity {}", parent, entityID) + return; + } + + SHSceneNode* currentNode = NODE_ITER->second; + currentNode->SetParent(PARENT_ITER->second); + } + + /*-----------------------------------------------------------------------------------*/ + /* Public Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHSceneNode::AddChild(SHSceneNode* newChild) noexcept + { + if (newChild == nullptr) + { + SHLOG_WARNING("Attempting to add a non-existent child to an entity!") + return; + } + + children.emplace_back(newChild); + } + + bool SHSceneNode::RemoveChild(EntityID childID) noexcept + { + if (!SHEntityManager::IsValidEID(childID)) + { + SHLOG_ERROR("Entity {} is invalid!", childID) + return false; + } + + SHSceneNode* removedChild = nullptr; + const auto ENTITY_MATCH = [&](SHSceneNode* node) + { + if (node->GetEntityID() == childID) + { + removedChild = node; + return true; + } + + return false; + }; + + children.end() = std::remove_if(children.begin(), children.end(), ENTITY_MATCH); + removedChild->parent = nullptr; + + return removedChild == nullptr; + } + + bool SHSceneNode::RemoveChild(SHSceneNode* childToRemove) noexcept + { + if (childToRemove == nullptr) + { + SHLOG_WARNING("Attempting to remove non-existent child from Entity {}", entityID) + return false; + } + + children.end() = std::remove(children.begin(), children.end(), childToRemove); + childToRemove->parent = nullptr; + + return true; + } + + void SHSceneNode::RemoveAllChildren() noexcept + { + for (const auto child : children) + child->parent = nullptr; + + children.clear(); + } + + + SHSceneNode* SHSceneGraph::AddNode(EntityID entityID, SHSceneNode* parent) + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return nullptr; + } + + if (auto NODE_ITER = entityNodeMap.find(entityID); NODE_ITER != entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} already exists in the scene!", entityID) + return NODE_ITER->second; + } + + SHSceneNode* newNode = AllocateNode(entityID); + newNode->SetParent(parent); + + return newNode; + } + + bool SHSceneGraph::RemoveNode(EntityID entityID) noexcept + { + if (!SHEntityManager::IsValidEID(entityID)) + { + SHLOG_ERROR("Entity {} is invalid!", entityID) + return false; + } + + auto NODE_ITER = entityNodeMap.find(entityID); + if (NODE_ITER == entityNodeMap.end()) + { + SHLOG_WARNING("Entity {} does not exist in the scene!", entityID) + return false; + } + + // Remove reference of current node from parent + SHSceneNode* currentNode = NODE_ITER->second; + SHSceneNode* parent = currentNode->GetParent(); + if (parent != nullptr) + parent->RemoveChild(currentNode); + + ReleaseNode(currentNode); + return true; + } + + bool SHSceneGraph::RemoveNode(SHSceneNode* nodeToRemove) noexcept + { + // Remove reference of current node from parent + SHSceneNode* parent = nodeToRemove->GetParent(); + if (parent != nullptr) + parent->RemoveChild(nodeToRemove); + + ReleaseNode(nodeToRemove); + return true; + } + + void SHSceneGraph::Reset() noexcept + { + for (auto* node : entityNodeMap | std::views::values) + ReleaseNode(node); + } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHSceneNode* SHSceneGraph::AllocateNode(EntityID entityID) + { + SHSceneNode* newNode = new SHSceneNode{entityID}; + + #ifdef _DEBUG + SHLOG_INFO("Allocated a new Scene Node for Entity {}!", entityID) + #endif + + entityNodeMap.emplace(entityID, newNode); + return newNode; + } + + void SHSceneGraph::ReleaseNode(SHSceneNode* node) noexcept + { + SHASSERT(node != nullptr, "Attempting to release Invalid Node!") + + // Remove parent's reference to this node if there is a parent + if (node->GetParent() != nullptr) + node->GetParent()->RemoveChild(node); + + // Remove child's references to this node. Children end up as floating nodes. + for (auto* child : node->GetChildren()) + { + child->SetParent(nullptr); + } + + entityNodeMap.erase(node->GetEntityID()); + delete node; + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h new file mode 100644 index 00000000..20830065 --- /dev/null +++ b/SHADE_Engine/src/Scene/SHSceneGraph.h @@ -0,0 +1,143 @@ +/**************************************************************************************** + * \file SHSceneGraph.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Scene Graph & Scene Nodes. + * + * \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. +****************************************************************************************/ + +#pragma once + +#include + +// Project Headers +#include "ECS_Base/Entity/SHEntity.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SHSceneNode + { + public: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + bool isActive; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + ~SHSceneNode () = default; + + SHSceneNode (EntityID eid, SHSceneNode* parent = nullptr) noexcept; + SHSceneNode (const SHSceneNode& rhs) noexcept; + SHSceneNode (SHSceneNode&& rhs) noexcept; + SHSceneNode& operator= (const SHSceneNode& rhs) noexcept; + SHSceneNode& operator= (SHSceneNode&& rhs) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] EntityID GetEntityID () const noexcept { return entityID ;} + [[nodiscard]] SHSceneNode* GetParent () const noexcept { return parent; } + [[nodiscard]] std::vector& GetChildren () noexcept { return children; } + + [[nodiscard]] SHSceneNode* GetChild (EntityID childID) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetParent (SHSceneNode* parentNode) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void AddChild (SHSceneNode* newChild) noexcept; + + bool RemoveChild (EntityID childID) noexcept; + bool RemoveChild (SHSceneNode* childToRemove) noexcept; + + void RemoveAllChildren () noexcept; + + private: + EntityID entityID; + SHSceneNode* parent; + std::vector children; + }; + + class SHSceneGraph + { + public: + /*---------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*---------------------------------------------------------------------------------*/ + + using EntityNodeMap = std::unordered_map; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHSceneGraph () noexcept; + ~SHSceneGraph () noexcept; + + SHSceneGraph (const SHSceneGraph&) = delete; + SHSceneGraph (SHSceneGraph&&) = delete; + SHSceneGraph& operator= (const SHSceneGraph&) = delete; + SHSceneGraph& operator= (SHSceneGraph&&) = delete; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] SHSceneNode* GetRoot () const noexcept; + [[nodiscard]] SHSceneNode* GetNode (EntityID entityID) const noexcept; + [[nodiscard]] SHSceneNode* GetParent (EntityID entityID) const noexcept; + [[nodiscard]] SHSceneNode* GetChild (EntityID entityID, SHSceneNode* childNode) const noexcept; + [[nodiscard]] SHSceneNode* GetChild (EntityID entityID, EntityID childEntityID) const noexcept; + [[nodiscard]] const std::vector& GetChildren (EntityID entityID) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetParent (EntityID entityID, SHSceneNode* parent) const noexcept; + void SetParent (EntityID entityID, EntityID parent) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + SHSceneNode* AddNode (EntityID entityID, SHSceneNode* parent = nullptr); + bool RemoveNode (EntityID entityID) noexcept; + bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; + void Reset () noexcept; + + private: + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + SHSceneNode* root; + EntityNodeMap entityNodeMap; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + SHSceneNode* AllocateNode (EntityID entityID); + void ReleaseNode (SHSceneNode* node) noexcept; + }; + + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Scene/SHSceneManager.cpp b/SHADE_Engine/src/Scene/SHSceneManager.cpp index ba2eafc2..a60df922 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.cpp +++ b/SHADE_Engine/src/Scene/SHSceneManager.cpp @@ -10,11 +10,11 @@ *********************************************************************/ #include "SHpch.h" #include "SHSceneManager.h" -#include "Engine/ECS_Base/System/SHComponentManager.h" +#include "ECS_Base/System/SHComponentManager.h" //#include "Input/SHInputManager.h" -//#include "Engine/Rendering/Window/SHRenderingWindow.h" -#include "Engine/ECS_Base/System/SHEntityManager.h" -#include "Engine/ECS_Base/System/SHSystemManager.h" +//#include "Rendering/Window/SHRenderingWindow.h" +#include "ECS_Base/System/SHEntityManager.h" +#include "ECS_Base/System/SHSystemManager.h" //#include "FRC/SHFrameRateController.h" //#include "ECS_Base/System/SHApplication.h" diff --git a/SHADE_Engine/src/Scene/SHSceneManager.h b/SHADE_Engine/src/Scene/SHSceneManager.h index 6e5caa37..4139309d 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.h +++ b/SHADE_Engine/src/Scene/SHSceneManager.h @@ -13,7 +13,7 @@ #define SH_SCENE_MANAGER_H -#include "Engine/ECS_Base/General/SHFamily.h" +#include "ECS_Base/General/SHFamily.h" #include "SHScene.h" #include