Merge remote-tracking branch 'origin/main' into SP3-2-Physics

This commit is contained in:
Diren D Bharwani 2022-11-12 16:57:45 +08:00
commit 3faf3804aa
14 changed files with 598 additions and 109 deletions

View File

@ -27,6 +27,11 @@ public class RaccoonShowcase : Script
Debug.LogError("Transform is NULL!");
}
foreach (var child in Owner)
{
Debug.Log(child.Name);
}
originalScale = Transform.LocalScale.z;
}
protected override void update()

View File

@ -52,6 +52,8 @@ enum class AssetType : AssetTypeMeta
PREFAB,
MATERIAL,
MESH,
SCRIPT,
FONT,
MAX_COUNT
};
constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) };
@ -85,32 +87,39 @@ 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 MODEL_EXTENSION {".shmodel"};
constexpr std::string_view MODEL_EXTENSION{ ".shmodel" };
constexpr std::string_view FONT_EXTENSION{ ".shfont" };
constexpr std::string_view EXTENSIONS[] = {
AUDIO_EXTENSION,
SHADER_EXTENSION,
SHADER_BUILT_IN_EXTENSION,
MATERIAL_EXTENSION,
TEXTURE_EXTENSION,
TEXTURE_EXTENSION,
MODEL_EXTENSION,
SCRIPT_EXTENSION,
SCENE_EXTENSION,
SCENE_EXTENSION,
PREFAB_EXTENSION,
MATERIAL_EXTENSION,
"dummy",
SCRIPT_EXTENSION,
FONT_EXTENSION,
AUDIO_WAV_EXTENSION,
};
constexpr size_t EXTENSIONS_COUNT{ 11 };
// EXTERNAL EXTENSIONS
constexpr std::string_view GLSL_EXTENSION{ ".glsl" };
constexpr std::string_view DDS_EXTENSION{ ".dds" };
constexpr std::string_view FBX_EXTENSION{ ".fbx" };
constexpr std::string_view GLTF_EXTENSION{ ".gltf" };
constexpr std::string_view TTF_EXTENSION{ ".ttf" };
constexpr std::string_view EXTERNALS[] = {
GLSL_EXTENSION,
DDS_EXTENSION,
FBX_EXTENSION,
GLTF_EXTENSION
GLTF_EXTENSION,
TTF_EXTENSION
};
// SHADER IDENTIFIERS
@ -125,11 +134,4 @@ constexpr std::pair<std::string_view, SHADE::SH_SHADER_TYPE> SHADER_IDENTIFIERS[
};
constexpr size_t SHADER_TYPE_MAX_COUNT{ 3 };
// Error flags
constexpr std::string_view FILE_NOT_FOUND_ERR {"FILE NOT FOUND"};
constexpr std::string_view META_NOT_FOUND_ERR {"META NOT FOUND"};
constexpr std::string_view ASSET_NOT_FOUND_ERR {"ASSET NOT FOUND"};
constexpr std::string_view EXT_DOES_NOT_EXIST {"TYPE DOES NOT HAVE EXTENSION DEFINED"};
#endif // !SH_ASSET_MACROS_H

View File

@ -338,7 +338,7 @@ namespace SHADE
return result;
}
void SHAssetManager::CompileAsset(AssetPath const& path) noexcept
void SHAssetManager::CompileAsset(AssetPath const& path, bool genMeta) noexcept
{
if (!std::filesystem::exists(path))
{
@ -360,10 +360,12 @@ namespace SHADE
std::string modelPath = path.string().substr(0, path.string().find_last_of('.'));
modelPath += MODEL_EXTENSION;
newPath = modelPath;
GenerateNewMeta(newPath);
}
if (genMeta)
{
GenerateNewMeta(newPath);
}
}
FolderPointer SHAssetManager::GetRootFolder() noexcept
@ -371,6 +373,13 @@ namespace SHADE
return folderRoot;
}
void SHAssetManager::RefreshDirectory() noexcept
{
SHFileSystem::DestroyDirectory(folderRoot);
assetCollection.clear();
BuildAssetCollection();
}
bool SHAssetManager::IsRecognised(char const* ext) noexcept
{
for (auto const& e : EXTENSIONS)
@ -396,51 +405,6 @@ namespace SHADE
return result;
}
void SHAssetManager::CompileAll() noexcept
{
std::vector<AssetPath> paths;
for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT })
{
if (dir.is_regular_file())
{
for (auto const& ext : EXTERNALS)
{
if (dir.path().extension().string() == ext.data())
{
paths.push_back(dir.path());
}
}
}
}
for (auto const& path : paths)
{
AssetPath newPath;
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newPath = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
}
else if (ext == DDS_EXTENSION.data())
{
newPath = SHTextureCompiler::CompileTextureAsset(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());
std::string modelPath = path.string().substr(0, path.string().find_last_of('.'));
modelPath += MODEL_EXTENSION;
newPath = modelPath;
}
GenerateNewMeta(newPath);
}
}
bool SHAssetManager::DeleteLocalFile(AssetPath path) noexcept
{
//TODO Move this to dedicated library

View File

@ -87,9 +87,10 @@ namespace SHADE
static std::vector<SHAssetData const*> GetAllDataOfType(AssetType type) noexcept;
static std::vector<SHAsset> GetAllRecordOfType(AssetType type) noexcept;
static void CompileAsset(AssetPath const& path) noexcept;
static void CompileAsset(AssetPath const& path, bool genMeta) noexcept;
static FolderPointer GetRootFolder() noexcept;
static void RefreshDirectory() noexcept;
private:
@ -106,8 +107,6 @@ namespace SHADE
static SHAsset CreateAssetFromPath(AssetPath path) noexcept;
static void CompileAll() noexcept;
static bool DeleteLocalFile(AssetPath path) noexcept;
//TODO use this function to create asset data internall at all calls to generate id

View File

@ -38,7 +38,7 @@ namespace SHADE
****************************************************************************/
AssetType SHAssetMetaHandler::GetTypeFromExtension(AssetExtension ext) noexcept
{
for (int i{0}; i < EXTENSIONS->size(); ++i)
for (auto i{0}; i < EXTENSIONS_COUNT; ++i)
{
if (strcmp(ext.c_str(), EXTENSIONS[i].data()) == 0)
{
@ -98,6 +98,7 @@ namespace SHADE
meta.type = static_cast<AssetType>(type);
meta.isSubAsset = false;
meta.parent = 0;
// Burn Line
if (std::getline(metaFile, line))

View File

@ -12,6 +12,7 @@
#include "SHFileSystem.h"
#include <filesystem>
#include <queue>
#include <stack>
#include "Assets/SHAssetMetaHandler.h"
@ -24,29 +25,77 @@ namespace SHADE
return true;
}
void SHFileSystem::BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept
bool SHFileSystem::IsCompilable(std::string ext) noexcept
{
for (auto const& external : EXTERNALS)
{
if (ext == external)
{
return true;
}
}
return false;
}
bool SHFileSystem::MatchExtention(FileExt raw, FileExt compiled) noexcept
{
if (raw == GLSL_EXTENSION)
{
if (compiled == SHADER_EXTENSION ||
compiled == SHADER_BUILT_IN_EXTENSION)
{
return true;
}
}
else if (raw == DDS_EXTENSION)
{
if (compiled == TEXTURE_EXTENSION)
{
return true;
}
}
else if (raw == FBX_EXTENSION)
{
if (compiled == MODEL_EXTENSION)
{
return true;
}
}
else if (raw == GLTF_EXTENSION)
{
if (compiled == MODEL_EXTENSION)
{
return true;
}
}
return false;
}
void SHFileSystem::BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept
{
std::queue<FolderPointer> folderQueue;
std::stack<FolderPointer> folderStack;
root = new SHFolder("root");
root->path = path;
folderQueue.push(root);
folderStack.push(root);
while (!folderQueue.empty())
while (!folderStack.empty())
{
auto const folder = folderQueue.front();
folderQueue.pop();
auto const folder = folderStack.top();
folderStack.pop();
std::vector<SHAsset> assets;
for (auto const& dirEntry : std::filesystem::directory_iterator(folder->path))
// Get all subfolders/files in this current folder
for (auto& dirEntry : std::filesystem::directory_iterator(folder->path))
{
auto const& path = dirEntry.path();
auto path = dirEntry.path();
path.make_preferred();
if (!dirEntry.is_directory())
{
if (path.extension().string() == META_EXTENSION)
{
//auto asset = SHAssetMetaHandler::RetrieveMetaData(path);
//assetCollection.insert({ asset.id, asset });
assets.push_back(SHAssetMetaHandler::RetrieveMetaData(path));
}
else
@ -55,14 +104,17 @@ namespace SHADE
path.stem().string(),
path.string(),
path.extension().string(),
nullptr
nullptr,
IsCompilable(path.extension().string()),
false
);
}
continue;
}
// If item is folder
auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) };
folderQueue.push(newFolder);
folderStack.push(newFolder);
}
for (auto const& asset : assets)
@ -72,11 +124,58 @@ namespace SHADE
{
if (file.name == asset.name)
{
file.assetMeta = &assetCollection[asset.id];
break;
AssetPath path{ file.path };
if (SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()) == asset.type)
{
file.assetMeta = &assetCollection[asset.id];
break;
}
}
}
}
for (auto i {0}; i < folder->files.size(); ++i)
{
auto& file = folder->files[i];
if (file.compilable)
{
for (auto j{ 0 }; j < folder->files.size(); ++j)
{
auto& check = folder->files[j];
if (i == j || check.compilable)
{
continue;
}
if (file.name == check.name)
{
if (MatchExtention(file.ext, check.ext))
{
file.compiled = true;
}
}
}
}
}
}
}
void SHFileSystem::DestroyDirectory(FolderPointer root) noexcept
{
std::stack<FolderPointer> folderStack;
folderStack.push(root);
while(!folderStack.empty())
{
auto const folder = folderStack.top();
folderStack.pop();
for (auto const& ptr : folder->subFolders)
{
folderStack.push(ptr);
}
delete folder;
}
}
}

