- Adjusted Node Rendering Code for Readability and Performance

This commit is contained in:
Maddie Slockbower 2024-07-16 21:05:13 -04:00
parent 3c3fdbcae8
commit b2baf596d4
5 changed files with 94 additions and 47 deletions

View File

@ -33,6 +33,8 @@ endif()
include_directories(Include) include_directories(Include)
include_directories(External) include_directories(External)
add_subdirectory(External/imnodes-master)
add_executable(OpenShaderDesigner add_executable(OpenShaderDesigner
Source/Entry.cpp Source/Entry.cpp
@ -75,4 +77,5 @@ target_link_libraries(OpenShaderDesigner PRIVATE
GLEW::GLEW GLEW::GLEW
OpenGL::GL OpenGL::GL
${SDL2_LIBRARIES} ${SDL2_LIBRARIES}
imnodes
) )

View File

@ -171,6 +171,9 @@ namespace OpenShaderDesigner
float BezierOffset(const ImVec2& out, const ImVec2& in); float BezierOffset(const ImVec2& out, const ImVec2& in);
bool AABB(const ImVec2& a0, const ImVec2& a1, const ImVec2& b0, const ImVec2& b1); bool AABB(const ImVec2& a0, const ImVec2& a1, const ImVec2& b0, const ImVec2& b1);
ImVec2 GridToScreen(const ImVec2& position);
ImVec2 ScreenToGrid(const ImVec2& position);
public: public:
ShaderGraph(); ShaderGraph();
~ShaderGraph(); ~ShaderGraph();

View File

@ -91,6 +91,12 @@ Window::Window(const Configuration& config)
// Set running // Set running
Open = true; Open = true;
const char* glVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
const char* glewVersion = reinterpret_cast<const char*>(glewGetString(GLEW_VERSION));
SDL_version sdlVersion; SDL_GetVersion(&sdlVersion);
Console::Log(Console::Severity::ALERT, "Initialized SDL ({}.{}.{})", sdlVersion.major, sdlVersion.minor, sdlVersion.patch);
Console::Log(Console::Severity::ALERT, "Running OpenGL ({}), GLEW ({})", glVersion, glewVersion);
} }
Window::~Window() Window::~Window()

View File

@ -10,6 +10,8 @@
#include <imgui-docking/backends/imgui_impl_opengl3.h> #include <imgui-docking/backends/imgui_impl_opengl3.h>
#include <imgui-docking/misc/freetype/imgui_freetype.h> #include <imgui-docking/misc/freetype/imgui_freetype.h>
#include <imnodes-master/imnodes.h>
using namespace OpenShaderDesigner; using namespace OpenShaderDesigner;
void EditorSystem::Initialize() void EditorSystem::Initialize()
@ -19,6 +21,7 @@ void EditorSystem::Initialize()
Console::Log(Console::Severity::ALERT, "Initializing Dear ImGUI"); Console::Log(Console::Severity::ALERT, "Initializing Dear ImGUI");
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
ImNodes::CreateContext();
// https://github.com/ocornut/imgui/issues/707#issuecomment-917151020 // https://github.com/ocornut/imgui/issues/707#issuecomment-917151020
@ -50,7 +53,7 @@ void EditorSystem::Initialize()
colors[ImGuiCol_Header] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f); colors[ImGuiCol_Header] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.00f, 0.00f, 0.00f, 0.36f); colors[ImGuiCol_HeaderHovered] = ImVec4(0.00f, 0.00f, 0.00f, 0.36f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.20f, 0.22f, 0.23f, 0.33f); colors[ImGuiCol_HeaderActive] = ImVec4(0.20f, 0.22f, 0.23f, 0.33f);
colors[ImGuiCol_Separator] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f); colors[ImGuiCol_Separator] = ImVec4(0.40f, 0.40f, 0.40f, 0.29f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.29f); colors[ImGuiCol_SeparatorHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.29f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.40f, 0.44f, 0.47f, 1.00f); colors[ImGuiCol_SeparatorActive] = ImVec4(0.40f, 0.44f, 0.47f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f); colors[ImGuiCol_ResizeGrip] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f);
@ -122,6 +125,7 @@ void EditorSystem::Initialize()
ImGui_ImplOpenGL3_Init("#version 460 core"); ImGui_ImplOpenGL3_Init("#version 460 core");
//ImGui::GetBackgroundDrawList()->AddText(ImVec2(0, 0), ImColor(0, 0, 0), "setup"); //ImGui::GetBackgroundDrawList()->AddText(ImVec2(0, 0), ImColor(0, 0, 0), "setup");
Console::Log(Console::Severity::ALERT, "Initialized ImGui ({})", IMGUI_VERSION);
} }
void EditorSystem::Draw() void EditorSystem::Draw()
@ -158,6 +162,7 @@ void EditorSystem::Shutdown()
// Shutdown ImGui // Shutdown ImGui
ImGui_ImplSDL2_Shutdown(); ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext(); ImGui::DestroyContext();
ImNodes::DestroyContext();
} }
void EditorSystem::HandleEvents(SDL_Event* event) void EditorSystem::HandleEvents(SDL_Event* event)

