Skip to content

Instantly share code, notes, and snippets.

@JSandusky
Last active September 14, 2016 20:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JSandusky/bf7fd6d79468542629829b67b37ce772 to your computer and use it in GitHub Desktop.
Save JSandusky/bf7fd6d79468542629829b67b37ce772 to your computer and use it in GitHub Desktop.
Graph snippets
class Graph
{
Node* masterNode_;
std::vector<Node*> nodes_; // List of all of the contained nodes
std::vector<Node*> entryNodes_; // Nodes that are known to be possible points of entry
std::multimap<Socket*, Socket*> upstreamEdges_; // link edges that go right->left, input -> output, we only ever allow a single upstream edge - except for with flowControl
std::multimap<Socket*, Socket*> downstreamEdges_; // link edges that go left->right, output -> input, flow control sockets can only have 1 downstream edge
unsigned currentExecutionContext_;
}
void Graph::Node::ExecuteDownstream(unsigned& executionContext, const Variant& parameter, unsigned ignoringNode)
{
if (lastExecutionContext == executionContext || id == ignoringNode)
return;
Variant param = FilterParameter(parameter);
int result = 0;
do {
result = Execute(parameter);
if (result == GRAPH_EXECUTE_COMPLETE)
return;
PropogateValues(true);
for (Socket* socket : outputSockets)
{
if (!(socket->typeID))
continue;
auto downstreamEdges = graph->downstreamEdges_.equal_range(socket);
for (auto edge = downstreamEdges.first; edge != downstreamEdges.second && edge != graph->downstreamEdges_.end(); ++edge)
edge->second->node->ExecuteDownstream(executionContext, param);
}
} while (result == GRAPH_EXECUTE_LOOP);
}
void Graph::Node::ExecuteHybridStrict(unsigned& executionContext, const Variant& parameter, unsigned ignoringNode)
{
if (lastExecutionContext == executionContext || id == ignoringNode)
return;
// Reset our selected exit
selectedExit = 0x0;
// Iterate through input variable sockets to get values
int result = 1;
do {
for (Socket* socket : inputSockets)
{
if (!socket->variable)
continue;
auto upstreamEdges = graph->upstreamEdges_.equal_range(socket);
for (auto edge = upstreamEdges.first; edge != upstreamEdges.second && edge != graph->upstreamEdges_.end(); ++edge)
edge->second->node->ExecuteUpstream(executionContext, parameter);
}
// Retrieve values from upstream sockets
PropogateValues(false);
result = Execute(parameter);
if (result == GRAPH_EXECUTE_COMPLETE)
return;
// Propogate into our output sockets
PropogateValues(true);
// Execute may assign our selectedExit
if (!selectedExit)
{
// Execute all output flow sockets
for (Socket* socket : outputFlowSockets)
{
//TODO: deal with branching/looping execution
auto downstreamEdges = graph->downstreamEdges_.equal_range(socket);
for (auto edge = downstreamEdges.first; edge != downstreamEdges.second && edge != graph->downstreamEdges_.end(); ++edge)
edge->second->node->ExecuteDownstream(executionContext, parameter);
}
}
else if (selectedExit != (Socket*)0xFFFFFFFF)
{
// Execute all connections downstream from the flow exit socket
auto edge = graph->downstreamEdges_.find(selectedExit);
if (edge != graph->downstreamEdges_.end())
edge->second->node->ExecuteDownstream(executionContext, parameter);
}
}
while (result == GRAPH_EXECUTE_LOOP);
}
void Graph::Node::ExecuteUpstream(unsigned& executionContext, const Variant& parameter, unsigned ignoringNode)
{
if (executionContext != -1 && lastExecutionContext == executionContext || id == ignoringNode)
return;
Variant param = FilterParameter(parameter);
do {
if (!WillForceExecute())
{
// Evaluate upstream nodes first
for (Socket* socket : inputSockets)
{
if (!(socket->typeID))
continue;
auto upstreamEdges = graph->upstreamEdges_.equal_range(socket);
for (auto edge = upstreamEdges.first; edge != upstreamEdges.second && edge != graph->upstreamEdges_.end(); ++edge)
edge->second->node->ExecuteUpstream(executionContext, param);
}
PropogateValues(false);
}
} while (Execute(executionContext, parameter) == GRAPH_EXECUTE_LOOP);
}
class Node : public IEditable
{
BASECLASSDEF(Node, IEditable);
NOCOPYDEF(Node);
public:
std::string name;
unsigned id;
std::vector<Socket*> inputSockets;
std::vector<Socket*> outputSockets;
Socket* inputFlowSocket; // Can only have one of these, it is always a one to many
std::vector<Socket*> outputFlowSockets;
Graph* graph;
float XPos; // GUI recorded X pos
float YPos; // GUI recorded Y pos
}
struct Socket
unsigned typeID;
Node* node;
std::string name;
unsigned input : 1; // Socket is an input
unsigned output : 1; // Socket is an output
unsigned control : 1; // Socket is a control socket
unsigned variable : 1; // Socket is a variable input (may overlap with input|output for hybrid tree evaluation)
unsigned secret : 1;
}
void Graph::Node::PropogateValues(bool down)
{
// Propogate socket values
if (down)
{
for (Socket* socket : outputSockets)
{
auto edges = graph->downstreamEdges_.equal_range(socket);
for (auto edge = edges.first; edge != edges.second; ++edge)
edge->first->StoreValue(edge->second->GetValue());
}
}
else
{
for (Socket* socket : inputSockets)
{
auto upstreamEdges = graph->upstreamEdges_.equal_range(socket);
for (auto edge = upstreamEdges.first; edge != upstreamEdges.second && edge != graph->upstreamEdges_.end(); ++edge)
edge->first->StoreValue(edge->second->GetValue());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment