From 187142d5c3e67f4ee403ac9032a6f81f582105f4 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Fri, 23 Sep 2022 19:57:29 +0800 Subject: [PATCH 01/13] Added Transform Component C# interface --- SHADE_Engine/src/Math/Transform/SHTransform.h | 4 +- SHADE_Managed/src/Components/Transform.cxx | 107 ++++++++++++++++ SHADE_Managed/src/Components/Transform.hxx | 121 ++++++++++++++++++ SHADE_Managed/src/Engine/ECS.cxx | 5 +- SHADE_Managed/src/Engine/ECS.h++ | 10 +- SHADE_Managed/src/Engine/ECS.hxx | 7 +- SHADE_Managed/src/Utility/Convert.cxx | 28 +++- SHADE_Managed/src/Utility/Convert.hxx | 32 +++++ 8 files changed, 297 insertions(+), 17 deletions(-) create mode 100644 SHADE_Managed/src/Components/Transform.cxx create mode 100644 SHADE_Managed/src/Components/Transform.hxx diff --git a/SHADE_Engine/src/Math/Transform/SHTransform.h b/SHADE_Engine/src/Math/Transform/SHTransform.h index 9edd7fdd..c1a0e565 100644 --- a/SHADE_Engine/src/Math/Transform/SHTransform.h +++ b/SHADE_Engine/src/Math/Transform/SHTransform.h @@ -12,7 +12,9 @@ // Project Headers #include "SH_API.h" -#include "Math/SHMath.h" +#include "Math/Vector/SHVec2.h" +#include "Math/Vector/SHVec3.h" +#include "Math/SHMatrix.h" namespace SHADE { diff --git a/SHADE_Managed/src/Components/Transform.cxx b/SHADE_Managed/src/Components/Transform.cxx new file mode 100644 index 00000000..e065015e --- /dev/null +++ b/SHADE_Managed/src/Components/Transform.cxx @@ -0,0 +1,107 @@ +/************************************************************************************//*! +\file Transform.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 23, 2022 +\brief Contains the definition of the functions of the managed Transform 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 "Transform.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Properties */ + /*---------------------------------------------------------------------------------*/ + Vector3 Transform::LocalPosition::get() + { + return Convert::ToCLI(GetNativeComponent()->GetLocalPosition()); + } + void Transform::LocalPosition::set(Vector3 val) + { + GetNativeComponent()->SetLocalPosition(Convert::ToNative(val)); + } + Vector3 Transform::LocalRotation::get() + { + return Convert::ToCLI(GetNativeComponent()->GetLocalRotation()); + } + void Transform::LocalRotation::set(Vector3 val) + { + GetNativeComponent()->SetLocalPosition(Convert::ToNative(val)); + } + Vector3 Transform::LocalScale::get() + { + return Convert::ToCLI(GetNativeComponent()->GetLocalScale()); + + } + void Transform::LocalScale::set(Vector3 val) + { + GetNativeComponent()->SetLocalScale(Convert::ToNative(val)); + } + Vector3 Transform::GlobalPosition::get() + { + return Convert::ToCLI(GetNativeComponent()->GetWorldPosition()); + } + void Transform::GlobalPosition::set(Vector3 val) + { + GetNativeComponent()->SetWorldPosition(Convert::ToNative(val)); + } + Vector3 Transform::GlobalRotation::get() + { + return Convert::ToCLI(GetNativeComponent()->GetWorldRotation()); + } + void Transform::GlobalRotation::set(Vector3 val) + { + GetNativeComponent()->SetWorldRotation(Convert::ToNative(val)); + } + Vector3 Transform::GlobalScale::get() + { + return Convert::ToCLI(GetNativeComponent()->GetWorldScale()); + + } + void Transform::GlobalScale::set(Vector3 val) + { + GetNativeComponent()->SetWorldScale(Convert::ToNative(val)); + } + Transform^ Transform::Parent::get() + { + auto node = SHSceneManager::GetCurrentSceneGraph().GetNode(owner.GetEntity()); + if (!node) + throw gcnew System::InvalidOperationException("[Transform] Unable to retrieve SceneGraphNode for an Entity."); + + const auto PARENT = node->GetParent(); + return PARENT ? gcnew Transform(PARENT->GetEntityID()) : nullptr; + } + + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + Transform::Transform(Entity entity) + : Component(entity) + {} + + /*---------------------------------------------------------------------------------*/ + /* Usage Functions */ + /*---------------------------------------------------------------------------------*/ + + void Transform::SetParent(Transform^ parent, bool worldPositionStays) + { + auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); + auto node = sceneGraph.GetNode(owner.GetEntity()); + if (!node) + throw gcnew System::InvalidOperationException("[Transform] Unable to retrieve SceneGraphNode for an Entity."); + + if (parent) + node->SetParent(sceneGraph.GetNode(parent->owner.GetEntity())); + else + sceneGraph.SetParent(parent->owner.GetEntity(), nullptr); + } +} diff --git a/SHADE_Managed/src/Components/Transform.hxx b/SHADE_Managed/src/Components/Transform.hxx new file mode 100644 index 00000000..9efd2927 --- /dev/null +++ b/SHADE_Managed/src/Components/Transform.hxx @@ -0,0 +1,121 @@ +/************************************************************************************//*! +\file Transform.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 23, 2022 +\brief Contains the definition of the managed Transform class with the + declaration of functions for working with it. + + 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 "Components/Component.hxx" +#include "Math/Vector3.hxx" +#include "Utility/Convert.hxx" +// External Dependencies +#include "Math/Transform/SHTransformComponent.h" + +namespace SHADE +{ + /// + /// CLR version of the the SHADE Engine's TransformComponent. + /// + public ref class Transform : public Component + { + internal: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructs a Transform Component that represents a native Transform component + /// tied to the specified Entity. + /// + /// Entity that this Component will be tied to. + Transform(Entity entity); + + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Local position stored by this Transform. + /// + property Vector3 LocalPosition + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Local Z-axis rotation angle stored by this Transform in Radians. + /// + property Vector3 LocalRotation + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Local scale stored by this Transform. + /// + property Vector3 LocalScale + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Global position stored by this Transform. + /// + property Vector3 GlobalPosition + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Global Z-axis rotation angle stored by this Transform in Radians. + /// + property Vector3 GlobalRotation + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Global scale stored by this Transform. + /// Note that this operation is expensive. + /// + property Vector3 GlobalScale + { + Vector3 get(); + void set(Vector3 val); + } + /// + /// Parent Transform that affects this Transform. + /// + property Transform^ Parent + { + Transform^ get(); + } + + /*-----------------------------------------------------------------------------*/ + /* Usage Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Sets the parent of this Transform component. + /// + /// + /// Entity that contains the Transform component that this Transform will be + /// parented to. If null, unparenting will occur. + /// + /// + /// If true, the transform values of this Transform component will retain their + /// pre-parent-change global transforms. The local transform values will be + /// modified to ensure that the global transforms do not change. + /// + void SetParent(Transform^ parent, bool worldPositionStays); + }; +} + diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx index 36bef851..4d62f643 100644 --- a/SHADE_Managed/src/Engine/ECS.cxx +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -21,12 +21,14 @@ of DigiPen Institute of Technology is prohibited. #include // External Dependencies #include "ECS_Base/Managers/SHEntityManager.h" +#include "Math/Transform/SHTransformComponent.h" #include "Scene/SHSceneManager.h" #include "Scene/SHSceneGraph.h" #include "Tools/SHLog.h" // Project Headers #include "Utility/Convert.hxx" #include "Utility/Debug.hxx" +#include "Components/Transform.hxx" namespace SHADE { @@ -239,8 +241,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ static ECS::ECS() { - // TODO - // componentMap.Add(createComponentSet()); + componentMap.Add(createComponentSet()); } /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Engine/ECS.h++ b/SHADE_Managed/src/Engine/ECS.h++ index daaa859f..f2588294 100644 --- a/SHADE_Managed/src/Engine/ECS.h++ +++ b/SHADE_Managed/src/Engine/ECS.h++ @@ -28,15 +28,8 @@ namespace SHADE template NativeComponent* ECS::GetNativeComponent(Entity entity) { - // Get native Entity - SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity); - - // Entity Validity Check - if (nativeEntity == nullptr) - throw gcnew System::InvalidOperationException("Attempted to get native Component to an invalid Entity."); - // Null Check - NativeComponent* component = SHComponentManager::GetComponent_s(nativeEntity); + NativeComponent* component = SHComponentManager::GetComponent_s(entity); if (component == nullptr) throw gcnew System::NullReferenceException("Attempted to get a native Component that does not exist."); @@ -52,7 +45,6 @@ namespace SHADE { ManagedType::typeid, SHComponentManager::AddComponent, - SHComponentManager::EnsureComponent, SHComponentManager::HasComponent, SHComponentManager::RemoveComponent }; diff --git a/SHADE_Managed/src/Engine/ECS.hxx b/SHADE_Managed/src/Engine/ECS.hxx index da73f14c..0563f678 100644 --- a/SHADE_Managed/src/Engine/ECS.hxx +++ b/SHADE_Managed/src/Engine/ECS.hxx @@ -99,8 +99,8 @@ namespace SHADE /// /// Pointer to a function for Component manipulation operations. /// - using ComponentFunc = void(*)(const EntityID&); - using ComponentHasFunc = bool(*)(const EntityID&); + using ComponentFunc = void(*)(EntityID) noexcept; + using ComponentHasFunc = bool(*)(EntityID) noexcept; /// /// Contains a set of Component related data used for resolving operations for /// each Component. @@ -108,11 +108,10 @@ namespace SHADE value struct ComponentSet { public: - System::Type^ Type; + System::Type^ Type; ComponentFunc AddFunction; ComponentHasFunc HasFunction; ComponentFunc RemoveFunction; - }; /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx index d222fbb3..661eb3e4 100644 --- a/SHADE_Managed/src/Utility/Convert.cxx +++ b/SHADE_Managed/src/Utility/Convert.cxx @@ -17,8 +17,8 @@ of DigiPen Institute of Technology is prohibited. // Primary Header #include "Convert.hxx" // External Dependencies -#include "ECS_Base/Managers/SHEntityManager.h" #include +#include "ECS_Base/Managers/SHEntityManager.h" namespace SHADE { @@ -30,6 +30,32 @@ namespace SHADE return static_cast(entity.GetEID()); } + /*---------------------------------------------------------------------------------*/ + /* Math Conversions */ + /*---------------------------------------------------------------------------------*/ + SHVec3 Convert::ToNative(Vector3 vec) + { + const double X = vec.x; + const double Y = vec.y; + const double Z = vec.z; + return SHVec3(X, Y, Z); + } + Vector3 Convert::ToCLI(const SHVec3& vec) + { + return Vector3(vec.x, vec.y, vec.z); + } + SHVec2 Convert::ToNative(Vector2 vec) + { + const double X = vec.x; + const double Y = vec.y; + return SHVec2(X, Y); + } + + Vector2 Convert::ToCLI(const SHVec2& vec) + { + return Vector2(vec.x, vec.y); + } + /*---------------------------------------------------------------------------------*/ /* String Conversions */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx index 241e5863..b41ffef4 100644 --- a/SHADE_Managed/src/Utility/Convert.hxx +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -16,8 +16,12 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include "ECS_Base/Entity/SHEntity.h" +#include "Math/Vector/SHVec2.h" +#include "Math/Vector/SHVec3.h" // Project Includes #include "Engine/Entity.hxx" +#include "Math/Vector2.hxx" +#include "Math/Vector3.hxx" namespace SHADE { @@ -43,6 +47,34 @@ namespace SHADE /// Managed representation of the specified Entity. static Entity ToCLI(SHEntity entity); + /*-----------------------------------------------------------------------------*/ + /* Math Conversions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Converts from a managed Vector3 to a native Vector3. + /// + /// The managed Vector3 to convert from. + /// Native copy of a managed Vector3. + static SHVec3 ToNative(Vector3 vec); + /// + /// Converts from a native Vector3 to a managed Vector3. + /// + /// The native Vector3 to convert from. + /// Managed copy of a native Vector3. + static Vector3 ToCLI(const SHVec3& vec); + /// + /// Converts from a managed Vector2 to a native Vector2. + /// + /// The managed Vector2 to convert from. + /// Native copy of a managed Vector2. + static SHVec2 ToNative(Vector2 vec); + /// + /// Converts from a native Vector2 to a managed Vector2. + /// + /// The native Vector2 to convert from. + /// Managed copy of a native Vector2. + static Vector2 ToCLI(const SHVec2& vec); + /*-----------------------------------------------------------------------------*/ /* String Conversions */ /*-----------------------------------------------------------------------------*/ From e42283a55326dd9ca0b050aa634d4046f6119249 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Tue, 27 Sep 2022 01:12:02 +0800 Subject: [PATCH 02/13] Fixed RTTR linker errors --- SHADE_Managed/premake5.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/SHADE_Managed/premake5.lua b/SHADE_Managed/premake5.lua index e50e9e86..a7b20144 100644 --- a/SHADE_Managed/premake5.lua +++ b/SHADE_Managed/premake5.lua @@ -33,6 +33,11 @@ project "SHADE_Managed" "%{IncludeDir.RTTR}/include", "%{wks.location}/SHADE_Engine/src" } + + libdirs + { + "%{IncludeDir.RTTR}/lib" + } links { @@ -68,7 +73,9 @@ project "SHADE_Managed" filter "configurations:Debug" symbols "On" defines {"_DEBUG"} + links{"librttr_core_d.lib"} filter "configurations:Release" optimize "On" defines{"_RELEASE"} + links{"librttr_core.lib"} From 085ab50ec7a3f89547100fb2a7d298420e9eb714 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Tue, 27 Sep 2022 01:57:23 +0800 Subject: [PATCH 03/13] Added a script to test Transform modifications --- SHADE_Application/src/Scenes/SBTestScene.cpp | 24 ++++++++++++-------- TempScriptsFolder/TestScript.cs | 10 +++++++- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 01d2a18e..184f62cb 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -35,14 +35,14 @@ namespace Sandbox SHADE::SHGraphicsSystem* graphicsSystem = static_cast(SHADE::SHSystemManager::GetSystem()); // Create temp meshes const auto CUBE_MESH = SHADE::SHPrimitiveGenerator::Cube(*graphicsSystem); - //graphicsSystem->BuildMeshBuffers(); //Test Racoon mesh auto meshes = SHADE::SHAssetManager::GetAllMeshes(); std::vector> handles; for (auto const& mesh : meshes) { - handles.push_back(graphicsSystem->AddMesh( + handles.push_back(graphicsSystem->AddMesh + ( mesh.header.vertexCount, mesh.vertexPosition.data(), mesh.texCoords.data(), @@ -80,19 +80,23 @@ namespace Sandbox // stressTestObjects.emplace_back(entity); //} - auto entity = SHEntityManager::CreateEntity(); - auto& renderable = *SHComponentManager::GetComponent_s(entity); - auto& transform = *SHComponentManager::GetComponent_s(entity); + auto entity = SHEntityManager::CreateEntity(); + auto& renderable = *SHComponentManager::GetComponent_s(entity); + auto& transform = *SHComponentManager::GetComponent_s(entity); - renderable.Mesh = handles.front(); - renderable.SetMaterial(matInst); + renderable.Mesh = handles.front(); + renderable.SetMaterial(matInst); - //transform.SetLocalScale(TEST_OBJ_SCALE); + //transform.SetLocalScale(TEST_OBJ_SCALE); - stressTestObjects.emplace_back(entity); + stressTestObjects.emplace_back(entity); // Create blank entity with a script - testObj = SHADE::SHEntityManager::CreateEntity(); + testObj = SHADE::SHEntityManager::CreateEntity(); + auto& renderableTestObj = *SHComponentManager::GetComponent_s(testObj); + + renderableTestObj.Mesh = CUBE_MESH; + renderableTestObj.SetMaterial(matInst); SHADE::SHScriptEngine* scriptEngine = static_cast(SHADE::SHSystemManager::GetSystem()); scriptEngine->AddScript(testObj, "TestScript"); } diff --git a/TempScriptsFolder/TestScript.cs b/TempScriptsFolder/TestScript.cs index c1ed5bd5..8159a78e 100644 --- a/TempScriptsFolder/TestScript.cs +++ b/TempScriptsFolder/TestScript.cs @@ -2,11 +2,18 @@ using SHADE; public class TestScript : Script { + private Transform Transform; + private double time = 0.0; public TestScript(GameObject gameObj) : base(gameObj) {} protected override void awake() { Debug.Log("TestScript.Awake()"); + Transform = GetComponent(); + if (Transform == null) + { + Debug.LogError("Transform is NULL!"); + } } protected override void start() { @@ -14,7 +21,8 @@ public class TestScript : Script } protected override void update() { - Debug.Log("TestScript.Update()"); + time += 0.16; + Transform.GlobalPosition = new Vector3(System.Math.Sin(time), System.Math.Cos(time), 0.0f); } protected override void onDestroy() { From 4effe016e40d7bf60852dfe7d7a822b100bca86e Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Tue, 27 Sep 2022 17:13:32 +0800 Subject: [PATCH 04/13] Options to rebuild scripts at runtime are now present in the editor --- .../EditorWindow/MenuBar/SHEditorMenuBar.cpp | 25 ++++++++++++++++--- SHADE_Engine/src/Scripting/SHScriptEngine.cpp | 14 ++++++++++- SHADE_Engine/src/Scripting/SHScriptEngine.h | 7 ++++-- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index 7e5f762c..8e26ae78 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -6,6 +6,9 @@ #include "SHEditorMenuBar.h" #include "Editor/IconsMaterialDesign.h" #include "Editor/Command/SHCommandManager.h" +#include "Scripting/SHScriptEngine.h" +#include "Editor/SHEditor.hpp" +#include "ECS_Base/Managers/SHSystemManager.h" //#==============================================================# //|| Library Includes || @@ -14,9 +17,6 @@ #include #include -#include "Editor/SHEditor.hpp" - - namespace SHADE { constexpr ImGuiWindowFlags editorMenuBarFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | @@ -100,6 +100,25 @@ namespace SHADE } ImGui::EndMenu(); } + if (ImGui::BeginMenu("Scripts")) + { + if (ImGui::Selectable("Generate Visual Studio Project")) + { + auto* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->GenerateScriptsCsProjFile(); + } + if (ImGui::Selectable("Build Scripts - Debug")) + { + auto* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->BuildScriptAssembly(true, true); + } + if (ImGui::Selectable("Build Scripts - Release")) + { + auto* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->BuildScriptAssembly(false, true); + } + ImGui::EndMenu(); + } ImGui::EndMainMenuBar(); } diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index 0c508a34..0c3e89e6 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -160,10 +160,16 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Static Utility Functions */ /*-----------------------------------------------------------------------------------*/ - bool SHScriptEngine::BuildScriptAssembly(bool debug) const + bool SHScriptEngine::BuildScriptAssembly(bool debug, bool reload) { static const std::string BUILD_LOG_PATH = "../Build.log"; + // Unload if we need to reload + if (reload) + { + UnloadScriptAssembly(); + } + // Generate csproj file if it doesn't exist if (!std::filesystem::exists(CSPROJ_PATH)) { @@ -209,6 +215,12 @@ namespace SHADE // Delete the build log file since we no longer need it deleteFile(BUILD_LOG_PATH); + // If reloading, we need to load + if (reload) + { + LoadScriptAssembly(); + } + return BUILD_SUCCESS; } diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h index 08852e90..329bb3a5 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.h +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -184,13 +184,16 @@ namespace SHADE /// Whether or not a debug build will be built. Only debug built C# assemblies /// can be debugged. /// + /// + /// Whether or not we are reloading the assembly, if so, unload and then reload it. + /// /// Whether or not the build succeeded. - bool BuildScriptAssembly(bool debug = false) const; + bool BuildScriptAssembly(bool debug = false, bool reload = false); /// /// Generates a .csproj file for editing and compiling the C# scripts. /// /// File path to the generated file. - void GenerateScriptsCsProjFile(const std::filesystem::path& path) const; + void GenerateScriptsCsProjFile(const std::filesystem::path& path = CSPROJ_PATH) const; private: /*-----------------------------------------------------------------------------*/ From a57c4d0d733045c20df3f8c80bb6dca4b17f3874 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Tue, 27 Sep 2022 19:17:53 +0800 Subject: [PATCH 05/13] WIP Script Inspector --- SHADE_Engine/src/Editor/SHEditorUI.cpp | 421 +++++++++++++++++++++++++ SHADE_Engine/src/Editor/SHEditorUI.h | 312 ++++++++++++++++++ SHADE_Engine/src/Editor/SHEditorUI.hpp | 49 +++ SHADE_Managed/src/Editor/Editor.cxx | 207 ++++++++++++ SHADE_Managed/src/Editor/Editor.hxx | 65 ++++ 5 files changed, 1054 insertions(+) create mode 100644 SHADE_Engine/src/Editor/SHEditorUI.cpp create mode 100644 SHADE_Engine/src/Editor/SHEditorUI.h create mode 100644 SHADE_Engine/src/Editor/SHEditorUI.hpp create mode 100644 SHADE_Managed/src/Editor/Editor.cxx create mode 100644 SHADE_Managed/src/Editor/Editor.hxx diff --git a/SHADE_Engine/src/Editor/SHEditorUI.cpp b/SHADE_Engine/src/Editor/SHEditorUI.cpp new file mode 100644 index 00000000..cbeb164f --- /dev/null +++ b/SHADE_Engine/src/Editor/SHEditorUI.cpp @@ -0,0 +1,421 @@ +/************************************************************************************//*! +\file EditorUI.cpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Nov 7, 2021 +\brief Contains the implementation of the EditorUI class. + +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. +*//*************************************************************************************/ +// Precompiled Header +#include +// Primary Header +#include "Editor/EditorUI.h" +// External Dependencies +#include +// Project Headers +#include "Core/Resource/ResourceManager.h" +#include "Editor/ImGuiExtensions.h" +#include "Editor/Editor.h" + +namespace Pls +{ + /*---------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - ID Stack */ + /*---------------------------------------------------------------------------------*/ + void EditorUI::PushID(const std::string& id) + { + ImGui::PushID(id.c_str()); + } + + void EditorUI::PushID(int id) + { + ImGui::PushID(id); + } + + void EditorUI::PopID() + { + ImGui::PopID(); + } + + /*---------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Indent */ + /*---------------------------------------------------------------------------------*/ + void EditorUI::Indent() + { + ImGui::Indent(); + } + void EditorUI::Unindent() + { + ImGui::Unindent(); + } + + /*---------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Organisers */ + /*---------------------------------------------------------------------------------*/ + bool EditorUI::CollapsingHeader(const std::string& title) + { + return ImGui::CollapsingHeader(title.c_str()); + } + + /*---------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Pop Ups */ + /*---------------------------------------------------------------------------------*/ + bool EditorUI::BeginPopup(const std::string& label) + { + return ImGui::BeginPopup(label.c_str()); + } + void EditorUI::EndPopup() + { + ImGui::EndPopup(); + } + void EditorUI::OpenPopup(const std::string& label) + { + ImGui::OpenPopup(label.c_str()); + } + + bool EditorUI::MenuItem(const std::string& label) + { + return ImGui::MenuItem(label.c_str()); + } + + /*---------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Widgets */ + /*---------------------------------------------------------------------------------*/ + void EditorUI::Text(const std::string& title) + { + ImGui::Text(title.c_str()); + } + bool EditorUI::SmallButton(const std::string& title) + { + return ImGui::SmallButton(title.c_str()); + } + bool EditorUI::Button(const std::string& title) + { + return ImGui::Button(title.c_str()); + } + bool EditorUI::InputCheckbox(const std::string& label, bool& value) + { + return ImGui::Checkbox(label.c_str(), &value); + } + bool EditorUI::InputInt(const std::string& label, int& value) + { + return ImGui::InputInt(label.c_str(), &value, + 1, 10, + ImGuiInputTextFlags_EnterReturnsTrue); + } + bool EditorUI::InputUnsignedInt(const std::string& label, unsigned int& value) + { + int signedVal = static_cast(value); + const bool CHANGED = InputInt(label, signedVal); + if (CHANGED) + { + signedVal = std::clamp(signedVal, 0, std::numeric_limits::max()); + value = static_cast(signedVal); + } + return CHANGED; + } + bool EditorUI::InputFloat(const std::string& label, float& value) + { + return ImGui::InputFloat(label.c_str(), &value, + 0.1f, 1.0f, "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + } + bool EditorUI::InputDouble(const std::string& label, double& value) + { + return ImGui::InputDouble(label.c_str(), &value, + 0.1, 1.0, "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + } + bool EditorUI::InputAngle(const std::string& label, double& value) + { + return ImGui::InputDouble(label.c_str(), &value, + 1.0, 45.0, "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + } + + bool EditorUI::InputSlider(const std::string& label, double min, double max, double& value) + { + float val = static_cast(value); + const bool CHANGED = ImGui::SliderFloat(label.c_str(), &val, + static_cast(min), static_cast(max), "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + + if (CHANGED) + { + value = val; + } + + + return CHANGED; + } + + bool EditorUI::InputVec2(const std::string& label, vec2& value) + { + float vec[2] = + { + static_cast(value.x), + static_cast(value.y) + }; + const bool CHANGED = ImGui::InputFloat2(label.c_str(), vec, "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + if (CHANGED) + { + value.x = vec[0]; + value.y = vec[1]; + } + return CHANGED; + } + bool EditorUI::InputVec3(const std::string& label, vec3& value) + { + float vec[3] = + { + static_cast(value.x), + static_cast(value.y), + static_cast(value.z) + }; + const bool CHANGED = ImGui::InputFloat3(label.c_str(), vec, "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + if (CHANGED) + { + value.x = vec[0]; + value.y = vec[1]; + value.z = vec[2]; + } + return CHANGED; + } + + bool EditorUI::InputSliderVec3(const std::string& label, double min, double max, vec3& value) + { + float vec[3] = + { + static_cast(value.x), + static_cast(value.y), + static_cast(value.z) + }; + const bool CHANGED = ImGui::SliderFloat3(label.c_str(), vec, + static_cast(min), static_cast(max), "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + if (CHANGED) + { + value.x = vec[0]; + value.y = vec[1]; + value.z = vec[2]; + } + return CHANGED; + } + + bool EditorUI::InputColor(const std::string& label, GFX::Color& value) + { + float color[4] = + { + value.R, + value.G, + value.B, + value.A + }; + const bool CHANGED = ImGui::ColorEdit4(label.c_str(), color, + ImGuiColorEditFlags_AlphaBar | + ImGuiColorEditFlags_AlphaPreview | + ImGuiColorEditFlags_Float); + if (CHANGED) + { + value.R = color[0]; + value.G = color[1]; + value.B = color[2]; + value.A = std::clamp(color[3], 0.f, 1.f); + } + return CHANGED; + } + bool EditorUI::InputTextField(const std::string& label, std::string& value) + { + std::array buffer = { '\0' }; + strcpy_s(buffer.data(), TEXT_FIELD_MAX_LENGTH, value.c_str()); + const bool CHANGED = ImGui::InputText(label.c_str(), &buffer[0], TEXT_FIELD_MAX_LENGTH); + if (CHANGED) + { + value = std::string(buffer.data(), buffer.data() + TEXT_FIELD_MAX_LENGTH); + } + return CHANGED; + } + + bool EditorUI::InputEnumCombo(const std::string& label, int& v, const std::vector& enumNames) + { + + // Clamp input value + const std::string& INITIAL_NAME = v >= static_cast(enumNames.size()) ? "Unknown" : enumNames[v]; + bool b = false; + if (ImGui::BeginCombo(label.c_str(), INITIAL_NAME.c_str(), ImGuiComboFlags_None)) + { + for (int i = 0; i < enumNames.size(); ++i) + { + const bool IS_SELECTED = v == i; + if (ImGui::Selectable(enumNames[i].c_str(), IS_SELECTED)) + { + v = i; + b = true; + } + if (IS_SELECTED) + { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + return b; + } + + bool EditorUI::InputTextureDropDown(const std::string& label, Resource::Snowflake& v) + { + static std::vector> resources; + + // Register texture popup + bool hasChanges = false; + if (ImGui::BeginPopup("Texture Menu")) + { + if (ImGui::Button("None")) + { + v = Resource::INVALID_SNOWFLAKE; + ImGui::CloseCurrentPopup(); + hasChanges = true; + } + for (auto& rscWrapper : resources) + { + Resource& rsc = rscWrapper.get(); + + ImGui::PushID(static_cast(rsc.GetID())); + + const GFX::Texture* TEX = rsc.LoadTexture(); + if (TEX == nullptr) + { + continue; + } + const ImTextureID TEX_ID = reinterpret_cast(static_cast(TEX->GetHandle())); + const std::string NAME = rsc.GetPath().filename().string(); + const std::string FP = rsc.GetPath().string(); + if (ImGui::ImageButtonWithText(TEX_ID, NAME.c_str())) + { + v = rsc.GetID(); + ImGui::CloseCurrentPopup(); + hasChanges = true; + } + ImGui::TextDisabled(FP.c_str()); + + ImGui::PopID(); + } + ImGui::EndPopup(); + } + + // Get texture ID of resource + ImTextureID texID = 0; + std::string texName = "None"; + Resource* rsc = ResourceManager::Find(v); + if (rsc) + { + // File + if (rsc->IsType()) + { + GFX::Texture* tex = rsc->LoadTexture(); + if (tex) + { + texID = reinterpret_cast(static_cast(tex->GetHandle())); + } + } + else + { + // TODO (Clarence): replace with missing texture image + texID = Editor::Editor::GetInternalTexture("scene.png"); + } + texName = rsc->GetPath().filename().string(); + } + + // Show texture selection menu + if (ImGui::ImageButtonWithText(texID, texName.c_str(), label.c_str())) + { + resources = ResourceManager::FindAllOfType(); + ImGui::OpenPopup("Texture Menu"); + } + + return hasChanges; + } + bool EditorUI::InputFontDropDown(const char* label, Resource::Snowflake& v) + { + static std::vector> resources; + + // Register texture popup + bool hasChanges = false; + if (ImGui::BeginPopup("Font Menu")) + { + if (ImGui::Button("None")) + { + v = Resource::INVALID_SNOWFLAKE; + ImGui::CloseCurrentPopup(); + hasChanges = true; + } + for (auto& rscWrapper : resources) + { + Resource& rsc = rscWrapper.get(); + + ImGui::PushID(static_cast(rsc.GetID())); + + const GFX::Font* FONT = rsc.LoadFont(); + if (FONT == nullptr) + { + continue; + } + const std::string NAME = rsc.GetPath().filename().string(); + const std::string FP = rsc.GetPath().string(); + if (ImGui::Button(NAME.c_str())) + { + v = rsc.GetID(); + ImGui::CloseCurrentPopup(); + hasChanges = true; + } + ImGui::TextDisabled(FP.c_str()); + + ImGui::PopID(); + } + ImGui::EndPopup(); + } + + // Get font ID of resource + ImTextureID fontID = 0; + std::string fontName = "None"; + Resource* rsc = ResourceManager::Find(v); + + if (rsc) + { + // File + if (rsc) + { + GFX::Font* font = rsc->LoadFont(); + if (font) + { + fontID = reinterpret_cast(static_cast(font->GetID())); + if (font->CreatedThisFrame()) + { + font->OnCreate() = false; + hasChanges = true; + } + } + } + else + { + // TODO (Clarence): replace with missing texture image + fontID = Editor::Editor::GetInternalFont("selawk.tff"); + } + fontName = rsc->GetPath().filename().string(); + } + + // Show font selection menu + if (ImGui::ButtonWithText(fontName.c_str(), label)) + { + resources = ResourceManager::FindAllOfType(); + ImGui::OpenPopup("Font Menu"); + } + + return hasChanges; + } +} // namespace PlushieEngine diff --git a/SHADE_Engine/src/Editor/SHEditorUI.h b/SHADE_Engine/src/Editor/SHEditorUI.h new file mode 100644 index 00000000..ce9d8608 --- /dev/null +++ b/SHADE_Engine/src/Editor/SHEditorUI.h @@ -0,0 +1,312 @@ +/************************************************************************************//*! +\file EditorUI.h +\author Tng Kah Wei, kahwei.tng, 390009620 (50%) +\par email: kahwei.tng\@digipen.edu +\author Tay Yan Chong Clarence, t.yanchongclarence, 620008720 (50%) +\par email: t.yanchongclarence\@digipen.edu +\date Nov 7, 2021 +\brief Defines a class that encapsulates the running of a Plushie Engine + application. + +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 +// Platform Defines +#include "PlushieDefines.h" +// Standard Library +#include // std::function +#include // std::string + +#include "Core/Resource/Resource.h" +#include "Graphics/Color.h" +#include "Math/Vector2.h" +#include "Math/Vector3.h" + +namespace Pls +{ + /// + /// Static class that contains useful functions for Editor UI using ImGui. + /// + class PLS_API EditorUI final + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constants */ + /*-----------------------------------------------------------------------------*/ + /// + /// Maximum length of a string supported by InputTextField() + /// + static constexpr size_t TEXT_FIELD_MAX_LENGTH = 256; + + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - ID Stack */ + /*-----------------------------------------------------------------------------*/ + /// + /// Marks the start of a stack of ImGui widgets with the specified id. + ///
+ /// Wraps up ImGui::PushID(). + ///
+ /// String-based ID. + static void PushID(const std::string& id); + /// + /// Marks the start of a stack of ImGui widgets with the specified id. + ///
+ /// Wraps up ImGui::PushID(). + ///
+ /// Integer-based ID. + static void PushID(int id); + /// + /// Marks the end of a stack of ImGui widgets from the last PushID() call. + ///
+ /// Wraps up ImGui::PopID(). + ///
+ static void PopID(); + + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Indent */ + /*-----------------------------------------------------------------------------*/ + /// + /// Indents the widgets rendered after this call. + ///
+ /// Wraps up ImGui::Indent(). + ///
+ static void Indent(); + /// + /// Unindents the widgets rendered after this call. + ///
+ /// Wraps up ImGui::Unindent(). + ///
+ static void Unindent(); + + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Organisers */ + /*-----------------------------------------------------------------------------*/ + /// + /// Creates a collapsing title header. + ///
+ /// Wraps up ImGui::CollapsingHeader(). + ///
+ /// Label for the header. + /// True if the header is open, false otherwise. + static bool CollapsingHeader(const std::string& title); + + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Pop Ups */ + /*-----------------------------------------------------------------------------*/ + /// + /// Marks the start of a definition of a mini pop up that can show options. + ///
+ /// Wraps up ImGui::BeginPopup(). + ///
+ /// Label used to identify this widget. + /// Whether or not the pop up is open. + static bool BeginPopup(const std::string& label); + /// + /// Marks the end of a definition of a mini pop up that can show options. + ///
+ /// Wraps up ImGui::EndPopup(). + ///
+ static void EndPopup(); + /// + /// Opens the popup that was defined with the specified label. + ///
+ /// Wraps up ImGui::OpenPopup(). + ///
+ static void OpenPopup(const std::string& label); + /// + /// Creates a menu item in the list of items for a mini popup. + ///
+ /// Wraps up ImGui::MenuItem(). + ///
+ /// Label used to identify this widget. + /// Whether or not the menu item was selected. + static bool MenuItem(const std::string& label); + + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Widgets */ + /*-----------------------------------------------------------------------------*/ + /// + /// Creates a visual text widget. + ///
+ /// Wraps up ImGui::Text(). + ///
+ /// Text to display. + static void Text(const std::string& title); + /// + /// Creates a small inline button widget. + ///
+ /// Wraps up ImGui::SmallButton(). + ///
+ /// Text to display. + /// True if button was pressed. + static bool SmallButton(const std::string& title); + /// + /// Creates a inline button widget. + ///
+ /// Wraps up ImGui::Button(). + ///
+ /// Text to display. + /// True if button was pressed. + static bool Button(const std::string& title); + /// + /// Creates a checkbox widget for boolean input. + ///
+ /// Wraps up ImGui::Checkbox(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputCheckbox(const std::string& label, bool& value); + /// + /// Creates a integer field widget for integer input. + ///
+ /// Wraps up ImGui::InputInt(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputInt(const std::string& label, int& value); + /// + /// Creates a integer field widget for unsigned integer input. + ///
+ /// Wraps up ImGui::InputInt() with an additional clamping of values. + ///
+ /// Note: As a result, the range of this function limits it to the maximum + /// value of a 32-bit signed integer instead of a 32-bit unsigned integer. + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputUnsignedInt(const std::string& label, unsigned int& value); + /// + /// Creates a decimal field widget for single precision float input. + ///
+ /// Wraps up ImGui::InputFloat(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputFloat(const std::string& label, float& value); + /// + /// Creates a decimal field widget for double precision float input. + ///
+ /// Wraps up ImGui::InputDouble(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputDouble(const std::string& label, double& value); + /// + /// Creates a decimal field widget for double input with increments of higher + /// steps meant for angle variables. + ///
+ /// Wraps up ImGui::InputDouble(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputAngle(const std::string& label, double& value); + /// + /// Creates a double slider field widget for double input. + ///
+ /// Wraps up ImGui::InputSliderFloat(). + ///
+ /// Label used to identify this widget. + /// Minimum value of the slider. + /// Maximum value of the slider. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputSlider(const std::string& label, double min, double max, double& value); + /// + /// Creates a 2x double field widget for Vector2 input. + ///
+ /// Wraps up ImGui::InputFloat2(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputVec2(const std::string& label, vec2& value); + /// + /// Creates a 3x double field widget for Vector3 input. + ///
+ /// Wraps up ImGui::InputFloat3(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputVec3(const std::string& label, vec3& value); + /// + /// Creates a 3x double slider field widget for Vector3 input. + ///
+ /// Wraps up ImGui::InputSliderFloat3(). + ///
+ /// Label used to identify this widget. + /// Minimum value of the slider. + /// Maximum value of the slider. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputSliderVec3(const std::string& label, double min, double max, vec3& value); + /// + /// Creates a colour field widget for Color input. + ///
+ /// Wraps up ImGui::ColorEdit4(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputColor(const std::string& label, GFX::Color& value); + /// + /// Creates a text field widget for string input. + ///
+ /// Wraps up ImGui::InputText(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputTextField(const std::string& label, std::string& value); + /// + /// Creates a combo box for enumeration input. + /// + /// The type of enum to input. + /// The name of the input. + /// The reference to the value to modify. + /// The maximum value of the enum. + /// + /// Conversion function from the type of enum + /// to C-style string. + /// Whether the value was modified. + template + static bool InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function toStrFn); + /// + /// Creates a combo box for enumeration input using a specified list of names. + /// + /// The name of the input. + /// The reference to the value to modify. + /// Vector of names for each enumeration value. + /// Whether the value was modified. + static bool InputEnumCombo(const std::string& label, int& v, const std::vector& enumNames); + /// + /// Creates a drop down widget for texture selection. + /// + /// The name of the input. + /// The reference to the value to modify. + /// Whether the value was modified. + static bool InputTextureDropDown(const std::string& label, Resource::Snowflake& v); + /// + /// Creates a drop down widget for font selection. + /// + /// The name of the input. + /// The reference to the value to modify. + /// Whether the value was modified. + static bool InputFontDropDown(const char* label, Resource::Snowflake& v); + + + private: + // Prevent instantiation of this static class + EditorUI() = delete; + }; +} // namespace PlushieEngine + +#include "EditorUI.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/SHEditorUI.hpp b/SHADE_Engine/src/Editor/SHEditorUI.hpp new file mode 100644 index 00000000..d7a3eae7 --- /dev/null +++ b/SHADE_Engine/src/Editor/SHEditorUI.hpp @@ -0,0 +1,49 @@ +/************************************************************************************//*! +\file EditorUI.hpp +\author Tay Yan Chong Clarence, t.yanchongclarence, 620008720 +\par email: t.yanchongclarence\@digipen.edu +\date Nov 8, 2021 +\brief Contains the implementation of editor inspector template functions. + +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. +*//*************************************************************************************/ +// Primary Header +#include "EditorUI.h" + +namespace Pls +{ + /*---------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Widgets */ + /*---------------------------------------------------------------------------------*/ + template + inline bool EditorUI::InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function toStrFn) + { + std::vector values; + for (int i = 0; i <= maxVal; ++i) + { + values.emplace_back(static_cast(i)); + } + bool b = false; + if (ImGui::BeginCombo(label.c_str(), toStrFn(v), ImGuiComboFlags_None)) + { + for (int i = 0; i <= maxVal; ++i) + { + const auto VALUE = values[i]; + const bool IS_SELECTED = v == VALUE; + if (ImGui::Selectable(toStrFn(VALUE), IS_SELECTED)) + { + v = VALUE; + b = true; + } + if (IS_SELECTED) + { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + return b; + } +} // namespace PlushieEngine diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx new file mode 100644 index 00000000..d6b02c8c --- /dev/null +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -0,0 +1,207 @@ +/************************************************************************************//*! +\file Editor.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 27, 2022 +\brief Contains the definition of the functions for the ScriptStore managed + static 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 "Editor/Editor.hxx" +// External Dependencies +#include "Editor/SHEditorUI::.h" +// Project Headers +#include "Components/Component.hxx" +#include "Scripts/ScriptStore.hxx" +#include "Utility/Convert.hxx" +#include "Utility/Debug.hxx" +#include "Serialisation/ReflectionUtilities.hxx" + +// Using Directives +using namespace System::Collections::Generic; + +/*-------------------------------------------------------------------------------------*/ +/* Macro Functions */ +/*-------------------------------------------------------------------------------------*/ +/// +/// Macro expansion that is used in renderFieldInInspector() to check the type of a field +/// named "field" against the specified type and if it matches, retrieves the value of +/// that field from an object named "object" and pass it into the specified SHEditorUI:: +/// function named "FUNC" by casting it into the NATIVE_TYPE specified. +///
+/// This only works for primitive types that have the same types for managed and native. +///
+/// The managed type of the object to edit. +/// The native type of the object to edit. +/// The SHEditorUI:: function to use for editing. +#define RENDER_FIELD(MANAGED_TYPE, NATIVE_TYPE, FUNC) \ +(field->FieldType == MANAGED_TYPE::typeid) \ +{ \ + NATIVE_TYPE val = safe_cast(field->GetValue(object)); \ + if (SHEditorUI::::FUNC(Convert::ToNative(field->Name), val)) \ + { \ + field->SetValue(object, val); \ + } \ +} \ +/// +/// Macro expansion that is used in renderFieldInInspector() to check the type of a field +/// named "field" against the specified type and if it matches, retrieves the value of +/// that field from an object named "object" and pass it into the specified SHEditorUI:: +/// function named "FUNC" by casting it into the NATIVE_TYPE specified. +///
+/// This only works for types that have an implementation of Convert::ToNative and +/// Convert::ToCLI. +///
+/// The managed type of the object to edit. +/// The native type of the object to edit. +/// The SHEditorUI:: function to use for editing. +#define RENDER_FIELD_CASTED(MANAGED_TYPE, NATIVE_TYPE, FUNC) \ +(field->FieldType == MANAGED_TYPE::typeid) \ +{ \ + NATIVE_TYPE val = Convert::ToNative(safe_cast(field->GetValue(object))); \ + if (SHEditorUI::::FUNC(Convert::ToNative(field->Name), val)) \ + { \ + field->SetValue(object, Convert::ToCLI(val)); \ + } \ +} \ + +/*-------------------------------------------------------------------------------------*/ +/* Function Definitions */ +/*-------------------------------------------------------------------------------------*/ +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Script Rendering Functions */ + /*---------------------------------------------------------------------------------*/ + void Editor::RenderScriptsInInspector(Entity entity) + { + SAFE_NATIVE_CALL_BEGIN + // Get scripts + IEnumerable^ scripts = ScriptStore::GetAllScripts(entity); + + // Skip if no scripts + if (scripts != nullptr) + { + // Display each script if any + int index = 0; + for each (Script^ script in scripts) + { + renderScriptInInspector(entity, script, index++); + } + } + + // Render Add Script + //RenderScriptAddButton(entity); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.RenderScriptsInInspector") + } + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + void Editor::renderScriptInInspector(Entity entity, Script^ script, int index) + { + // Constants + const std::string LABEL = Convert::ToNative(script->GetType()->Name); + const char* CONTEXT_MENU_ID = "scriptContextMenu"; + + // Header + SHEditorUI::::PushID(index); + if (SHEditorUI::::CollapsingHeader(LABEL)) + { + SHEditorUI::::PushID(LABEL); + SHEditorUI::::Indent(); + { + // Define context menu + if (SHEditorUI::::BeginPopup(CONTEXT_MENU_ID)) + { + if (SHEditorUI::::MenuItem("Remove Script")) + { + // Mark script for removal + ScriptStore::RemoveScript(entity, script); + } + SHEditorUI::::EndPopup(); + } + + // Context menu button + if (SHEditorUI::::SmallButton("...")) + { + SHEditorUI::::OpenPopup(CONTEXT_MENU_ID); + } + + // Go through all fields and output them + auto fields = ReflectionUtilities::GetInstanceFields(script); + int id = 0; + for each (auto field in fields) + { + // Ignore non-serialisable fields + if (!ReflectionUtilities::FieldIsSerialisable(field)) + continue; + + // Render the input field for this field + SHEditorUI::::PushID(LABEL + std::to_string(id++)); + renderFieldInInspector(field, script); + SHEditorUI::::PopID(); + } + + } + SHEditorUI::::Unindent(); + SHEditorUI::::PopID(); + } + SHEditorUI::::PopID(); + } + void Editor::renderFieldInInspector(Reflection::FieldInfo^ field, Object^ object) + { + if RENDER_FIELD (Int16, int, InputInt) + else if RENDER_FIELD (Int32, int, InputInt) + else if RENDER_FIELD (Int64, int, InputInt) + else if RENDER_FIELD (UInt16, unsigned int, InputUnsignedInt) + else if RENDER_FIELD (UInt32, unsigned int, InputUnsignedInt) + else if RENDER_FIELD (UInt64, unsigned int, InputUnsignedInt) + else if RENDER_FIELD (Byte, int, InputInt) + else if RENDER_FIELD (bool, bool, InputCheckbox) + else if RENDER_FIELD (float, float, InputFloat) + else if RENDER_FIELD (double, double, InputDouble) + else if (field->FieldType->IsSubclassOf(Enum::typeid)) + { + // Get all the names of the enums + const array^ ENUM_NAMES = field->FieldType->GetEnumNames(); + std::vector nativeEnumNames; + for each (String^ str in ENUM_NAMES) + { + nativeEnumNames.emplace_back(Convert::ToNative(str)); + } + + int val = safe_cast(field->GetValue(object)); + if (SHEditorUI::::InputEnumCombo(Convert::ToNative(field->Name), val, nativeEnumNames)) + { + field->SetValue(object, val); + } + } + else if RENDER_FIELD_CASTED(Vector2, vec2, InputVec2) + else if RENDER_FIELD_CASTED(Vector3, vec3, InputVec3) + else if (field->FieldType == String::typeid) + { + // Prevent issues where String^ is null due to being empty + String^ stringVal = safe_cast(field->GetValue(object)); + if (stringVal == nullptr) + { + stringVal = ""; + } + + // Actual Field + std::string val = Convert::ToNative(stringVal); + if (SHEditorUI::::InputTextField(Convert::ToNative(field->Name), val)) + { + field->SetValue(object, Convert::ToCLI(val)); + } + } + } +} diff --git a/SHADE_Managed/src/Editor/Editor.hxx b/SHADE_Managed/src/Editor/Editor.hxx new file mode 100644 index 00000000..b85e9203 --- /dev/null +++ b/SHADE_Managed/src/Editor/Editor.hxx @@ -0,0 +1,65 @@ +/************************************************************************************//*! +\file Editor.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 27, 2022 +\brief Contains the definition of the managed Editor static 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 "Engine/Entity.hxx" +#include "Scripts/Script.hxx" + +namespace SHADE +{ + /// + /// Static class for Editor-related functions + /// + public ref class Editor abstract sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Script Rendering Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Renders the set of attached Scripts for the specified Entity into the + /// inspector. + ///
+ /// This function is meant for consumption from native code in the inspector + /// rendering code. + ///
+ /// The Entity to render the Scripts of. + static void RenderScriptsInInspector(Entity entity); + + private: + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Renders a single specified Script's inspector. + /// + /// The Entity to render the Scripts of. + /// The Script to render the inspector for. + /// + /// Indices used internally to differentiate each rendered Script + /// inspector. This is required to open and close each Script's inspector + /// independently from each other. + /// + static void renderScriptInInspector(Entity entity, Script^ script, int index); + /// + /// Renders a field specified into the inspector. + /// + /// The field to render. + /// + /// The object that contains the data of the field to render. + /// + static void renderFieldInInspector(System::Reflection::FieldInfo^ field, Object^ object); + }; +} From 7010e1b688e01d579f32f5f26f4f0c2c5fbe2d61 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Wed, 28 Sep 2022 00:06:47 +0800 Subject: [PATCH 06/13] Added initial implementation of script inspector --- .../Inspector/SHEditorInspector.cpp | 7 + SHADE_Engine/src/Editor/SHEditorUI.cpp | 628 +++++++----------- SHADE_Engine/src/Editor/SHEditorUI.h | 567 ++++++++-------- SHADE_Engine/src/Editor/SHEditorUI.hpp | 78 +-- SHADE_Engine/src/Scripting/SHScriptEngine.cpp | 78 ++- SHADE_Engine/src/Scripting/SHScriptEngine.h | 2 +- SHADE_Managed/src/Editor/Editor.cxx | 72 +- SHADE_Managed/src/Editor/Editor.hxx | 8 +- TempScriptsFolder/TestScript.cs | 5 +- 9 files changed, 662 insertions(+), 783 deletions(-) diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index fba9512e..ed4792de 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -12,6 +12,8 @@ #include "Editor/SHEditorWidgets.hpp" #include "SHEditorComponentView.hpp" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Scripting/SHScriptEngine.h" +#include "ECS_Base/Managers/SHSystemManager.h" namespace SHADE { @@ -61,6 +63,11 @@ namespace SHADE DrawAddComponentButton(eid); ImGui::EndMenu(); } + + // Render Scripts + SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); + scriptEngine->RenderScriptsInInspector(eid); + } ImGui::End(); } diff --git a/SHADE_Engine/src/Editor/SHEditorUI.cpp b/SHADE_Engine/src/Editor/SHEditorUI.cpp index cbeb164f..16e06f09 100644 --- a/SHADE_Engine/src/Editor/SHEditorUI.cpp +++ b/SHADE_Engine/src/Editor/SHEditorUI.cpp @@ -10,412 +10,276 @@ Reproduction or disclosure of this file or its contents without the prior writte of DigiPen Institute of Technology is prohibited. *//*************************************************************************************/ // Precompiled Header -#include +#include "SHpch.h" // Primary Header -#include "Editor/EditorUI.h" +#include "SHEditorUI.h" // External Dependencies #include -// Project Headers -#include "Core/Resource/ResourceManager.h" -#include "Editor/ImGuiExtensions.h" -#include "Editor/Editor.h" -namespace Pls +namespace SHADE { - /*---------------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - ID Stack */ - /*---------------------------------------------------------------------------------*/ - void EditorUI::PushID(const std::string& id) + /*-----------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - ID Stack */ + /*-----------------------------------------------------------------------------------*/ + void SHEditorUI::PushID(const std::string& id) + { + ImGui::PushID(id.c_str()); + } + + void SHEditorUI::PushID(int id) + { + ImGui::PushID(id); + } + + void SHEditorUI::PopID() + { + ImGui::PopID(); + } + + /*-----------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Indent */ + /*-----------------------------------------------------------------------------------*/ + void SHEditorUI::Indent() + { + ImGui::Indent(); + } + void SHEditorUI::Unindent() + { + ImGui::Unindent(); + } + + /*-----------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Organizers */ + /*-----------------------------------------------------------------------------------*/ + bool SHEditorUI::CollapsingHeader(const std::string& title) + { + return ImGui::CollapsingHeader(title.c_str()); + } + + void SHEditorUI::SameLine() + { + ImGui::SameLine(); + } + + void SHEditorUI::Separator() + { + ImGui::Separator(); + } + + bool SHEditorUI::BeginMenu(const std::string& label) + { + return ImGui::BeginMenu(label.data()); + } + + bool SHEditorUI::BeginMenu(const std::string& label, const char* icon) + { + return ImGui::BeginMenu(std::format("{} {}", icon, label.data()).data()); + } + + void SHEditorUI::EndMenu() + { + ImGui::EndMenu(); + } + + /*-----------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Pop Ups */ + /*-----------------------------------------------------------------------------------*/ + bool SHEditorUI::BeginPopup(const std::string& label) + { + return ImGui::BeginPopup(label.c_str()); + } + + bool SHEditorUI::BeginPopupContextItem(const std::string& label) + { + return ImGui::BeginPopupContextItem(label.data()); + } + + void SHEditorUI::EndPopup() + { + ImGui::EndPopup(); + } + void SHEditorUI::OpenPopup(const std::string& label) + { + ImGui::OpenPopup(label.c_str()); + } + + bool SHEditorUI::MenuItem(const std::string& label) + { + return ImGui::MenuItem(label.c_str()); + } + + /*-----------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Widgets */ + /*-----------------------------------------------------------------------------------*/ + void SHEditorUI::Text(const std::string& title) + { + ImGui::Text(title.c_str()); + } + bool SHEditorUI::SmallButton(const std::string& title) + { + return ImGui::SmallButton(title.c_str()); + } + bool SHEditorUI::Button(const std::string& title) + { + return ImGui::Button(title.c_str()); + } + + bool SHEditorUI::Selectable(const std::string& label) + { + return ImGui::Selectable(label.data()); + } + + bool SHEditorUI::Selectable(const std::string& label, const char* icon) + { + return ImGui::Selectable(std::format("{} {}", icon, label).data()); + } + + bool SHEditorUI::InputCheckbox(const std::string& label, bool& value) + { + return ImGui::Checkbox(label.c_str(), &value); + } + bool SHEditorUI::InputInt(const std::string& label, int& value) + { + return ImGui::InputInt(label.c_str(), &value, + 1, 10, + ImGuiInputTextFlags_EnterReturnsTrue); + } + bool SHEditorUI::InputUnsignedInt(const std::string& label, unsigned int& value) + { + int signedVal = static_cast(value); + const bool CHANGED = InputInt(label, signedVal); + if (CHANGED) { - ImGui::PushID(id.c_str()); + signedVal = std::clamp(signedVal, 0, std::numeric_limits::max()); + value = static_cast(signedVal); + } + return CHANGED; + } + bool SHEditorUI::InputFloat(const std::string& label, float& value) + { + return ImGui::InputFloat(label.c_str(), &value, + 0.1f, 1.0f, "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + } + bool SHEditorUI::InputDouble(const std::string& label, double& value) + { + return ImGui::InputDouble(label.c_str(), &value, + 0.1, 1.0, "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + } + bool SHEditorUI::InputAngle(const std::string& label, double& value) + { + return ImGui::InputDouble(label.c_str(), &value, + 1.0, 45.0, "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + } + + bool SHEditorUI::InputSlider(const std::string& label, double min, double max, double& value) + { + float val = static_cast(value); + const bool CHANGED = ImGui::SliderFloat(label.c_str(), &val, + static_cast(min), static_cast(max), "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + + if (CHANGED) + { + value = val; } - void EditorUI::PushID(int id) - { - ImGui::PushID(id); - } - void EditorUI::PopID() - { - ImGui::PopID(); - } + return CHANGED; + } - /*---------------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - Indent */ - /*---------------------------------------------------------------------------------*/ - void EditorUI::Indent() + bool SHEditorUI::InputVec2(const std::string& label, SHVec2& value) + { + float vec[2] = { - ImGui::Indent(); - } - void EditorUI::Unindent() + static_cast(value.x), + static_cast(value.y) + }; + const bool CHANGED = ImGui::InputFloat2(label.c_str(), vec, "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + if (CHANGED) { - ImGui::Unindent(); + value.x = vec[0]; + value.y = vec[1]; } + return CHANGED; + } + bool SHEditorUI::InputVec3(const std::string& label, SHVec3& value) + { + float vec[3] = + { + static_cast(value.x), + static_cast(value.y), + static_cast(value.z) + }; + const bool CHANGED = ImGui::InputFloat3(label.c_str(), vec, "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + if (CHANGED) + { + value.x = vec[0]; + value.y = vec[1]; + value.z = vec[2]; + } + return CHANGED; + } - /*---------------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - Organisers */ - /*---------------------------------------------------------------------------------*/ - bool EditorUI::CollapsingHeader(const std::string& title) + bool SHEditorUI::InputSliderVec3(const std::string& label, double min, double max, SHVec3& value) + { + float vec[3] = { - return ImGui::CollapsingHeader(title.c_str()); - } - - /*---------------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - Pop Ups */ - /*---------------------------------------------------------------------------------*/ - bool EditorUI::BeginPopup(const std::string& label) + static_cast(value.x), + static_cast(value.y), + static_cast(value.z) + }; + const bool CHANGED = ImGui::SliderFloat3(label.c_str(), vec, + static_cast(min), static_cast(max), "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + if (CHANGED) { - return ImGui::BeginPopup(label.c_str()); - } - void EditorUI::EndPopup() - { - ImGui::EndPopup(); - } - void EditorUI::OpenPopup(const std::string& label) - { - ImGui::OpenPopup(label.c_str()); + value.x = vec[0]; + value.y = vec[1]; + value.z = vec[2]; } + return CHANGED; + } - bool EditorUI::MenuItem(const std::string& label) + bool SHEditorUI::InputTextField(const std::string& label, std::string& value) + { + std::array buffer = { '\0' }; + strcpy_s(buffer.data(), TEXT_FIELD_MAX_LENGTH, value.c_str()); + const bool CHANGED = ImGui::InputText(label.c_str(), &buffer[0], TEXT_FIELD_MAX_LENGTH); + if (CHANGED) { - return ImGui::MenuItem(label.c_str()); + value = std::string(buffer.data(), buffer.data() + TEXT_FIELD_MAX_LENGTH); } + return CHANGED; + } - /*---------------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - Widgets */ - /*---------------------------------------------------------------------------------*/ - void EditorUI::Text(const std::string& title) + bool SHEditorUI::InputEnumCombo(const std::string& label, int& v, const std::vector& enumNames) + { + + // Clamp input value + const std::string& INITIAL_NAME = v >= static_cast(enumNames.size()) ? "Unknown" : enumNames[v]; + bool b = false; + if (ImGui::BeginCombo(label.c_str(), INITIAL_NAME.c_str(), ImGuiComboFlags_None)) { - ImGui::Text(title.c_str()); - } - bool EditorUI::SmallButton(const std::string& title) - { - return ImGui::SmallButton(title.c_str()); - } - bool EditorUI::Button(const std::string& title) - { - return ImGui::Button(title.c_str()); - } - bool EditorUI::InputCheckbox(const std::string& label, bool& value) - { - return ImGui::Checkbox(label.c_str(), &value); - } - bool EditorUI::InputInt(const std::string& label, int& value) - { - return ImGui::InputInt(label.c_str(), &value, - 1, 10, - ImGuiInputTextFlags_EnterReturnsTrue); - } - bool EditorUI::InputUnsignedInt(const std::string& label, unsigned int& value) - { - int signedVal = static_cast(value); - const bool CHANGED = InputInt(label, signedVal); - if (CHANGED) + for (int i = 0; i < enumNames.size(); ++i) + { + const bool IS_SELECTED = v == i; + if (ImGui::Selectable(enumNames[i].c_str(), IS_SELECTED)) { - signedVal = std::clamp(signedVal, 0, std::numeric_limits::max()); - value = static_cast(signedVal); + v = i; + b = true; } - return CHANGED; - } - bool EditorUI::InputFloat(const std::string& label, float& value) - { - return ImGui::InputFloat(label.c_str(), &value, - 0.1f, 1.0f, "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); - } - bool EditorUI::InputDouble(const std::string& label, double& value) - { - return ImGui::InputDouble(label.c_str(), &value, - 0.1, 1.0, "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); - } - bool EditorUI::InputAngle(const std::string& label, double& value) - { - return ImGui::InputDouble(label.c_str(), &value, - 1.0, 45.0, "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); - } - - bool EditorUI::InputSlider(const std::string& label, double min, double max, double& value) - { - float val = static_cast(value); - const bool CHANGED = ImGui::SliderFloat(label.c_str(), &val, - static_cast(min), static_cast(max), "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); - - if (CHANGED) + if (IS_SELECTED) { - value = val; + ImGui::SetItemDefaultFocus(); } - - - return CHANGED; + } + ImGui::EndCombo(); } - - bool EditorUI::InputVec2(const std::string& label, vec2& value) - { - float vec[2] = - { - static_cast(value.x), - static_cast(value.y) - }; - const bool CHANGED = ImGui::InputFloat2(label.c_str(), vec, "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); - if (CHANGED) - { - value.x = vec[0]; - value.y = vec[1]; - } - return CHANGED; - } - bool EditorUI::InputVec3(const std::string& label, vec3& value) - { - float vec[3] = - { - static_cast(value.x), - static_cast(value.y), - static_cast(value.z) - }; - const bool CHANGED = ImGui::InputFloat3(label.c_str(), vec, "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); - if (CHANGED) - { - value.x = vec[0]; - value.y = vec[1]; - value.z = vec[2]; - } - return CHANGED; - } - - bool EditorUI::InputSliderVec3(const std::string& label, double min, double max, vec3& value) - { - float vec[3] = - { - static_cast(value.x), - static_cast(value.y), - static_cast(value.z) - }; - const bool CHANGED = ImGui::SliderFloat3(label.c_str(), vec, - static_cast(min), static_cast(max), "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); - if (CHANGED) - { - value.x = vec[0]; - value.y = vec[1]; - value.z = vec[2]; - } - return CHANGED; - } - - bool EditorUI::InputColor(const std::string& label, GFX::Color& value) - { - float color[4] = - { - value.R, - value.G, - value.B, - value.A - }; - const bool CHANGED = ImGui::ColorEdit4(label.c_str(), color, - ImGuiColorEditFlags_AlphaBar | - ImGuiColorEditFlags_AlphaPreview | - ImGuiColorEditFlags_Float); - if (CHANGED) - { - value.R = color[0]; - value.G = color[1]; - value.B = color[2]; - value.A = std::clamp(color[3], 0.f, 1.f); - } - return CHANGED; - } - bool EditorUI::InputTextField(const std::string& label, std::string& value) - { - std::array buffer = { '\0' }; - strcpy_s(buffer.data(), TEXT_FIELD_MAX_LENGTH, value.c_str()); - const bool CHANGED = ImGui::InputText(label.c_str(), &buffer[0], TEXT_FIELD_MAX_LENGTH); - if (CHANGED) - { - value = std::string(buffer.data(), buffer.data() + TEXT_FIELD_MAX_LENGTH); - } - return CHANGED; - } - - bool EditorUI::InputEnumCombo(const std::string& label, int& v, const std::vector& enumNames) - { - - // Clamp input value - const std::string& INITIAL_NAME = v >= static_cast(enumNames.size()) ? "Unknown" : enumNames[v]; - bool b = false; - if (ImGui::BeginCombo(label.c_str(), INITIAL_NAME.c_str(), ImGuiComboFlags_None)) - { - for (int i = 0; i < enumNames.size(); ++i) - { - const bool IS_SELECTED = v == i; - if (ImGui::Selectable(enumNames[i].c_str(), IS_SELECTED)) - { - v = i; - b = true; - } - if (IS_SELECTED) - { - ImGui::SetItemDefaultFocus(); - } - } - ImGui::EndCombo(); - } - return b; - } - - bool EditorUI::InputTextureDropDown(const std::string& label, Resource::Snowflake& v) - { - static std::vector> resources; - - // Register texture popup - bool hasChanges = false; - if (ImGui::BeginPopup("Texture Menu")) - { - if (ImGui::Button("None")) - { - v = Resource::INVALID_SNOWFLAKE; - ImGui::CloseCurrentPopup(); - hasChanges = true; - } - for (auto& rscWrapper : resources) - { - Resource& rsc = rscWrapper.get(); - - ImGui::PushID(static_cast(rsc.GetID())); - - const GFX::Texture* TEX = rsc.LoadTexture(); - if (TEX == nullptr) - { - continue; - } - const ImTextureID TEX_ID = reinterpret_cast(static_cast(TEX->GetHandle())); - const std::string NAME = rsc.GetPath().filename().string(); - const std::string FP = rsc.GetPath().string(); - if (ImGui::ImageButtonWithText(TEX_ID, NAME.c_str())) - { - v = rsc.GetID(); - ImGui::CloseCurrentPopup(); - hasChanges = true; - } - ImGui::TextDisabled(FP.c_str()); - - ImGui::PopID(); - } - ImGui::EndPopup(); - } - - // Get texture ID of resource - ImTextureID texID = 0; - std::string texName = "None"; - Resource* rsc = ResourceManager::Find(v); - if (rsc) - { - // File - if (rsc->IsType()) - { - GFX::Texture* tex = rsc->LoadTexture(); - if (tex) - { - texID = reinterpret_cast(static_cast(tex->GetHandle())); - } - } - else - { - // TODO (Clarence): replace with missing texture image - texID = Editor::Editor::GetInternalTexture("scene.png"); - } - texName = rsc->GetPath().filename().string(); - } - - // Show texture selection menu - if (ImGui::ImageButtonWithText(texID, texName.c_str(), label.c_str())) - { - resources = ResourceManager::FindAllOfType(); - ImGui::OpenPopup("Texture Menu"); - } - - return hasChanges; - } - bool EditorUI::InputFontDropDown(const char* label, Resource::Snowflake& v) - { - static std::vector> resources; - - // Register texture popup - bool hasChanges = false; - if (ImGui::BeginPopup("Font Menu")) - { - if (ImGui::Button("None")) - { - v = Resource::INVALID_SNOWFLAKE; - ImGui::CloseCurrentPopup(); - hasChanges = true; - } - for (auto& rscWrapper : resources) - { - Resource& rsc = rscWrapper.get(); - - ImGui::PushID(static_cast(rsc.GetID())); - - const GFX::Font* FONT = rsc.LoadFont(); - if (FONT == nullptr) - { - continue; - } - const std::string NAME = rsc.GetPath().filename().string(); - const std::string FP = rsc.GetPath().string(); - if (ImGui::Button(NAME.c_str())) - { - v = rsc.GetID(); - ImGui::CloseCurrentPopup(); - hasChanges = true; - } - ImGui::TextDisabled(FP.c_str()); - - ImGui::PopID(); - } - ImGui::EndPopup(); - } - - // Get font ID of resource - ImTextureID fontID = 0; - std::string fontName = "None"; - Resource* rsc = ResourceManager::Find(v); - - if (rsc) - { - // File - if (rsc) - { - GFX::Font* font = rsc->LoadFont(); - if (font) - { - fontID = reinterpret_cast(static_cast(font->GetID())); - if (font->CreatedThisFrame()) - { - font->OnCreate() = false; - hasChanges = true; - } - } - } - else - { - // TODO (Clarence): replace with missing texture image - fontID = Editor::Editor::GetInternalFont("selawk.tff"); - } - fontName = rsc->GetPath().filename().string(); - } - - // Show font selection menu - if (ImGui::ButtonWithText(fontName.c_str(), label)) - { - resources = ResourceManager::FindAllOfType(); - ImGui::OpenPopup("Font Menu"); - } - - return hasChanges; - } -} // namespace PlushieEngine + return b; + } +} diff --git a/SHADE_Engine/src/Editor/SHEditorUI.h b/SHADE_Engine/src/Editor/SHEditorUI.h index ce9d8608..06768b87 100644 --- a/SHADE_Engine/src/Editor/SHEditorUI.h +++ b/SHADE_Engine/src/Editor/SHEditorUI.h @@ -1,312 +1,297 @@ /************************************************************************************//*! -\file EditorUI.h -\author Tng Kah Wei, kahwei.tng, 390009620 (50%) +\file SHEditorUI.h +\author Tng Kah Wei, kahwei.tng, 390009620 \par email: kahwei.tng\@digipen.edu -\author Tay Yan Chong Clarence, t.yanchongclarence, 620008720 (50%) \par email: t.yanchongclarence\@digipen.edu -\date Nov 7, 2021 -\brief Defines a class that encapsulates the running of a Plushie Engine - application. +\date Sep 27, 2022 +\brief Defines a class that contains wrapper functions for ImGui. -Copyright (C) 2021 DigiPen Institute of Technology. +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 -// Platform Defines -#include "PlushieDefines.h" // Standard Library -#include // std::function -#include // std::string +#include // std::function +#include // std::string +// Project Includes +#include "Math/Vector/SHVec2.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec4.h" +#include "Math/SHMatrix.h" -#include "Core/Resource/Resource.h" -#include "Graphics/Color.h" -#include "Math/Vector2.h" -#include "Math/Vector3.h" - -namespace Pls +namespace SHADE { + /// + /// Static class that contains useful functions for Editor UI using ImGui. + /// + class SH_API SHEditorUI final + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constants */ + /*-----------------------------------------------------------------------------*/ /// - /// Static class that contains useful functions for Editor UI using ImGui. + /// Maximum length of a string supported by InputTextField() /// - class PLS_API EditorUI final - { - public: - /*-----------------------------------------------------------------------------*/ - /* Constants */ - /*-----------------------------------------------------------------------------*/ - /// - /// Maximum length of a string supported by InputTextField() - /// - static constexpr size_t TEXT_FIELD_MAX_LENGTH = 256; + static constexpr size_t TEXT_FIELD_MAX_LENGTH = 256; - /*-----------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - ID Stack */ - /*-----------------------------------------------------------------------------*/ - /// - /// Marks the start of a stack of ImGui widgets with the specified id. - ///
- /// Wraps up ImGui::PushID(). - ///
- /// String-based ID. - static void PushID(const std::string& id); - /// - /// Marks the start of a stack of ImGui widgets with the specified id. - ///
- /// Wraps up ImGui::PushID(). - ///
- /// Integer-based ID. - static void PushID(int id); - /// - /// Marks the end of a stack of ImGui widgets from the last PushID() call. - ///
- /// Wraps up ImGui::PopID(). - ///
- static void PopID(); + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - ID Stack */ + /*-----------------------------------------------------------------------------*/ + /// + /// Marks the start of a stack of ImGui widgets with the specified id. + ///
+ /// Wraps up ImGui::PushID(). + ///
+ /// String-based ID. + static void PushID(const std::string& id); + /// + /// Marks the start of a stack of ImGui widgets with the specified id. + ///
+ /// Wraps up ImGui::PushID(). + ///
+ /// Integer-based ID. + static void PushID(int id); + /// + /// Marks the end of a stack of ImGui widgets from the last PushID() call. + ///
+ /// Wraps up ImGui::PopID(). + ///
+ static void PopID(); - /*-----------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - Indent */ - /*-----------------------------------------------------------------------------*/ - /// - /// Indents the widgets rendered after this call. - ///
- /// Wraps up ImGui::Indent(). - ///
- static void Indent(); - /// - /// Unindents the widgets rendered after this call. - ///
- /// Wraps up ImGui::Unindent(). - ///
- static void Unindent(); + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Indent */ + /*-----------------------------------------------------------------------------*/ + /// + /// Indents the widgets rendered after this call. + ///
+ /// Wraps up ImGui::Indent(). + ///
+ static void Indent(); + /// + /// Unindents the widgets rendered after this call. + ///
+ /// Wraps up ImGui::Unindent(). + ///
+ static void Unindent(); - /*-----------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - Organisers */ - /*-----------------------------------------------------------------------------*/ - /// - /// Creates a collapsing title header. - ///
- /// Wraps up ImGui::CollapsingHeader(). - ///
- /// Label for the header. - /// True if the header is open, false otherwise. - static bool CollapsingHeader(const std::string& title); + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Organizers */ + /*-----------------------------------------------------------------------------*/ + /// + /// Creates a collapsing title header. + ///
+ /// Wraps up ImGui::CollapsingHeader(). + ///
+ /// Label for the header. + /// True if the header is open, false otherwise. + static bool CollapsingHeader(const std::string& title); + static void SameLine(); + static void Separator(); - /*-----------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - Pop Ups */ - /*-----------------------------------------------------------------------------*/ - /// - /// Marks the start of a definition of a mini pop up that can show options. - ///
- /// Wraps up ImGui::BeginPopup(). - ///
- /// Label used to identify this widget. - /// Whether or not the pop up is open. - static bool BeginPopup(const std::string& label); - /// - /// Marks the end of a definition of a mini pop up that can show options. - ///
- /// Wraps up ImGui::EndPopup(). - ///
- static void EndPopup(); - /// - /// Opens the popup that was defined with the specified label. - ///
- /// Wraps up ImGui::OpenPopup(). - ///
- static void OpenPopup(const std::string& label); - /// - /// Creates a menu item in the list of items for a mini popup. - ///
- /// Wraps up ImGui::MenuItem(). - ///
- /// Label used to identify this widget. - /// Whether or not the menu item was selected. - static bool MenuItem(const std::string& label); + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Menu */ + /*-----------------------------------------------------------------------------*/ + static bool BeginMenu(const std::string& label); + static bool BeginMenu(const std::string& label, const char* icon); + static void EndMenu(); - /*-----------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - Widgets */ - /*-----------------------------------------------------------------------------*/ - /// - /// Creates a visual text widget. - ///
- /// Wraps up ImGui::Text(). - ///
- /// Text to display. - static void Text(const std::string& title); - /// - /// Creates a small inline button widget. - ///
- /// Wraps up ImGui::SmallButton(). - ///
- /// Text to display. - /// True if button was pressed. - static bool SmallButton(const std::string& title); - /// - /// Creates a inline button widget. - ///
- /// Wraps up ImGui::Button(). - ///
- /// Text to display. - /// True if button was pressed. - static bool Button(const std::string& title); - /// - /// Creates a checkbox widget for boolean input. - ///
- /// Wraps up ImGui::Checkbox(). - ///
- /// Label used to identify this widget. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputCheckbox(const std::string& label, bool& value); - /// - /// Creates a integer field widget for integer input. - ///
- /// Wraps up ImGui::InputInt(). - ///
- /// Label used to identify this widget. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputInt(const std::string& label, int& value); - /// - /// Creates a integer field widget for unsigned integer input. - ///
- /// Wraps up ImGui::InputInt() with an additional clamping of values. - ///
- /// Note: As a result, the range of this function limits it to the maximum - /// value of a 32-bit signed integer instead of a 32-bit unsigned integer. - ///
- /// Label used to identify this widget. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputUnsignedInt(const std::string& label, unsigned int& value); - /// - /// Creates a decimal field widget for single precision float input. - ///
- /// Wraps up ImGui::InputFloat(). - ///
- /// Label used to identify this widget. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputFloat(const std::string& label, float& value); - /// - /// Creates a decimal field widget for double precision float input. - ///
- /// Wraps up ImGui::InputDouble(). - ///
- /// Label used to identify this widget. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputDouble(const std::string& label, double& value); - /// - /// Creates a decimal field widget for double input with increments of higher - /// steps meant for angle variables. - ///
- /// Wraps up ImGui::InputDouble(). - ///
- /// Label used to identify this widget. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputAngle(const std::string& label, double& value); - /// - /// Creates a double slider field widget for double input. - ///
- /// Wraps up ImGui::InputSliderFloat(). - ///
- /// Label used to identify this widget. - /// Minimum value of the slider. - /// Maximum value of the slider. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputSlider(const std::string& label, double min, double max, double& value); - /// - /// Creates a 2x double field widget for Vector2 input. - ///
- /// Wraps up ImGui::InputFloat2(). - ///
- /// Label used to identify this widget. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputVec2(const std::string& label, vec2& value); - /// - /// Creates a 3x double field widget for Vector3 input. - ///
- /// Wraps up ImGui::InputFloat3(). - ///
- /// Label used to identify this widget. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputVec3(const std::string& label, vec3& value); - /// - /// Creates a 3x double slider field widget for Vector3 input. - ///
- /// Wraps up ImGui::InputSliderFloat3(). - ///
- /// Label used to identify this widget. - /// Minimum value of the slider. - /// Maximum value of the slider. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputSliderVec3(const std::string& label, double min, double max, vec3& value); - /// - /// Creates a colour field widget for Color input. - ///
- /// Wraps up ImGui::ColorEdit4(). - ///
- /// Label used to identify this widget. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputColor(const std::string& label, GFX::Color& value); - /// - /// Creates a text field widget for string input. - ///
- /// Wraps up ImGui::InputText(). - ///
- /// Label used to identify this widget. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputTextField(const std::string& label, std::string& value); - /// - /// Creates a combo box for enumeration input. - /// - /// The type of enum to input. - /// The name of the input. - /// The reference to the value to modify. - /// The maximum value of the enum. - /// - /// Conversion function from the type of enum - /// to C-style string. - /// Whether the value was modified. - template - static bool InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function toStrFn); - /// - /// Creates a combo box for enumeration input using a specified list of names. - /// - /// The name of the input. - /// The reference to the value to modify. - /// Vector of names for each enumeration value. - /// Whether the value was modified. - static bool InputEnumCombo(const std::string& label, int& v, const std::vector& enumNames); - /// - /// Creates a drop down widget for texture selection. - /// - /// The name of the input. - /// The reference to the value to modify. - /// Whether the value was modified. - static bool InputTextureDropDown(const std::string& label, Resource::Snowflake& v); - /// - /// Creates a drop down widget for font selection. - /// - /// The name of the input. - /// The reference to the value to modify. - /// Whether the value was modified. - static bool InputFontDropDown(const char* label, Resource::Snowflake& v); + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Pop Ups */ + /*-----------------------------------------------------------------------------*/ + /// + /// Marks the start of a definition of a mini pop up that can show options. + ///
+ /// Wraps up ImGui::BeginPopup(). + ///
+ /// Label used to identify this widget. + /// Whether or not the pop up is open. + static bool BeginPopup(const std::string& label); + static bool BeginPopupContextItem(const std::string& label); + /// + /// Marks the end of a definition of a mini pop up that can show options. + ///
+ /// Wraps up ImGui::EndPopup(). + ///
+ static void EndPopup(); + /// + /// Opens the popup that was defined with the specified label. + ///
+ /// Wraps up ImGui::OpenPopup(). + ///
+ static void OpenPopup(const std::string& label); + /// + /// Creates a menu item in the list of items for a mini popup. + ///
+ /// Wraps up ImGui::MenuItem(). + ///
+ /// Label used to identify this widget. + /// Whether or not the menu item was selected. + static bool MenuItem(const std::string& label); + + /*-----------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Widgets */ + /*-----------------------------------------------------------------------------*/ + /// + /// Creates a visual text widget. + ///
+ /// Wraps up ImGui::Text(). + ///
+ /// Text to display. + static void Text(const std::string& title); + /// + /// Creates a small inline button widget. + ///
+ /// Wraps up ImGui::SmallButton(). + ///
+ /// Text to display. + /// True if button was pressed. + static bool SmallButton(const std::string& title); + /// + /// Creates a inline button widget. + ///
+ /// Wraps up ImGui::Button(). + ///
+ /// Text to display. + /// True if button was pressed. + static bool Button(const std::string& title); + static bool Selectable(const std::string& label); + static bool Selectable(const std::string& label, const char* icon); + /// + /// Creates a checkbox widget for boolean input. + ///
+ /// Wraps up ImGui::Checkbox(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputCheckbox(const std::string& label, bool& value); + /// + /// Creates a integer field widget for integer input. + ///
+ /// Wraps up ImGui::InputInt(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputInt(const std::string& label, int& value); + /// + /// Creates a integer field widget for unsigned integer input. + ///
+ /// Wraps up ImGui::InputInt() with an additional clamping of values. + ///
+ /// Note: As a result, the range of this function limits it to the maximum + /// value of a 32-bit signed integer instead of a 32-bit unsigned integer. + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputUnsignedInt(const std::string& label, unsigned int& value); + /// + /// Creates a decimal field widget for single precision float input. + ///
+ /// Wraps up ImGui::InputFloat(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputFloat(const std::string& label, float& value); + /// + /// Creates a decimal field widget for double precision float input. + ///
+ /// Wraps up ImGui::InputDouble(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputDouble(const std::string& label, double& value); + /// + /// Creates a decimal field widget for double input with increments of higher + /// steps meant for angle variables. + ///
+ /// Wraps up ImGui::InputDouble(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputAngle(const std::string& label, double& value); + /// + /// Creates a double slider field widget for double input. + ///
+ /// Wraps up ImGui::InputSliderFloat(). + ///
+ /// Label used to identify this widget. + /// Minimum value of the slider. + /// Maximum value of the slider. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputSlider(const std::string& label, double min, double max, double& value); + /// + /// Creates a 2x double field widget for Vector2 input. + ///
+ /// Wraps up ImGui::InputFloat2(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputVec2(const std::string& label, SHVec2& value); + /// + /// Creates a 3x double field widget for Vector3 input. + ///
+ /// Wraps up ImGui::InputFloat3(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputVec3(const std::string& label, SHVec3& value); + /// + /// Creates a 3x double slider field widget for Vector3 input. + ///
+ /// Wraps up ImGui::InputSliderFloat3(). + ///
+ /// Label used to identify this widget. + /// Minimum value of the slider. + /// Maximum value of the slider. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputSliderVec3(const std::string& label, double min, double max, SHVec3& value); + /// + /// Creates a text field widget for string input. + ///
+ /// Wraps up ImGui::InputText(). + ///
+ /// Label used to identify this widget. + /// Reference to the variable to store the result. + /// True if the value was changed. + static bool InputTextField(const std::string& label, std::string& value); + /// + /// Creates a combo box for enumeration input. + /// + /// The type of enum to input. + /// The name of the input. + /// The reference to the value to modify. + /// The maximum value of the enum. + /// + /// Conversion function from the type of enum to C-style string. + /// + /// Whether the value was modified. + template + static bool InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function toStrFn); + /// + /// Creates a combo box for enumeration input using a specified list of names. + /// + /// The name of the input. + /// The reference to the value to modify. + /// Vector of names for each enumeration value. + /// Whether the value was modified. + static bool InputEnumCombo(const std::string& label, int& v, const std::vector& enumNames); - private: - // Prevent instantiation of this static class - EditorUI() = delete; - }; -} // namespace PlushieEngine + private: + // Prevent instantiation of this static class + SHEditorUI() = delete; + }; +} -#include "EditorUI.hpp" \ No newline at end of file +#include "SHEditorUI.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/SHEditorUI.hpp b/SHADE_Engine/src/Editor/SHEditorUI.hpp index d7a3eae7..f3af0412 100644 --- a/SHADE_Engine/src/Editor/SHEditorUI.hpp +++ b/SHADE_Engine/src/Editor/SHEditorUI.hpp @@ -1,49 +1,51 @@ /************************************************************************************//*! -\file EditorUI.hpp -\author Tay Yan Chong Clarence, t.yanchongclarence, 620008720 -\par email: t.yanchongclarence\@digipen.edu -\date Nov 8, 2021 +\file SHEditorUI.hpp +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Sep 27, 2022 \brief Contains the implementation of editor inspector template functions. -Copyright (C) 2021 DigiPen Institute of Technology. +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. *//*************************************************************************************/ // Primary Header -#include "EditorUI.h" +#include "SHEditorUI.h" +// External Dependencies +#include -namespace Pls +namespace SHADE { - /*---------------------------------------------------------------------------------*/ - /* ImGui Wrapper Functions - Widgets */ - /*---------------------------------------------------------------------------------*/ - template - inline bool EditorUI::InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function toStrFn) + /*---------------------------------------------------------------------------------*/ + /* ImGui Wrapper Functions - Widgets */ + /*---------------------------------------------------------------------------------*/ + template + inline bool SHEditorUI::InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function toStrFn) + { + std::vector values; + for (int i = 0; i <= maxVal; ++i) { - std::vector values; - for (int i = 0; i <= maxVal; ++i) - { - values.emplace_back(static_cast(i)); - } - bool b = false; - if (ImGui::BeginCombo(label.c_str(), toStrFn(v), ImGuiComboFlags_None)) - { - for (int i = 0; i <= maxVal; ++i) - { - const auto VALUE = values[i]; - const bool IS_SELECTED = v == VALUE; - if (ImGui::Selectable(toStrFn(VALUE), IS_SELECTED)) - { - v = VALUE; - b = true; - } - if (IS_SELECTED) - { - ImGui::SetItemDefaultFocus(); - } - } - ImGui::EndCombo(); - } - return b; + values.emplace_back(static_cast(i)); } -} // namespace PlushieEngine + bool b = false; + if (ImGui::BeginCombo(label.c_str(), toStrFn(v), ImGuiComboFlags_None)) + { + for (int i = 0; i <= maxVal; ++i) + { + const auto VALUE = values[i]; + const bool IS_SELECTED = v == VALUE; + if (ImGui::Selectable(toStrFn(VALUE), IS_SELECTED)) + { + v = VALUE; + b = true; + } + if (IS_SELECTED) + { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + return b; + } +} diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index 0c3e89e6..d613dbfe 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -82,22 +82,18 @@ namespace SHADE void SHScriptEngine::Exit() { - // Do not allow deinitialization if not initialised - if (!dotNet.IsLoaded()) - { - SHLOG_ERROR("[ScriptEngine] Attempted to clean up an unloaded DotNetRuntime."); - return; - } + // Do not allow deinitialization if not initialised + if (!dotNet.IsLoaded()) + { + SHLOG_ERROR("[ScriptEngine] Attempted to clean up an unloaded DotNetRuntime."); + return; + } - // Unlink events - /*ECS::OnEntityCreated -= onEntityCreate; - ECS::OnEntityDestroy -= onEntityDestroy;*/ + // Clean up the CSharp Engine + csEngineExit(); - // Clean up the CSharp Engine - csEngineExit(); - - // Shut down the CLR - dotNet.Exit(); + // Shut down the CLR + dotNet.Exit(); } /*-----------------------------------------------------------------------------------*/ @@ -105,15 +101,15 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ bool SHScriptEngine::AddScript(EntityID entity, const std::string_view& scriptName) { - return csScriptsAdd(entity, scriptName.data()); + return csScriptsAdd(entity, scriptName.data()); } void SHScriptEngine::RemoveAllScripts(EntityID entity) { - csScriptsRemoveAll(entity); + csScriptsRemoveAll(entity); } void SHScriptEngine::RemoveAllScriptsImmediately(EntityID entity, bool callOnDestroy) { - csScriptsRemoveAllImmediately(entity, callOnDestroy); + csScriptsRemoveAllImmediately(entity, callOnDestroy); } /*---------------------------------------------------------------------------------*/ @@ -121,24 +117,24 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ std::string SHScriptEngine::SerialiseScripts(const SHEntity& entity) const { - // Create buffer needed to store serialised script data - constexpr int BUFFER_SIZE = 10240; - std::unique_ptr buffer { new char[BUFFER_SIZE] }; - std::memset(buffer.get(), 0, BUFFER_SIZE); + // Create buffer needed to store serialised script data + constexpr int BUFFER_SIZE = 10240; + std::unique_ptr buffer { new char[BUFFER_SIZE] }; + std::memset(buffer.get(), 0, BUFFER_SIZE); - // Attempt to serialise the script - std::string result; - if (csScriptsSerialise(entity.GetEID(), buffer.get(), BUFFER_SIZE)) - { - result = std::string(buffer.get()); - } - else - { - SHLOG_ERROR("[ScriptEngine] Failed to serialise scripts as string buffer is too small!"); - } + // Attempt to serialise the script + std::string result; + if (csScriptsSerialise(entity.GetEID(), buffer.get(), BUFFER_SIZE)) + { + result = std::string(buffer.get()); + } + else + { + SHLOG_ERROR("[ScriptEngine] Failed to serialise scripts as string buffer is too small!"); + } - // Return an empty string since we failed to serialise - return result; + // Return an empty string since we failed to serialise + return result; } /*-----------------------------------------------------------------------------------*/ @@ -152,9 +148,9 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Script Editor Functions */ /*-----------------------------------------------------------------------------------*/ - void SHScriptEngine::RenderScriptsInInspector(const SHEntity& entity) const + void SHScriptEngine::RenderScriptsInInspector(EntityID entity) const { - csEditorRenderScripts(entity.GetEID()); + csEditorRenderScripts(entity); } /*-----------------------------------------------------------------------------------*/ @@ -267,7 +263,7 @@ namespace SHADE // Attempt to create the file std::ofstream file(path); if (!file.is_open()) - throw std::runtime_error("Unable to create CsProj file!"); + throw std::runtime_error("Unable to create CsProj file!"); // Fill the file file << FILE_CONTENTS; @@ -281,9 +277,9 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHEventHandle SHScriptEngine::onEntityDestroyed(SHEventPtr eventPtr) { - auto eventData = reinterpret_cast*>(eventPtr.get()); - csScriptsRemoveAll(eventData->data->eid); - return eventData->handle; + auto eventData = reinterpret_cast*>(eventPtr.get()); + csScriptsRemoveAll(eventData->data->eid); + return eventData->handle; } /*-----------------------------------------------------------------------------------*/ @@ -397,13 +393,13 @@ namespace SHADE DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", "SerialiseScriptsYaml" - ); + );*/ csEditorRenderScripts = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_NAMESPACE + ".Editor", "RenderScriptsInInspector" - );*/ + ); } void SHScriptEngine::registerEvents() diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h index 329bb3a5..710421e8 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.h +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -170,7 +170,7 @@ namespace SHADE /// rendering code. ///
/// The Entity to render the Scripts of. - void RenderScriptsInInspector(const SHEntity& entity) const; + void RenderScriptsInInspector(EntityID entity) const; /*-----------------------------------------------------------------------------*/ /* Static Utility Functions */ diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index d6b02c8c..db49201b 100644 --- a/SHADE_Managed/src/Editor/Editor.cxx +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -17,15 +17,17 @@ of DigiPen Institute of Technology is prohibited. // Primary Header #include "Editor/Editor.hxx" // External Dependencies -#include "Editor/SHEditorUI::.h" +#include "Editor/SHEditorUI.h" // Project Headers #include "Components/Component.hxx" #include "Scripts/ScriptStore.hxx" #include "Utility/Convert.hxx" #include "Utility/Debug.hxx" #include "Serialisation/ReflectionUtilities.hxx" +#include "Editor/IconsMaterialDesign.h" // Using Directives +using namespace System; using namespace System::Collections::Generic; /*-------------------------------------------------------------------------------------*/ @@ -46,7 +48,7 @@ using namespace System::Collections::Generic; (field->FieldType == MANAGED_TYPE::typeid) \ { \ NATIVE_TYPE val = safe_cast(field->GetValue(object)); \ - if (SHEditorUI::::FUNC(Convert::ToNative(field->Name), val)) \ + if (SHEditorUI::FUNC(Convert::ToNative(field->Name), val)) \ { \ field->SetValue(object, val); \ } \ @@ -67,7 +69,7 @@ using namespace System::Collections::Generic; (field->FieldType == MANAGED_TYPE::typeid) \ { \ NATIVE_TYPE val = Convert::ToNative(safe_cast(field->GetValue(object))); \ - if (SHEditorUI::::FUNC(Convert::ToNative(field->Name), val)) \ + if (SHEditorUI::FUNC(Convert::ToNative(field->Name), val)) \ { \ field->SetValue(object, Convert::ToCLI(val)); \ } \ @@ -99,10 +101,31 @@ namespace SHADE } // Render Add Script - //RenderScriptAddButton(entity); + RenderScriptAddButton(entity); SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.RenderScriptsInInspector") } + void Editor::RenderScriptAddButton(Entity entity) + { + // Get list of Scripts + auto scriptTypes = ScriptStore::GetAvailableScriptList(); + + // Define pop up + if (SHEditorUI::BeginMenu("Add Script", ICON_MD_LIBRARY_ADD)) + { + for each (Type ^ type in scriptTypes) + { + if (SHEditorUI::Selectable(Convert::ToNative(type->Name))) + { + // Add the script + ScriptStore::AddScriptViaName(entity, type->Name); + } + } + + SHEditorUI::EndMenu(); + } + } + /*---------------------------------------------------------------------------------*/ /* Helper Functions */ /*---------------------------------------------------------------------------------*/ @@ -110,30 +133,23 @@ namespace SHADE { // Constants const std::string LABEL = Convert::ToNative(script->GetType()->Name); - const char* CONTEXT_MENU_ID = "scriptContextMenu"; // Header - SHEditorUI::::PushID(index); - if (SHEditorUI::::CollapsingHeader(LABEL)) + SHEditorUI::PushID(index); + if (SHEditorUI::CollapsingHeader(LABEL)) { - SHEditorUI::::PushID(LABEL); - SHEditorUI::::Indent(); + SHEditorUI::PushID(LABEL); + SHEditorUI::Indent(); { - // Define context menu - if (SHEditorUI::::BeginPopup(CONTEXT_MENU_ID)) + // Right Click Menu + if (SHEditorUI::BeginPopupContextItem("scriptContextMenu")) { - if (SHEditorUI::::MenuItem("Remove Script")) + if (SHEditorUI::Selectable("Delete Script", ICON_MD_DELETE)) { // Mark script for removal ScriptStore::RemoveScript(entity, script); } - SHEditorUI::::EndPopup(); - } - - // Context menu button - if (SHEditorUI::::SmallButton("...")) - { - SHEditorUI::::OpenPopup(CONTEXT_MENU_ID); + SHEditorUI::EndPopup(); } // Go through all fields and output them @@ -146,16 +162,16 @@ namespace SHADE continue; // Render the input field for this field - SHEditorUI::::PushID(LABEL + std::to_string(id++)); + SHEditorUI::PushID(LABEL + std::to_string(id++)); renderFieldInInspector(field, script); - SHEditorUI::::PopID(); + SHEditorUI::PopID(); } } - SHEditorUI::::Unindent(); - SHEditorUI::::PopID(); + SHEditorUI::Unindent(); + SHEditorUI::PopID(); } - SHEditorUI::::PopID(); + SHEditorUI::PopID(); } void Editor::renderFieldInInspector(Reflection::FieldInfo^ field, Object^ object) { @@ -180,13 +196,13 @@ namespace SHADE } int val = safe_cast(field->GetValue(object)); - if (SHEditorUI::::InputEnumCombo(Convert::ToNative(field->Name), val, nativeEnumNames)) + if (SHEditorUI::InputEnumCombo(Convert::ToNative(field->Name), val, nativeEnumNames)) { field->SetValue(object, val); } } - else if RENDER_FIELD_CASTED(Vector2, vec2, InputVec2) - else if RENDER_FIELD_CASTED(Vector3, vec3, InputVec3) + else if RENDER_FIELD_CASTED(Vector2, SHVec2, InputVec2) + else if RENDER_FIELD_CASTED(Vector3, SHVec3, InputVec3) else if (field->FieldType == String::typeid) { // Prevent issues where String^ is null due to being empty @@ -198,7 +214,7 @@ namespace SHADE // Actual Field std::string val = Convert::ToNative(stringVal); - if (SHEditorUI::::InputTextField(Convert::ToNative(field->Name), val)) + if (SHEditorUI::InputTextField(Convert::ToNative(field->Name), val)) { field->SetValue(object, Convert::ToCLI(val)); } diff --git a/SHADE_Managed/src/Editor/Editor.hxx b/SHADE_Managed/src/Editor/Editor.hxx index b85e9203..a38cbf79 100644 --- a/SHADE_Managed/src/Editor/Editor.hxx +++ b/SHADE_Managed/src/Editor/Editor.hxx @@ -36,7 +36,13 @@ namespace SHADE /// rendering code. /// /// The Entity to render the Scripts of. - static void RenderScriptsInInspector(Entity entity); + static void RenderScriptsInInspector(Entity entity); + /// + /// Renders a dropdown button that allows for the addition of PlushieScripts + /// onto the specified Entity. + /// + /// The Entity to add PlushieScripts to. + static void RenderScriptAddButton(Entity entity); private: /*-----------------------------------------------------------------------------*/ diff --git a/TempScriptsFolder/TestScript.cs b/TempScriptsFolder/TestScript.cs index 8159a78e..185b543e 100644 --- a/TempScriptsFolder/TestScript.cs +++ b/TempScriptsFolder/TestScript.cs @@ -2,6 +2,9 @@ using SHADE; public class TestScript : Script { + public double Speed = 1.0; + public Vector3 ATestVector; + public bool ABoolean; private Transform Transform; private double time = 0.0; public TestScript(GameObject gameObj) : base(gameObj) {} @@ -21,7 +24,7 @@ public class TestScript : Script } protected override void update() { - time += 0.16; + time += Speed * 0.16; Transform.GlobalPosition = new Vector3(System.Math.Sin(time), System.Math.Cos(time), 0.0f); } protected override void onDestroy() From 3730c2125f5498273325af83387b85bec3106b59 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Wed, 28 Sep 2022 15:28:59 +0800 Subject: [PATCH 07/13] Modified script inspectors to use the vector widgets from SHEditorWidgets. SHEditorWidget is now a static class. --- .../Inspector/SHEditorComponentView.hpp | 6 +- .../Inspector/SHEditorInspector.cpp | 2 +- SHADE_Engine/src/Editor/SHEditorUI.cpp | 94 +++--- SHADE_Engine/src/Editor/SHEditorUI.h | 13 +- SHADE_Engine/src/Editor/SHEditorWidgets.hpp | 289 +++++++++--------- 5 files changed, 186 insertions(+), 218 deletions(-) diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 080cbf2c..d1e4a74e 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -45,7 +45,7 @@ namespace SHADE if (!component) return; auto componentType = rttr::type::get(*component); - CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }); + SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }); ImGui::SameLine(); if (ImGui::CollapsingHeader(componentType.get_name().data())) { @@ -57,11 +57,11 @@ namespace SHADE if (type == rttr::type::get()) { - DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); }); + SHEditorWidgets::DragVec4(property.get_name().data(), { "X", "Y", "Z", "W" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec4 vec) {return property.set_value(component, vec); }); } else if (type == rttr::type::get()) { - DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); }); + SHEditorWidgets::DragVec3(property.get_name().data(), { "X", "Y", "Z" }, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec3 vec) {return property.set_value(component, vec); }); } } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index ed4792de..9d7ffadd 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -47,7 +47,7 @@ namespace SHADE SHEntity* entity = SHEntityManager::GetEntityByID(eid); ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid); - CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); }); + SHEditorWidgets::CheckBox("##IsActive", [entity]()->bool {return entity->GetActive(); }, [entity](bool const& active) {entity->SetActive(active); }); ImGui::SameLine(); ImGui::InputText("##EntityName", &entity->name); diff --git a/SHADE_Engine/src/Editor/SHEditorUI.cpp b/SHADE_Engine/src/Editor/SHEditorUI.cpp index 16e06f09..65b65827 100644 --- a/SHADE_Engine/src/Editor/SHEditorUI.cpp +++ b/SHADE_Engine/src/Editor/SHEditorUI.cpp @@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited. #include "SHEditorUI.h" // External Dependencies #include +#include "SHEditorWidgets.hpp" namespace SHADE { @@ -136,18 +137,24 @@ namespace SHADE bool SHEditorUI::InputCheckbox(const std::string& label, bool& value) { - return ImGui::Checkbox(label.c_str(), &value); + ImGui::Text(label.c_str()); + ImGui::SameLine(); + return ImGui::Checkbox("#", &value); } bool SHEditorUI::InputInt(const std::string& label, int& value) { - return ImGui::InputInt(label.c_str(), &value, + ImGui::Text(label.c_str()); + ImGui::SameLine(); + return ImGui::InputInt("#", &value, 1, 10, ImGuiInputTextFlags_EnterReturnsTrue); } bool SHEditorUI::InputUnsignedInt(const std::string& label, unsigned int& value) { int signedVal = static_cast(value); - const bool CHANGED = InputInt(label, signedVal); + ImGui::Text(label.c_str()); + ImGui::SameLine(); + const bool CHANGED = InputInt("#", signedVal); if (CHANGED) { signedVal = std::clamp(signedVal, 0, std::numeric_limits::max()); @@ -157,19 +164,25 @@ namespace SHADE } bool SHEditorUI::InputFloat(const std::string& label, float& value) { - return ImGui::InputFloat(label.c_str(), &value, + ImGui::Text(label.c_str()); + ImGui::SameLine(); + return ImGui::InputFloat("#", &value, 0.1f, 1.0f, "%.3f", ImGuiInputTextFlags_EnterReturnsTrue); } bool SHEditorUI::InputDouble(const std::string& label, double& value) { - return ImGui::InputDouble(label.c_str(), &value, + ImGui::Text(label.c_str()); + ImGui::SameLine(); + return ImGui::InputDouble("#", &value, 0.1, 1.0, "%.3f", ImGuiInputTextFlags_EnterReturnsTrue); } bool SHEditorUI::InputAngle(const std::string& label, double& value) { - return ImGui::InputDouble(label.c_str(), &value, + ImGui::Text(label.c_str()); + ImGui::SameLine(); + return ImGui::InputDouble("#", &value, 1.0, 45.0, "%.3f", ImGuiInputTextFlags_EnterReturnsTrue); } @@ -177,7 +190,9 @@ namespace SHADE bool SHEditorUI::InputSlider(const std::string& label, double min, double max, double& value) { float val = static_cast(value); - const bool CHANGED = ImGui::SliderFloat(label.c_str(), &val, + ImGui::Text(label.c_str()); + ImGui::SameLine(); + const bool CHANGED = ImGui::SliderFloat("#", &val, static_cast(min), static_cast(max), "%.3f", ImGuiInputTextFlags_EnterReturnsTrue); @@ -186,70 +201,27 @@ namespace SHADE value = val; } - return CHANGED; } bool SHEditorUI::InputVec2(const std::string& label, SHVec2& value) { - float vec[2] = - { - static_cast(value.x), - static_cast(value.y) - }; - const bool CHANGED = ImGui::InputFloat2(label.c_str(), vec, "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); - if (CHANGED) - { - value.x = vec[0]; - value.y = vec[1]; - } - return CHANGED; + static const std::vector COMPONENT_LABELS = { "X", "Y" }; + return SHEditorWidgets::DragN(label, COMPONENT_LABELS, { &value.x, &value.y }); } - bool SHEditorUI::InputVec3(const std::string& label, SHVec3& value) + bool SHEditorUI::InputVec3(const std::string& label, SHVec3& value, float speed) { - float vec[3] = - { - static_cast(value.x), - static_cast(value.y), - static_cast(value.z) - }; - const bool CHANGED = ImGui::InputFloat3(label.c_str(), vec, "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); - if (CHANGED) - { - value.x = vec[0]; - value.y = vec[1]; - value.z = vec[2]; - } - return CHANGED; - } - - bool SHEditorUI::InputSliderVec3(const std::string& label, double min, double max, SHVec3& value) - { - float vec[3] = - { - static_cast(value.x), - static_cast(value.y), - static_cast(value.z) - }; - const bool CHANGED = ImGui::SliderFloat3(label.c_str(), vec, - static_cast(min), static_cast(max), "%.3f", - ImGuiInputTextFlags_EnterReturnsTrue); - if (CHANGED) - { - value.x = vec[0]; - value.y = vec[1]; - value.z = vec[2]; - } - return CHANGED; + static const std::vector COMPONENT_LABELS = { "X", "Y", "Z"}; + return SHEditorWidgets::DragN(label, COMPONENT_LABELS, { &value.x, &value.y, &value.z }, speed, "%.3f"); } bool SHEditorUI::InputTextField(const std::string& label, std::string& value) { std::array buffer = { '\0' }; strcpy_s(buffer.data(), TEXT_FIELD_MAX_LENGTH, value.c_str()); - const bool CHANGED = ImGui::InputText(label.c_str(), &buffer[0], TEXT_FIELD_MAX_LENGTH); + ImGui::Text(label.c_str()); + ImGui::SameLine(); + const bool CHANGED = ImGui::InputText("#", &buffer[0], TEXT_FIELD_MAX_LENGTH); if (CHANGED) { value = std::string(buffer.data(), buffer.data() + TEXT_FIELD_MAX_LENGTH); @@ -259,11 +231,13 @@ namespace SHADE bool SHEditorUI::InputEnumCombo(const std::string& label, int& v, const std::vector& enumNames) { - // Clamp input value const std::string& INITIAL_NAME = v >= static_cast(enumNames.size()) ? "Unknown" : enumNames[v]; bool b = false; - if (ImGui::BeginCombo(label.c_str(), INITIAL_NAME.c_str(), ImGuiComboFlags_None)) + + ImGui::Text(label.c_str()); + ImGui::SameLine(); + if (ImGui::BeginCombo("#", INITIAL_NAME.c_str(), ImGuiComboFlags_None)) { for (int i = 0; i < enumNames.size(); ++i) { diff --git a/SHADE_Engine/src/Editor/SHEditorUI.h b/SHADE_Engine/src/Editor/SHEditorUI.h index 06768b87..13468215 100644 --- a/SHADE_Engine/src/Editor/SHEditorUI.h +++ b/SHADE_Engine/src/Editor/SHEditorUI.h @@ -244,18 +244,7 @@ namespace SHADE /// Label used to identify this widget. /// Reference to the variable to store the result. /// True if the value was changed. - static bool InputVec3(const std::string& label, SHVec3& value); - /// - /// Creates a 3x double slider field widget for Vector3 input. - ///
- /// Wraps up ImGui::InputSliderFloat3(). - ///
- /// Label used to identify this widget. - /// Minimum value of the slider. - /// Maximum value of the slider. - /// Reference to the variable to store the result. - /// True if the value was changed. - static bool InputSliderVec3(const std::string& label, double min, double max, SHVec3& value); + static bool InputVec3(const std::string& label, SHVec3& value, float speed = 0.1f); /// /// Creates a text field widget for string input. ///
diff --git a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp index 4a934e8c..9bdd545c 100644 --- a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp +++ b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp @@ -12,6 +12,7 @@ #include "Math/SHMath.h" #include "Command/SHCommandManager.h" #include "SHImGuiHelpers.hpp" +#include "SH_API.h" //#==============================================================# //|| Library Includes || @@ -26,162 +27,166 @@ namespace SHADE //#==============================================================# //|| Custom Widgets || //#==============================================================# - static bool Splitter(bool verticalSplit, float thickness, float* size1, float* size2, float minSize1, float minSize2, float splitterAxisSize = -1.0f) + class SH_API SHEditorWidgets { - ImGuiWindow* window = ImGui::GetCurrentWindow(); - const ImGuiID id = window->GetID("##Splitter"); - ImRect bb; - bb.Min = window->DC.CursorPos + (verticalSplit ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1)); - bb.Max = bb.Min + (verticalSplit ? ImVec2(thickness, splitterAxisSize) : ImVec2(splitterAxisSize, thickness)); - return ImGui::SplitterBehavior(bb, id, verticalSplit ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, minSize1, minSize2, 0.0f); - } + public: + // Disable constructor for static class + SHEditorWidgets() = delete; - template - static bool DragN(const std::string& fieldLabel, std::vectorconst& componentLabels, - std::vector values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(), - ImGuiSliderFlags flags = 0) - { - const ImGuiWindow* const window = ImGui::GetCurrentWindow(); - if (window->SkipItems) - return false; - - const ImGuiContext& g = *GImGui; - bool valueChanged = false; - ImGui::BeginGroup(); - ImGui::PushID(fieldLabel.c_str()); - PushMultiItemsWidthsAndLabels(componentLabels, 0.0f); - ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize); - ImGui::SetColumnWidth(-1, 80.0f); - ImGui::Text(fieldLabel.c_str()); - ImGui::NextColumn(); - for (std::size_t i = 0; i < N; ++i) + static bool Splitter(bool verticalSplit, float thickness, float* size1, float* size2, float minSize1, float minSize2, float splitterAxisSize = -1.0f) { - ImGui::PushID(static_cast(i)); - ImGui::TextUnformatted(componentLabels[i].c_str(), ImGui::FindRenderedTextEnd(componentLabels[i].c_str())); ImGui::SameLine(); - ImGui::SetNextItemWidth(80.0f); - valueChanged |= ImGui::DragFloat("##v", values[i], speed, valueMin, valueMax, displayFormat, flags); - - const ImVec2 min = ImGui::GetItemRectMin(); - const ImVec2 max = ImGui::GetItemRectMax(); - const float spacing = g.Style.FrameRounding; - const float halfSpacing = spacing / 2; - - window->DrawList->AddLine({ min.x + spacing, max.y - halfSpacing }, { max.x - spacing, max.y - halfSpacing }, - ImGuiColors::colors[i], 4); - - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); + ImGuiWindow* window = ImGui::GetCurrentWindow(); + const ImGuiID id = window->GetID("##Splitter"); + ImRect bb; + bb.Min = window->DC.CursorPos + (verticalSplit ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1)); + bb.Max = bb.Min + (verticalSplit ? ImVec2(thickness, splitterAxisSize) : ImVec2(splitterAxisSize, thickness)); + return ImGui::SplitterBehavior(bb, id, verticalSplit ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, minSize1, minSize2, 0.0f); + } + + template + static bool DragN(const std::string& fieldLabel, std::vectorconst& componentLabels, + std::vector values, float speed = 0.1f, const char* displayFormat = "", T valueMin = T(), T valueMax = T(), + ImGuiSliderFlags flags = 0) + { + const ImGuiWindow* const window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiContext& g = *GImGui; + bool valueChanged = false; + ImGui::BeginGroup(); + ImGui::PushID(fieldLabel.c_str()); + PushMultiItemsWidthsAndLabels(componentLabels, 0.0f); + ImGui::BeginColumns("DragVecCol", 2, ImGuiOldColumnFlags_NoBorder | ImGuiOldColumnFlags_NoResize); + ImGui::SetColumnWidth(-1, 80.0f); + ImGui::Text(fieldLabel.c_str()); + ImGui::NextColumn(); + for (std::size_t i = 0; i < N; ++i) + { + ImGui::PushID(static_cast(i)); + ImGui::TextUnformatted(componentLabels[i].c_str(), ImGui::FindRenderedTextEnd(componentLabels[i].c_str())); ImGui::SameLine(); + ImGui::SetNextItemWidth(80.0f); + valueChanged |= ImGui::DragFloat("##v", values[i], speed, valueMin, valueMax, displayFormat, flags); + + const ImVec2 min = ImGui::GetItemRectMin(); + const ImVec2 max = ImGui::GetItemRectMax(); + const float spacing = g.Style.FrameRounding; + const float halfSpacing = spacing / 2; + + window->DrawList->AddLine({ min.x + spacing, max.y - halfSpacing }, { max.x - spacing, max.y - halfSpacing }, + ImGuiColors::colors[i], 4); + + ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); + ImGui::PopID(); + ImGui::PopItemWidth(); + } + ImGui::EndColumns(); ImGui::PopID(); - ImGui::PopItemWidth(); + ImGui::EndGroup(); + + return valueChanged; } - ImGui::EndColumns(); - ImGui::PopID(); - ImGui::EndGroup(); - - return valueChanged; - } - - static bool DragVec2(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, - std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, - ImGuiSliderFlags flags = 0) - { - SHVec2 values = get(); - bool changed = false; - if (DragN(fieldLabel, componentLabels, {&values.x, &values.y}, speed, displayFormat, valueMin, valueMax, flags)) + + static bool DragVec2(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, + std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, + ImGuiSliderFlags flags = 0) { - changed = true; + SHVec2 values = get(); + bool changed = false; + if (DragN(fieldLabel, componentLabels, {&values.x, &values.y}, speed, displayFormat, valueMin, valueMax, flags)) + { + changed = true; + } + + if (changed) + { + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); + else if(ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + } + + return changed; } - - if (changed) + + static bool DragVec3(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, + std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, + ImGuiSliderFlags flags = 0) { - if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); - else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); - else if(ImGui::IsItemDeactivatedAfterEdit()) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + SHVec3 values = get(); + bool changed = false; + if (DragN(fieldLabel, componentLabels, {&values.x, &values.y, &values.z}, speed, displayFormat, valueMin, valueMax, flags)) + { + changed = true; + } + + if (changed) + { + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); + else if(ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + } + + return changed; } - - return changed; - } - - static bool DragVec3(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, - std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, - ImGuiSliderFlags flags = 0) - { - SHVec3 values = get(); - bool changed = false; - if (DragN(fieldLabel, componentLabels, {&values.x, &values.y, &values.z}, speed, displayFormat, valueMin, valueMax, flags)) + + static bool DragVec4(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, + std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, + ImGuiSliderFlags flags = 0) { - changed = true; + SHVec4 values = get(); + bool changed = false; + if (DragN(fieldLabel, componentLabels, {&values.x, &values.y, &values.z, &values.w}, speed, displayFormat, valueMin, valueMax, flags)) + { + changed = true; + } + + if (changed) + { + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); + else if(ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + } + + return changed; } - - if (changed) + + //#==============================================================# + //|| Widget Extensions || + //#==============================================================# + + static bool CheckBox(std::string const& label, std::function get, std::function set) { - if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); - else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); - else if(ImGui::IsItemDeactivatedAfterEdit()) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); + bool value = get(); + if (ImGui::Checkbox(label.c_str(), &value)) + { + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + return true; + } + return false; } - - return changed; - } - - static bool DragVec4(const std::string& fieldLabel, std::vectorconst& componentLabels, std::function get, - std::function set, float speed = 0.1f, const char* displayFormat = "%.3f", float valueMin = 0.0f, float valueMax = 0.0f, - ImGuiSliderFlags flags = 0) - { - SHVec4 values = get(); - bool changed = false; - if (DragN(fieldLabel, componentLabels, {&values.x, &values.y, &values.z, &values.w}, speed, displayFormat, valueMin, valueMax, flags)) + + template + static bool RadioButton(std::vector const& listLabels, std::vector const& listTypes, std::function get, std::function set) { - changed = true; - } - - if (changed) - { - if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); - else if(ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), true); - else if(ImGui::IsItemDeactivatedAfterEdit()) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), values, set)), false); - } - - return changed; - } - - //#==============================================================# - //|| Widget Extensions || - //#==============================================================# - - static bool CheckBox(std::string const& label, std::function get, std::function set) - { - bool value = get(); - if (ImGui::Checkbox(label.c_str(), &value)) - { - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + T type = get(); + for (size_t i = 0; i < listTypes.size(); i++) + { + if (ImGui::RadioButton(listLabels[i].c_str(), type == listTypes[i])) + { + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), listTypes[i], set)), false); + } + ImGui::SameLine(); + } return true; } - return false; - } - - template - static bool RadioButton(std::vector const& listLabels, std::vector const& listTypes, std::function get, std::function set) - { - T type = get(); - for (size_t i = 0; i < listTypes.size(); i++) - { - if (ImGui::RadioButton(listLabels[i].c_str(), type == listTypes[i])) - { - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), listTypes[i], set)), false); - } - ImGui::SameLine(); - } - return true; - } - - - + }; }//namespace SHADE From 94a7258eb35b7854b464ffc3c27c9a6767ee8e6c Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Wed, 28 Sep 2022 15:33:32 +0800 Subject: [PATCH 08/13] Context menu for the script inspector will now work even when collapsed --- SHADE_Managed/src/Editor/Editor.cxx | 29 ++++++++++++++++++++--------- SHADE_Managed/src/Editor/Editor.hxx | 6 ++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index db49201b..629c9e65 100644 --- a/SHADE_Managed/src/Editor/Editor.cxx +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -142,15 +142,7 @@ namespace SHADE SHEditorUI::Indent(); { // Right Click Menu - if (SHEditorUI::BeginPopupContextItem("scriptContextMenu")) - { - if (SHEditorUI::Selectable("Delete Script", ICON_MD_DELETE)) - { - // Mark script for removal - ScriptStore::RemoveScript(entity, script); - } - SHEditorUI::EndPopup(); - } + renderScriptContextMenu(entity, script); // Go through all fields and output them auto fields = ReflectionUtilities::GetInstanceFields(script); @@ -171,6 +163,10 @@ namespace SHADE SHEditorUI::Unindent(); SHEditorUI::PopID(); } + else + { + renderScriptContextMenu(entity, script); + } SHEditorUI::PopID(); } void Editor::renderFieldInInspector(Reflection::FieldInfo^ field, Object^ object) @@ -220,4 +216,19 @@ namespace SHADE } } } + + void Editor::renderScriptContextMenu(Entity entity, Script^ script) + { + // Right Click Menu + if (SHEditorUI::BeginPopupContextItem("scriptContextMenu")) + { + if (SHEditorUI::Selectable("Delete Script", ICON_MD_DELETE)) + { + // Mark script for removal + ScriptStore::RemoveScript(entity, script); + } + SHEditorUI::EndPopup(); + } + } + } diff --git a/SHADE_Managed/src/Editor/Editor.hxx b/SHADE_Managed/src/Editor/Editor.hxx index a38cbf79..188da660 100644 --- a/SHADE_Managed/src/Editor/Editor.hxx +++ b/SHADE_Managed/src/Editor/Editor.hxx @@ -67,5 +67,11 @@ namespace SHADE /// The object that contains the data of the field to render. /// static void renderFieldInInspector(System::Reflection::FieldInfo^ field, Object^ object); + /// + /// Renders a context menu when right clicked for the scripts + /// + /// The Entity to render the Scripts of. + /// The Script to render the inspector for. + static void renderScriptContextMenu(Entity entity, Script^ script); }; } From 70559204bffb23beacc8a6a60654fd305a251519 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Wed, 28 Sep 2022 23:55:44 +0800 Subject: [PATCH 09/13] Added spinning raccoons and fixed TRansform component bug --- SHADE_Application/src/Scenes/SBTestScene.cpp | 24 +++++++++++--- SHADE_Managed/src/Components/Transform.cxx | 2 +- TempScriptsFolder/RaccoonShowcase.cs | 31 ++++++++++++++++++ TempScriptsFolder/RaccoonSpin.cs | 24 ++++++++++++++ TempScriptsFolder/TestScript.cs | 34 -------------------- 5 files changed, 75 insertions(+), 40 deletions(-) create mode 100644 TempScriptsFolder/RaccoonShowcase.cs create mode 100644 TempScriptsFolder/RaccoonSpin.cs delete mode 100644 TempScriptsFolder/TestScript.cs diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index a6aa0f36..664497df 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -44,7 +44,7 @@ namespace Sandbox { if (mesh.meshName == "Cube.012") { - handles.push_back(graphicsSystem->AddMesh( + handles.push_back(graphicsSystem->AddMesh( mesh.header.vertexCount, mesh.vertexPosition.data(), mesh.texCoords.data(), @@ -107,9 +107,9 @@ namespace Sandbox stressTestObjects.emplace_back(entity); } - auto entity = SHEntityManager::CreateEntity(); - auto& renderable = *SHComponentManager::GetComponent_s(entity); - auto& transform = *SHComponentManager::GetComponent_s(entity); + auto raccoonSpin = SHEntityManager::CreateEntity(); + auto& renderable = *SHComponentManager::GetComponent_s(raccoonSpin); + auto& transform = *SHComponentManager::GetComponent_s(raccoonSpin); renderable.Mesh = handles.front(); renderable.SetMaterial(customMat); @@ -137,7 +137,21 @@ namespace Sandbox //testObjRenderable.SetMaterial(matInst); SHADE::SHScriptEngine* scriptEngine = static_cast(SHADE::SHSystemManager::GetSystem()); - scriptEngine->AddScript(testObj, "TestScript"); + scriptEngine->AddScript(raccoonSpin, "RaccoonSpin"); + + auto raccoonShowcase = SHEntityManager::CreateEntity(); + auto& renderableShowcase = *SHComponentManager::GetComponent_s(raccoonShowcase); + auto& transformShowcase = *SHComponentManager::GetComponent_s(raccoonShowcase); + + renderableShowcase.Mesh = handles.front(); + renderableShowcase.SetMaterial(customMat); + renderableShowcase.GetModifiableMaterial()->SetProperty("data.color", SHVec4(0.0f, 0.0f, 0.0f, 0.0f)); + renderableShowcase.GetModifiableMaterial()->SetProperty("data.alpha", 1.0f); + renderableShowcase.GetModifiableMaterial()->SetProperty("data.textureIndex", 1); + + transformShowcase.SetWorldPosition({ 3.0f, -1.0f, -1.0f }); + transformShowcase.SetLocalScale({ 5.0f, 5.0f, 5.0f }); + scriptEngine->AddScript(raccoonShowcase, "RaccoonShowcase"); } void SBTestScene::Update(float dt) diff --git a/SHADE_Managed/src/Components/Transform.cxx b/SHADE_Managed/src/Components/Transform.cxx index e065015e..0f0716dc 100644 --- a/SHADE_Managed/src/Components/Transform.cxx +++ b/SHADE_Managed/src/Components/Transform.cxx @@ -35,7 +35,7 @@ namespace SHADE } void Transform::LocalRotation::set(Vector3 val) { - GetNativeComponent()->SetLocalPosition(Convert::ToNative(val)); + GetNativeComponent()->SetLocalRotation(Convert::ToNative(val)); } Vector3 Transform::LocalScale::get() { diff --git a/TempScriptsFolder/RaccoonShowcase.cs b/TempScriptsFolder/RaccoonShowcase.cs new file mode 100644 index 00000000..e2d6454d --- /dev/null +++ b/TempScriptsFolder/RaccoonShowcase.cs @@ -0,0 +1,31 @@ +using SHADE; +using System; + +public class RaccoonShowcase : Script +{ + public double RotateSpeed = 1.0; + public Vector3 ScaleSpeed = new Vector3(1.0, 1.0, 0.0); + private Transform Transform; + private double rotation = 0.0; + private Vector3 scale = Vector3.Zero; + private double originalScale = 1.0f; + public RaccoonShowcase(GameObject gameObj) : base(gameObj) {} + + protected override void awake() + { + Transform = GetComponent(); + if (Transform == null) + { + Debug.LogError("Transform is NULL!"); + } + + originalScale = Transform.LocalScale.z; + } + protected override void update() + { + rotation += RotateSpeed * 0.16; + scale += ScaleSpeed * 0.16; + Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); + Transform.LocalScale = new Vector3(System.Math.Abs(System.Math.Sin(scale.x)) * originalScale, System.Math.Abs(System.Math.Cos(scale.y)) * originalScale, System.Math.Abs(System.Math.Sin(scale.z)) * originalScale); + } +} \ No newline at end of file diff --git a/TempScriptsFolder/RaccoonSpin.cs b/TempScriptsFolder/RaccoonSpin.cs new file mode 100644 index 00000000..7785cfd5 --- /dev/null +++ b/TempScriptsFolder/RaccoonSpin.cs @@ -0,0 +1,24 @@ +using SHADE; +using System; + +public class RaccoonSpin : Script +{ + public double RotateSpeed = 1.0; + private double rotation = 0.0; + private Transform Transform; + public RaccoonSpin(GameObject gameObj) : base(gameObj) { } + + protected override void awake() + { + Transform = GetComponent(); + if (Transform == null) + { + Debug.LogError("Transform is NULL!"); + } + } + protected override void update() + { + rotation += RotateSpeed * 0.16; + Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); + } +} \ No newline at end of file diff --git a/TempScriptsFolder/TestScript.cs b/TempScriptsFolder/TestScript.cs deleted file mode 100644 index 185b543e..00000000 --- a/TempScriptsFolder/TestScript.cs +++ /dev/null @@ -1,34 +0,0 @@ -using SHADE; - -public class TestScript : Script -{ - public double Speed = 1.0; - public Vector3 ATestVector; - public bool ABoolean; - private Transform Transform; - private double time = 0.0; - public TestScript(GameObject gameObj) : base(gameObj) {} - - protected override void awake() - { - Debug.Log("TestScript.Awake()"); - Transform = GetComponent(); - if (Transform == null) - { - Debug.LogError("Transform is NULL!"); - } - } - protected override void start() - { - Debug.Log("TestScript.Start()"); - } - protected override void update() - { - time += Speed * 0.16; - Transform.GlobalPosition = new Vector3(System.Math.Sin(time), System.Math.Cos(time), 0.0f); - } - protected override void onDestroy() - { - Debug.Log("TestScript.OnDestroy()"); - } -} \ No newline at end of file From b1a799cf052471c6e125123a5ec9e09ec76372d3 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Thu, 29 Sep 2022 07:59:04 +0800 Subject: [PATCH 10/13] Attempt using dllimport/dllexport --- .../src/Application/SBApplication.cpp | 4 ++++ SHADE_Engine/src/ECS_Base/General/SHFamily.cpp | 15 +++++++++++++++ SHADE_Engine/src/ECS_Base/General/SHFamily.h | 16 +++++++++++----- SHADE_Engine/src/ECS_Base/SHECSMacros.h | 10 ++++++++++ SHADE_Engine/src/Editor/SHEditor.cpp | 5 ++++- 5 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 SHADE_Engine/src/ECS_Base/General/SHFamily.cpp diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 64095e03..0847de65 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -32,6 +32,8 @@ #include "Assets/SHAssetManager.h" +#include "Tools/SHLogger.h" + using namespace SHADE; namespace Sandbox @@ -110,6 +112,8 @@ namespace Sandbox //TODO: Change true to window is open while (!window.WindowShouldClose()) { + auto id = SystemFamily::GetID(); + SHLOG_INFO("Transform system id in application : {} {}", id, SystemFamily::currentID); SHFrameRateController::UpdateFRC(); SHSceneManager::UpdateSceneManager(); SHSceneManager::SceneUpdate(1/60.0f); diff --git a/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp b/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp new file mode 100644 index 00000000..d51a8b35 --- /dev/null +++ b/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp @@ -0,0 +1,15 @@ +#pragma once +#define COMPULING_THE_DLL +#include "SHFamily.h" +#include "SHpch.h" + +namespace SHADE +{ + //initialize currentID as 0 + + + + + + +} diff --git a/SHADE_Engine/src/ECS_Base/General/SHFamily.h b/SHADE_Engine/src/ECS_Base/General/SHFamily.h index 5815703f..7ef01f54 100644 --- a/SHADE_Engine/src/ECS_Base/General/SHFamily.h +++ b/SHADE_Engine/src/ECS_Base/General/SHFamily.h @@ -18,12 +18,12 @@ namespace SHADE { + template class SHFamilyID { private: - //this is used to keep track of the new current ID to be assign to a new Derived class type. - static ComponentTypeID currentID; + /*!************************************************************************* * \brief Construct a new SHFamilyID object @@ -46,6 +46,9 @@ namespace SHADE } public: + //this is used to keep track of the new current ID to be assign to a new Derived class type. + static MY_DLL_EXPORT ComponentTypeID currentID; + /*!************************************************************************* * \brief * Checks if this identifier is cuurrently in use / valid. @@ -59,7 +62,6 @@ namespace SHADE { return(id < currentID); } - /*!************************************************************************* * \brief * Get the ID of a derived class type. @@ -75,9 +77,13 @@ namespace SHADE static ComponentTypeID id = currentID++; return id; } + + + }; - //initialize currentID as 0 + +#ifdef COMPILING_THE_DLL template ComponentTypeID SHFamilyID::currentID = 0; - +#endif } \ No newline at end of file diff --git a/SHADE_Engine/src/ECS_Base/SHECSMacros.h b/SHADE_Engine/src/ECS_Base/SHECSMacros.h index 02615ca4..8de356f8 100644 --- a/SHADE_Engine/src/ECS_Base/SHECSMacros.h +++ b/SHADE_Engine/src/ECS_Base/SHECSMacros.h @@ -26,4 +26,14 @@ const EntityIndex MAX_EID = 51000; #define ENABLE_IF_UINT(_TYPE, _RETURN)\ typename std::enable_if<(std::is_integral<_TYPE>::value && !std::is_signed<_TYPE>::value),_RETURN>::type +#ifdef COMPILING_THE_DLL +#ifndef MY_DLL_EXPORT + #define MY_DLL_EXPORT __declspec(dllexport) +#endif +#else +#ifndef MY_DLL_EXPORT + #define MY_DLL_EXPORT __declspec(dllimport) +#endif +#endif + #endif \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index b36518fd..f1a363e3 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -23,6 +23,8 @@ #include "SHEditor.hpp" #include "SHEditorWidgets.hpp" +#include "Math/Transform/SHTransformSystem.h" + //#==============================================================# //|| Editor Window Includes || //#==============================================================# @@ -104,7 +106,8 @@ namespace SHADE { (void)dt; NewFrame(); - + auto id = SystemFamily::GetID(); + SHLOG_INFO("Transform system id in Editor Update : {} {}", id, SystemFamily::currentID); for (const auto& window : editorWindows | std::views::values) { if(window->isOpen) From 114ae86a9f57940274c36fc8704eeabfe907225f Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Fri, 30 Sep 2022 20:13:18 +0800 Subject: [PATCH 11/13] Fixed SHFamilyID for SHSystem and SHComponent but still have issues with SHScene --- .../src/Application/SBApplication.cpp | 9 +++++-- .../src/ECS_Base/Components/SHComponent.h | 4 ++++ .../src/ECS_Base/General/SHFamily.cpp | 1 - SHADE_Engine/src/ECS_Base/General/SHFamily.h | 24 ++++++++++++------- .../src/ECS_Base/Managers/SHSystemManager.h | 3 +++ SHADE_Engine/src/ECS_Base/SHECSMacros.h | 10 +------- SHADE_Engine/src/ECS_Base/System/SHSystem.h | 5 ++++ SHADE_Engine/src/Editor/SHEditor.cpp | 7 ++++-- SHADE_Engine/src/Scene/SHScene.h | 2 ++ SHADE_Engine/src/Scene/SHSceneManager.h | 7 +++--- 10 files changed, 47 insertions(+), 25 deletions(-) diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 0847de65..3e9b0dce 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -87,6 +87,11 @@ namespace Sandbox SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonBag_Color_Ver4.dds"); SHADE::SHAssetManager::LoadDataTemp("../../Assets/RaccoonPreTexturedVer1_Base9.dds"); SHADE::SHAssetManager::LoadDataTemp("../../Assets/TD_Checker_Base_Color.dds"); + + + auto id = SHFamilyID::GetID(); + auto id2 = SHFamilyID::GetID(); + auto id3 = SHFamilyID::GetID(); //TODO: REMOVE AFTER PRESENTATION //SHADE::SHSystemManager::RegisterRoutine(); @@ -102,7 +107,9 @@ namespace Sandbox #else #endif + SHSceneManager::InitSceneManager("TestScene"); + SHFrameRateController::UpdateFRC(); } @@ -112,8 +119,6 @@ namespace Sandbox //TODO: Change true to window is open while (!window.WindowShouldClose()) { - auto id = SystemFamily::GetID(); - SHLOG_INFO("Transform system id in application : {} {}", id, SystemFamily::currentID); SHFrameRateController::UpdateFRC(); SHSceneManager::UpdateSceneManager(); SHSceneManager::SceneUpdate(1/60.0f); diff --git a/SHADE_Engine/src/ECS_Base/Components/SHComponent.h b/SHADE_Engine/src/ECS_Base/Components/SHComponent.h index aba3ba51..cfcd724c 100644 --- a/SHADE_Engine/src/ECS_Base/Components/SHComponent.h +++ b/SHADE_Engine/src/ECS_Base/Components/SHComponent.h @@ -14,6 +14,7 @@ #include "SHpch.h" #include "../SHECSMacros.h" #include "SH_API.h" +#include "ECS_Base/General/SHFamily.h" namespace SHADE { @@ -117,4 +118,7 @@ namespace SHADE }; + + + template class SH_API SHFamilyID; } diff --git a/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp b/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp index d51a8b35..bd5c0378 100644 --- a/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp +++ b/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp @@ -1,5 +1,4 @@ #pragma once -#define COMPULING_THE_DLL #include "SHFamily.h" #include "SHpch.h" diff --git a/SHADE_Engine/src/ECS_Base/General/SHFamily.h b/SHADE_Engine/src/ECS_Base/General/SHFamily.h index 7ef01f54..51bd6a25 100644 --- a/SHADE_Engine/src/ECS_Base/General/SHFamily.h +++ b/SHADE_Engine/src/ECS_Base/General/SHFamily.h @@ -14,13 +14,14 @@ #pragma once #include "../SHECSMacros.h" +#include "SH_API.h" namespace SHADE { template - class SHFamilyID + class SH_API SHFamilyID { private: @@ -47,7 +48,7 @@ namespace SHADE public: //this is used to keep track of the new current ID to be assign to a new Derived class type. - static MY_DLL_EXPORT ComponentTypeID currentID; + static inline ComponentTypeID currentID = 0; /*!************************************************************************* * \brief @@ -70,20 +71,27 @@ namespace SHADE * @tparam DerivedClass * The derived class type that we are trying to get the ID of. ***************************************************************************/ +#ifdef SH_API_EXPORT template - static ENABLE_IF_DERIVED(ComponentTypeID, BaseClass, DerivedClass) GetID() noexcept + static SH_API ENABLE_IF_DERIVED(ComponentTypeID, BaseClass, DerivedClass) GetID() noexcept { //The first time a new derived class type call this get id, it will initialize id using the currentID from familyID class. - static ComponentTypeID id = currentID++; + static ComponentTypeID id = SHFamilyID::currentID++; return id; + //return 0; } +#else + template + static SH_API ENABLE_IF_DERIVED(ComponentTypeID, BaseClass, DerivedClass) GetID() noexcept; +#endif // SH_API_EXPORT + + }; -#ifdef COMPILING_THE_DLL - template - ComponentTypeID SHFamilyID::currentID = 0; -#endif + + + } \ No newline at end of file diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHSystemManager.h b/SHADE_Engine/src/ECS_Base/Managers/SHSystemManager.h index f92f6635..995a1cf5 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHSystemManager.h +++ b/SHADE_Engine/src/ECS_Base/Managers/SHSystemManager.h @@ -68,6 +68,9 @@ namespace SHADE id = ((SystemID)version << sizeof(SystemVersionID) * CHAR_BIT) + typeID; } systemContainer.emplace(id, std::make_unique()); + + auto size = systemContainer.size(); + systemContainer[id].get()->systemID = id; return id; diff --git a/SHADE_Engine/src/ECS_Base/SHECSMacros.h b/SHADE_Engine/src/ECS_Base/SHECSMacros.h index 8de356f8..4690099f 100644 --- a/SHADE_Engine/src/ECS_Base/SHECSMacros.h +++ b/SHADE_Engine/src/ECS_Base/SHECSMacros.h @@ -26,14 +26,6 @@ const EntityIndex MAX_EID = 51000; #define ENABLE_IF_UINT(_TYPE, _RETURN)\ typename std::enable_if<(std::is_integral<_TYPE>::value && !std::is_signed<_TYPE>::value),_RETURN>::type -#ifdef COMPILING_THE_DLL -#ifndef MY_DLL_EXPORT - #define MY_DLL_EXPORT __declspec(dllexport) -#endif -#else -#ifndef MY_DLL_EXPORT - #define MY_DLL_EXPORT __declspec(dllimport) -#endif -#endif + #endif \ No newline at end of file diff --git a/SHADE_Engine/src/ECS_Base/System/SHSystem.h b/SHADE_Engine/src/ECS_Base/System/SHSystem.h index 93ea6a59..fe852b9a 100644 --- a/SHADE_Engine/src/ECS_Base/System/SHSystem.h +++ b/SHADE_Engine/src/ECS_Base/System/SHSystem.h @@ -12,6 +12,7 @@ #include "../SHECSMacros.h" #include "SH_API.h" +#include "ECS_Base/General/SHFamily.h" namespace SHADE { @@ -69,5 +70,9 @@ namespace SHADE }; + template class SH_API SHFamilyID; + + + } \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index f1a363e3..e94f7398 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -89,6 +89,11 @@ namespace SHADE io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking InitFonts(); + + + auto id = SHFamilyID::GetID(); + auto id2 = SHFamilyID::GetID(); + auto id3 = SHFamilyID::GetID(); InitBackend(sdlWindow); SetStyle(Style::SHADE); @@ -106,8 +111,6 @@ namespace SHADE { (void)dt; NewFrame(); - auto id = SystemFamily::GetID(); - SHLOG_INFO("Transform system id in Editor Update : {} {}", id, SystemFamily::currentID); for (const auto& window : editorWindows | std::views::values) { if(window->isOpen) diff --git a/SHADE_Engine/src/Scene/SHScene.h b/SHADE_Engine/src/Scene/SHScene.h index 372981a6..a81c70ef 100644 --- a/SHADE_Engine/src/Scene/SHScene.h +++ b/SHADE_Engine/src/Scene/SHScene.h @@ -13,6 +13,7 @@ #include #include "SHSceneGraph.h" +#include "ECS_Base/General/SHFamily.h" namespace SHADE { @@ -42,6 +43,7 @@ namespace SHADE virtual void Unload() = 0; }; + template class SH_API SHFamilyID; } diff --git a/SHADE_Engine/src/Scene/SHSceneManager.h b/SHADE_Engine/src/Scene/SHSceneManager.h index 83ebab0f..2e4b1717 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.h +++ b/SHADE_Engine/src/Scene/SHSceneManager.h @@ -84,7 +84,8 @@ namespace SHADE { //prevSceneCreate = newScene; newScene = [sceneName]() { currentScene = new T(); currentScene->sceneName = sceneName; }; - nextSceneID = SHFamilyID::template GetID(); + //nextSceneID = SHFamilyID::GetID(); + nextSceneID = 0; sceneChanged = true; } @@ -101,13 +102,13 @@ namespace SHADE static std::enable_if_t, void> ChangeScene(std::string const& sceneName) noexcept { //check if this new Scene is current Scene (Use RestartScene instead) - if (currentSceneID == SHFamilyID::template GetID()) + if (currentSceneID == SHFamilyID::GetID()) { return; } //prevSceneCreate = newScene; newScene = [sceneName]() { currentScene = new T(); currentScene->sceneName; }; - nextSceneID = SHFamilyID::template GetID(); + nextSceneID = SHFamilyID::GetID(); sceneChanged = true; } From 2d07fb0afcae86ac9a3bcfc1653aae07919951e6 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Fri, 30 Sep 2022 20:25:26 +0800 Subject: [PATCH 12/13] Added component added and removed events --- .../ECS_Base/Events/SHComponentAddedEvent.h | 12 +++++++++ .../ECS_Base/Events/SHComponentRemovedEvent.h | 12 +++++++++ .../ECS_Base/Managers/SHComponentManager.h | 25 +++++++++++++++---- SHADE_Engine/src/Events/SHEventDefines.h | 2 ++ 4 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 SHADE_Engine/src/ECS_Base/Events/SHComponentAddedEvent.h create mode 100644 SHADE_Engine/src/ECS_Base/Events/SHComponentRemovedEvent.h diff --git a/SHADE_Engine/src/ECS_Base/Events/SHComponentAddedEvent.h b/SHADE_Engine/src/ECS_Base/Events/SHComponentAddedEvent.h new file mode 100644 index 00000000..1f2b62d5 --- /dev/null +++ b/SHADE_Engine/src/ECS_Base/Events/SHComponentAddedEvent.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ECS_Base/Components/SHComponent.h" + +namespace SHADE +{ + struct SHComponentAddedEvent + { + EntityID eid; + ComponentTypeID addedComponentType; + }; +} diff --git a/SHADE_Engine/src/ECS_Base/Events/SHComponentRemovedEvent.h b/SHADE_Engine/src/ECS_Base/Events/SHComponentRemovedEvent.h new file mode 100644 index 00000000..34d6f9c8 --- /dev/null +++ b/SHADE_Engine/src/ECS_Base/Events/SHComponentRemovedEvent.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ECS_Base/Components/SHComponent.h" + +namespace SHADE +{ + struct SHComponentRemovedEvent + { + EntityID eid; + ComponentTypeID removedComponentType; + }; +} diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h b/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h index 60625d6a..12b5b001 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h +++ b/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h @@ -17,6 +17,8 @@ #include "../General/SHSparseSetContainer.h" #include "../Components/SHComponent.h" #include "../Components/SHComponentGroup.h" +#include "../Events/SHComponentAddedEvent.h" +#include "../Events/SHComponentRemovedEvent.h" //#include "Scene/SHSceneNode.h" #include "SH_API.h" @@ -216,6 +218,11 @@ namespace SHADE comp->OnCreate(); } + SHComponentAddedEvent eventData; + eventData.eid = entityID; + eventData.addedComponentType = ComponentFamily::GetID(); + + SHEventManager::BroadcastEvent(eventData, SH_COMPONENT_ADDED_EVENT); } /************************************************************************** @@ -247,6 +254,13 @@ namespace SHADE { comp->OnCreate(); } + + SHComponentAddedEvent eventData; + eventData.eid = entityID; + eventData.addedComponentType = componentTypeID; + + SHEventManager::BroadcastEvent(eventData, SH_COMPONENT_ADDED_EVENT); + } @@ -313,6 +327,12 @@ namespace SHADE componentSet.GetSparseSet()->Remove(EntityHandleGenerator::GetIndex(entityID)); + + SHComponentRemovedEvent eventData; + eventData.eid = entityID; + eventData.addedComponentType = ComponentFamily::GetID(); + + SHEventManager::BroadcastEvent(eventData, SH_COMPONENT_REMOVED_EVENT); } /*!************************************************************************* @@ -464,11 +484,6 @@ namespace SHADE return componentGroups[index]; } - static void AddScriptComponent(EntityID eid, std::string const& scriptClassName) noexcept; - - static void RemoveScriptComponent(EntityID eid, std::string const& scriptClassName) noexcept; - - };// end SHComponentManager diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index f1e92b42..317b67c1 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -8,3 +8,5 @@ typedef uint32_t SHEventHandle; constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0}; constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT{ 1 }; constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT{ 2 }; +constexpr SHEventIdentifier SH_COMPONENT_ADDED_EVENT{ 3 }; +constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT{ 4 }; From e4be5e098766eb9a42aed8f1eaee327b14dc27ca Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Fri, 30 Sep 2022 20:34:46 +0800 Subject: [PATCH 13/13] Added event manager include --- SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h b/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h index 12b5b001..8921fbce 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h +++ b/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h @@ -21,6 +21,7 @@ #include "../Events/SHComponentRemovedEvent.h" //#include "Scene/SHSceneNode.h" #include "SH_API.h" +#include "Events/SHEventManager.hpp" #include @@ -330,7 +331,7 @@ namespace SHADE SHComponentRemovedEvent eventData; eventData.eid = entityID; - eventData.addedComponentType = ComponentFamily::GetID(); + eventData.removedComponentType = ComponentFamily::GetID(); SHEventManager::BroadcastEvent(eventData, SH_COMPONENT_REMOVED_EVENT); }