View File

@ -207,17 +207,12 @@ void ShaderGraph::DrawWindow()
void ShaderGraph::HandleInput() void ShaderGraph::HandleInput()
{ {
// Window Info
const ImVec2 CanvasMin = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin();
const ImVec2 CanvasMax = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMax();
const ImVec2 CanvasSize = CanvasMax - CanvasMin;
const ImVec2 CanvasCenter = CanvasMin + CanvasSize * 0.5f;
Focused = ImGui::IsWindowFocused(); Focused = ImGui::IsWindowFocused();
// Calculate Mouse Delta // Calculate Mouse Delta
Mouse.ClickedSomething = false; Mouse.ClickedSomething = false;
Mouse.Location = (Mouse.ScreenLocation - CanvasCenter + Camera.Location) * Camera.Zoom; Mouse.Location = ScreenToGrid(Mouse.ScreenLocation);
Mouse.Delta = ImGui::GetMousePos() - Mouse.ScreenLocation; Mouse.Delta = ImGui::GetMousePos() - Mouse.ScreenLocation;
Mouse.ScreenLocation = ImGui::GetMousePos(); Mouse.ScreenLocation = ImGui::GetMousePos();
Mouse.Scroll = ImGui::GetIO().MouseWheel; Mouse.Scroll = ImGui::GetIO().MouseWheel;
@ -332,27 +327,36 @@ void ShaderGraph::DrawNode(Node& node, NodeId id)
// Window Info // Window Info
const ImVec2 CanvasMin = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin(); const ImVec2 CanvasMin = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin();
const ImVec2 CanvasMax = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMax(); const ImVec2 CanvasMax = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMax();
const ImVec2 CanvasSize = CanvasMax - CanvasMin;
const ImVec2 CanvasCenter = CanvasMin + CanvasSize * 0.5f;
// ImGui Vars // ImGui Vars
ImDrawList& DrawList = *ImGui::GetWindowDrawList(); ImDrawList& DrawList = *ImGui::GetWindowDrawList();
// Draw Vars // Draw Vars
const float HeaderHeight = Style.FontSize;
const ImVec2 Padding = { Style.Grid.Lines.Padding, Style.Grid.Lines.Padding }; const ImVec2 Padding = { Style.Grid.Lines.Padding, Style.Grid.Lines.Padding };
const float HeaderHeight = Style.FontSize / Camera.Zoom; const ImVec2 NodePos = node.Position + Padding;
const ImVec2 Size = node.Info.Size / Camera.Zoom; const ImVec2 NodeRoot = GridToScreen(NodePos);
const ImVec2 Position = CanvasCenter - Camera.Location + node.Position / Camera.Zoom + Padding; const ImVec2 NodeEdge = GridToScreen(NodePos + node.Info.Size);
const bool NodeHovered = ImGui::IsMouseHoveringRect(Position, Position + Size); const ImVec2 HeaderEdge = GridToScreen(NodePos + ImVec2(node.Info.Size.x, HeaderHeight));
const bool HeaderHovered = ImGui::IsMouseHoveringRect(Position, Position + ImVec2(Size.x, HeaderHeight)); const ImVec2 HeaderText = GridToScreen(NodePos + ImVec2(Style.Nodes.Rounding, 0) + Padding * 0.5f);
const ImVec2 InputRoot = GridToScreen(NodePos + ImVec2(Style.Nodes.Pins.Padding, HeaderHeight));
const ImVec2 OutputRoot = GridToScreen(NodePos + ImVec2(node.Info.Size.x - HeaderHeight - Style.Nodes.Pins.Padding, HeaderHeight));
const bool HasLock = Mouse.FocusedNode(); const bool HasLock = Mouse.FocusedNode();
const bool NodeHovered = ImGui::IsMouseHoveringRect(NodeRoot, NodeEdge);
const bool HeaderHovered = ImGui::IsMouseHoveringRect(NodeRoot, HeaderEdge);
const ImColor HeaderColor = node.Header.Color * (HeaderHovered || HasLock ? 1.2f : 1.0f) * (HasLock ? 0.8f : 1.0f); const ImColor HeaderColor = node.Header.Color * (HeaderHovered || HasLock ? 1.2f : 1.0f) * (HasLock ? 0.8f : 1.0f);
const ImVec2 InputLoc = Position + ImVec2(Style.Nodes.Pins.Padding / Camera.Zoom, HeaderHeight);
const ImVec2 OutputLoc = Position + ImVec2(Size.x - HeaderHeight - Style.Nodes.Pins.Padding / Camera.Zoom, HeaderHeight); const float Rounding = Style.Nodes.Rounding / Camera.Zoom;
const float PinSpacing = HeaderHeight / Camera.Zoom;
const float BorderThickness = Style.Nodes.Border.Thickness / Camera.Zoom;
const float GridSize = (Style.FontSize + Style.Grid.Lines.Padding); const float GridSize = (Style.FontSize + Style.Grid.Lines.Padding);
const bool Ctrl = ImGui::IsKeyDown(ImGuiKey_ModCtrl); const bool Ctrl = ImGui::IsKeyDown(ImGuiKey_ModCtrl);
const bool Shift = ImGui::IsKeyDown(ImGuiKey_ModShift); const bool Shift = ImGui::IsKeyDown(ImGuiKey_ModShift);
if(!AABB(CanvasMin, CanvasMax, NodeRoot, NodeEdge)) return;
// Input =========================================================================================================== // Input ===========================================================================================================
Mouse.NodeHovered = Mouse.NodeHovered ? true : NodeHovered; Mouse.NodeHovered = Mouse.NodeHovered ? true : NodeHovered;
@ -409,8 +413,8 @@ void ShaderGraph::DrawNode(Node& node, NodeId id)
ImVec2 Drag = ImGui::GetMouseDragDelta() * Camera.Zoom; ImVec2 Drag = ImGui::GetMouseDragDelta() * Camera.Zoom;
ImVec2 A0 = Mouse.Location - Drag; ImVec2 A0 = Mouse.Location - Drag;
ImVec2 A1 = Mouse.Location; ImVec2 A1 = Mouse.Location;
ImVec2 B0 = node.Position; ImVec2 B0 = NodePos;
ImVec2 B1 = node.Position + node.Info.Size; ImVec2 B1 = NodePos + node.Info.Size;
bool Intersect = AABB(A0, A1, B0, B1); bool Intersect = AABB(A0, A1, B0, B1);
// Clear selection for new selection // Clear selection for new selection
@ -484,38 +488,38 @@ void ShaderGraph::DrawNode(Node& node, NodeId id)
// Content ========================================================================================================= // Content =========================================================================================================
DrawList.AddRectFilled(Position, Position + Size, Style.Nodes.Content, Style.Nodes.Rounding / Camera.Zoom + 1); DrawList.AddRectFilled(NodeRoot, NodeEdge, Style.Nodes.Content, Rounding + 1);
// Header ========================================================================================================== // Header ==========================================================================================================
if(node.Header.Enabled) if(node.Header.Enabled)
{ {
DrawList.PushClipRect(Position, Position + ImVec2(Size.x, HeaderHeight), true); DrawList.PushClipRect(NodeRoot, HeaderEdge, true);
DrawList.AddRectFilled(Position, Position + Size, HeaderColor, Style.Nodes.Rounding / Camera.Zoom + 1); DrawList.AddRectFilled(NodeRoot, NodeEdge, HeaderColor, Rounding + 1);
DrawList.AddText(NULL, Style.FontSize / Camera.Zoom, Position + ImVec2(Style.Nodes.Rounding / Camera.Zoom, 0) + Padding / 2.0f, Style.Nodes.Title, node.Header.Title.c_str()); DrawList.AddText(NULL, Style.FontSize / Camera.Zoom, HeaderText, Style.Nodes.Title, node.Header.Title.c_str());
DrawList.PopClipRect(); DrawList.PopClipRect();
DrawList.AddLine(InputLoc, Position + ImVec2(Size.x, HeaderHeight), Style.Nodes.Border.Color, Style.Nodes.Border.Thickness / Camera.Zoom); DrawList.AddLine(InputRoot, HeaderEdge, Style.Nodes.Border.Color, BorderThickness);
} }
// Border ========================================================================================================== // Border ==========================================================================================================
if(Selected.contains(id)) DrawList.AddRect(Position, Position + Size, Style.Nodes.SelectedBorder.Color, Style.Nodes.Rounding / Camera.Zoom, 0, Style.Nodes.SelectedBorder.Thickness / Camera.Zoom); if(Selected.contains(id)) DrawList.AddRect(NodeRoot, NodeEdge, Style.Nodes.SelectedBorder.Color, Rounding, 0, Style.Nodes.SelectedBorder.Thickness / Camera.Zoom);
else DrawList.AddRect(Position, Position + Size, Style.Nodes.Border.Color, Style.Nodes.Rounding / Camera.Zoom, 0, Style.Nodes.Border.Thickness / Camera.Zoom); else DrawList.AddRect(NodeRoot, NodeEdge, Style.Nodes.Border.Color, Rounding, 0, BorderThickness);
// Pins ============================================================================================================ // Pins ============================================================================================================
int i = 0; int i = 0;
for(Pin& pin : node.IO.Inputs) for(Pin& pin : node.IO.Inputs)
{ {
DrawPin(id, pin, i, InputLoc + ImVec2(0, HeaderHeight) * (i + 0.5f), true); DrawPin(id, pin, i, InputRoot + ImVec2(0, PinSpacing) * (i + 0.5f), true);
++i; ++i;
} }
int j = 0; int j = 0;
for(Pin& pin : node.IO.Outputs) for(Pin& pin : node.IO.Outputs)
{ {
DrawPin(id, pin, j, OutputLoc + ImVec2(0, HeaderHeight) * (j + 0.5f), false); DrawPin(id, pin, j, OutputRoot + ImVec2(0, PinSpacing) * (j + 0.5f), false);
++j; ++j;
} }
} }
@ -529,9 +533,14 @@ void ShaderGraph::DrawPin(NodeId node_id, Pin& pin, PinId pin_id, ImVec2 locatio
// Draw Vars // Draw Vars
const float HeaderHeight = Style.FontSize / Camera.Zoom; const float HeaderHeight = Style.FontSize / Camera.Zoom;
const float PinRadius = (Style.FontSize - Style.Nodes.Pins.Padding - 2.0f * Style.Nodes.Pins.BorderThickness) * 0.5f / Camera.Zoom;
const ImVec2 Offset = ImVec2(HeaderHeight, HeaderHeight) * 0.5f; const ImVec2 Offset = ImVec2(HeaderHeight, HeaderHeight) * 0.5f;
const bool Hovered = ImGui::IsMouseHoveringRect(location, location + ImVec2(HeaderHeight, HeaderHeight) / Camera.Zoom); const ImVec2 PinRoot = location;
const ImVec2 PinEdge = PinRoot + Offset * 2.0f;
const ImVec2 PinCenter = PinRoot + Offset;
const float PinPadding = Style.Nodes.Pins.Padding / Camera.Zoom;
const float BorderThickness = Style.Nodes.Pins.BorderThickness / Camera.Zoom;
const float PinRadius = (HeaderHeight - PinPadding - 2.0f * Style.Nodes.Pins.BorderThickness) * 0.5f;
const bool Hovered = ImGui::IsMouseHoveringRect(PinRoot, PinEdge);
// Pin ============================================================================================================= // Pin =============================================================================================================
@ -544,16 +553,16 @@ void ShaderGraph::DrawPin(NodeId node_id, Pin& pin, PinId pin_id, ImVec2 locatio
// Circle // Circle
PinPtr ptr = { node_id, pin_id, input }; PinPtr ptr = { node_id, pin_id, input };
auto it = Connections.find(ptr); auto it = Connections.find(ptr);
if(Mouse.NewConnection() && *Mouse.NewConnection == ptr) DrawList.AddCircleFilled(location + Offset, PinRadius, Pin::Colors[pin.Type]); if(Mouse.NewConnection() && *Mouse.NewConnection == ptr) DrawList.AddCircleFilled(PinCenter, PinRadius, Pin::Colors[pin.Type]);
else if(!input && it != Connections.end()) DrawList.AddCircleFilled(location + Offset, PinRadius, Pin::Colors[pin.Type] * (Hovered ? 0.8f : 1.0f)); else if(!input && it != Connections.end()) DrawList.AddCircleFilled(PinCenter, PinRadius, Pin::Colors[pin.Type] * (Hovered ? 0.8f : 1.0f));
else if(it != Connections.end()) DrawList.AddCircleFilled(location + Offset, PinRadius, Pin::Colors[Nodes[it->second.Node]->IO.Outputs[it->second.Pin].Type] * (Hovered ? 0.8f : 1.0f)); else if(it != Connections.end()) DrawList.AddCircleFilled(PinCenter, PinRadius, Pin::Colors[Nodes[it->second.Node]->IO.Outputs[it->second.Pin].Type] * (Hovered ? 0.8f : 1.0f));
else if(Hovered) DrawList.AddCircleFilled(location + Offset, PinRadius, Pin::Colors[pin.Type]); else if(Hovered) DrawList.AddCircleFilled(PinCenter, PinRadius, Pin::Colors[pin.Type]);
else DrawList.AddCircleFilled(location + Offset, PinRadius, Style.Nodes.Pins.Background); else DrawList.AddCircleFilled(PinCenter, PinRadius, Style.Nodes.Pins.Background);
DrawList.AddCircle(location + Offset, PinRadius, Pin::Colors[pin.Type], 0, Style.Nodes.Pins.BorderThickness / Camera.Zoom); DrawList.AddCircle(PinCenter, PinRadius, Pin::Colors[pin.Type], 0, BorderThickness);
// Text // Text
const ImVec2 TextOffset = location + ImVec2((input ? HeaderHeight : -ImGui::CalcTextSize(pin.Name.c_str()).x / Camera.Zoom), 0); const ImVec2 TextOffset = location + ImVec2((input ? HeaderHeight : -ImGui::CalcTextSize(pin.Name.c_str()).x / Camera.Zoom), 0);
DrawList.AddText(NULL, Style.FontSize / Camera.Zoom, TextOffset, Style.Nodes.Pins.Text, pin.Name.c_str()); DrawList.AddText(NULL, HeaderHeight, TextOffset, Style.Nodes.Pins.Text, pin.Name.c_str());
// Input =========================================================================================================== // Input ===========================================================================================================
@ -588,6 +597,10 @@ void ShaderGraph::DrawContextMenu()
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Create");
ImGui::Separator();
// Create Nodes // Create Nodes
ImVec2 position = ContextMenuPosition; ImVec2 position = ContextMenuPosition;
position = ImFloor(position / GridSize) * GridSize; position = ImFloor(position / GridSize) * GridSize;
@ -665,10 +678,6 @@ void ShaderGraph::DrawConnections()
const float HeaderHeight = Style.FontSize / Camera.Zoom; const float HeaderHeight = Style.FontSize / Camera.Zoom;
const float PinRadius = (Style.FontSize - Style.Nodes.Pins.Padding - 2.0f * Style.Nodes.Pins.BorderThickness) * 0.5f / Camera.Zoom; const float PinRadius = (Style.FontSize - Style.Nodes.Pins.Padding - 2.0f * Style.Nodes.Pins.BorderThickness) * 0.5f / Camera.Zoom;
const ImVec2 Padding = { Style.Grid.Lines.Padding, Style.Grid.Lines.Padding }; const ImVec2 Padding = { Style.Grid.Lines.Padding, Style.Grid.Lines.Padding };
const ImVec2 CanvasMin = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin();
const ImVec2 CanvasMax = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMax();
const ImVec2 CanvasSize = CanvasMax - CanvasMin;
const ImVec2 CanvasCenter = CanvasMin + CanvasSize * 0.5f;
const ImVec2 Offset = ImVec2(HeaderHeight, HeaderHeight) * 0.5f; const ImVec2 Offset = ImVec2(HeaderHeight, HeaderHeight) * 0.5f;
// Connections ============================================================================================================= // Connections =============================================================================================================
@ -683,12 +692,11 @@ void ShaderGraph::DrawConnections()
const Node& Node = *Nodes[Mouse.NewConnection->Node]; const Node& Node = *Nodes[Mouse.NewConnection->Node];
const Pin& Pin = Mouse.NewConnection->Input ? Node.IO.Inputs[Mouse.NewConnection->Pin] : Node.IO.Outputs[Mouse.NewConnection->Pin]; const Pin& Pin = Mouse.NewConnection->Input ? Node.IO.Inputs[Mouse.NewConnection->Pin] : Node.IO.Outputs[Mouse.NewConnection->Pin];
const ImVec2 Size = Node.Info.Size / Camera.Zoom; const ImVec2 NodePos = Node.Position + Padding;
const ImVec2 Position = CanvasCenter - Camera.Location + Node.Position / Camera.Zoom + Padding; const ImVec2 InputRoot = GridToScreen(NodePos + ImVec2(Style.Nodes.Pins.Padding, HeaderHeight));
const ImVec2 InputLoc = Position + ImVec2(Style.Nodes.Pins.Padding / Camera.Zoom, HeaderHeight); const ImVec2 OutputRoot = GridToScreen(NodePos + ImVec2(Node.Info.Size.x - HeaderHeight - Style.Nodes.Pins.Padding, HeaderHeight));
const ImVec2 OutputLoc = Position + ImVec2(Size.x - HeaderHeight - Style.Nodes.Pins.Padding / Camera.Zoom, HeaderHeight);
const ImVec2 Root = (Mouse.NewConnection->Input ? InputLoc : OutputLoc) + ImVec2(0, HeaderHeight) * (Mouse.NewConnection->Pin + 0.5f); const ImVec2 Root = (Mouse.NewConnection->Input ? InputRoot : OutputRoot) + ImVec2(0, HeaderHeight) * (Mouse.NewConnection->Pin + 0.5f);
const ImVec2 A = Root + Offset + ImVec2(Mouse.NewConnection->Input ? -PinRadius : PinRadius, 0); const ImVec2 A = Root + Offset + ImVec2(Mouse.NewConnection->Input ? -PinRadius : PinRadius, 0);
const ImVec2 D = ImGui::GetMousePos(); const ImVec2 D = ImGui::GetMousePos();
@ -853,6 +861,7 @@ NodeId ShaderGraph::AddNode(Node* node)
void ShaderGraph::RemoveNode(NodeId id) void ShaderGraph::RemoveNode(NodeId id)
{ {
Node* node = Nodes[id]; Node* node = Nodes[id];
if(node->Info.Const) return;
PinId i = 0; PinId i = 0;
for(const auto& pin : node->IO.Inputs) EraseConnections({ id, i++, true }); for(const auto& pin : node->IO.Inputs) EraseConnections({ id, i++, true });
@ -874,6 +883,8 @@ void ShaderGraph::ClearClipboard()
void ShaderGraph::Copy() void ShaderGraph::Copy()
{ {
if(Selected.empty()) return;
// Helper for connections // Helper for connections
std::unordered_map<NodeId, NodeId> clipboardTransform; std::unordered_map<NodeId, NodeId> clipboardTransform;
ImVec2 min = Nodes[*Selected.begin()]->Position; ImVec2 min = Nodes[*Selected.begin()]->Position;
@ -917,14 +928,18 @@ void ShaderGraph::Paste(const ImVec2& location)
const float GridSize = (Style.FontSize + Style.Grid.Lines.Padding); const float GridSize = (Style.FontSize + Style.Grid.Lines.Padding);
std::unordered_map<NodeId, NodeId> clipboardTransform; std::unordered_map<NodeId, NodeId> clipboardTransform;
ImVec2 root = ImFloor(location / GridSize + ImVec2(0.5f, 0.5f)) * GridSize; ImVec2 root = ImFloor(location / GridSize + ImVec2(0.5f, 0.5f)) * GridSize;
Selected.clear();
// Paste the nodes
NodeId id = 0; NodeId id = 0;
for(Node* node : Clipboard.Nodes) for(Node* node : Clipboard.Nodes)
{ {
node->Position += root; NodeId index = clipboardTransform[id++] = AddNode(node->Copy(*this));
clipboardTransform[id++] = AddNode(node->Copy(*this)); Nodes[index]->Position += root;
Selected.insert(index);
} }
// Paste the connections
for(const Connection& connection : Clipboard.Connections) for(const Connection& connection : Clipboard.Connections)
{ {
CreateConnection( CreateConnection(
@ -962,6 +977,21 @@ bool ShaderGraph::AABB(const ImVec2& a0, const ImVec2& a1, const ImVec2& b0, con
return X && Y; return X && Y;
} }
ImVec2 ShaderGraph::GridToScreen(const ImVec2& position)
{
// Window Info
const ImVec2 CanvasCenter = ImGui::GetWindowPos()
+ (ImGui::GetWindowContentRegionMin() + ImGui::GetWindowContentRegionMax()) * 0.5f;
return CanvasCenter - Camera.Location + position / Camera.Zoom;
}
ImVec2 ShaderGraph::ScreenToGrid(const ImVec2& position)
{
const ImVec2 CanvasCenter = ImGui::GetWindowPos()
+ (ImGui::GetWindowContentRegionMin() + ImGui::GetWindowContentRegionMax()) * 0.5f;
return (position - CanvasCenter + Camera.Location) * Camera.Zoom;
}
void ShaderGraph::Register(const std::filesystem::path& path, ConstructorPtr constructor) void ShaderGraph::Register(const std::filesystem::path& path, ConstructorPtr constructor)
{ {
const std::string name = path.filename().string(); const std::string name = path.filename().string();