View File

@ -20,9 +20,10 @@ namespace SHADE
{
public:
static void BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept;
static void DestroyDirectory(FolderPointer root) noexcept;
private:
static bool DeleteFolder(FolderPointer location) noexcept;
static bool IsCompilable(std::string ext) noexcept;
static bool MatchExtention(FileExt raw, FileExt compiled) noexcept;
};
}

View File

@ -33,6 +33,8 @@ namespace SHADE
FilePath path;
FileExt ext;
SHAsset const* assetMeta;
bool compilable;
bool compiled;
};
class SHFolder

View File

@ -265,18 +265,18 @@ namespace SHADE
</ItemGroup>\n\
<ItemGroup>\n\
<Reference Include=\"SHADE_Managed\">\n\
<HintPath Condition=\"Exists('..\\bin\\Debug\\SHADE_Managed.dll')\">..\\bin\\Debug\\SHADE_Managed.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\bin\\Release\\SHADE_Managed.dll')\">..\\bin\\Release\\SHADE_Managed.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\..\\bin\\Debug\\SHADE_Managed.dll')\">..\\..\\bin\\Debug\\SHADE_Managed.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\..\\bin\\Release\\SHADE_Managed.dll')\">..\\..\\bin\\Release\\SHADE_Managed.dll</HintPath>\n\
</Reference>\n\
<Reference Include=\"SHADE_CSharp\">\n\
<HintPath Condition=\"Exists('..\\bin\\Debug\\SHADE_Managed.dll')\">..\\bin\\Debug\\SHADE_CSharp.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\bin\\Release\\SHADE_Managed.dll')\">..\\bin\\Release\\SHADE_CSharp.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\..\\bin\\Debug\\SHADE_Managed.dll')\">..\\..\\bin\\Debug\\SHADE_CSharp.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\..\\bin\\Release\\SHADE_Managed.dll')\">..\\..\\bin\\Release\\SHADE_CSharp.dll</HintPath>\n\
</Reference>\n\
</ItemGroup>\n\
</Project>";
// Attempt to create the file
std::ofstream file(path);
std::ofstream file(path, std::ios::out | std::ios::trunc);
if (!file.is_open())
throw std::runtime_error("Unable to create CsProj file!");
@ -319,6 +319,20 @@ namespace SHADE
return eventData->handle;
}
SHEventHandle SHScriptEngine::onSceneNodeChildrenAdded(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHSceneGraphAddChildEvent>*>(eventPtr.get());
csSceneNodeChildrenChanged(eventData->data->parent->GetEntityID());
return eventData->handle;
}
SHEventHandle SHScriptEngine::onSceneNodeChildrenRemoved(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHSceneGraphRemoveChildEvent>*>(eventPtr.get());
csSceneNodeChildrenChanged(eventData->data->parent->GetEntityID());
return eventData->handle;
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
@ -443,6 +457,12 @@ namespace SHADE
DEFAULT_CSHARP_NAMESPACE + ".Collider",
"OnCollisionShapeRemoved"
);
csSceneNodeChildrenChanged = dotNet.GetFunctionPtr<CsEventRelayFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ChildListCache",
"OnChildrenChanged"
);
csEditorRenderScripts = dotNet.GetFunctionPtr<CsScriptEditorFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
@ -465,6 +485,7 @@ namespace SHADE
void SHScriptEngine::registerEvents()
{
/* Entity */
// Register for entity destroyed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> destroyedEventReceiver
{
@ -472,26 +493,39 @@ namespace SHADE
};
SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(destroyedEventReceiver));
/* Colliders */
// Register for collider added event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> addedColliderEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderAdded)
};
SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_ADDED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(addedColliderEventReceiver));
// Register for collider removed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedColliderEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderRemoved)
};
SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedColliderEventReceiver));
// Register for collider component removed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedColliderComponentEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderComponentRemoved)
};
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedColliderComponentEventReceiver));
/* SceneGraph */
// Register for SceneNode child added event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> addChildEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onSceneNodeChildrenAdded)
};
SHEventManager::SubscribeTo(SH_SCENEGRAPH_ADD_CHILD_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(addChildEventReceiver));
// Register for SceneNode child removed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removeChildEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onSceneNodeChildrenRemoved)
};
SHEventManager::SubscribeTo(SH_SCENEGRAPH_REMOVE_CHILD_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removeChildEventReceiver));
}
void SHScriptEngine::dumpBuildLog(const std::string_view& buildLogPath)

