Add Editor Features - Transform Gizmo #105

Merged
srishamharan merged 14 commits from SP3-4-editor_fix into main 2022-10-21 20:58:48 +08:00
26 changed files with 1937 additions and 113 deletions

Binary file not shown.

View File

@ -1,48 +0,0 @@
[Window][MainStatusBar]
Pos=0,1060
Size=1920,20
Collapsed=0
[Window][SHEditorMenuBar]
Pos=0,48
Size=1920,1012
Collapsed=0
[Window][Hierarchy Panel]
Pos=0,142
Size=571,918
Collapsed=0
DockId=0x00000004,0
[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0
[Window][Inspector]
Pos=1649,48
Size=271,1012
Collapsed=0
DockId=0x00000006,0
[Window][Profiler]
Pos=0,48
Size=571,92
Collapsed=0
DockId=0x00000003,0
[Window][Viewport]
Pos=573,48
Size=1074,1012
Collapsed=0
DockId=0x00000002,0
[Docking][Data]
DockSpace ID=0xC5C9B8AB Window=0xBE4044E9 Pos=8,79 Size=1920,1012 Split=X
DockNode ID=0x00000005 Parent=0xC5C9B8AB SizeRef=1992,1036 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=571,1036 Split=Y Selected=0x1E6EB881
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=225,94 Selected=0x1E6EB881
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=225,940 Selected=0xE096E5AE
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1074,1036 CentralNode=1 Selected=0x13926F0B
DockNode ID=0x00000006 Parent=0xC5C9B8AB SizeRef=271,1036 Selected=0xE7039252

View File

@ -149,11 +149,10 @@ namespace Sandbox
SHSceneManager::SceneUpdate(0.016f); SHSceneManager::SceneUpdate(0.016f);
#endif #endif
SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f); SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f);
editor->PollPicking(); //editor->PollPicking();
} }
// Finish all graphics jobs first // Finish all graphics jobs first
graphicsSystem->AwaitGraphicsExecution(); graphicsSystem->AwaitGraphicsExecution();
} }

View File

@ -154,7 +154,6 @@ namespace SHADE
target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw)); target = SHVec3::RotateY(target, SHMath::DegreesToRadians(camera.yaw));
target =SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch)); target =SHVec3::RotateX(target, SHMath::DegreesToRadians(camera.pitch));
std::cout << "Target vec: " << target.x<<", "<<target.y<<", "<<target.z << std::endl;
target += camera.position; target += camera.position;
////SHVec3::RotateZ(target, SHMath::DegreesToRadians(camera.roll)); ////SHVec3::RotateZ(target, SHMath::DegreesToRadians(camera.roll));

View File

@ -24,6 +24,7 @@ namespace SHADE
class SHCommand : SHBaseCommand class SHCommand : SHBaseCommand
{ {
public: public:
using SHCommandPtr = std::unique_ptr<T>;
typedef std::function<void(T const&)> SetterFunction; typedef std::function<void(T const&)> SetterFunction;
SHCommand(T const& oldVal, T const& value, SetterFunction setFnc) SHCommand(T const& oldVal, T const& value, SetterFunction setFnc)

View File

@ -13,7 +13,7 @@ namespace SHADE
SHCommandManager::CommandStack SHCommandManager::undoStack{}; SHCommandManager::CommandStack SHCommandManager::undoStack{};
SHCommandManager::CommandStack SHCommandManager::redoStack{}; SHCommandManager::CommandStack SHCommandManager::redoStack{};
void SHCommandManager::PerformCommand(CommandPtr commandPtr, bool const& overrideValue) void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue)
{ {
redoStack = CommandStack(); redoStack = CommandStack();
commandPtr->Execute(); commandPtr->Execute();
@ -27,9 +27,9 @@ namespace SHADE
} }
} }
void SHCommandManager::RegisterCommand(CommandPtr commandPtr) void SHCommandManager::RegisterCommand(BaseCommandPtr commandPtr)
{ {
undoStack.push(commandPtr); undoStack.push(commandPtr);
} }
void SHCommandManager::UndoCommand() void SHCommandManager::UndoCommand()
@ -59,4 +59,14 @@ namespace SHADE
{ {
return redoStack.size(); return redoStack.size();
} }
void SHCommandManager::PopLatestCommandFromRedoStack()
{
redoStack.pop();
}
void SHCommandManager::PopLatestCommandFromUndoStack()
{
undoStack.pop();
}
}//namespace SHADE }//namespace SHADE

View File

@ -19,16 +19,21 @@ namespace SHADE
//#==============================================================# //#==============================================================#
//|| Type Aliases || //|| Type Aliases ||
//#==============================================================# //#==============================================================#
using CommandPtr = std::shared_ptr<SHBaseCommand>; using BaseCommandPtr = std::shared_ptr<SHBaseCommand>;
using CommandStack = std::stack<CommandPtr>; template<typename T>
using SHCommandPtr = std::shared_ptr<SHCommand<T>>;
using CommandStack = std::stack<BaseCommandPtr>;
static void PerformCommand(CommandPtr commandPtr, bool const& overrideValue = false); static void PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue = false);
static void RegisterCommand(CommandPtr commandPtr); static void RegisterCommand(BaseCommandPtr commandPtr);
static void UndoCommand(); static void UndoCommand();
static void RedoCommand(); static void RedoCommand();
static std::size_t GetUndoStackSize(); static std::size_t GetUndoStackSize();
static std::size_t GetRedoStackSize(); static std::size_t GetRedoStackSize();
static void PopLatestCommandFromRedoStack();
static void PopLatestCommandFromUndoStack();
private: private:
static CommandStack undoStack; static CommandStack undoStack;
static CommandStack redoStack; static CommandStack redoStack;

