aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/Model/Workflow/Workflow.hpp28
-rw-r--r--core/src/Model/Workflow/Workflow_Main.cpp324
2 files changed, 58 insertions, 294 deletions
diff --git a/core/src/Model/Workflow/Workflow.hpp b/core/src/Model/Workflow/Workflow.hpp
index 77341fa..7bcd349 100644
--- a/core/src/Model/Workflow/Workflow.hpp
+++ b/core/src/Model/Workflow/Workflow.hpp
@@ -19,34 +19,17 @@ class WorkflowConnection
public:
static constexpr auto kInvalidId = std::numeric_limits<size_t>::max();
- enum Direction
- {
- ManyToOne,
- OneToMany,
- };
-
- struct ConnectionPoint
- {
- size_t Node;
- int Pin;
-
- bool operator==(const ConnectionPoint&) const = default;
- };
-
- std::vector<ConnectionPoint> MultiConnections;
/// Used for `LinkId` when interfacing with imgui node editor. Runtime only (not saved to disk and generated when loading).
size_t UniqueId;
- ConnectionPoint SingleConnection;
- Direction ConnectionDirection;
+ size_t SourceNode;
+ size_t DestinationNode;
+ int SourcePin;
+ int DestinationPin;
public:
WorkflowConnection();
bool IsValid() const;
- std::span<ConnectionPoint> GetSourcePoints();
- std::span<const ConnectionPoint> GetSourcePoints() const;
- std::span<ConnectionPoint> GetDestinationPoints();
- std::span<const ConnectionPoint> GetDestinationPoints() const;
void DrawDebugInfo() const;
void ReadFrom(std::istream& stream);
@@ -89,13 +72,11 @@ protected:
size_t Connection = WorkflowConnection::kInvalidId;
BaseValue::Kind MatchingType = BaseValue::InvalidKind;
bool ConnectionToConst = false;
- bool AllowsMultipleConnections = false;
/// A constant connection connects from a user-specified constant value, feeding to a valid \c Destination and \c DestinationPin (i.e. input pins).
bool IsConstantConnection() const;
bool IsConnected() const;
BaseValue::Kind GetMatchingType() const;
- WorkflowConnection::Direction GetSupportedDirection() const;
};
struct OutputPin
@@ -108,7 +89,6 @@ protected:
bool IsConnected() const;
BaseValue::Kind GetMatchingType() const;
- WorkflowConnection::Direction GetSupportedDirection() const;
};
friend class Workflow;
diff --git a/core/src/Model/Workflow/Workflow_Main.cpp b/core/src/Model/Workflow/Workflow_Main.cpp
index 39a08df..cfa7cea 100644
--- a/core/src/Model/Workflow/Workflow_Main.cpp
+++ b/core/src/Model/Workflow/Workflow_Main.cpp
@@ -12,128 +12,38 @@
namespace ImNodes = ax::NodeEditor;
WorkflowConnection::WorkflowConnection()
- : MultiConnections{}
- , SingleConnection{ WorkflowNode::kInvalidId, -1 }
- , ConnectionDirection{ OneToMany }
+ : SourceNode{ WorkflowNode::kInvalidId }
+ , DestinationNode{ WorkflowNode::kInvalidId }
+ , SourcePin{ -1 }
+ , DestinationPin{ -1 }
{
}
bool WorkflowConnection::IsValid() const
{
- return SingleConnection.Node != WorkflowNode::kInvalidId;
-}
-
-std::span<WorkflowConnection::ConnectionPoint> WorkflowConnection::GetSourcePoints()
-{
- switch (ConnectionDirection) {
- case ManyToOne: return MultiConnections;
- case OneToMany: return { &SingleConnection, 1 };
- }
-}
-
-std::span<const WorkflowConnection::ConnectionPoint> WorkflowConnection::GetSourcePoints() const
-{
- switch (ConnectionDirection) {
- case ManyToOne: return MultiConnections;
- case OneToMany: return { &SingleConnection, 1 };
- }
-}
-
-std::span<WorkflowConnection::ConnectionPoint> WorkflowConnection::GetDestinationPoints()
-{
- switch (ConnectionDirection) {
- case ManyToOne: return { &SingleConnection, 1 };
- case OneToMany: return MultiConnections;
- }
-}
-
-std::span<const WorkflowConnection::ConnectionPoint> WorkflowConnection::GetDestinationPoints() const
-{
- switch (ConnectionDirection) {
- case ManyToOne: return { &SingleConnection, 1 };
- case OneToMany: return MultiConnections;
- }
-}
-
-static void DrawConnectionPoints(const std::vector<WorkflowConnection::ConnectionPoint>& points, const char* pinHint)
-{
- ImGui::Indent(32.0f);
- for (auto& pt : points) {
- ImGui::Text("{ Node = %llu, Pin (%s) = %d }", pt.Node, pinHint, pt.Pin);
- if (ImGui::IsItemHovered()) {
- // TODO highlight node
- }
- }
- ImGui::Unindent();
-}
-
-static void DrawConnectionPoint(const WorkflowConnection::ConnectionPoint& point, const char* pinHint)
-{
- ImGui::Indent(32.0f);
- ImGui::Text("{ Node = %llu, Pin (%s) = %d }", point.Node, pinHint, point.Pin);
- ImGui::Unindent();
+ return SourceNode != WorkflowNode::kInvalidId;
}
void WorkflowConnection::DrawDebugInfo() const
{
ImGui::BeginTooltip();
- switch (ConnectionDirection) {
- case ManyToOne: {
- ImGui::Text("Type: many-to-one");
- ImGui::Text("Sources:");
- ::DrawConnectionPoints(MultiConnections, "output");
- ImGui::Text("Destination:");
- ::DrawConnectionPoint(SingleConnection, "input");
- } break;
-
- case OneToMany: {
- ImGui::Text("Type: one-to-many");
- ImGui::Text("Source:");
- ::DrawConnectionPoint(SingleConnection, "output");
- ImGui::Text("Destinations:");
- ::DrawConnectionPoints(MultiConnections, "input");
- } break;
- }
+ ImGui::Text("Source (node with output pin):");
+ ImGui::Text("{ Node = %llu, Pin = %d }", SourceNode, SourcePin);
+ ImGui::Text("Destination (node with input pin):");
+ ImGui::Text("{ Node = %llu, Pin = %d }", DestinationNode, DestinationPin);
ImGui::EndTooltip();
}
-static WorkflowConnection::ConnectionPoint ReadConnectionPoint(std::istream& stream)
-{
- WorkflowConnection::ConnectionPoint pt;
- stream >> pt.Node;
- stream >> pt.Pin;
- return pt;
-}
-
void WorkflowConnection::ReadFrom(std::istream& stream)
{
- int n;
- stream >> n;
- ConnectionDirection = (Direction)n;
-
- SingleConnection = ::ReadConnectionPoint(stream);
-
- size_t size;
- stream >> size;
- for (size_t i = 0; i < size; ++i) {
- MultiConnections.push_back(::ReadConnectionPoint(stream));
- }
-}
-
-static void WriteConnectionPoint(std::ostream& stream, const WorkflowConnection::ConnectionPoint& pt)
-{
- stream << pt.Node;
- stream << pt.Pin;
+ stream >> SourceNode >> DestinationNode;
+ stream >> SourcePin >> DestinationPin;
}
void WorkflowConnection::WriteTo(std::ostream& stream)
{
- stream << (int)ConnectionDirection;
- ::WriteConnectionPoint(stream, SingleConnection);
- stream << (size_t)MultiConnections.size();
- for (auto& pt : MultiConnections) {
- ::WriteConnectionPoint(stream, pt);
- }
+ stream << SourceNode << DestinationNode;
+ stream << SourcePin << DestinationPin;
}
bool WorkflowNode::InputPin::IsConstantConnection() const
@@ -151,11 +61,6 @@ BaseValue::Kind WorkflowNode::InputPin::GetMatchingType() const
return MatchingType;
}
-WorkflowConnection::Direction WorkflowNode::InputPin::GetSupportedDirection() const
-{
- return AllowsMultipleConnections ? WorkflowConnection::ManyToOne : WorkflowConnection::OneToMany;
-}
-
bool WorkflowNode::OutputPin::IsConnected() const
{
return Connection != WorkflowConnection::kInvalidId;
@@ -166,11 +71,6 @@ BaseValue::Kind WorkflowNode::OutputPin::GetMatchingType() const
return MatchingType;
}
-WorkflowConnection::Direction WorkflowNode::OutputPin::GetSupportedDirection() const
-{
- return AllowsMultipleConnections ? WorkflowConnection::OneToMany : WorkflowConnection::ManyToOne;
-}
-
WorkflowNode::WorkflowNode(Kind kind)
: mKind{ kind }
, mDepth{ -1 }
@@ -319,24 +219,14 @@ void WorkflowNode::SwapInputPin(int a, int b)
auto& pinB = mInputs[b];
if (mWorkflow) {
- // Delay assignment to ConnectionPoint::Pin so that the pinB loop (if it happens to run and looks in the same Connection) doesn't match the point updated in the pinA loop
- using Pt = WorkflowConnection::ConnectionPoint;
- Pt* pointA = nullptr;
- Pt* pointB = nullptr;
-
if (pinA.IsConnected() && !pinA.IsConstantConnection()) {
- auto pts = mWorkflow->GetConnectionById(pinA.Connection)->GetDestinationPoints();
- auto it = std::find(pts.begin(), pts.end(), Pt{ mId, a });
- pointA = it == pts.end() ? nullptr : &*it;
+ auto& conn = *mWorkflow->GetConnectionById(pinA.Connection);
+ conn.DestinationPin = b;
}
if (pinB.IsConnected() && !pinB.IsConstantConnection()) {
- auto pts = mWorkflow->GetConnectionById(pinB.Connection)->GetDestinationPoints();
- auto it = std::find(pts.begin(), pts.end(), Pt{ mId, b });
- pointB = it == pts.end() ? nullptr : &*it;
+ auto& conn = *mWorkflow->GetConnectionById(pinB.Connection);
+ conn.DestinationPin = a;
}
-
- if (pointA) pointA->Pin = b;
- if (pointB) pointB->Pin = a;
}
std::swap(pinA, pinB);
@@ -369,23 +259,14 @@ void WorkflowNode::SwapOutputPin(int a, int b)
auto& pinB = mOutputs[b];
if (mWorkflow) {
- using Pt = WorkflowConnection::ConnectionPoint;
- Pt* pointA = nullptr;
- Pt* pointB = nullptr;
-
if (pinA.IsConnected()) {
- auto pts = mWorkflow->GetConnectionById(pinA.Connection)->GetSourcePoints();
- auto it = std::find(pts.begin(), pts.end(), Pt{ mId, a });
- pointA = it == pts.end() ? nullptr : &*it;
+ auto& conn = *mWorkflow->GetConnectionById(pinA.Connection);
+ conn.SourcePin = b;
}
if (pinB.IsConnected()) {
- auto pts = mWorkflow->GetConnectionById(pinB.Connection)->GetSourcePoints();
- auto it = std::find(pts.begin(), pts.end(), Pt{ mId, b });
- pointB = it == pts.end() ? nullptr : &*it;
+ auto& conn = *mWorkflow->GetConnectionById(pinB.Connection);
+ conn.SourcePin = a;
}
-
- if (pointA) pointA->Pin = b;
- if (pointB) pointB->Pin = a;
}
std::swap(pinA, pinB);
@@ -470,16 +351,8 @@ void Workflow::RemoveConnection(size_t id)
auto& conn = mConnections[id];
if (!conn.IsValid()) return;
- for (auto& point : conn.GetSourcePoints()) {
- auto& node = *mNodes[point.Node];
- auto& pin = node.mOutputs[point.Pin];
- pin.Connection = WorkflowNode::kInvalidId;
- }
- for (auto& point : conn.GetDestinationPoints()) {
- auto& node = *mNodes[point.Node];
- auto& pin = node.mInputs[point.Pin];
- pin.Connection = WorkflowNode::kInvalidId;
- }
+ mNodes[conn.SourceNode]->mInputs[conn.SourcePin].Connection = WorkflowNode::kInvalidId;
+ mNodes[conn.DestinationNode]->mInputs[conn.DestinationPin].Connection = WorkflowNode::kInvalidId;
conn = {};
mDepthsDirty = true;
@@ -490,102 +363,39 @@ bool Workflow::Connect(WorkflowNode& sourceNode, int sourcePin, WorkflowNode& de
auto& src = sourceNode.mOutputs[sourcePin];
auto& dst = destinationNode.mInputs[destinationPin];
- // Equivalent to `if (o.GetSupportedDirection() != i.GetSupportedDirection()) return false;`
- // Cannot connect two pins of different type
- if (src.AllowsMultipleConnections == dst.AllowsMultipleConnections) return false;
- // Would be same as `dst.GetSupportedDirection()` because we validated that they are the same above
- auto direction = src.GetSupportedDirection();
-
// TODO report error to user?
if (src.GetMatchingType() != dst.GetMatchingType()) {
return false;
}
- using Pt = WorkflowConnection::ConnectionPoint;
- Pt* srcConnPt;
- Pt* dstConnPt;
- size_t connId;
-
- switch (direction) {
- case WorkflowConnection::ManyToOne: {
- if (dst.IsConnected()) return false;
-
- WorkflowConnection* conn;
- if (src.IsConnected()) {
- conn = &mConnections[src.Connection];
- connId = src.Connection;
- } else {
- auto p = AllocWorkflowConnection();
- conn = &p.first;
- connId = p.second;
- }
-
- srcConnPt = &conn->MultiConnections.emplace_back();
- dstConnPt = &conn->SingleConnection;
- } break;
-
- case WorkflowConnection::OneToMany: {
- if (src.IsConnected()) return false;
-
- WorkflowConnection* conn;
- if (dst.IsConnected()) {
- conn = &mConnections[src.Connection];
- connId = src.Connection;
- } else {
- auto p = AllocWorkflowConnection();
- conn = &p.first;
- connId = p.second;
- }
-
- srcConnPt = &conn->SingleConnection;
- dstConnPt = &conn->MultiConnections.emplace_back();
- } break;
+ if (src.IsConnected()) {
+ DisconnectBySource(sourceNode, sourcePin);
}
- srcConnPt->Node = sourceNode.GetId();
- srcConnPt->Pin = sourcePin;
- dstConnPt->Node = destinationNode.GetId();
- dstConnPt->Pin = destinationPin;
+ auto [conn, id] = AllocWorkflowConnection();
+ conn.SourceNode = sourceNode.GetId();
+ conn.SourcePin = sourcePin;
+ conn.DestinationNode = destinationNode.GetId();
+ conn.DestinationPin = destinationPin;
- src.Connection = connId;
- dst.Connection = connId;
+ src.Connection = id;
+ dst.Connection = id;
mDepthsDirty = true;
return true;
}
-// TODO cleanup these two implementation
-
bool Workflow::DisconnectBySource(WorkflowNode& sourceNode, int sourcePin)
{
- auto& sp = sourceNode.mOutputs[sourcePin];
- if (!sp.IsConnected()) return false;
-
- auto& conn = mConnections[sp.Connection];
-
- using Pt = WorkflowConnection::ConnectionPoint;
- switch (sp.GetSupportedDirection()) {
- case WorkflowConnection::ManyToOne: {
- // Recessive pin, remove ConnectionPoint associated with this pin only
-
- auto& vec = conn.MultiConnections;
- vec.erase(std::remove(vec.begin(), vec.end(), Pt{ sourceNode.GetId(), sourcePin }), vec.end());
-
- sp.Connection = WorkflowNode::kInvalidId;
- } break;
+ auto& sn = sourceNode.mOutputs[sourcePin];
+ if (!sn.IsConnected()) return false;
- case WorkflowConnection::OneToMany: {
- // Dominate pin, removes whole connection
+ auto& conn = mConnections[sn.Connection];
+ auto& dn = mNodes[conn.DestinationNode]->mInputs[conn.DestinationPin];
- for (auto& pt : conn.MultiConnections) {
- auto& node = *mNodes[pt.Node];
- node.mInputs[pt.Pin].Connection = WorkflowNode::kInvalidId;
- }
- sp.Connection = WorkflowNode::kInvalidId;
-
- conn = {};
- } break;
- }
+ sn.Connection = WorkflowConnection::kInvalidId;
+ dn.Connection = WorkflowConnection::kInvalidId;
+ conn = {};
mDepthsDirty = true;
return true;
@@ -593,39 +403,15 @@ bool Workflow::DisconnectBySource(WorkflowNode& sourceNode, int sourcePin)
bool Workflow::DisconnectByDestination(WorkflowNode& destinationNode, int destinationPin)
{
- auto& dp = destinationNode.mInputs[destinationPin];
- if (!dp.IsConnected()) return false;
- if (dp.IsConstantConnection()) {
- dp.ConnectionToConst = false;
- dp.Connection = WorkflowNode::kInvalidId;
- return true;
- }
-
- auto& conn = mConnections[dp.Connection];
-
- using Pt = WorkflowConnection::ConnectionPoint;
- switch (dp.GetSupportedDirection()) {
- case WorkflowConnection::ManyToOne: {
- // Dominate pin, removes whole connection
-
- for (auto& pt : conn.MultiConnections) {
- auto& node = *mNodes[pt.Node];
- node.mOutputs[pt.Pin].Connection = WorkflowNode::kInvalidId;
- }
- dp.Connection = WorkflowNode::kInvalidId;
+ auto& dn = destinationNode.mOutputs[destinationPin];
+ if (!dn.IsConnected()) return false;
- conn = {};
- } break;
+ auto& conn = mConnections[dn.Connection];
+ auto& sn = mNodes[conn.SourceNode]->mInputs[conn.SourcePin];
- case WorkflowConnection::OneToMany: {
- // Recessive pin, remove ConnectionPoint associated with this pin only
-
- auto& vec = conn.MultiConnections;
- vec.erase(std::remove(vec.begin(), vec.end(), Pt{ destinationNode.GetId(), destinationPin }), vec.end());
-
- dp.Connection = WorkflowNode::kInvalidId;
- } break;
- }
+ sn.Connection = WorkflowConnection::kInvalidId;
+ dn.Connection = WorkflowConnection::kInvalidId;
+ conn = {};
mDepthsDirty = true;
return true;
@@ -693,18 +479,16 @@ Workflow::GraphUpdateResult::T Workflow::UpdateGraph()
if (!pin.IsConnected()) continue;
auto& conn = mConnections[pin.Connection];
- for (auto& point : conn.GetDestinationPoints()) {
- auto& wn = workingNodes[point.Node];
- auto& n = *mNodes[point.Node].get();
+ auto& wn = workingNodes[conn.DestinationNode];
+ auto& n = *mNodes[conn.DestinationPin].get();
- wn.FulfilledInputCount++;
- wn.MaximumDepth = std::max(node.mDepth, wn.MaximumDepth);
+ wn.FulfilledInputCount++;
+ wn.MaximumDepth = std::max(node.mDepth, wn.MaximumDepth);
- // Node's dependency is fulfilled, we can process its dependents next
- // We use >= here because for a many-to-one pin, the dependency is an "or" relation ship, i.e. any of the nodes firing before this will fulfill the requirement
- if (n.mInputs.size() >= wn.FulfilledInputCount) {
- n.mDepth = wn.MaximumDepth + 1;
- }
+ // Node's dependency is fulfilled, we can process its dependents next
+ // We use >= here because for a many-to-one pin, the dependency is an "or" relation ship, i.e. any of the nodes firing before this will fulfill the requirement
+ if (n.mInputs.size() >= wn.FulfilledInputCount) {
+ n.mDepth = wn.MaximumDepth + 1;
}
}
};