View File

@ -267,6 +267,7 @@ namespace SHADE
// - Events
CsEventRelayFuncPtr csColliderOnListChanged = nullptr;
CsEventRelayFuncPtr csColliderOnRemoved = nullptr;
CsEventRelayFuncPtr csSceneNodeChildrenChanged = nullptr;
// - Editor
CsScriptEditorFuncPtr csEditorRenderScripts = nullptr;
CsFuncPtr csEditorUndo = nullptr;
@ -279,6 +280,8 @@ namespace SHADE
SHEventHandle onColliderAdded(SHEventPtr eventPtr);
SHEventHandle onColliderRemoved(SHEventPtr eventPtr);
SHEventHandle onColliderComponentRemoved(SHEventPtr eventPtr);
SHEventHandle onSceneNodeChildrenAdded(SHEventPtr eventPtr);
SHEventHandle onSceneNodeChildrenRemoved(SHEventPtr eventPtr);
/*-----------------------------------------------------------------------------*/
/* Helper Functions */

View File

@ -0,0 +1,89 @@
/************************************************************************************//*!
\file ChildListCache.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 11, 2022
\brief Contains the definition of the functions for the ChildListCache managed
class.
Note: This file is written in C++17/CLI.
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.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "ChildListCache.hxx"
// External Dependencies
#include "Scene/SHSceneManager.h"
// Project Headers
#include "Utility/Debug.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Static Usage Functions */
/*---------------------------------------------------------------------------------*/
ChildListCache::ChildEnumerable^ ChildListCache::GetChildList(Entity entity)
{
// Ignore if invalid
if (entity == MAX_EID)
return nullptr;
// Check if in cache
if (cachedLists->ContainsKey(entity))
return cachedLists[entity];
// Grab the native child list
auto node = GameObject(entity).GetSceneNode();
if (!node || node->GetChildren().empty())
return nullptr;
// Otherwise
// - Create the list
ChildList^ list = gcnew ChildList();
updateChildList(list, node);
// - Cache it
cachedLists[entity] = list;
return list;
}
void ChildListCache::UpdateChildList(Entity entity)
{
// Ignore if invalid
if (entity == MAX_EID)
return;
// Check if in cache
if (!cachedLists->ContainsKey(entity))
return;
// Update
updateChildList(cachedLists[entity], GameObject(entity).GetSceneNode());
}
/*---------------------------------------------------------------------------------*/
/* Event Handling Functions */
/*---------------------------------------------------------------------------------*/
void ChildListCache::OnChildrenChanged(EntityID entity)
{
SAFE_NATIVE_CALL_BEGIN
UpdateChildList(entity);
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ChildListCache")
}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
void ChildListCache::updateChildList(ChildList^ list, const SHSceneNode* sceneNode)
{
list->Clear();
for (auto node : sceneNode->GetChildren())
{
list->Add(GameObject(node->GetEntityID()));
}
}
}