View File

@ -22,6 +22,7 @@
#include <imgui.h> #include <imgui.h>
#include "Serialization/SHSerialization.h" #include "Serialization/SHSerialization.h"
#include "Tools/SHClipboardUtilities.h"
namespace SHADE namespace SHADE
@ -52,6 +53,7 @@ namespace SHADE
if(const auto root = sceneGraph.GetRoot()) if(const auto root = sceneGraph.GetRoot())
{ {
auto const& children = root->GetChildren(); auto const& children = root->GetChildren();
for (const auto child : children) for (const auto child : children)
{ {
RecursivelyDrawEntityNode(child); RecursivelyDrawEntityNode(child);
@ -79,6 +81,8 @@ namespace SHADE
void SHHierarchyPanel::SetScrollTo(EntityID eid) void SHHierarchyPanel::SetScrollTo(EntityID eid)
{ {
if(eid == MAX_EID)
return;
scrollTo = eid; scrollTo = eid;
} }
@ -104,7 +108,7 @@ namespace SHADE
} }
if (ImGui::SmallButton(ICON_MD_ADD_CIRCLE)) if (ImGui::SmallButton(ICON_MD_ADD_CIRCLE))
{ {
SHEntityManager::CreateEntity(); SHCommandManager::PerformCommand(std::make_shared<SHCreateEntityCommand>());
} }
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
@ -144,23 +148,32 @@ namespace SHADE
auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID()); auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID());
//Draw Node //Draw Node
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(eid), entity->name.c_str()); bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str());
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
//Check For Begin Drag //Check For Begin Drag
if (SHDragDrop::BeginSource()) if (SHDragDrop::BeginSource())
{ {
ImGui::Text("Moving EID: %zu", eid); std::string moveLabel = "Moving EID: ";
SHDragDrop::SetPayload<EntityID>(DRAG_EID, &eid); if(!isSelected)
editor->selectedEntities.push_back(eid);
for(int i = 0; i < static_cast<int>(editor->selectedEntities.size()); ++i)
{
moveLabel.append(std::to_string(editor->selectedEntities[i]));
if(i + 1 < static_cast<int>(editor->selectedEntities.size()))
{
moveLabel.append(", ");
}
}
ImGui::Text(moveLabel.c_str());
SHDragDrop::SetPayload<std::vector<EntityID>>(DRAG_EID, &editor->selectedEntities);
SHDragDrop::EndSource(); SHDragDrop::EndSource();
} }
else if (SHDragDrop::BeginTarget()) //If Received DragDrop else if (SHDragDrop::BeginTarget()) //If Received DragDrop
{ {
if (const EntityID* eidPayload = SHDragDrop::AcceptPayload<EntityID>(DRAG_EID)) //If payload is valid if (const std::vector<EntityID>* eidPayload = SHDragDrop::AcceptPayload<std::vector<EntityID>>(DRAG_EID)) //If payload is valid
{ {
EntityID const dropEID = *eidPayload; ParentSelectedEntities(eid);
if(!sceneGraph.GetChild(dropEID, eid))
sceneGraph.SetParent(dropEID, eid); //Set dropEID parent to eid (belonging to current Node)
SHDragDrop::EndTarget(); SHDragDrop::EndTarget();
} }
} }
@ -175,7 +188,15 @@ namespace SHADE
} }
if(ImGui::Selectable("Copy")) if(ImGui::Selectable("Copy"))
{ {
SHLOG_INFO(SHSerialization::SerializeEntitiesToString(editor->selectedEntities)) SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(editor->selectedEntities));
}
if(ImGui::Selectable("Paste"))
{
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard()));
}
if(ImGui::Selectable("Paste as Child"))
{
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), eid));
} }
if(ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data())) if(ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data()))
{ {
@ -184,7 +205,7 @@ namespace SHADE
if((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data())) if((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
{ {
sceneGraph.SetParent(currentNode->GetEntityID(), nullptr); ParentSelectedEntities(MAX_EID);
} }
ImGui::EndPopup(); ImGui::EndPopup();
} }
@ -196,7 +217,15 @@ namespace SHADE
{ {
if (!isSelected) if (!isSelected)
{ {
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) if(ImGui::IsKeyDown(ImGuiKey_LeftShift))
{
if(editor->selectedEntities.size() >= 1)
{
SelectRangeOfEntities(editor->selectedEntities[0], eid);
}
else editor->selectedEntities.clear();
}
else if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
editor->selectedEntities.clear(); editor->selectedEntities.clear();
editor->selectedEntities.push_back(eid); editor->selectedEntities.push_back(eid);
}//if not selected }//if not selected
@ -243,4 +272,90 @@ namespace SHADE
{ {
SHEntityManager::CreateEntity(MAX_EID, "DefaultChild", parentEID); SHEntityManager::CreateEntity(MAX_EID, "DefaultChild", parentEID);
} }
void SHHierarchyPanel::ParentSelectedEntities(EntityID parentEID) const noexcept
{
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
auto const editor = SHSystemManager::GetSystem<SHEditor>();
SHEntityParentCommand::EntityParentData entityParentData;
std::vector<EntityID> parentedEIDS;
for(auto const& eid : editor->selectedEntities)
{
if(sceneGraph.GetChild(eid, parentEID) == nullptr)
{
parentedEIDS.push_back(eid);
if(auto parent = sceneGraph.GetParent(eid))
entityParentData[eid].oldParentEID = parent->GetEntityID();
entityParentData[eid].newParentEID = parentEID;
}
}
SHCommandManager::PerformCommand(std::make_shared<SHEntityParentCommand>(parentedEIDS, entityParentData));
}
void SHHierarchyPanel::SelectRangeOfEntities(EntityID beginEID, EntityID endEID)
{
bool startSelecting = false; bool endSelecting = false;
auto const editor = SHSystemManager::GetSystem<SHEditor>();
editor->selectedEntities.clear();
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
sceneGraph.Traverse([&](SHSceneNode* nodePtr)
{
auto eid = nodePtr->GetEntityID();
if(!startSelecting)
{
if(eid == beginEID || eid == endEID)
{
startSelecting = true;
editor->selectedEntities.push_back(eid);
}
}
else
{
if(!endSelecting)
{
editor->selectedEntities.push_back(eid);
if(eid == endEID || eid == beginEID)
{
endSelecting = true;
}
}
}
});
}
void SHCreateEntityCommand::Execute()
{
EntityID newEID = SHEntityManager::CreateEntity(eid);
if(eid == MAX_EID)
eid = newEID;
}
void SHCreateEntityCommand::Undo()
{
SHEntityManager::DestroyEntity(eid);
}
void SHEntityParentCommand::Execute()
{
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for(auto const& eid : entities)
{
if(entityParentData[eid].newParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].newParentEID);
}
}
void SHEntityParentCommand::Undo()
{
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for(auto const& eid : entities)
{
if(entityParentData[eid].oldParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID);
}
}
}//namespace SHADE }//namespace SHADE

View File

@ -10,7 +10,7 @@
#include "imgui_internal.h" #include "imgui_internal.h"
#include "ECS_Base/SHECSMacros.h" #include "ECS_Base/SHECSMacros.h"
#include "Editor/EditorWindow/SHEditorWindow.h" #include "Editor/EditorWindow/SHEditorWindow.h"
#include "Editor/Command/SHCommand.hpp"
namespace SHADE namespace SHADE
{ {
class SHSceneNode; class SHSceneNode;
@ -28,8 +28,40 @@ namespace SHADE
void DrawMenuBar() const noexcept; void DrawMenuBar() const noexcept;
ImRect RecursivelyDrawEntityNode(SHSceneNode*); ImRect RecursivelyDrawEntityNode(SHSceneNode*);
void CreateChildEntity(EntityID parentEID) const noexcept; void CreateChildEntity(EntityID parentEID) const noexcept;
void ParentSelectedEntities(EntityID parentEID) const noexcept;
void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID);
std::string filter; std::string filter;
bool isAnyNodeSelected = false; bool isAnyNodeSelected = false;
EntityID scrollTo = MAX_EID; EntityID scrollTo = MAX_EID;
};//class SHHierarchyPanel };//class SHHierarchyPanel
//Might move to a different file
class SHCreateEntityCommand final : public SHBaseCommand
{
public:
void Execute() override;
void Undo() override;
private:
EntityID eid = MAX_EID;
};
class SHEntityParentCommand final : public SHBaseCommand
{
public:
struct Data
{
EntityID oldParentEID = MAX_EID;
EntityID newParentEID = MAX_EID;
};
using EntityParentData = std::unordered_map<EntityID, Data>;
SHEntityParentCommand(std::vector<EntityID> entityIDs, EntityParentData inEntityParentData):entities(entityIDs),entityParentData(inEntityParentData){}
void Execute() override;
void Undo() override;
private:
std::vector<EntityID> entities;
std::unordered_map<EntityID, Data> entityParentData;
};
}//namespace SHADE }//namespace SHADE

View File

@ -10,6 +10,7 @@
//|| SHADE Includes || //|| SHADE Includes ||
//#==============================================================# //#==============================================================#
#include "Editor/IconsMaterialDesign.h" #include "Editor/IconsMaterialDesign.h"
#include "Editor/IconsFontAwesome6.h"
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "Editor/SHEditorWidgets.hpp" #include "Editor/SHEditorWidgets.hpp"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Components/SHColliderComponent.h"
@ -216,7 +217,7 @@ namespace SHADE
if (collider.GetType() == SHCollider::Type::BOX) if (collider.GetType() == SHCollider::Type::BOX)
{ {
SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_MD_VIEW_IN_AR, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto box = reinterpret_cast<SHBoundingBox*>(collider.GetShape()); auto box = reinterpret_cast<SHBoundingBox*>(collider.GetShape());
SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);}); SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);});
} }

