diff --git a/CMakeLists.txt b/CMakeLists.txt index ac10a4b..6145f76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ include_directories(External) # Add External Libraries add_subdirectory(External/open-cpp-utils) +add_subdirectory(External/glw) # Configure ImGui set(IMGUI_BACKEND_SDL2 ON) @@ -77,6 +78,7 @@ target_link_libraries(OpenShaderDesigner PRIVATE imgui-docking imgui-extras imnode-graph + glw ) # DOXYGEN ============================================================================================================== diff --git a/External/imgui-docking/CMakeLists.txt b/External/imgui-docking/CMakeLists.txt index 9316bf0..fcd9806 100644 --- a/External/imgui-docking/CMakeLists.txt +++ b/External/imgui-docking/CMakeLists.txt @@ -1,6 +1,11 @@ cmake_minimum_required(VERSION 3.5) -project(imgui-docking) +set(VERSION_MAJOR 0) +set(VERSION_MINOR 0) +set(VERSION_PATCH 1) +set(PROJECT_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") + +project(imgui-docking VERSION ${PROJECT_VERSION}) # Required Source Files diff --git a/External/open-cpp-utils/CMakeLists.txt b/External/open-cpp-utils/CMakeLists.txt index 3abd2cb..e6c123b 100644 --- a/External/open-cpp-utils/CMakeLists.txt +++ b/External/open-cpp-utils/CMakeLists.txt @@ -1,6 +1,11 @@ cmake_minimum_required(VERSION 3.5) -project(open-cpp-utils) +set(VERSION_MAJOR 0) +set(VERSION_MINOR 0) +set(VERSION_PATCH 1) +set(PROJECT_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") + +project(open-cpp-utils VERSION ${PROJECT_VERSION}) set(OPENCPPUTILS_HEADERS any.h @@ -32,12 +37,11 @@ find_package(GTest) add_executable(open-cpp-utils-test Test/Test.cpp - - ${OPENCPPUTILS_HEADERS} ) target_link_libraries(open-cpp-utils-test PRIVATE GTest::gtest + open-cpp-utils ) endif () diff --git a/External/open-cpp-utils/LICENSE b/External/open-cpp-utils/LICENSE index 261eeb9..ba0cc5b 100644 --- a/External/open-cpp-utils/LICENSE +++ b/External/open-cpp-utils/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2024 Medusa Slockbower Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/External/open-cpp-utils/Test/Test.cpp b/External/open-cpp-utils/Test/Test.cpp index f30dfd9..ce6d440 100644 --- a/External/open-cpp-utils/Test/Test.cpp +++ b/External/open-cpp-utils/Test/Test.cpp @@ -13,8 +13,6 @@ // limitations under the License. // ===================================================================================================================== -#include - #include "../object_pool.h" diff --git a/External/open-cpp-utils/set.h b/External/open-cpp-utils/set.h index a4509f4..fdb0522 100644 --- a/External/open-cpp-utils/set.h +++ b/External/open-cpp-utils/set.h @@ -16,6 +16,8 @@ #ifndef SET_H #define SET_H +#include + #include "hash_table.h" namespace open_cpp_utils @@ -23,6 +25,8 @@ namespace open_cpp_utils template, class Alloc = std::allocator> using set = hash_table; +template, class Alloc = std::allocator> using ordered_set = std::set; + } #endif //SET_H diff --git a/Include/Graph/Nodes/Math.h b/Include/Graph/Nodes/Math.h index d163afe..b396951 100644 --- a/Include/Graph/Nodes/Math.h +++ b/Include/Graph/Nodes/Math.h @@ -33,16 +33,20 @@ inline static constexpr ImColor HeaderActiveColor = ImColor(0x82, 0x4C, 0x40); inline static const std::string HeaderMarker = "\uF3B9 "; + // ===================================================================================================================== -// Integral +// Constants // ===================================================================================================================== -struct Integral : public Node + +// Integer ------------------------------------------------------------------------------------------------------------- + +struct Integer : public Node { using ValueType = ocu::any; - Integral(ShaderGraph& graph, ImVec2 pos); - virtual ~Integral() = default; + Integer(ShaderGraph& graph, ImVec2 pos); + virtual ~Integer() = default; [[nodiscard]] Node* Copy(ShaderGraph& graph) const override; void Inspect() override; @@ -50,19 +54,17 @@ struct Integral : public Node ValueType Value; }; -RegisterNode("Math/Constants/Integral", Integral); +RegisterNode("Math/Constants/Integer", Integer); -// ===================================================================================================================== -// Unsigned Integral -// ===================================================================================================================== +// Unsigned Integer ---------------------------------------------------------------------------------------------------- -struct UnsignedIntegral : public Node +struct UnsignedInteger : public Node { using ValueType = ocu::any; - UnsignedIntegral(ShaderGraph& graph, ImVec2 pos); - virtual ~UnsignedIntegral() = default; + UnsignedInteger(ShaderGraph& graph, ImVec2 pos); + virtual ~UnsignedInteger() = default; [[nodiscard]] Node* Copy(ShaderGraph& graph) const override; void Inspect() override; @@ -70,12 +72,10 @@ struct UnsignedIntegral : public Node ValueType Value; }; -RegisterNode("Math/Constants/Unsigned Integral", UnsignedIntegral); +RegisterNode("Math/Constants/Unsigned Integer", UnsignedInteger); -// ===================================================================================================================== -// Scalar -// ===================================================================================================================== +// Scalar -------------------------------------------------------------------------------------------------------------- struct Scalar : public Node { @@ -93,9 +93,7 @@ struct Scalar : public Node RegisterNode("Math/Constants/Scalar", Scalar); -// ===================================================================================================================== -// Vector -// ===================================================================================================================== +// Vector -------------------------------------------------------------------------------------------------------------- struct Vector : public Node { @@ -113,12 +111,29 @@ struct Vector : public Node RegisterNode("Math/Constants/Vector", Vector); + // ===================================================================================================================== -// Add +// Operations // ===================================================================================================================== -struct Add : public Node +// Math Op Prototype --------------------------------------------------------------------------------------------------- + +struct MathOp : public Node +{ + MathOp(ShaderGraph& graph, ImVec2 pos); + virtual ~MathOp() = default; + + virtual bool CheckConnection(Pin *, Pin *) override; + virtual void ValidateConnections() override; + + bool AllowMultiWidthInputs; +}; + + +// Add ----------------------------------------------------------------------------------------------------------------- + +struct Add : public MathOp { Add(ShaderGraph& graph, ImVec2 pos); virtual ~Add() = default; @@ -129,6 +144,82 @@ struct Add : public Node RegisterNode("Math/Operators/Add", Add); + +// Subtract ------------------------------------------------------------------------------------------------------------ + +struct Subtract : public MathOp +{ + Subtract(ShaderGraph& graph, ImVec2 pos); + virtual ~Subtract() = default; + + [[nodiscard]] Node* Copy(ShaderGraph& graph) const override; + void Inspect() override; +}; + +RegisterNode("Math/Operators/Subtract", Subtract); + + +// Multiply ------------------------------------------------------------------------------------------------------------ + +struct Multiply : public MathOp +{ + Multiply(ShaderGraph& graph, ImVec2 pos); + virtual ~Multiply() = default; + + [[nodiscard]] Node* Copy(ShaderGraph& graph) const override; + void Inspect() override; +}; + +RegisterNode("Math/Operators/Multiply", Multiply); + + +// Divide -------------------------------------------------------------------------------------------------------------- + +struct Divide : public MathOp +{ + Divide(ShaderGraph& graph, ImVec2 pos); + virtual ~Divide() = default; + + [[nodiscard]] Node* Copy(ShaderGraph& graph) const override; + void Inspect() override; +}; + +RegisterNode("Math/Operators/Divide", Divide); + + + +// ===================================================================================================================== +// Utilities +// ===================================================================================================================== + + +// Make Vector --------------------------------------------------------------------------------------------------------- + +struct MakeVector : public Node +{ + MakeVector(ShaderGraph& graph, ImVec2 pos); + virtual ~MakeVector() = default; + + [[nodiscard]] Node* Copy(ShaderGraph& graph) const override; + void Inspect() override; +}; + + RegisterNode("Math/Utilities/Make Vector", MakeVector); + + +// Break Vector --------------------------------------------------------------------------------------------------------- + +struct BreakVector : public Node +{ + BreakVector(ShaderGraph& graph, ImVec2 pos); + virtual ~BreakVector() = default; + + [[nodiscard]] Node* Copy(ShaderGraph& graph) const override; + void Inspect() override; +}; + +RegisterNode("Math/Utilities/Break Vector", BreakVector); + } #endif //MATH_H diff --git a/Include/Graph/ShaderGraph.h b/Include/Graph/ShaderGraph.h index bf3114d..e2fbf91 100644 --- a/Include/Graph/ShaderGraph.h +++ b/Include/Graph/ShaderGraph.h @@ -25,6 +25,8 @@ #include #include +#include + #include #include #include @@ -47,8 +49,8 @@ namespace OpenShaderDesigner using PinType = int; enum PinType_ { - PinType_Int = 0 - , PinType_UInt + PinType_UInt = 0 + , PinType_Int , PinType_Float , PinType_Vector @@ -59,35 +61,46 @@ namespace OpenShaderDesigner using PinFlags = unsigned int; enum PinFlags_ { - PinFlags_None = 0 - , PinFlags_NoCollapse = 1 << 0 - , PinFlags_NoPadding = 1 << 1 + PinFlags_None = 0 + , PinFlags_NoCollapse = 1 << 0 + , PinFlags_AlwaysCollapse = 1 << 1 + , PinFlags_NoPadding = 1 << 2 + , PinFlags_Ambiguous = 1 << 3 }; struct Pin { inline const static ImColor Colors[PinType_COUNT] = { - ImColor(0x64, 0x94, 0xAA) // Int - , ImColor(0x7A, 0x9F, 0x82) // Unsigned Int + ImColor(0x7A, 0x9F, 0x82) // Unsigned Int + , ImColor(0x64, 0x94, 0xAA) // Int , ImColor(0xA6, 0x3D, 0x40) // Float , ImColor(0xE9, 0xB8, 0x72) // Vector - , ImColor(0xD2, 0xD5, 0xD3) // Any + , ImColor(0xFF, 0xFF, 0xFF) // Any }; inline const static std::string TypeNames[PinType_COUNT] = { - "Int" - , "Unsigned Int" + "Unsigned Int" + , "Int" , "Float" , "Vector" , "Any" }; - using Ambiguous = ocu::any; + inline const static int TypeWidths[PinType_COUNT] = { + 1 // Unsigned Int + , 1 // Int + , 1 // Float + , 3 // Vector + , -1 // Any + }; + + using Ambiguous = ocu::any; std::string Name; PinType Type; PinFlags Flags; Ambiguous Value; + ImPinPtr Ptr; Pin(const std::string& name, PinType type, PinFlags flags = PinFlags_None) : Name(name) @@ -99,7 +112,8 @@ namespace OpenShaderDesigner struct Node { public: - ImVec2 Position = { 0, 0 }; + ShaderGraph& Graph; + ImVec2 Position = { 0, 0 }; struct { @@ -122,9 +136,11 @@ namespace OpenShaderDesigner Node(ShaderGraph& graph, ImVec2 pos); ~Node() = default; - void DrawPin(ImGuiID id, Pin& pin, ImPinDirection direction); + void DrawPin(int id, Pin& pin, ImPinDirection direction); void Draw(ImGuiID id); + virtual bool CheckConnection(Pin*, Pin*) { return false; } + virtual void ValidateConnections() { } virtual Node* Copy(ShaderGraph& graph) const = 0; virtual void Inspect() = 0; }; @@ -132,6 +148,19 @@ namespace OpenShaderDesigner class ShaderGraph : public EditorWindow { + public: + struct GraphState + { + ShaderGraph& Parent; + ocu::object_list Nodes; + + GraphState(ShaderGraph& parent); + GraphState(const GraphState& other); + ~GraphState(); + + GraphState& operator=(const GraphState& other); + }; + private: friend Node; @@ -142,25 +171,10 @@ namespace OpenShaderDesigner ConstructorPtr Constructor; }; - struct GraphState - { - ShaderGraph& Parent; - ocu::object_list Nodes; - - GraphState(ShaderGraph& parent); - GraphState(const GraphState& other); - ~GraphState(); - - GraphState& operator=(const GraphState& other); - }; - using ContextMenuHierarchy = ocu::directed_tree; using ContextID = ContextMenuHierarchy::node; inline static ContextMenuHierarchy ContextMenu; - // History Functionality - void PushState(); - void PopState(); public: ShaderGraph(); @@ -175,7 +189,15 @@ namespace OpenShaderDesigner void Erase(); void Paste(ImVec2 pos); - static void Register(const std::filesystem::path& path, ConstructorPtr constructor); + Node* FindNode(ImPinPtr ptr); + Pin& FindPin(ImPinPtr ptr); + + static void Register(const std::filesystem::path& path, ConstructorPtr constructor); + + // History Functionality + void PushState(); + void PopState(); + GraphState& GetState() { return State; } private: bool GrabFocus; diff --git a/Source/Entry.cpp b/Source/Entry.cpp index 0ae506e..4fe0c9a 100644 --- a/Source/Entry.cpp +++ b/Source/Entry.cpp @@ -22,7 +22,7 @@ int main(int, char**) Window::Configuration config; config.Application.Title = "OpenShaderDesigner"; - config.Video.Multisamples = 4; + config.Video.Multisamples = 16; config.Video.Fullscreen = Window::FullscreenMode::WINDOWED; config.Video.Resolution = { 1280, 720 }; config.Video.HDR = false; diff --git a/Source/Graph/Nodes/Math.cpp b/Source/Graph/Nodes/Math.cpp index 921fce1..7a6307d 100644 --- a/Source/Graph/Nodes/Math.cpp +++ b/Source/Graph/Nodes/Math.cpp @@ -16,65 +16,65 @@ #include #include +#include + using namespace OpenShaderDesigner; using namespace OpenShaderDesigner::Nodes::Math; - // ===================================================================================================================== -// Integral +// Constants // ===================================================================================================================== -Integral::Integral(ShaderGraph& graph, ImVec2 pos) + +// Integer ------------------------------------------------------------------------------------------------------------- + +Integer::Integer(ShaderGraph& graph, ImVec2 pos) : Node(graph, pos) { - Header.Title = HeaderMarker + "Integral"; + Header.Title = HeaderMarker + "Integer"; Header.Color = HeaderColor; Header.HoveredColor = HeaderHoveredColor; Header.ActiveColor = HeaderActiveColor; - IO.Outputs.emplace_back("Out", PinType_Float, PinFlags_NoCollapse | PinFlags_NoPadding); + IO.Outputs.emplace_back("Out", PinType_Int, PinFlags_NoCollapse | PinFlags_NoPadding); } -Node* Integral::Copy(ShaderGraph& graph) const +Node* Integer::Copy(ShaderGraph& graph) const { - return new Integral(graph, Position); + return new Integer(graph, Position); } -void Integral::Inspect() +void Integer::Inspect() { } -// ===================================================================================================================== -// Scalar -// ===================================================================================================================== +// Unsigned Integer ---------------------------------------------------------------------------------------------------- -UnsignedIntegral::UnsignedIntegral(ShaderGraph& graph, ImVec2 pos) +UnsignedInteger::UnsignedInteger(ShaderGraph& graph, ImVec2 pos) : Node(graph, pos) { - Header.Title = HeaderMarker + "Unsigned Integral"; + Header.Title = HeaderMarker + "Unsigned Integer"; Header.Color = HeaderColor; Header.HoveredColor = HeaderHoveredColor; Header.ActiveColor = HeaderActiveColor; - IO.Outputs.emplace_back("Out", PinType_Float, PinFlags_NoCollapse | PinFlags_NoPadding); + IO.Outputs.emplace_back("Out", PinType_UInt, PinFlags_NoCollapse | PinFlags_NoPadding); } -Node* UnsignedIntegral::Copy(ShaderGraph& graph) const +Node* UnsignedInteger::Copy(ShaderGraph& graph) const { - return new UnsignedIntegral(graph, Position); + return new UnsignedInteger(graph, Position); } -void UnsignedIntegral::Inspect() +void UnsignedInteger::Inspect() { } -// ===================================================================================================================== -// Scalar -// ===================================================================================================================== +// Scalar -------------------------------------------------------------------------------------------------------------- Scalar::Scalar(ShaderGraph& graph, ImVec2 pos) : Node(graph, pos) @@ -98,9 +98,7 @@ void Scalar::Inspect() } -// ===================================================================================================================== -// Vector -// ===================================================================================================================== +// Vector -------------------------------------------------------------------------------------------------------------- Vector::Vector(ShaderGraph &graph, ImVec2 pos) : Node(graph, pos) @@ -112,7 +110,7 @@ Vector::Vector(ShaderGraph &graph, ImVec2 pos) IO.Outputs.emplace_back("Out", PinType_Vector, PinFlags_NoCollapse | PinFlags_NoPadding); - IO.Outputs[0].Value.get() = ImVec4(0, 0, 0, 1); + IO.Outputs[0].Value.get() = glm::vec3(0); } Node* Vector::Copy(ShaderGraph &graph) const @@ -127,22 +125,84 @@ void Vector::Inspect() // ===================================================================================================================== -// Add +// Math Operations // ===================================================================================================================== + +// Math Operation Interface -------------------------------------------------------------------------------------------- + +MathOp::MathOp(ShaderGraph &graph, ImVec2 pos) + : Node(graph, pos) + , AllowMultiWidthInputs(false) +{ + +} + +bool MathOp::CheckConnection(Pin* a, Pin* b) +{ + if(AllowMultiWidthInputs) return false; + + for(Pin& pin : IO.Inputs) + { + if(&pin == a) continue; + if((pin.Flags & PinFlags_Ambiguous) == false) continue; + if(ImNodeGraph::IsPinConnected(pin.Ptr) == false) continue; + if(pin.Type == PinType_Any) continue; + + if(Pin::TypeWidths[pin.Type] != Pin::TypeWidths[b->Type]) return true; + } + + return false; +} + +void MathOp::ValidateConnections() +{ + std::set present; + + for(Pin& pin : IO.Inputs) + { + if((pin.Flags & PinFlags_Ambiguous) == false) continue; + if(ImNodeGraph::IsPinConnected(pin.Ptr) == false) continue; + if(pin.Type == PinType_Any) continue; + + present.insert(pin.Type); + } + + PinType type = present.empty() ? PinType_Any : *present.rbegin(); + + for(Pin& pin : IO.Inputs) + { + if((pin.Flags & PinFlags_Ambiguous) == false) continue; + if(ImNodeGraph::IsPinConnected(pin.Ptr)) continue; + + pin.Type = type; + } + + for(Pin& pin : IO.Outputs) + { + if((pin.Flags & PinFlags_Ambiguous) == false) continue; + if(ImNodeGraph::IsPinConnected(pin.Ptr)) continue; + + pin.Type = type; + } +} + + +// Add ----------------------------------------------------------------------------------------------------------------- + Add::Add(ShaderGraph& graph, ImVec2 pos) - : Node(graph, pos) + : MathOp(graph, pos) { Header.Title = HeaderMarker + "Add"; Header.Color = HeaderColor; Header.HoveredColor = HeaderHoveredColor; Header.ActiveColor = HeaderActiveColor; - IO.Inputs.emplace_back("A", PinType_Any); - IO.Inputs.emplace_back("B", PinType_Any); + IO.Inputs.emplace_back("A", PinType_Any, PinFlags_Ambiguous); + IO.Inputs.emplace_back("B", PinType_Any, PinFlags_Ambiguous); IO.DynamicInputs = true; - IO.Outputs.emplace_back("B", PinType_Any); + IO.Outputs.emplace_back("Out", PinType_Any, PinFlags_Ambiguous); } Node* Add::Copy(ShaderGraph& graph) const @@ -154,3 +214,153 @@ void Add::Inspect() { } + + +// Subtract ------------------------------------------------------------------------------------------------------------ + +Subtract::Subtract(ShaderGraph& graph, ImVec2 pos) + : MathOp(graph, pos) +{ + Header.Title = HeaderMarker + "Subtract"; + Header.Color = HeaderColor; + Header.HoveredColor = HeaderHoveredColor; + Header.ActiveColor = HeaderActiveColor; + + IO.Inputs.emplace_back("A", PinType_Any, PinFlags_Ambiguous); + IO.Inputs.emplace_back("B", PinType_Any, PinFlags_Ambiguous); + IO.DynamicInputs = true; + + IO.Outputs.emplace_back("Out", PinType_Any, PinFlags_Ambiguous); +} + +Node* Subtract::Copy(ShaderGraph& graph) const +{ + return new Subtract(graph, Position); +} + +void Subtract::Inspect() +{ + +} + + +// Multiply ------------------------------------------------------------------------------------------------------------ + +Multiply::Multiply(ShaderGraph& graph, ImVec2 pos) + : MathOp(graph, pos) +{ + Header.Title = HeaderMarker + "Multiply"; + Header.Color = HeaderColor; + Header.HoveredColor = HeaderHoveredColor; + Header.ActiveColor = HeaderActiveColor; + + IO.Inputs.emplace_back("A", PinType_Any, PinFlags_Ambiguous); + IO.Inputs.emplace_back("B", PinType_Any, PinFlags_Ambiguous); + IO.DynamicInputs = true; + + IO.Outputs.emplace_back("Out", PinType_Any, PinFlags_Ambiguous); + + AllowMultiWidthInputs = true; +} + +Node* Multiply::Copy(ShaderGraph& graph) const +{ + return new Multiply(graph, Position); +} + +void Multiply::Inspect() +{ + +} + + +// Divide -------------------------------------------------------------------------------------------------------------- + +Divide::Divide(ShaderGraph& graph, ImVec2 pos) + : MathOp(graph, pos) +{ + Header.Title = HeaderMarker + "Divide"; + Header.Color = HeaderColor; + Header.HoveredColor = HeaderHoveredColor; + Header.ActiveColor = HeaderActiveColor; + + IO.Inputs.emplace_back("A", PinType_Any, PinFlags_Ambiguous); + IO.Inputs.emplace_back("B", PinType_Any, PinFlags_Ambiguous); + IO.DynamicInputs = true; + + IO.Outputs.emplace_back("Out", PinType_Any, PinFlags_Ambiguous); + + AllowMultiWidthInputs = true; +} + +Node* Divide::Copy(ShaderGraph& graph) const +{ + return new Divide(graph, Position); +} + +void Divide::Inspect() +{ + +} + + + +// ===================================================================================================================== +// Utilities +// ===================================================================================================================== + + +// Make Vector --------------------------------------------------------------------------------------------------------- + +MakeVector::MakeVector(ShaderGraph& graph, ImVec2 pos) + : Node(graph, pos) +{ + Header.Title = HeaderMarker + "Make Vector"; + Header.Color = HeaderColor; + Header.HoveredColor = HeaderHoveredColor; + Header.ActiveColor = HeaderActiveColor; + + IO.Inputs.emplace_back("X", PinType_Float, PinFlags_AlwaysCollapse); + IO.Inputs.emplace_back("Y", PinType_Float, PinFlags_AlwaysCollapse); + IO.Inputs.emplace_back("Z", PinType_Float, PinFlags_AlwaysCollapse); + + IO.Outputs.emplace_back("Out", PinType_Vector); +} + +Node* MakeVector::Copy(ShaderGraph& graph) const +{ + return new MakeVector(graph, Position); +} + +void MakeVector::Inspect() +{ + +} + + +// Break Vector --------------------------------------------------------------------------------------------------------- + +BreakVector::BreakVector(ShaderGraph& graph, ImVec2 pos) + : Node(graph, pos) +{ + Header.Title = HeaderMarker + "Make Vector"; + Header.Color = HeaderColor; + Header.HoveredColor = HeaderHoveredColor; + Header.ActiveColor = HeaderActiveColor; + + IO.Inputs.emplace_back("In", PinType_Vector, PinFlags_AlwaysCollapse); + + IO.Outputs.emplace_back("X", PinType_Float); + IO.Outputs.emplace_back("Y", PinType_Float); + IO.Outputs.emplace_back("Z", PinType_Float); +} + +Node* BreakVector::Copy(ShaderGraph& graph) const +{ + return new MakeVector(graph, Position); +} + +void BreakVector::Inspect() +{ + +} diff --git a/Source/Graph/ShaderGraph.cpp b/Source/Graph/ShaderGraph.cpp index 51eb4cb..7126731 100644 --- a/Source/Graph/ShaderGraph.cpp +++ b/Source/Graph/ShaderGraph.cpp @@ -29,6 +29,21 @@ using namespace OpenShaderDesigner; +static ShaderGraph* GCurrentGraph = nullptr; + +static bool ValidateConnection(ImPinPtr a, ImPinPtr b) +{ + ShaderGraph& Graph = *GCurrentGraph; + + bool result = false; + result |= Graph.FindNode(a)->CheckConnection(&Graph.FindPin(a), &Graph.FindPin(b)); + result |= Graph.FindNode(b)->CheckConnection(&Graph.FindPin(b), &Graph.FindPin(a)); + + return result; +} + + + ImColor operator*(const ImColor& c, float f) { return ImVec4(c.Value.x * f, c.Value.y * f, c.Value.z * f, c.Value.w); @@ -66,9 +81,9 @@ ShaderGraph::GraphState& ShaderGraph::GraphState::operator=(const GraphState& ot return *this; } -Node::Node( - ShaderGraph& graph, ImVec2 pos) - : Position(pos) +Node::Node(ShaderGraph& graph, ImVec2 pos) + : Graph(graph) + , Position(pos) , Header { .Title = "Node" @@ -87,16 +102,38 @@ Node::Node( } { } -void Node::DrawPin(ImGuiID id, Pin& pin, ImPinDirection direction) +void Node::DrawPin(int id, Pin& pin, ImPinDirection direction) { ImPinFlags flags = 0; if(pin.Flags & PinFlags_NoPadding) flags |= ImPinFlags_NoPadding; - ImNodeGraph::BeginPin(std::format("{}##{}", pin.Name, id).c_str(), pin.Type, direction, flags); + bool res = ImNodeGraph::BeginPin(id, pin.Type, direction, flags); + pin.Ptr = ImNodeGraph::GetPinPtr(); + if(res) + { + const ImVector& connections = ImNodeGraph::GetConnections(); + const ImVector& new_conns = ImNodeGraph::GetNewConnections(); - bool connected = ImNodeGraph::IsPinConnected(); + if(pin.Flags & PinFlags_Ambiguous) + { + if(connections.size() == new_conns.size() && new_conns.size() > 0) + { + Pin& first = Graph.FindPin(new_conns.front()); + if(first.Type != PinType_Any) pin.Type = first.Type; + } - if((connected || pin.Type == PinType_Any) && !(pin.Flags & PinFlags_NoCollapse)) + if(connections.size() == 0) pin.Type = PinType_Any; + } + + ValidateConnections(); + } + + const bool connected = ImNodeGraph::IsPinConnected(); + const bool any = pin.Type == PinType_Any; + const bool force_collapse = pin.Flags & PinFlags_AlwaysCollapse; + const bool no_collapse = pin.Flags & PinFlags_NoCollapse; + + if((connected || any || direction || force_collapse) && !no_collapse) { ImGui::Text(pin.Name.c_str()); } @@ -107,25 +144,28 @@ void Node::DrawPin(ImGuiID id, Pin& pin, ImPinDirection direction) case PinType_Int: ImNodeGraph::PushItemWidth(200.0f); ImGui::InputInt(std::format("##in{}{}", pin.Name, id).c_str(), pin.Value); break; + case PinType_UInt: ImNodeGraph::PushItemWidth(200.0f); ImGui::InputUInt(std::format("##in{}{}", pin.Name, id).c_str(), pin.Value); break; + case PinType_Float: ImNodeGraph::PushItemWidth(100.0f); ImGui::InputFloat(std::format("##in{}{}", pin.Name, id).c_str(), pin.Value); break; + case PinType_Vector: ImGui::BeginGroup(); // Color Picker ImNodeGraph::PushItemWidth(150.0f); - ImGui::ColorPicker4( - std::format("##in{}{}", pin.Name, id).c_str(), &pin.Value.get().x + ImGui::ColorPicker3( + std::format("##in{}{}", pin.Name, id).c_str(), &pin.Value.get().x , ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_Float ); ImNodeGraph::PushItemWidth(150.0f); - ImGui::ColorPreview( - std::format("##invec{}{}", pin.Name, id).c_str(), &pin.Value.get().x + ImGui::ColorPreview3( + std::format("##invec{}{}", pin.Name, id).c_str(), &pin.Value.get().x , ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_Float ); @@ -150,8 +190,20 @@ void Node::Draw(ImGuiID id) ImNodeGraph::EndNodeHeader(); } - for(Pin& pin : IO.Inputs) DrawPin(id, pin, ImPinDirection_Input); - for(Pin& pin : IO.Outputs) DrawPin(id, pin, ImPinDirection_Output); + ImGuiID pid = 0; + for(Pin& pin : IO.Inputs) DrawPin(++pid, pin, ImPinDirection_Input); + + ImVec2 cursor = ImGui::GetCursorPos(); + + pid = 0; + for(Pin& pin : IO.Outputs) DrawPin(--pid, pin, ImPinDirection_Output); + + ImGui::SetCursorPos(cursor); + + //if(IO.DynamicInputs) + //{ + // ImGui::Text("\uEA11"); + //} ImNodeGraph::EndNode(); } @@ -177,9 +229,13 @@ void ShaderGraph::OnOpen() void ShaderGraph::DrawWindow() { + GCurrentGraph = this; + ImNodeGraph::BeginGraph("ShaderGraph"); ImNodeGraph::SetPinColors(Pin::Colors); + ImNodeGraph::SetGraphValidation(ValidateConnection); + if(GrabFocus) { GrabFocus = false; @@ -198,6 +254,20 @@ void ShaderGraph::DrawWindow() ImNodeGraph::EndGraph(); + + ImNodeGraph::BeginGraphPostOp("ShaderGraph"); + + if(ImGui::IsKeyPressed(ImGuiKey_Delete)) + { + auto& selected = ImNodeGraph::GetSelected(); + for(ImGuiID node : selected) + { + State.Nodes.erase(ImNodeGraph::GetUserID(node).Int); + } + selected.Clear(); + } + + ImNodeGraph::EndGraphPostOp(); } @@ -208,7 +278,7 @@ void ShaderGraph::DrawContextMenu() ContextMenuPosition = ImNodeGraph::ScreenToGrid(ImGui::GetMousePos()); } - if(ImGui::BeginPopupContextWindow()) + if(ImGui::BeginPopupContextWindow("graph_context")) { if(ImGui::MenuItem("Copy", "Ctrl+C", false, false)) Copy(); if(ImGui::MenuItem("Cut", "Ctrl+X", false, false)) @@ -294,6 +364,21 @@ void ShaderGraph::Copy() {} void ShaderGraph::Erase() {} void ShaderGraph::Paste(ImVec2) {} +Node* ShaderGraph::FindNode(ImPinPtr ptr) +{ + return State.Nodes[ImNodeGraph::GetUserID(ptr.Node).Int]; +} + +Pin& ShaderGraph::FindPin(ImPinPtr ptr) +{ + Node* node = State.Nodes[ImNodeGraph::GetUserID(ptr.Node).Int]; + auto& pins = ptr.Direction ? node->IO.Outputs : node->IO.Inputs; + int idx = ImNodeGraph::GetUserID(ptr).Int; + if(ptr.Direction) idx *= -1; + idx -= 1; + return pins[idx]; +} + void ShaderGraph::Register(const std::filesystem::path& path, ConstructorPtr constructor) { const std::string name = path.filename().string(); diff --git a/imgui.ini b/imgui.ini index a0c2c58..5b08191 100644 --- a/imgui.ini +++ b/imgui.ini @@ -8,25 +8,26 @@ Size=400,400 Collapsed=0 [Window][Dear ImGui Demo] -Pos=171,229 -Size=375,341 +Pos=3070,364 +Size=370,711 Collapsed=0 +DockId=0x00000008,0 [Window][ Console] -Pos=303,953 -Size=3137,464 +Pos=303,1077 +Size=3137,340 Collapsed=0 DockId=0x00000004,0 [Window][ Profiler] -Pos=0,953 -Size=301,464 +Pos=0,1077 +Size=301,340 Collapsed=0 DockId=0x00000003,0 [Window][ Shader Graph] Pos=0,0 -Size=3068,951 +Size=3068,1075 Collapsed=0 DockId=0x00000005,0 @@ -65,16 +66,18 @@ Collapsed=0 [Window][Inspector] Pos=3070,0 -Size=370,951 +Size=370,362 Collapsed=0 -DockId=0x00000006,0 +DockId=0x00000007,0 [Docking][Data] -DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=3440,1417 Split=Y - DockNode ID=0x00000001 Parent=0x7C6B3D9B SizeRef=3440,974 Split=X - DockNode ID=0x00000005 Parent=0x00000001 SizeRef=3068,1417 CentralNode=1 Selected=0xD4C89E35 - DockNode ID=0x00000006 Parent=0x00000001 SizeRef=370,1417 Selected=0xE7039252 - DockNode ID=0x00000002 Parent=0x7C6B3D9B SizeRef=3440,464 Split=X Selected=0xE9F1AFD1 - DockNode ID=0x00000003 Parent=0x00000002 SizeRef=301,448 Selected=0xAC4B19AE - DockNode ID=0x00000004 Parent=0x00000002 SizeRef=3137,448 Selected=0xE9F1AFD1 +DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=3440,1417 Split=Y + DockNode ID=0x00000001 Parent=0x7C6B3D9B SizeRef=3440,378 Split=X + DockNode ID=0x00000005 Parent=0x00000001 SizeRef=3068,1417 CentralNode=1 Selected=0xD4C89E35 + DockNode ID=0x00000006 Parent=0x00000001 SizeRef=370,1417 Split=Y Selected=0xE7039252 + DockNode ID=0x00000007 Parent=0x00000006 SizeRef=370,127 Selected=0xE7039252 + DockNode ID=0x00000008 Parent=0x00000006 SizeRef=370,249 Selected=0xE87781F4 + DockNode ID=0x00000002 Parent=0x7C6B3D9B SizeRef=3440,340 Split=X Selected=0xE9F1AFD1 + DockNode ID=0x00000003 Parent=0x00000002 SizeRef=301,448 Selected=0xAC4B19AE + DockNode ID=0x00000004 Parent=0x00000002 SizeRef=3137,448 Selected=0xE9F1AFD1