View File

@ -0,0 +1,80 @@
/************************************************************************************//*!
\file ChildListCache.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 11, 2022
\brief Contains the definition of the ChildListCache managed class.
Note: This file is written in C++17/CLI.
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
// Project Includes
#include "GameObject.hxx"
namespace SHADE { }
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Forward Declarations */
/*---------------------------------------------------------------------------------*/
class SHSceneNode;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Static class that caches all the lists of children for GameObjects.
/// </summary>
private ref class ChildListCache abstract sealed
{
public:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
using ChildList = System::Collections::Generic::List<GameObject>;
using ChildEnumerable = System::Collections::Generic::IEnumerable<GameObject>;
using ListMap = System::Collections::Generic::Dictionary<Entity, ChildList^>;
internal:
/*-----------------------------------------------------------------------------*/
/* Static Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Retrieves the children list for the specified Entity.
/// </summary>
/// <returns>
/// Enumerable read only list of an Entity's children. Null if entity is invalid
/// or there are no children.
/// </returns>
static ChildEnumerable^ GetChildList(Entity entity);
/// <summary>
/// Updates the children list for the specified Entity if it exists.
/// </summary>
static void UpdateChildList(Entity entity);
/*-----------------------------------------------------------------------------*/
/* Event Handling Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// To be
/// </summary>
static void OnChildrenChanged(EntityID entity);
private:
/*-----------------------------------------------------------------------------*/
/* Static Data Members */
/*-----------------------------------------------------------------------------*/
static ListMap^ cachedLists = gcnew ListMap();
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
static void updateChildList(ChildList^ list, const SHSceneNode* sceneNode);
};
}

View File