View File

@ -55,7 +55,11 @@ namespace SHADE
{ {
EntityID const& eid = editor->selectedEntities[0]; EntityID const& eid = editor->selectedEntities[0];
SHEntity* entity = SHEntityManager::GetEntityByID(eid); SHEntity* entity = SHEntityManager::GetEntityByID(eid);
if(!entity)
{
ImGui::End();
return;
}
ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid); ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid);
SHEditorWidgets::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::SameLine();

View File

@ -3,6 +3,7 @@
#include <imgui.h> #include <imgui.h>
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/Command/SHCommandManager.h"
#include "FRC/SHFramerateController.h" #include "FRC/SHFramerateController.h"
namespace SHADE namespace SHADE
@ -38,6 +39,11 @@ namespace SHADE
{ {
ImGui::PlotLines("DT", frames.data(), static_cast<int>(frames.size()), 0, nullptr, 0.0f, 16.0f); ImGui::PlotLines("DT", frames.data(), static_cast<int>(frames.size()), 0, nullptr, 0.0f, 16.0f);
} }
if(ImGui::CollapsingHeader("Command Manager"))
{
ImGui::Text("Undo: %zu", SHCommandManager::GetUndoStackSize());
ImGui::Text("Redo: %zu", SHCommandManager::GetRedoStackSize());
}
ImGui::End(); ImGui::End();
} }

