diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 60deb78d..57e14d71 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -42,6 +42,8 @@ #include "Assets/SHAssetManager.h" +#include "Tools/SHLogger.h" + using namespace SHADE; namespace Sandbox @@ -97,6 +99,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(); @@ -112,7 +119,9 @@ namespace Sandbox #else #endif + SHSceneManager::InitSceneManager("TestScene"); + SHFrameRateController::UpdateFRC(); } diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 74ac4c1d..664497df 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -36,7 +36,6 @@ 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(); @@ -45,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(), @@ -108,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); @@ -138,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_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/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/General/SHFamily.cpp b/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp new file mode 100644 index 00000000..bd5c0378 --- /dev/null +++ b/SHADE_Engine/src/ECS_Base/General/SHFamily.cpp @@ -0,0 +1,14 @@ +#pragma once +#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..51bd6a25 100644 --- a/SHADE_Engine/src/ECS_Base/General/SHFamily.h +++ b/SHADE_Engine/src/ECS_Base/General/SHFamily.h @@ -14,16 +14,17 @@ #pragma once #include "../SHECSMacros.h" +#include "SH_API.h" namespace SHADE { + template - class SHFamilyID + class SH_API 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 +47,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 inline ComponentTypeID currentID = 0; + /*!************************************************************************* * \brief * Checks if this identifier is cuurrently in use / valid. @@ -59,7 +63,6 @@ namespace SHADE { return(id < currentID); } - /*!************************************************************************* * \brief * Get the ID of a derived class type. @@ -68,16 +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 + + + + + }; - //initialize currentID as 0 - template - ComponentTypeID SHFamilyID::currentID = 0; + + + } \ No newline at end of file diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h b/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h index 60625d6a..8921fbce 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h +++ b/SHADE_Engine/src/ECS_Base/Managers/SHComponentManager.h @@ -17,8 +17,11 @@ #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" +#include "Events/SHEventManager.hpp" #include @@ -216,6 +219,11 @@ namespace SHADE comp->OnCreate(); } + SHComponentAddedEvent eventData; + eventData.eid = entityID; + eventData.addedComponentType = ComponentFamily::GetID(); + + SHEventManager::BroadcastEvent(eventData, SH_COMPONENT_ADDED_EVENT); } /************************************************************************** @@ -247,6 +255,13 @@ namespace SHADE { comp->OnCreate(); } + + SHComponentAddedEvent eventData; + eventData.eid = entityID; + eventData.addedComponentType = componentTypeID; + + SHEventManager::BroadcastEvent(eventData, SH_COMPONENT_ADDED_EVENT); + } @@ -313,6 +328,12 @@ namespace SHADE componentSet.GetSparseSet()->Remove(EntityHandleGenerator::GetIndex(entityID)); + + SHComponentRemovedEvent eventData; + eventData.eid = entityID; + eventData.removedComponentType = ComponentFamily::GetID(); + + SHEventManager::BroadcastEvent(eventData, SH_COMPONENT_REMOVED_EVENT); } /*!************************************************************************* @@ -464,11 +485,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/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 02615ca4..4690099f 100644 --- a/SHADE_Engine/src/ECS_Base/SHECSMacros.h +++ b/SHADE_Engine/src/ECS_Base/SHECSMacros.h @@ -26,4 +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 + + #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/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 2d326d09..a546504b 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -46,7 +46,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())) { @@ -63,7 +63,7 @@ namespace SHADE std::vector list; for(auto const& name : names) list.push_back(name.data()); - ComboBox(property.get_name().data(), list, [component, property]{return property.get_value(component).to_int();}, [component, property](int const& idx) + SHEditorWidgets::ComboBox(property.get_name().data(), list, [component, property]{return property.get_value(component).to_int();}, [component, property](int const& idx) { auto enumAlign = property.get_enumeration(); auto values = enumAlign.get_values(); @@ -75,7 +75,7 @@ namespace SHADE { if (type == rttr::type::get()) { - CheckBox(property.get_name().data(), [component, property]{return property.get_value(component).to_bool();}, [component, property](bool const& result){property.set_value(component, result);}); + SHEditorWidgets::CheckBox(property.get_name().data(), [component, property]{return property.get_value(component).to_bool();}, [component, property](bool const& result){property.set_value(component, result);}); } //else if (type == rttr::type::get()) //{ @@ -87,11 +87,11 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if(metaMin && metaMax) { - SliderInt(property.get_name().data(), metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_int();}, [component, property](int const& result){property.set_value(component, result);}); + SHEditorWidgets::SliderInt(property.get_name().data(), metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_int();}, [component, property](int const& result){property.set_value(component, result);}); } else { - DragInt(property.get_name().data(), [component, property]{return property.get_value(component).to_int();}, [component, property](int const& result){property.set_value(component, result);}); + SHEditorWidgets::DragInt(property.get_name().data(), [component, property]{return property.get_value(component).to_int();}, [component, property](int const& result){property.set_value(component, result);}); } } else if (type == rttr::type::get()) @@ -100,11 +100,11 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if(metaMin.is_valid() && metaMax.is_valid()) { - SliderScalar(property.get_name().data(), ImGuiDataType_U8, metaMin.template get_value(), metaMax.template get_value(), [component, property]{return property.get_value(component).to_uint8();}, [component, property](uint8_t const& result){property.set_value(component, result);},"%zu"); + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U8, metaMin.template get_value(), metaMax.template get_value(), [component, property]{return property.get_value(component).to_uint8();}, [component, property](uint8_t const& result){property.set_value(component, result);},"%zu"); } else { - DragScalar(property.get_name().data(), ImGuiDataType_U8, [component, property]{return property.get_value(component).to_uint8();}, [component, property](uint8_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu"); + SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U8, [component, property]{return property.get_value(component).to_uint8();}, [component, property](uint8_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu"); } } else if (type == rttr::type::get()) @@ -113,11 +113,11 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if(metaMin.is_valid() && metaMax.is_valid()) { - SliderScalar(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_uint16();}, [component, property](uint16_t const& result){property.set_value(component, result);},"%zu"); + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U16, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_uint16();}, [component, property](uint16_t const& result){property.set_value(component, result);},"%zu"); } else { - DragScalar(property.get_name().data(), ImGuiDataType_U16, [component, property]{return property.get_value(component).to_uint16();}, [component, property](uint16_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu"); + SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U16, [component, property]{return property.get_value(component).to_uint16();}, [component, property](uint16_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu"); } } else if (type == rttr::type::get()) @@ -126,11 +126,11 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if (metaMin.is_valid() && metaMax.is_valid()) { - SliderScalar(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value(), metaMin.template get_value(), [component, property]{ return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result){property.set_value(component, result); },"%zu"); + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U32, metaMin.template get_value(), metaMin.template get_value(), [component, property]{ return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result){property.set_value(component, result); },"%zu"); } else { - DragScalar(property.get_name().data(), ImGuiDataType_U32, [component, property]{ return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result){property.set_value(component, result); },0.1f,0,0,"%zu"); + SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U32, [component, property]{ return property.get_value(component).to_uint32(); }, [component, property](uint32_t const& result){property.set_value(component, result); },0.1f,0,0,"%zu"); } } else if (type == rttr::type::get()) @@ -139,11 +139,11 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if(metaMin.is_valid() && metaMax.is_valid()) { - SliderScalar(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_uint64();}, [component, property](uint64_t const& result){property.set_value(component, result);},"%zu"); + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_U64, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_uint64();}, [component, property](uint64_t const& result){property.set_value(component, result);},"%zu"); } else { - DragScalar(property.get_name().data(), ImGuiDataType_U64, [component, property]{return property.get_value(component).to_uint64();}, [component, property](uint64_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu"); + SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_U64, [component, property]{return property.get_value(component).to_uint64();}, [component, property](uint64_t const& result){property.set_value(component, result);},0.1f,0,0,"%zu"); } } else if (type == rttr::type::get()) @@ -152,11 +152,11 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if(metaMin.is_valid() && metaMax.is_valid()) { - SliderFloat(property.get_name().data(), metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_float();}, [component, property](float const& result){property.set_value(component, result);}); + SHEditorWidgets::SliderFloat(property.get_name().data(), metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_float();}, [component, property](float const& result){property.set_value(component, result);}); } else { - DragFloat(property.get_name().data(), [component, property]{return property.get_value(component).to_float();}, [component, property](float const& result){property.set_value(component, result);}); + SHEditorWidgets::DragFloat(property.get_name().data(), [component, property]{return property.get_value(component).to_float();}, [component, property](float const& result){property.set_value(component, result);}); } } else if (type == rttr::type::get()) @@ -165,25 +165,25 @@ namespace SHADE auto metaMax = property.get_metadata(META::max); if(metaMin.is_valid() && metaMax.is_valid()) { - SliderScalar(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_double();}, [component, property](double const& result){property.set_value(component, result);}); + SHEditorWidgets::SliderScalar(property.get_name().data(), ImGuiDataType_Double, metaMin.template get_value(), metaMin.template get_value(), [component, property]{return property.get_value(component).to_double();}, [component, property](double const& result){property.set_value(component, result);}); } else { - DragScalar(property.get_name().data(), ImGuiDataType_Double, [component, property]{return property.get_value(component).to_double();}, [component, property](double const& result){property.set_value(component, result);}, 0.1f); + SHEditorWidgets::DragScalar(property.get_name().data(), ImGuiDataType_Double, [component, property]{return property.get_value(component).to_double();}, [component, property](double const& result){property.set_value(component, result);}, 0.1f); } } } else 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); }); } else if (type == rttr::type::get()) { - DragVec2(property.get_name().data(), { "X", "Y"}, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec2 vec) {return property.set_value(component, vec); }); + SHEditorWidgets::DragVec2(property.get_name().data(), { "X", "Y"}, [component, property]() {return property.get_value(component).template convert(); }, [component, property](SHVec2 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 7ba0c609..25d3d955 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -13,6 +13,8 @@ #include "SHEditorComponentView.hpp" #include "ECS_Base/UnitTesting/SHTestComponents.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Scripting/SHScriptEngine.h" +#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "AudioSystem/SHAudioSystem.h" @@ -49,7 +51,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); @@ -74,6 +76,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/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/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index b36518fd..e94f7398 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 || //#==============================================================# @@ -87,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); @@ -104,7 +111,6 @@ namespace SHADE { (void)dt; NewFrame(); - for (const auto& window : editorWindows | std::views::values) { if(window->isOpen) diff --git a/SHADE_Engine/src/Editor/SHEditorUI.cpp b/SHADE_Engine/src/Editor/SHEditorUI.cpp new file mode 100644 index 00000000..65b65827 --- /dev/null +++ b/SHADE_Engine/src/Editor/SHEditorUI.cpp @@ -0,0 +1,259 @@ +/************************************************************************************//*! +\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 "SHpch.h" +// Primary Header +#include "SHEditorUI.h" +// External Dependencies +#include +#include "SHEditorWidgets.hpp" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* 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) + { + ImGui::Text(label.c_str()); + ImGui::SameLine(); + return ImGui::Checkbox("#", &value); + } + bool SHEditorUI::InputInt(const std::string& label, int& 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); + ImGui::Text(label.c_str()); + ImGui::SameLine(); + const bool CHANGED = InputInt("#", signedVal); + if (CHANGED) + { + signedVal = std::clamp(signedVal, 0, std::numeric_limits::max()); + value = static_cast(signedVal); + } + return CHANGED; + } + bool SHEditorUI::InputFloat(const std::string& label, float& 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) + { + 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) + { + ImGui::Text(label.c_str()); + ImGui::SameLine(); + return ImGui::InputDouble("#", &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); + ImGui::Text(label.c_str()); + ImGui::SameLine(); + const bool CHANGED = ImGui::SliderFloat("#", &val, + static_cast(min), static_cast(max), "%.3f", + ImGuiInputTextFlags_EnterReturnsTrue); + + if (CHANGED) + { + value = val; + } + + return CHANGED; + } + + bool SHEditorUI::InputVec2(const std::string& label, SHVec2& value) + { + 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, float speed) + { + 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()); + 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); + } + return CHANGED; + } + + 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; + + ImGui::Text(label.c_str()); + ImGui::SameLine(); + if (ImGui::BeginCombo("#", 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; + } +} diff --git a/SHADE_Engine/src/Editor/SHEditorUI.h b/SHADE_Engine/src/Editor/SHEditorUI.h new file mode 100644 index 00000000..13468215 --- /dev/null +++ b/SHADE_Engine/src/Editor/SHEditorUI.h @@ -0,0 +1,286 @@ +/************************************************************************************//*! +\file SHEditorUI.h +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\par email: t.yanchongclarence\@digipen.edu +\date Sep 27, 2022 +\brief Defines a class that contains wrapper functions for ImGui. + +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 +// Standard Library +#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" + +namespace SHADE +{ + /// + /// Static class that contains useful functions for Editor UI using ImGui. + /// + class SH_API SHEditorUI 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 - 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 - Menu */ + /*-----------------------------------------------------------------------------*/ + static bool BeginMenu(const std::string& label); + static bool BeginMenu(const std::string& label, const char* icon); + static void EndMenu(); + + /*-----------------------------------------------------------------------------*/ + /* 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, float speed = 0.1f); + /// + /// 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 + SHEditorUI() = delete; + }; +} + +#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 new file mode 100644 index 00000000..f3af0412 --- /dev/null +++ b/SHADE_Engine/src/Editor/SHEditorUI.hpp @@ -0,0 +1,51 @@ +/************************************************************************************//*! +\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) 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 "SHEditorUI.h" +// External Dependencies +#include + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* 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) + { + 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; + } +} diff --git a/SHADE_Engine/src/Editor/SHEditorWidgets.hpp b/SHADE_Engine/src/Editor/SHEditorWidgets.hpp index 6dcf5dfd..88cea814 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 || @@ -23,308 +24,315 @@ 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: + //#==============================================================# + //|| Constructor || + //#==============================================================# + 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) + //#==============================================================# + //|| Custom Widgets || + //#==============================================================# + 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); - ImGui::PopID(); - ImGui::PopItemWidth(); + 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); } - 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)) + + 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) { - 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; - } - - 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)) - { - 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; - } - - 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)) - { - 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); - 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])) + 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) { - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), listTypes[i], set)), false); + 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::SameLine(); + ImGui::EndColumns(); + ImGui::PopID(); + ImGui::EndGroup(); + + return valueChanged; } - return true; - } - - static bool InputText(const std::string& label, const std::function get, - const std::function set, ImGuiInputTextFlags flag = 0, - ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0) - { - std::string text = get(); - if (ImGui::InputText(label.c_str(), &text, flag, callback, userData)) + + 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) { - if (ImGui::IsItemDeactivatedAfterEdit()) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), text, set)), false); - - return true; - } - return false; - } - - template - static bool DragScalar(const std::string& fieldLabel, ImGuiDataType data_type, std::function get, std::function set, - float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) - { - T value = get(); - std::cout << value <<" \n"; - //bool hasChange = ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags); - - if (ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags)) - { - if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); - else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); - else if (ImGui::IsItemDeactivatedAfterEdit()) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); - - return true; - } - return false; - } - - static bool DragFloat(const std::string& fieldLabel, std::function get, std::function set, - float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) - { - float value = get(); - //bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags); - if (ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags)) - { - if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); - else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); - else if (ImGui::IsItemDeactivatedAfterEdit()) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); - - return true; - } - - return false; - } - - static bool DragInt(const std::string& fieldLabel, std::function get, std::function set, - float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0) - { - int value = get(); - //bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags); - if (ImGui::DragInt(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags)) - { - if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); - else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); - else if (ImGui::IsItemDeactivatedAfterEdit()) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); - - return true; - } - - return false; - } - template - static bool SliderScalar(const std::string& fieldLabel, ImGuiDataType data_type, T min, T max, std::function get, std::function set, - const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) - { - T value = get(); - if (ImGui::SliderScalar(fieldLabel.c_str(), data_type, &value, &min, &max, displayFormat, flags)) - { - if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + 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(), value, set)), true); - + 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; + } + + 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)) + { + 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; + } + + 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)) + { + 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); return true; } - return false; } - - static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function get, std::function set, - const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) - { - float value = get(); - if (ImGui::SliderFloat(fieldLabel.c_str(), &value, min, max, displayFormat, flags)) - { - if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); - else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); - - - return true; - } - - return false; - } - - static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function get, std::function set, - const char* displayFormat = "%d", ImGuiSliderFlags flags = 0) - { - int value = get(); - if (ImGui::SliderInt(fieldLabel.c_str(), &value, min, max, displayFormat, flags)) - { - if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); - else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); - - return true; - } - - return false; - } - - static bool ComboBox(const std::string& fieldLabel, std::vector list, std::function get, std::function set) - { - bool edited = false; - int selected = get(); - ImGui::PushID(fieldLabel.c_str()); - ImGui::Text(fieldLabel.c_str()); ImGui::SameLine(); - if (edited = ImGui::Combo("##Combo", &selected, list.data(), list.size())) + template + static bool RadioButton(std::vector const& listLabels, std::vector const& listTypes, std::function get, std::function set) { - SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), selected, 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; } - ImGui::PopID(); - return edited; - } - - + + static bool InputText(const std::string& label, const std::function get, + const std::function set, ImGuiInputTextFlags flag = 0, + ImGuiInputTextCallback callback = (ImGuiInputTextCallback)0, void* userData = (void*)0) + { + std::string text = get(); + if (ImGui::InputText(label.c_str(), &text, flag, callback, userData)) + { + if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), text, set)), false); + + return true; + } + return false; + } + + template + static bool DragScalar(const std::string& fieldLabel, ImGuiDataType data_type, std::function get, std::function set, + float speed = 1.0f, T p_min = T(), T p_max = T(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) + { + T value = get(); + std::cout << value <<" \n"; + //bool hasChange = ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags); + + if (ImGui::DragScalar(fieldLabel.c_str(), data_type, &value, speed, &p_min, &p_max, displayFormat, flags)) + { + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + + return true; + } + return false; + } + + static bool DragFloat(const std::string& fieldLabel, std::function get, std::function set, + float speed = 0.1f, float p_min = float(), float p_max = float(), const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) + { + float value = get(); + //bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags); + if (ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags)) + { + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + + return true; + } + + return false; + } + + static bool DragInt(const std::string& fieldLabel, std::function get, std::function set, + float speed = 1.0f, int p_min = int(), int p_max = int(), const char* displayFormat = "%d", ImGuiSliderFlags flags = 0) + { + int value = get(); + //bool hasChange = ImGui::DragFloat(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags); + if (ImGui::DragInt(fieldLabel.c_str(), &value, speed, p_min, p_max, displayFormat, flags)) + { + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + else if (ImGui::IsItemDeactivatedAfterEdit()) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + + return true; + } + + return false; + } + template + static bool SliderScalar(const std::string& fieldLabel, ImGuiDataType data_type, T min, T max, std::function get, std::function set, + const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) + { + T value = get(); + if (ImGui::SliderScalar(fieldLabel.c_str(), data_type, &value, &min, &max, displayFormat, flags)) + { + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + + return true; + } + + return false; + } + + static bool SliderFloat(const std::string& fieldLabel, float min, float max, std::function get, std::function set, + const char* displayFormat = "%.3f", ImGuiSliderFlags flags = 0) + { + float value = get(); + if (ImGui::SliderFloat(fieldLabel.c_str(), &value, min, max, displayFormat, flags)) + { + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + + + return true; + } + + return false; + } + + static bool SliderInt(const std::string& fieldLabel, int min, int max, std::function get, std::function set, + const char* displayFormat = "%d", ImGuiSliderFlags flags = 0) + { + int value = get(); + if (ImGui::SliderInt(fieldLabel.c_str(), &value, min, max, displayFormat, flags)) + { + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left, false) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, -0.2f)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), false); + else if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), value, set)), true); + + return true; + } + + return false; + } + + static bool ComboBox(const std::string& fieldLabel, std::vector list, std::function get, std::function set) + { + bool edited = false; + int selected = get(); + ImGui::PushID(fieldLabel.c_str()); + ImGui::Text(fieldLabel.c_str()); ImGui::SameLine(); + + if (edited = ImGui::Combo("##Combo", &selected, list.data(), list.size())) + { + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast(std::make_shared>(get(), selected, set)), false); + } + ImGui::PopID(); + return edited; + } + }; }//namespace SHADE 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 }; 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_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; } diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index 0c508a34..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,18 +148,24 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Script Editor Functions */ /*-----------------------------------------------------------------------------------*/ - void SHScriptEngine::RenderScriptsInInspector(const SHEntity& entity) const + void SHScriptEngine::RenderScriptsInInspector(EntityID entity) const { - csEditorRenderScripts(entity.GetEID()); + csEditorRenderScripts(entity); } /*-----------------------------------------------------------------------------------*/ /* 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 +211,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; } @@ -255,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; @@ -269,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; } /*-----------------------------------------------------------------------------------*/ @@ -385,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 08852e90..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 */ @@ -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: /*-----------------------------------------------------------------------------*/ 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"} diff --git a/SHADE_Managed/src/Components/Transform.cxx b/SHADE_Managed/src/Components/Transform.cxx new file mode 100644 index 00000000..0f0716dc --- /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()->SetLocalRotation(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/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx new file mode 100644 index 00000000..629c9e65 --- /dev/null +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -0,0 +1,234 @@ +/************************************************************************************//*! +\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" +#include "Editor/IconsMaterialDesign.h" + +// Using Directives +using namespace System; +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") + } + + 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 */ + /*---------------------------------------------------------------------------------*/ + void Editor::renderScriptInInspector(Entity entity, Script^ script, int index) + { + // Constants + const std::string LABEL = Convert::ToNative(script->GetType()->Name); + + // Header + SHEditorUI::PushID(index); + if (SHEditorUI::CollapsingHeader(LABEL)) + { + SHEditorUI::PushID(LABEL); + SHEditorUI::Indent(); + { + // Right Click Menu + renderScriptContextMenu(entity, script); + + // 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(); + } + else + { + renderScriptContextMenu(entity, script); + } + 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, 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 + 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)); + } + } + } + + 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 new file mode 100644 index 00000000..188da660 --- /dev/null +++ b/SHADE_Managed/src/Editor/Editor.hxx @@ -0,0 +1,77 @@ +/************************************************************************************//*! +\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); + /// + /// 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: + /*-----------------------------------------------------------------------------*/ + /* 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); + /// + /// 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); + }; +} 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 */ /*-----------------------------------------------------------------------------*/ 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 c1ed5bd5..00000000 --- a/TempScriptsFolder/TestScript.cs +++ /dev/null @@ -1,23 +0,0 @@ -using SHADE; - -public class TestScript : Script -{ - public TestScript(GameObject gameObj) : base(gameObj) {} - - protected override void awake() - { - Debug.Log("TestScript.Awake()"); - } - protected override void start() - { - Debug.Log("TestScript.Start()"); - } - protected override void update() - { - Debug.Log("TestScript.Update()"); - } - protected override void onDestroy() - { - Debug.Log("TestScript.OnDestroy()"); - } -} \ No newline at end of file