@ -23,6 +23,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Utility/Convert.hxx"
#include "Scripts/ScriptStore.hxx"
#include "Utility/Debug.hxx"
#include "ChildListCache.hxx"
namespace SHADE
{
@ -87,30 +88,43 @@ namespace SHADE
throw gcnew System::NullReferenceException();
return entity;
}
GameObject^ GameObject::Parent::get()
GameObject GameObject::Parent::get()
{
if (!valid)
throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot();
const auto* NODE = SCENE_GRAPH.GetNode(entity);
if (NODE == nullptr)
throw gcnew System::InvalidOperationException("Unable to retrieve SceneGraphNode for Entity " + entity.ToString());
const auto* PARENT = NODE->GetParent();
return PARENT != ROOT ? gcnew GameObject(PARENT->GetEntityID()) : nullptr;
return PARENT != ROOT ? GameObject(PARENT->GetEntityID()) : GameObject();
}
void GameObject::Parent::set(GameObject^ newParent)
void GameObject::Parent::set(GameObject newParent)
{
if (!valid)
throw gcnew System::NullReferenceException();
auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
if (newParent == nullptr)
SCENE_GRAPH.SetParent(entity, nullptr);
if (newParent)
SCENE_GRAPH.SetParent(entity, newParent.EntityId);
else
SCENE_GRAPH.SetParent(entity, newParent->EntityId);
SCENE_GRAPH.SetParent(entity, nullptr);
}
int GameObject::ChildCount::get()
{
if (!valid)
throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot();
const auto* NODE = SCENE_GRAPH.GetNode(entity);
if (NODE == nullptr)
throw gcnew System::InvalidOperationException("Unable to retrieve SceneGraphNode for Entity " + entity.ToString());
return static_cast<int>(NODE->GetChildren().size());
}
/*---------------------------------------------------------------------------------*/
@ -215,6 +229,90 @@ namespace SHADE
ScriptStore::RemoveScript<T>(entity);
}
/*---------------------------------------------------------------------------------*/
/* Scene Graph Functions */
/*---------------------------------------------------------------------------------*/
void GameObject::DetachChildren()
{
// Validity Checks
if (!valid)
throw gcnew System::NullReferenceException();
auto node = GetSceneNode();
if (!node)
throw gcnew System::NullReferenceException();
// Unparent all children to the root
for (auto child : node->GetChildren())
{
SHSceneManager::GetCurrentSceneGraph().SetParent(child->GetEntityID(), nullptr);
}
ChildListCache::UpdateChildList(entity);
}
GameObject GameObject::GetChild(int index)
{
// Validity Checks
if (!valid)
throw gcnew System::NullReferenceException();
auto node = GetSceneNode();
if (!node)
throw gcnew System::NullReferenceException();
auto child = node->GetChild(index);
return child ? GameObject(child->GetEntityID()) : GameObject();
}
System::Collections::Generic::IEnumerable<GameObject>^ GameObject::GetChildren()
{
// Validity Checks
if (!valid)
throw gcnew System::NullReferenceException();
return ChildListCache::GetChildList(entity);
}
int GameObject::GetSiblingIndex()
{
throw gcnew System::NotImplementedException();
}
bool GameObject::IsChildOf(GameObject gameObj)
{
// Search parents recursively
auto node = GetSceneNode();
while (node != nullptr)
{
if (node->GetEntityID() == gameObj.entity)
return true;
// Go up higher
node = node->GetParent();
}
return false;
}
void GameObject::SetAsFirstSibling()
{
throw gcnew System::NotImplementedException();
}
void GameObject::SetAsLastSibling()
{
throw gcnew System::NotImplementedException();
}
void GameObject::SetSiblingIndex(int index)
{
throw gcnew System::NotImplementedException();
}
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
GameObject::operator bool(GameObject gameObj)
{
return gameObj.valid;
}
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
@ -245,11 +343,15 @@ namespace SHADE
}
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
GameObject::operator bool(GameObject gameObj)
SHSceneNode* GameObject::GetSceneNode()
{
return gameObj.valid;
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot();
if (!ROOT)
return nullptr;
return SCENE_GRAPH.GetNode(entity);
}
/*---------------------------------------------------------------------------------*/
@ -290,4 +392,21 @@ namespace SHADE
{
return !(lhs == rhs);
}
/*---------------------------------------------------------------------------------*/
/* IEnummerable */
/*---------------------------------------------------------------------------------*/
System::Collections::Generic::IEnumerator<GameObject>^ GameObject::GetEnumerator()
{
System::Collections::Generic::IEnumerable<GameObject>^ childList = GetChildren();
if (childList == nullptr)
return System::Linq::Enumerable::Empty<GameObject>()->GetEnumerator();
else
return childList->GetEnumerator();
}
System::Collections::IEnumerator^ GameObject::GetEnumeratorNonGeneric()
{
return GetEnumerator();
}
}

View File