View File

@ -43,9 +43,12 @@ namespace SHADE
bool result = ImGui::Begin(windowName.data(), &isOpen, windowFlags); bool result = ImGui::Begin(windowName.data(), &isOpen, windowFlags);
auto wndSize = ImGui::GetWindowSize(); auto wndSize = ImGui::GetWindowSize();
if(windowSize.x != wndSize.x || windowSize.y != wndSize.y) auto contentRegionAvail = ImGui::GetContentRegionAvail();
if( beginContentRegionAvailable.x != contentRegionAvail.x || beginContentRegionAvailable.y != contentRegionAvail.y || windowSize.x != wndSize.x || windowSize.y != wndSize.y)
{ {
windowSize = {wndSize.x, wndSize.y}; windowSize = {wndSize.x, wndSize.y};
beginContentRegionAvailable = {contentRegionAvail.x, contentRegionAvail.y};
OnResize(); OnResize();
} }
auto wndPos = ImGui::GetWindowPos(); auto wndPos = ImGui::GetWindowPos();

View File

@ -26,6 +26,10 @@ namespace SHADE
bool isOpen; bool isOpen;
bool isWindowHovered; bool isWindowHovered;
std::string_view windowName; std::string_view windowName;
SHVec2 windowSize;
SHVec2 windowPos;
SHVec2 viewportMousePos;
SHVec2 beginContentRegionAvailable;
protected: protected:
virtual bool Begin(); virtual bool Begin();
virtual void OnResize(); virtual void OnResize();
@ -33,8 +37,6 @@ namespace SHADE
ImGuiWindowFlags windowFlags = 0; ImGuiWindowFlags windowFlags = 0;
ImGuiIO& io; ImGuiIO& io;
SHVec2 windowSize;
SHVec2 windowPos;
SHVec2 viewportMousePos;
};//class SHEditorWindow };//class SHEditorWindow
}//namespace SHADE }//namespace SHADE

View File

@ -1,17 +1,23 @@
#include "SHpch.h" #include "SHpch.h"
#include "Editor/SHImGuiHelpers.hpp"
#include "SHEditorViewport.h" #include "SHEditorViewport.h"
#include "ImGuizmo.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/IconsMaterialDesign.h"
#include "Editor/SHEditor.hpp" #include "Editor/SHEditor.hpp"
#include "Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h" #include "Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" #include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h" #include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h"
#include <Editor/IconsFontAwesome6.h>
constexpr std::string_view windowName = "\xef\x80\x95 Viewport";
namespace SHADE namespace SHADE
{ {
SHEditorViewport::SHEditorViewport() SHEditorViewport::SHEditorViewport()
:SHEditorWindow("Viewport", ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoScrollbar) :SHEditorWindow("\xee\x90\x8b Viewport", ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoScrollbar)
{ {
} }
@ -26,31 +32,30 @@ namespace SHADE
SHEditorWindow::Update(); SHEditorWindow::Update();
if(Begin()) if(Begin())
{ {
ImGuizmo::SetDrawlist();
DrawMenuBar(); DrawMenuBar();
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>(); auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
auto const& descriptorSet = gfxSystem->GetPostOffscreenRenderSystem()->GetDescriptorSetGroup()->GetVkHandle()[0]; auto const& descriptorSet = gfxSystem->GetPostOffscreenRenderSystem()->GetDescriptorSetGroup()->GetVkHandle()[0];
auto mousePos = ImGui::GetMousePos(); auto mousePos = ImGui::GetMousePos();
auto cursorPos = ImGui::GetCursorScreenPos(); beginCursorPos = ImGui::GetCursorScreenPos();
viewportMousePos = {mousePos.x - cursorPos.x, mousePos.y - cursorPos.y}; viewportMousePos = {mousePos.x - beginCursorPos.x, mousePos.y - beginCursorPos.y};
gfxSystem->GetMousePickSystem ()->SetViewportMousePos (viewportMousePos); gfxSystem->GetMousePickSystem ()->SetViewportMousePos (viewportMousePos);
//if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
//{
// auto eid = gfxSystem->GetMousePickSystem ()->GetPickedEntity();
// if(eid != MAX_EID)
// {
// auto editor = SHSystemManager::GetSystem<SHEditor>();
// editor->selectedEntities.clear();
// editor->selectedEntities.push_back(eid);
// if (const auto hierarchyPanel = SHEditorWindowManager::GetEditorWindow<SHHierarchyPanel>())
// {
// hierarchyPanel->SetScrollTo(eid);
// }
// }
//}
ImGui::Image((ImTextureID)descriptorSet, ImGui::GetWindowSize()); ImGui::Image((ImTextureID)descriptorSet, {beginContentRegionAvailable.x, beginContentRegionAvailable.y});
if(ImGui::IsWindowHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Right))
{
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
ImGui::SetCursorScreenPos(ImGui::GetMousePos());
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiColors::green);
ImGui::Text(ICON_FA_EYE);
ImGui::PopStyleColor();
}
} }
ImGuizmo::SetRect(beginCursorPos.x , beginCursorPos.y, beginContentRegionAvailable.x, beginContentRegionAvailable.y);
transformGizmo.Draw();
ImGui::End(); ImGui::End();
} }
void SHEditorViewport::Exit() void SHEditorViewport::Exit()
@ -66,7 +71,11 @@ namespace SHADE
//auto pos = ImGui::GetCursorPos(); //auto pos = ImGui::GetCursorPos();
//windowCursorPos = {} //windowCursorPos = {}
gfxSystem->PrepareResize(static_cast<uint32_t>(windowSize.x), static_cast<uint32_t>(windowSize.y)); if(beginContentRegionAvailable.x == 0 || beginContentRegionAvailable.y == 0)
{
beginContentRegionAvailable = windowSize;
}
gfxSystem->PrepareResize(static_cast<uint32_t>(beginContentRegionAvailable.x), static_cast<uint32_t>(beginContentRegionAvailable.y));
} }
void SHEditorViewport::OnPosChange() void SHEditorViewport::OnPosChange()
@ -74,10 +83,46 @@ namespace SHADE
SHEditorWindow::OnPosChange(); SHEditorWindow::OnPosChange();
} }
void SHEditorViewport::DrawMenuBar() const noexcept void SHEditorViewport::DrawMenuBar() noexcept
{ {
if(ImGui::BeginMenuBar()) if(ImGui::BeginMenuBar())
{ {
bool const isTranslate = transformGizmo.operation == SHTransformGizmo::Operation::TRANSLATE;
ImGui::BeginDisabled(isTranslate);
if(isTranslate)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
if(ImGui::Button(ICON_MD_OPEN_WITH))
{
transformGizmo.operation = SHTransformGizmo::Operation::TRANSLATE;
}
ImGui::EndDisabled();
if(isTranslate)
ImGui::PopStyleColor();
bool const isRotate = transformGizmo.operation == SHTransformGizmo::Operation::ROTATE;
ImGui::BeginDisabled(isRotate);
if(isRotate)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
if(ImGui::Button(ICON_MD_AUTORENEW))
{
transformGizmo.operation = SHTransformGizmo::Operation::ROTATE;
}
ImGui::EndDisabled();
if(isRotate)
ImGui::PopStyleColor();
bool const isScale = transformGizmo.operation == SHTransformGizmo::Operation::SCALE;
ImGui::BeginDisabled(isScale);
if(isScale)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_CheckMark]);
if(ImGui::Button(ICON_MD_EXPAND))
{
transformGizmo.operation = SHTransformGizmo::Operation::SCALE;
}
ImGui::EndDisabled();
if(isScale)
ImGui::PopStyleColor();
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
} }

View File

@ -10,6 +10,7 @@
#include "imgui_internal.h" #include "imgui_internal.h"
#include "ECS_Base/SHECSMacros.h" #include "ECS_Base/SHECSMacros.h"
#include "Editor/EditorWindow/SHEditorWindow.h" #include "Editor/EditorWindow/SHEditorWindow.h"
#include "Editor/Gizmos/SHTransformGizmo.h"
namespace SHADE namespace SHADE
{ {
@ -20,10 +21,12 @@ namespace SHADE
void Init() override; void Init() override;
void Update() override; void Update() override;
void Exit() override; void Exit() override;
SHTransformGizmo transformGizmo;
protected: protected:
void OnResize() override; void OnResize() override;
void OnPosChange() override; void OnPosChange() override;
private: private:
void DrawMenuBar() const noexcept; void DrawMenuBar() noexcept;
SHVec2 beginCursorPos;
};//class SHEditorViewport };//class SHEditorViewport
}//namespace SHADE }//namespace SHADE

View File