@ -20,7 +20,7 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Forward Declarations */
/* Forward Declarations */
/*---------------------------------------------------------------------------------*/
ref class Script;
ref class BaseComponent;
@ -32,8 +32,9 @@ namespace SHADE
/// Lightweight object for an Entity that allows for easy access to Component and
/// Script operations.
/// Can be set to a invalid/null GameObject by default construction.
/// Can also be iterated to access children.
/// </summary>
public value class GameObject : public System::IEquatable<GameObject>
public value class GameObject : public System::IEquatable<GameObject>, public System::Collections::Generic::IEnumerable<GameObject>
{
public:
/*-----------------------------------------------------------------------------*/
@ -97,10 +98,17 @@ namespace SHADE
/// <summary>
/// The parent entity for this GameObject.
/// </summary>
property GameObject^ Parent
property GameObject Parent
{
GameObject^ get();
void set(GameObject^);
GameObject get();
void set(GameObject);
}
/// <summary>
/// Number of Children held by this GameObject
/// </summary>
property int ChildCount
{
int get();
}
/*-----------------------------------------------------------------------------*/
@ -120,8 +128,7 @@ namespace SHADE
/// <param name="active">
/// Whether to activate or deactivate this GameObject.
/// </param>
void SetActive(bool active);
void SetActive(bool active);
/*-----------------------------------------------------------------------------*/
/* Component Access Functions */
@ -214,6 +221,82 @@ namespace SHADE
generic<typename T> where T : ref class, Script
void RemoveScript();
/*-----------------------------------------------------------------------------*/
/* Scene Graph Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Unparents all children. Useful if you want to destroy the root of a hierarchy
/// without destroying the children.
/// </summary>
void DetachChildren();
/// <summary>
/// Returns a child by index.
/// </summary>
/// <param name="index">Index of the child GameObject to retrieve.</param>
/// <returns>
/// Handle to the GameObject if the index is valid. Invalid GameObject otherwise.
/// </returns>
GameObject GetChild(int index);
/// <summary>
/// Returns a cached enumerable container of child GameObjects of this
/// GameObject.
/// </summary>
/// <returns>
/// Enumerable container of child GameObjects of this GameObject. Null if
/// ChildCount is 0.
/// </returns>
System::Collections::Generic::IEnumerable<GameObject>^ GetChildren();
/// <summary>
/// Gets the sibling index. Use GetSiblingIndex to find out the GameObjects
/// place in this hierarchy. When the sibling index of a GameObject is changed,
/// its order in the Hierarchy window will also change.
/// </summary>
/// <returns>
/// Index of this GameObject among the parent GameObject's children.
/// </returns>
[System::ObsoleteAttribute("Not yet implemented.", true)]
int GetSiblingIndex();
/// <summary>
/// Checks if this GameObject a direct or indirect child of the specified
/// GameObject.
/// </summary>
/// <returns>
/// True if this GameObject is a child, deep child (child of a child) or
/// identical to this GameObject, otherwise false.
/// </returns>
bool IsChildOf(GameObject gameObj);
/// <summary>
/// Move the GameObject to the start of the parent GameObject's children list.
/// </summary>
[System::ObsoleteAttribute("Not yet implemented.", true)]
void SetAsFirstSibling();
/// <summary>
/// Move the GameObject to the end of the parent GameObject's children list.
/// </summary>
[System::ObsoleteAttribute("Not yet implemented.", true)]
void SetAsLastSibling();
/// <summary>
/// Move the GameObject to the specified position in the parent GameObject's
/// children list. An existing object at that position if any, will be pushed
/// to the next index (existing element will be at index + 1).
/// </summary>
/// <param name="index">
/// Position to place this GameObject at in the hierarchy. Clamped to between
/// [0, parent.ChildCount].
/// </param>
[System::ObsoleteAttribute("Not yet implemented.", true)]
void SetSiblingIndex(int index);
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a GameObject is valid.
/// </summary>
/// <param name="gameObj">GameObjects to check.</param>
/// <returns>True if the GameObject is valid.</returns>
static operator bool(GameObject gameObj);
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
@ -249,13 +332,13 @@ namespace SHADE
SHEntity& GetNativeEntity();
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a GameObject is valid.
/// Retrieves the SceneNode for this GameObject's referenced entity.
/// </summary>
/// <param name="gameObj">GameObjects to check.</param>
static operator bool(GameObject gameObj);
/// <returns>Pointer to the SceneNode for this GameObject..</returns>
SHSceneNode* GetSceneNode();
private:
/*-----------------------------------------------------------------------------*/
@ -304,6 +387,14 @@ namespace SHADE
/// <param name="rhs">Another GameObject to check with.</param>
/// <returns>True if both Components are different.</returns>
static bool operator!=(GameObject lhs, GameObject rhs);
/*-----------------------------------------------------------------------------*/
/* IEnummerable */
/*-----------------------------------------------------------------------------*/
/// <inheritdoc/>
System::Collections::Generic::IEnumerator<GameObject>^ GetEnumerator() override;
/// <inheritdoc/>
System::Collections::IEnumerator^ GetEnumeratorNonGeneric() override = System::Collections::IEnumerable::GetEnumerator;
};
}