@ -0,0 +1,85 @@
#include "SHpch.h"
#include "SHTransformGizmo.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.hpp"
#include "Editor/SHImGuiHelpers.hpp"
#include <imgui.h>
#include <ImGuizmo.h>
#include "Camera/SHCameraSystem.h"
#include "Editor/Command/SHCommandManager.h"
#include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
namespace SHADE
{
void SHTransformGizmo::Draw()
{
bool justChangedTfm = false;
if (!editorCamera)
{
auto const cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
editorCamera = cameraSystem->GetEditorCamera();
}
auto viewportWindow = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>();
ImGuizmo::SetOrthographic(false);
SHMatrix view = SHMatrix::Transpose(editorCamera->GetViewMatrix());
SHMatrix proj = SHMatrix::Transpose(editorCamera->GetProjMatrix());
proj(1, 1) *= -1;
static SHMatrix gridMat = SHMatrix::Translate(0, -0.5f, 0.f) * SHMatrix::Identity;
//ImGuizmo::DrawGrid(&view._11, &proj._11, &gridMat._11, 100.f);
if (selectedEntityTransformComponent == nullptr)
{
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
if (editor->selectedEntities.empty())
return;
EntityID eid = editor->selectedEntities.back();
selectedEntityTransformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
justChangedTfm = true;
}
else
{
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
if (editor->selectedEntities.empty())
return;
EntityID eid = editor->selectedEntities.back();
auto tfmComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
if (selectedEntityTransformComponent != tfmComponent)
{
selectedEntityTransformComponent = tfmComponent;
justChangedTfm = true;
}
}
if (selectedEntityTransformComponent == nullptr)
return;
SHMatrix mat = selectedEntityTransformComponent->GetTRS();
isManipulating = ImGuizmo::Manipulate(&view._11, &proj._11, static_cast<ImGuizmo::OPERATION>(operation), ImGuizmo::MODE::WORLD, &mat._11);
if (!justChangedTfm)
{
if (ImGui::IsItemClicked())
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx)
{
if (!tfm)
return;
SHVec3 translate{}, rotate{}, scale{};
mtx.Decompose(translate, rotate, scale);
tfm->SetWorldPosition(translate);
tfm->SetWorldRotation(rotate);
tfm->SetWorldScale(scale);
})));
else if (ImGui::IsItemHovered(ImGuiMouseButton_Left) && ImGui::IsMouseDown(ImGuiMouseButton_Left) && isManipulating)
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCommand<SHMatrix>>(selectedEntityTransformComponent->GetTRS(), mat, [tfm = std::move(selectedEntityTransformComponent)](SHMatrix const& mtx)
{
if (!tfm)
return;
SHVec3 translate{}, rotate{}, scale{};
mtx.Decompose(translate, rotate, scale);
tfm->SetWorldPosition(translate);
tfm->SetWorldRotation(rotate);
tfm->SetWorldScale(scale);
})), true);
}
}
}

View File

@ -0,0 +1,48 @@
#pragma once
#include "Camera/SHCameraComponent.h"
#include "Math/Transform/SHTransformComponent.h"
namespace SHADE
{
class SHTransformGizmo
{
public:
enum class Mode
{
WORLD,
LOCAL
};
enum class Operation
{
TRANSLATE_X = (1u << 0),
TRANSLATE_Y = (1u << 1),
TRANSLATE_Z = (1u << 2),
ROTATE_X = (1u << 3),
ROTATE_Y = (1u << 4),
ROTATE_Z = (1u << 5),
ROTATE_SCREEN = (1u << 6),
SCALE_X = (1u << 7),
SCALE_Y = (1u << 8),
SCALE_Z = (1u << 9),
BOUNDS = (1u << 10),
SCALE_XU = (1u << 11),
SCALE_YU = (1u << 12),
SCALE_ZU = (1u << 13),
TRANSLATE = TRANSLATE_X | TRANSLATE_Y | TRANSLATE_Z,
ROTATE = ROTATE_X | ROTATE_Y | ROTATE_Z | ROTATE_SCREEN,
SCALE = SCALE_X | SCALE_Y | SCALE_Z,
SCALEU = SCALE_XU | SCALE_YU | SCALE_ZU, // universal
UNIVERSAL = TRANSLATE | ROTATE | SCALEU
};
void Draw();
bool isManipulating = false;
Mode mode = Mode::WORLD;
Operation operation = Operation::TRANSLATE;
private:
SHTransformComponent* selectedEntityTransformComponent{nullptr};
SHCameraComponent* editorCamera{nullptr};
};
}

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@
#include "SHpch.h" #include "SHpch.h"
#include "IconsMaterialDesign.h" #include "IconsMaterialDesign.h"
#include "IconsFontAwesome6.h"
#include "DragDrop/SHDragDrop.hpp" #include "DragDrop/SHDragDrop.hpp"
//#==============================================================# //#==============================================================#
@ -36,6 +37,7 @@
#include <imgui.h> #include <imgui.h>
#include <SDL.h> #include <SDL.h>
#include <rttr/registration> #include <rttr/registration>
#include <ImGuizmo.h>
//#==============================================================# //#==============================================================#
//|| ImGui Backend Includes || //|| ImGui Backend Includes ||
@ -87,10 +89,10 @@ namespace SHADE
//Add editor windows //Add editor windows
SHEditorWindowManager::CreateEditorWindow<SHEditorMenuBar>(); SHEditorWindowManager::CreateEditorWindow<SHEditorMenuBar>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>(); SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>(); SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>(); SHEditorWindowManager::CreateEditorWindow<SHEditorProfiler>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
io = &ImGui::GetIO(); io = &ImGui::GetIO();
@ -98,7 +100,7 @@ namespace SHADE
io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; //Enable for Multi-Viewports io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; //Enable for Multi-Viewports
io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; //Enable docking
io->IniFilename = "../../Assets/Editor/Layouts/UserLayout.ini"; io->IniFilename = "../../Assets/Editor/Layouts/UserLayout.ini";
io->ConfigWindowsMoveFromTitleBarOnly = true;
InitLayout(); InitLayout();
InitFonts(); InitFonts();
@ -127,9 +129,13 @@ namespace SHADE
for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values) for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values)
{ {
if(window->isOpen) if(window->isOpen)
{
window->Update(); window->Update();
}
} }
PollPicking();
if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z)) if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
{ {
SHCommandManager::RedoCommand(); SHCommandManager::RedoCommand();
@ -165,10 +171,11 @@ namespace SHADE
{ {
ImFont* mainFont = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/Segoe UI.ttf", 20.f);//TODO: Change to config based assets path ImFont* mainFont = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/Segoe UI.ttf", 20.f);//TODO: Change to config based assets path
constexpr ImWchar icon_ranges[] = { ICON_MIN_MD, ICON_MAX_16_MD, 0 };
ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f; ImFontConfig icons_config{}; icons_config.MergeMode = true; icons_config.GlyphOffset.y = 5.f;
ImFont* UIFont = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges); //TODO: Change to config based assets path constexpr ImWchar icon_ranges_fa[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFont* UIFontFA = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/fa-solid-900.ttf", 20.f, &icons_config, icon_ranges_fa); //TODO: Change to config based assets path
constexpr ImWchar icon_ranges_md[] = { ICON_MIN_MD, ICON_MAX_MD, 0 };
ImFont* UIFontMD = io->Fonts->AddFontFromFileTTF("../../Assets/Editor/Fonts/MaterialIcons-Regular.ttf", 20.f, &icons_config, icon_ranges_md); //TODO: Change to config based assets path
io->Fonts->Build(); io->Fonts->Build();
} }
@ -338,7 +345,7 @@ namespace SHADE
if (auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>()) if (auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>())
{ {
auto viewportWindow = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>(); auto viewportWindow = SHEditorWindowManager::GetEditorWindow<SHEditorViewport>();
if (viewportWindow->isWindowHovered && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) if (viewportWindow->isWindowHovered && !viewportWindow->transformGizmo.isManipulating && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{ {
EntityID pickedEID = gfxSystem->GetMousePickSystem()->GetPickedEntity(); EntityID pickedEID = gfxSystem->GetMousePickSystem()->GetPickedEntity();
if(pickedEID == MAX_EID) if(pickedEID == MAX_EID)
@ -366,6 +373,7 @@ namespace SHADE
ImGui_ImplVulkan_NewFrame(); ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame(); ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
ImGuizmo::BeginFrame();
} }

View File

@ -16,6 +16,8 @@
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "EditorWindow/SHEditorWindow.h" #include "EditorWindow/SHEditorWindow.h"
#include "Tools/SHLogger.h" #include "Tools/SHLogger.h"
#include "Gizmos/SHTransformGizmo.h"
//#==============================================================# //#==============================================================#
//|| Library Includes || //|| Library Includes ||
@ -200,5 +202,7 @@ namespace SHADE
SDL_Window* sdlWindow {nullptr}; SDL_Window* sdlWindow {nullptr};
ImGuiIO* io{nullptr}; ImGuiIO* io{nullptr};
//SHTransformGizmo transformGizmo;
};//class SHEditor };//class SHEditor
}//namespace SHADE }//namespace SHADE

View File

@ -15,7 +15,7 @@
//#==============================================================# //#==============================================================#
#ifndef SH_IM_MATH #ifndef SH_IM_MATH
#define IM_VEC2_CLASS_EXTRA \ #define IM_VEC2_CLASS_EXTRA \
ImVec2(const SHADE::SHVec2& vec) {x = vec.x; y = vec.y;} \ ImVec2(const SHADE::SHVec2& vec) {x = vec.x; y = vec.y;} \
operator SHADE::SHVec2() const {return SHADE::SHVec2(x,y);} operator SHADE::SHVec2() const {return SHADE::SHVec2(x,y);}
#define IM_VEC3_CLASS_EXTRA \ #define IM_VEC3_CLASS_EXTRA \
ImVec3(const SHADE::SHVec3& vec) {x = vec.x; y = vec.y; z = vec.z;} \ ImVec3(const SHADE::SHVec3& vec) {x = vec.x; y = vec.y; z = vec.z;} \
@ -43,6 +43,10 @@ namespace SHADE
constexpr ImVec4 blue = {0.0f, 0.0f, 1.0f, 1.f}; constexpr ImVec4 blue = {0.0f, 0.0f, 1.0f, 1.f};
constexpr ImVec4 white = {1.0f, 1.0f, 1.0f, 1.f}; constexpr ImVec4 white = {1.0f, 1.0f, 1.0f, 1.f};
constexpr int colors_red = 0;
constexpr int colors_green = 1;
constexpr int colors_blue = 2;
constexpr int colors_white = 3;
constexpr ImU32 colors[] = { constexpr ImU32 colors[] = {
0xBB0000FF, // red 0xBB0000FF, // red
0xBB00FF00, // green 0xBB00FF00, // green

View File

@ -54,11 +54,13 @@ namespace SHADE
out << YAML::EndSeq; out << YAML::EndSeq;
} }
static void DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector<EntityID>& createdEntities, EntityID parentEID = MAX_EID) static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector<EntityID>& createdEntities, EntityID parentEID = MAX_EID)
{ {
if (!node[EIDNode]) EntityID eid = MAX_EID;
return; if(!node)
EntityID eid = node[EIDNode].as<EntityID>(); return eid;
if (node[EIDNode])
eid = node[EIDNode].as<EntityID>();
std::string name = "Default"; std::string name = "Default";
if (node[EntityNameNode]) if (node[EntityNameNode])
name = node[EntityNameNode].as<std::string>(); name = node[EntityNameNode].as<std::string>();
@ -117,7 +119,11 @@ namespace SHADE
{ {
DeserializeEntity(it, (*it), createdEntities); DeserializeEntity(it, (*it), createdEntities);
} }
if(createdEntities.empty())
{
SHLOG_ERROR("Failed to create entities from deserializaiton")
return;
}
//Initialize Entity //Initialize Entity
auto entityVecIt = createdEntities.begin(); auto entityVecIt = createdEntities.begin();
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
@ -136,17 +142,19 @@ namespace SHADE
} }
} }
std::string SHSerialization::SerializeEntitiesToString(std::vector<EntityID> const& entities) std::string SHSerialization::SerializeEntitiesToString(std::vector<EntityID> const& entities) noexcept
{ {
YAML::Emitter out; YAML::Emitter out;
YAML::Node node; YAML::Node node;
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
out << YAML::BeginSeq;
for (auto const& eid : entities) for (auto const& eid : entities)
{ {
auto entityNode = sceneGraph.GetNode(eid); auto entityNode = sceneGraph.GetNode(eid);
EmitEntity(entityNode, out); EmitEntity(entityNode, out);
} }
return std::basic_string<char>(out.c_str()); out << YAML::EndSeq;
return std::string(out.c_str());
} }
void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path) void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path)
@ -193,6 +201,30 @@ namespace SHADE
return node; return node;
} }
EntityID SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept
{
if(data.empty())
return MAX_EID;
YAML::Node entities = YAML::Load(data.c_str());
EntityID eid{MAX_EID};
std::vector<EntityID> createdEntities;
for(auto it = entities.begin(); it != entities.end(); ++it)
{
eid = DeserializeEntity(it, *it, createdEntities, parentEID);
}
if(createdEntities.empty())
{
SHLOG_ERROR("Failed to create entities from deserializaiton")
return MAX_EID;
}
auto entityVecIt = createdEntities.begin();
for(auto it = entities.begin(); it != entities.end(); ++it)
{
InitializeEntity(*it, *entityVecIt++);
}
return eid;
}
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
std::optional<ComponentTypeID> GetComponentID(YAML::Node const& componentNode) std::optional<ComponentTypeID> GetComponentID(YAML::Node const& componentNode)
{ {

View File

@ -29,14 +29,18 @@ namespace SHADE
static void SerializeSceneToFile(std::filesystem::path const& path); static void SerializeSceneToFile(std::filesystem::path const& path);
static std::string SerializeSceneToString(); static std::string SerializeSceneToString();
static void SerializeSceneToEmitter(YAML::Emitter& out); static void SerializeSceneToEmitter(YAML::Emitter& out);
static void DeserializeSceneFromFile(std::filesystem::path const& path); static void DeserializeSceneFromFile(std::filesystem::path const& path);
static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out); static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out);
static std::string SerializeEntitiesToString(std::vector<EntityID> const& entities);
static std::string SerializeEntitiesToString(std::vector<EntityID> const& entities) noexcept;
static void SerializeEntityToFile(std::filesystem::path const& path); static void SerializeEntityToFile(std::filesystem::path const& path);
static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode); static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode);
static EntityID DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept;
static std::vector<ComponentTypeID> GetComponentIDList(YAML::Node const& componentsNode); static std::vector<ComponentTypeID> GetComponentIDList(YAML::Node const& componentsNode);
private: private:
static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid); static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid);

View File

@ -0,0 +1,49 @@
#include "SHpch.h"
#include "SHClipboardUtilities.h"
namespace SHADE
{
void SHClipboardUtilities::WriteToClipboard(std::string const& str) noexcept
{
if(str.empty())
return;
HWND const hwnd = GetDesktopWindow();
OpenClipboard(hwnd);
EmptyClipboard();
auto const size = str.size() + 1;
const HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, size);
if(hGlobal)
{
std::memcpy(GlobalLock(hGlobal), str.c_str(), size);
GlobalUnlock(hGlobal);
SetClipboardData(CF_TEXT, hGlobal);
}
else
{
SHLOG_ERROR("Failed to write to clipboard: {}", str.c_str())
}
CloseClipboard();
GlobalFree(hGlobal);
}
std::string const SHClipboardUtilities::GetDataFromClipboard() noexcept
{
HWND const hwnd = GetDesktopWindow();
if(!OpenClipboard(hwnd))
{
SHLOG_ERROR("Failed to open clipboard")
return std::string();
}
if(HANDLE const dataHandle = GetClipboardData(CF_TEXT); dataHandle)
{
std::string data(static_cast<char*>(GlobalLock(dataHandle)));
GlobalUnlock(dataHandle);
CloseClipboard();
return data;
}
CloseClipboard();
return std::string();
}
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <string_view>
namespace SHADE
{
class SHClipboardUtilities
{
public:
static void WriteToClipboard(std::string const& str) noexcept;
static std::string const GetDataFromClipboard() noexcept;
};
}