use strings to connect nodes

This makes the node system somewhat more high-level with the intent of making
working with them far more flexible and stable. By making the architecture more
abstracted, it becomes far less rigid which should allow us to do even more
with it and make it much less crash prone.
This commit is contained in:
itsmattkc
2021-02-09 15:48:37 +11:00
parent d1a3e22eaa
commit 81c1922911
138 changed files with 4487 additions and 3913 deletions
+655 -72
View File
@@ -21,6 +21,7 @@
#ifndef NODE_H
#define NODE_H
#include <map>
#include <QCryptographicHash>
#include <QObject>
#include <QPainter>
@@ -30,15 +31,17 @@
#include "codec/frame.h"
#include "codec/samplebuffer.h"
#include "common/rational.h"
#include "common/timerange.h"
#include "common/xmlutils.h"
#include "node/connectable.h"
#include "node/input.h"
#include "node/value.h"
#include "node/keyframe.h"
#include "node/inputimmediate.h"
#include "node/param.h"
#include "render/audioparams.h"
#include "render/job/generatejob.h"
#include "render/job/samplejob.h"
#include "render/job/shaderjob.h"
#include "render/shadercode.h"
#include "splitvalue.h"
namespace olive {
@@ -58,7 +61,7 @@ class NodeGraph;
* This is a simple base class designed to contain all the functionality for this kind of processing connective unit.
* It is an abstract class intended to be subclassed to create nodes with actual functionality.
*/
class Node : public NodeConnectable
class Node : public QObject
{
Q_OBJECT
public:
@@ -80,7 +83,7 @@ public:
kCategoryCount
};
Node();
Node(bool create_default_output = true);
virtual ~Node() override;
@@ -154,6 +157,31 @@ public:
*/
virtual void Retranslate();
const QVector<QString>& inputs() const
{
return input_ids_;
}
const QVector<QString>& outputs() const
{
return outputs_;
}
bool HasInputWithID(const QString& id) const
{
return input_ids_.contains(id);
}
bool HasOutputWithID(const QString& id) const
{
return outputs_.contains(id);
}
bool HasParamWithID(const QString& id) const
{
return HasInputWithID(id) || HasOutputWithID(id);
}
/**
* @brief Retrieve the color of this node
*/
@@ -180,26 +208,266 @@ public:
}
}
/**
* @brief Return a list of NodeParams
*/
const QVector<NodeInput*>& parameters() const
static void ConnectEdge(const NodeOutput& output, const NodeInput& input);
static void DisconnectEdge(const NodeOutput& output, const NodeInput& input);
QString GetInputName(const QString& id) const;
void LoadInput(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled);
void SaveInput(QXmlStreamWriter* writer, const QString& id) const;
bool IsInputConnectable(const QString& input) const;
bool IsInputKeyframable(const QString& input) const;
bool IsInputKeyframing(const QString& input, int element = -1) const;
bool IsInputKeyframing(const NodeInput& input) const
{
return inputs_;
return IsInputKeyframing(input.input(), input.element());
}
const QVector<NodeInput*>& inputs() const
void SetInputIsKeyframing(const QString& input, bool e, int element = -1);
void SetInputIsKeyframing(const NodeInput& input, bool e)
{
return inputs_;
SetInputIsKeyframing(input.input(), e, input.element());
}
/**
* @brief Return the index of a parameter
* @return Parameter index or -1 if this parameter is not part of this Node
*/
int IndexOfParameter(NodeInput* param) const
bool IsInputConnected(const QString& input, int element = -1) const;
bool IsInputConnected(const NodeInput& input) const
{
return inputs_.indexOf(param);
return IsInputConnected(input.input(), input.element());
}
bool IsInputStatic(const QString& input, int element = -1) const
{
return !IsInputConnected(input, element) && !IsInputKeyframing(input, element);
}
bool IsInputStatic(const NodeInput& input) const
{
return IsInputStatic(input.input(), input.element());
}
NodeOutput GetConnectedOutput(const QString& input, int element = -1) const;
NodeOutput GetConnectedOutput(const NodeInput& input) const
{
return GetConnectedOutput(input.input(), input.element());
}
Node* GetConnectedNode(const QString& input, int element = -1) const
{
return GetConnectedOutput(input, element).node();
}
Node* GetConnectedNode(const NodeInput& input) const
{
return GetConnectedNode(input.input(), input.element());
}
bool IsUsingStandardValue(const QString& input, int track, int element = -1) const;
NodeValue::Type GetInputDataType(const QString& id) const;
void SetInputDataType(const QString& id, const NodeValue::Type& type);
bool HasInputProperty(const QString& id, const QString& name) const;
QHash<QString, QVariant> GetInputProperties(const QString& id) const;
QVariant GetInputProperty(const QString& id, const QString& name) const;
void SetInputProperty(const QString& id, const QString& name, const QVariant& value);
QVariant GetValueAtTime(const QString& input, const rational& time, int element = -1) const
{
NodeValue::Type type = GetInputDataType(input);
return NodeValue::combine_track_values_into_normal_value(type, GetSplitValueAtTime(input, time, element));
}
QVariant GetValueAtTime(const NodeInput& input, const rational& time)
{
return GetValueAtTime(input.input(), time, input.element());
}
SplitValue GetSplitValueAtTime(const QString& input, const rational& time, int element = -1) const;
SplitValue GetSplitValueAtTime(const NodeInput& input, const rational& time)
{
return GetSplitValueAtTime(input.input(), time, input.element());
}
QVariant GetSplitValueAtTimeOnTrack(const QString& input, const rational& time, int track, int element = -1) const;
QVariant GetSplitValueAtTimeOnTrack(const NodeInput& input, const rational& time, int track) const
{
return GetSplitValueAtTimeOnTrack(input.input(), time, track, input.element());
}
QVariant GetSplitValueAtTimeOnTrack(const NodeKeyframeTrackReference& input, const rational& time) const
{
return GetSplitValueAtTimeOnTrack(input.input(), time, input.track());
}
QVariant GetDefaultValue(const QString& input) const;
SplitValue GetSplitDefaultValue(const QString& input) const;
QVariant GetSplitDefaultValueOnTrack(const QString& input, int track) const;
const QVector<NodeKeyframeTrack>& GetKeyframeTracks(const QString& input, int element) const;
const QVector<NodeKeyframeTrack>& GetKeyframeTracks(const NodeInput& input) const
{
return GetKeyframeTracks(input.input(), input.element());
}
QVector<NodeKeyframe*> GetKeyframesAtTime(const QString& input, const rational& time, int element = -1) const;
QVector<NodeKeyframe*> GetKeyframesAtTime(const NodeInput& input, const rational& time) const
{
return GetKeyframesAtTime(input.input(), time, input.element());
}
NodeKeyframe* GetKeyframeAtTimeOnTrack(const QString& input, const rational& time, int track, int element = -1) const;
NodeKeyframe* GetKeyframeAtTimeOnTrack(const NodeInput& input, const rational& time, int track) const
{
return GetKeyframeAtTimeOnTrack(input.input(), time, track, input.element());
}
NodeKeyframe* GetKeyframeAtTimeOnTrack(const NodeKeyframeTrackReference& input, const rational& time) const
{
return GetKeyframeAtTimeOnTrack(input.input(), time, input.track());
}
NodeKeyframe::Type GetBestKeyframeTypeForTimeOnTrack(const QString& input, const rational& time, int track, int element = -1) const;
NodeKeyframe::Type GetBestKeyframeTypeForTimeOnTrack(const NodeInput& input, const rational& time, int track) const
{
return GetBestKeyframeTypeForTimeOnTrack(input.input(), time, track, input.element());
}
NodeKeyframe::Type GetBestKeyframeTypeForTimeOnTrack(const NodeKeyframeTrackReference& input, const rational& time) const
{
return GetBestKeyframeTypeForTimeOnTrack(input.input(), time, input.track());
}
int GetNumberOfKeyframeTracks(const QString& id) const;
int GetNumberOfKeyframeTracks(const NodeInput& id) const
{
return GetNumberOfKeyframeTracks(id.input());
}
NodeKeyframe* GetEarliestKeyframe(const QString& id, int element = -1) const;
NodeKeyframe* GetEarliestKeyframe(const NodeInput& id) const
{
return GetEarliestKeyframe(id.input(), id.element());
}
NodeKeyframe* GetLatestKeyframe(const QString& id, int element = -1) const;
NodeKeyframe* GetLatestKeyframe(const NodeInput& id) const
{
return GetLatestKeyframe(id.input(), id.element());
}
NodeKeyframe* GetClosestKeyframeBeforeTime(const QString& id, const rational& time, int element = -1) const;
NodeKeyframe* GetClosestKeyframeBeforeTime(const NodeInput& id, const rational& time) const
{
return GetClosestKeyframeBeforeTime(id.input(), time, id.element());
}
NodeKeyframe* GetClosestKeyframeAfterTime(const QString& id, const rational& time, int element = -1) const;
NodeKeyframe* GetClosestKeyframeAfterTime(const NodeInput& id, const rational& time) const
{
return GetClosestKeyframeAfterTime(id.input(), time, id.element());
}
bool HasKeyframeAtTime(const QString& id, const rational& time, int element = -1) const;
bool HasKeyframeAtTime(const NodeInput& id, const rational& time) const
{
return HasKeyframeAtTime(id.input(), time, id.element());
}
QStringList GetComboBoxStrings(const QString& id) const;
QVariant GetStandardValue(const QString& id, int element = -1) const;
QVariant GetStandardValue(const NodeInput& id) const
{
return GetStandardValue(id.input(), id.element());
}
SplitValue GetSplitStandardValue(const QString& id, int element = -1) const;
SplitValue GetSplitStandardValue(const NodeInput& id) const
{
return GetSplitStandardValue(id.input(), id.element());
}
QVariant GetSplitStandardValueOnTrack(const QString& input, int track, int element = -1) const;
QVariant GetSplitStandardValueOnTrack(const NodeKeyframeTrackReference& id) const
{
return GetSplitStandardValueOnTrack(id.input().input(), id.track(), id.input().element());
}
void SetStandardValue(const QString& id, const QVariant& value, int element = -1);
void SetStandardValue(const NodeInput& id, const QVariant& value)
{
SetStandardValue(id.input(), value, id.element());
}
void SetSplitStandardValue(const QString& id, const SplitValue& value, int element = -1);
void SetSplitStandardValue(const NodeInput& id, const SplitValue& value)
{
SetSplitStandardValue(id.input(), value, id.element());
}
void SetSplitStandardValueOnTrack(const QString& id, int track, const QVariant& value, int element = -1);
void SetSplitStandardValueOnTrack(const NodeKeyframeTrackReference& id, const QVariant& value)
{
SetSplitStandardValueOnTrack(id.input().input(), id.track(), value, id.input().element());
}
bool InputIsArray(const QString& id) const;
void InputArrayInsert(const QString& id, int index, bool undoable = false);
void InputArrayResize(const QString& id, int size, bool undoable = false);
void InputArrayRemove(const QString& id, int index, bool undoable = false);
void InputArrayAppend(const QString& id, bool undoable = false)
{
InputArrayResize(id, InputArraySize(id) + 1, undoable);
}
void InputArrayPrepend(const QString& id, bool undoable = false)
{
InputArrayInsert(id, 0, undoable);
}
void InputArrayRemoveLast(const QString& id, bool undoable = false)
{
InputArrayResize(id, InputArraySize(id) - 1, undoable);
}
int InputArraySize(const QString& id) const;
const NodeKeyframeTrack& GetTrackFromKeyframe(NodeKeyframe* key) const;
using InputConnections = std::map<NodeInput, NodeOutput>;
/**
* @brief Return map of input connections
*
* Inputs can only have one connection, so the key is the input connected and the value is the
* output that it's connected to.
*/
const InputConnections& input_connections() const
{
return input_connections_;
}
using OutputConnection = std::pair<NodeOutput, NodeInput>;
using OutputConnections = std::vector<OutputConnection>;
/**
* @brief Return list of output connections
*
* An output can connect an infinite amount of inputs, so in this map, the key is the output and
* the value is a vector of inputs.
*/
const OutputConnections& output_connections() const
{
return output_connections_;
}
/**
@@ -239,11 +507,6 @@ public:
*/
virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const;
/**
* @brief Returns the input with the specified ID (or nullptr if it doesn't exist)
*/
NodeInput* GetInputWithID(const QString& id) const;
/**
* @brief Returns whether this Node outputs to `n`
*
@@ -257,7 +520,6 @@ public:
* (FALSE).
*/
bool OutputsTo(Node* n, bool recursively) const;
/**
* @brief Same as OutputsTo(Node*), but for a node ID rather than a specific instance.
*/
@@ -266,7 +528,7 @@ public:
/**
* @brief Same as OutputsTo(Node*), but for a specific node input rather than just a node.
*/
bool OutputsTo(NodeInput* input, bool recursively) const;
bool OutputsTo(const NodeInput &input, bool recursively) const;
/**
* @brief Returns whether this node ever receives an input from a particular node instance
@@ -330,7 +592,11 @@ public:
* the DAG. Even if the time needs to be transformed somehow (e.g. converting media time to sequence time), you can
* call this function with transformed time and relay the signal that way.
*/
virtual void InvalidateCache(const TimeRange& range, const InputConnection& from = InputConnection());
virtual void InvalidateCache(const TimeRange& range, const QString& from, int element = -1);
void InvalidateCache(const TimeRange& range, const NodeInput& from)
{
InvalidateCache(range, from.input(), from.element());
}
/**
* @brief Limits cache invalidation temporarily
@@ -351,12 +617,12 @@ public:
* If this node modifies the `time` (i.e. a clip converting sequence time to media time), this function should be
* overridden to do so. Also make sure to override OutputTimeAdjustment() to provide the inverse function.
*/
virtual TimeRange InputTimeAdjustment(NodeInput* input, int element, const TimeRange& input_time) const;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const;
/**
* @brief The inverse of InputTimeAdjustment()
*/
virtual TimeRange OutputTimeAdjustment(NodeInput* input, int element, const TimeRange& input_time) const;
virtual TimeRange OutputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const;
/**
* @brief Copies inputs from from Node to another including connections
@@ -365,6 +631,14 @@ public:
*/
static void CopyInputs(Node* source, Node* destination, bool include_connections = true);
static void CopyInput(Node* src, Node* dst, const QString& input, bool include_connections, bool traverse_arrays);
static void CopyValuesOfElement(Node* src, Node* dst, const QString& input, int src_element, int dst_element);
static void CopyValuesOfElement(Node* src, Node* dst, const QString& input, int element)
{
return CopyValuesOfElement(src, dst, input, element, element);
}
/**
* @brief Clones a set of nodes and connects the new ones the way the old ones were
*/
@@ -394,12 +668,7 @@ public:
* corresponding output if it's connected to one. If your node doesn't directly deal with time, the default behavior
* of the NodeParam objects will handle everything related to it automatically.
*/
virtual NodeValueTable Value(NodeValueDatabase& value) const;
/**
* @brief Return whether a parameter with ID `id` has already been added to this Node
*/
bool HasParamWithID(const QString& id) const;
virtual NodeValueTable Value(const QString &output, NodeValueDatabase& value) const;
const QPointF& GetPosition() const;
@@ -418,12 +687,7 @@ public:
virtual void Hash(QCryptographicHash& hash, const rational &time) const;
const std::vector<InputConnection>& edges() const
{
return output_connections();
}
void InvalidateAll(NodeInput *input, int element);
void InvalidateAll(const QString& input, int element = -1);
bool HasLinks() const
{
@@ -439,7 +703,58 @@ public:
static bool Unlink(Node* a, Node* b);
static bool AreLinked(Node* a, Node* b);
static const QString kDefaultOutput;
protected:
enum InputFlag {
/// By default, inputs are keyframable, connectable, and NOT arrays
kInputFlagNormal = 0x0,
kInputFlagArray = 0x1,
kInputFlagNotKeyframable = 0x2,
kInputFlagNotConnectable = 0x4
};
class InputFlags {
public:
explicit InputFlags()
{
f_ = kInputFlagNormal;
}
explicit InputFlags(uint64_t flags)
{
f_ = flags;
}
bool operator&(const InputFlag& f) const
{
return f_ & f;
}
private:
uint64_t f_;
};
void AddInput(const QString& id, NodeValue::Type type, const QVariant& default_value, InputFlags flags = InputFlags(kInputFlagNormal));
void AddInput(const QString& id, NodeValue::Type type, InputFlags flags = InputFlags(kInputFlagNormal))
{
AddInput(id, type, QVariant(), flags);
}
void RemoveInput(const QString& id);
void AddOutput(const QString& id = kDefaultOutput);
void RemoveOutput(const QString& id);
void SetInputName(const QString& id, const QString& name);
void SetComboBoxStrings(const QString& id, const QStringList& strings)
{
SetInputProperty(id, QStringLiteral("combo_str"), strings);
}
void SendInvalidateCache(const TimeRange &range);
/**
@@ -449,14 +764,14 @@ protected:
* parameters has changed throughout the duration of the clip (essential from 0 to infinity).
* In some scenarios, it may be preferable to handle this signal separately in order to
*/
void IgnoreInvalidationsFrom(NodeInput* input);
void IgnoreInvalidationsFrom(const QString &input_id);
void IgnoreHashingFrom(const QString& input_id);
virtual void LoadInternal(QXmlStreamReader* reader, XMLNodeData& xml_node_data);
virtual void SaveInternal(QXmlStreamWriter* writer) const;
virtual QVector<NodeInput*> GetInputsToHash() const;
enum GizmoScaleHandles {
kGizmoScaleTopLeft,
kGizmoScaleTopCenter,
@@ -475,10 +790,16 @@ protected:
static void DrawAndExpandGizmoHandles(QPainter* p, int handle_radius, QRectF* rects, int count);
virtual void childEvent(QChildEvent* event) override;
virtual void LinkChangeEvent(){}
virtual void InputValueChangedEvent(const QString& input, int element);
virtual void InputConnectedEvent(const QString& input, int element, const NodeOutput& output);
virtual void InputDisconnectedEvent(const QString& input, int element, const NodeOutput& output);
virtual void childEvent(QChildEvent *event) override;
signals:
/**
* @brief Signal emitted whenever the position is set through SetPosition()
@@ -492,19 +813,231 @@ signals:
void ColorChanged();
void ValueChanged(NodeInput* input, int element);
void ValueChanged(const NodeInput& input, const TimeRange& range);
void InputConnected(Node* output, NodeInput* input, int element);
void InputConnected(const NodeOutput& output, const NodeInput& input);
void InputDisconnected(Node* output, NodeInput* input, int element);
void InputDisconnected(const NodeOutput& output, const NodeInput& input);
void OutputConnected(NodeInput* destination, int element);
void OutputConnected(const NodeOutput& output, const NodeInput& input);
void OutputDisconnected(NodeInput* destination, int element);
void OutputDisconnected(const NodeOutput& output, const NodeInput& input);
void InputPropertyChanged(const QString& input, const QString& key, const QVariant& value);
void LinksChanged();
void InputArraySizeChanged(const QString& input, int new_size);
void KeyframeAdded(NodeKeyframe* key);
void KeyframeRemoved(NodeKeyframe* key);
void KeyframeTimeChanged();
void KeyframeEnableChanged(const NodeInput& input, bool enabled);
void InputAdded(const QString& id);
void InputRemoved(const QString& id);
void OutputAdded(const QString& id);
void OutputRemoved(const QString& id);
void InputNameChanged(const QString& id, const QString& name);
void InputDataTypeChanged(const QString& id, NodeValue::Type type);
private:
class ArrayInsertCommand : public UndoCommand
{
public:
ArrayInsertCommand(Node* node, const QString& input, int index) :
node_(node),
input_(input),
index_(index)
{
}
virtual Project* GetRelevantProject() const override;
virtual void redo() override
{
node_->InputArrayInsert(input_, index_, false);
}
virtual void undo() override
{
node_->InputArrayRemove(input_, index_, false);
}
private:
Node* node_;
QString input_;
int index_;
};
class ArrayRemoveCommand : public UndoCommand
{
public:
ArrayRemoveCommand(Node* node, const QString& input, int index) :
node_(node),
input_(input),
index_(index)
{
}
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo() override
{
// Save immediate data
if (node_->IsInputKeyframable(input_)) {
is_keyframing_ = node_->IsInputKeyframing(input_, index_);
}
standard_value_ = node_->GetSplitStandardValue(input_, index_);
keyframes_ = node_->GetKeyframeTracks(input_, index_);
node_->GetImmediate(input_, index_)->delete_all_keyframes(&memory_manager_);
node_->InputArrayRemove(input_, index_, false);
}
virtual void undo() override
{
node_->InputArrayInsert(input_, index_, false);
// Restore keyframes
foreach (const NodeKeyframeTrack& track, keyframes_) {
foreach (NodeKeyframe* key, track) {
key->setParent(node_);
}
}
node_->SetSplitStandardValue(input_, standard_value_, index_);
if (node_->IsInputKeyframable(input_)) {
node_->SetInputIsKeyframing(input_, is_keyframing_, index_);
}
}
private:
Node* node_;
QString input_;
int index_;
SplitValue standard_value_;
bool is_keyframing_;
QVector<NodeKeyframeTrack> keyframes_;
QObject memory_manager_;
};
class ArrayResizeCommand : public UndoCommand
{
public:
ArrayResizeCommand(Node* node, const QString& input, int size) :
node_(node),
input_(input),
size_(size)
{}
virtual void redo() override
{
old_size_ = node_->GetInternalInputArraySize(input_);
if (old_size_ > size_) {
// Decreasing in size, disconnect any extraneous edges
for (int i=size_; i<old_size_; i++) {
try {
NodeInput input(node_, input_, i);
NodeOutput output = node_->input_connections().at(input);
removed_connections_[input] = output;
DisconnectEdge(output, input);
} catch (std::out_of_range&) {}
}
}
node_->ArrayResizeInternal(input_, size_);
}
virtual void undo() override
{
for (auto it=removed_connections_.cbegin(); it!=removed_connections_.cend(); it++) {
ConnectEdge(it->second, it->first);
}
removed_connections_.clear();
node_->ArrayResizeInternal(input_, old_size_);
}
virtual Project* GetRelevantProject() const override;
private:
Node* node_;
QString input_;
int size_;
int old_size_;
InputConnections removed_connections_;
};
struct Input {
NodeValue::Type type;
InputFlags flags;
SplitValue default_value;
QHash<QString, QVariant> properties;
QString human_name;
int array_size;
};
NodeInputImmediate* CreateImmediate(const QString& input);
NodeInputImmediate* GetImmediate(const QString& input, int element) const;
int GetInternalInputIndex(const QString& input) const
{
return input_ids_.indexOf(input);
}
InputFlags GetInputFlags(const QString& input) const;
Input* GetInternalInputData(const QString& input)
{
int i = GetInternalInputIndex(input);
if (i == -1) {
return nullptr;
} else {
return &input_data_[i];
}
}
const Input* GetInternalInputData(const QString& input) const
{
int i = GetInternalInputIndex(input);
if (i == -1) {
return nullptr;
} else {
return &input_data_.at(i);
}
}
void ReportInvalidInput(const char* attempted_action, const QString &id) const;
void ArrayResizeInternal(const QString& id, int size);
/**
* @brief Immediates aren't deleted, so the actual array size may be larger than ArraySize()
*/
int GetInternalInputArraySize(const QString& input);
template<class T>
static void FindInputNodeInternal(const Node* n, QVector<T *>& list);
@@ -513,11 +1046,29 @@ private:
QVector<Node*> GetDependenciesInternal(bool traverse, bool exclusive_only) const;
void HashInputElement(QCryptographicHash& hash, NodeInput* input, int element, const rational& time) const;
void HashInputElement(QCryptographicHash& hash, const QString &input, int element, const rational& time) const;
QVector<NodeInput*> inputs_;
void ParameterValueChanged(const QString &input, int element, const olive::TimeRange &range);
QVector<NodeInput*> ignore_connections_;
void LoadImmediate(QXmlStreamReader *reader, const QString& input, int element, XMLNodeData& xml_node_data, const QAtomicInt* cancelled);
void SaveImmediate(QXmlStreamWriter *writer, const QString &input, int element) const;
/**
* @brief Intelligently determine how what time range is affected by a keyframe
*/
TimeRange GetRangeAffectedByKeyframe(NodeKeyframe *key) const;
/**
* @brief Gets a time range between the previous and next keyframes of index
*/
TimeRange GetRangeAroundIndex(const QString& input, int index, int track, int element) const;
void ClearElement(const QString &input, int index);
QVector<QString> ignore_connections_;
QVector<QString> ignore_when_hashing_;
/**
* @brief Internal variable for whether this Node can be deleted or not
@@ -544,29 +1095,59 @@ private:
*/
QVector<Node*> links_;
QVector<QString> input_ids_;
QVector<Input> input_data_;
QVector<QString> outputs_;
QMap<QString, NodeInputImmediate*> standard_immediates_;
QMap<QString, QVector<NodeInputImmediate*> > array_immediates_;
InputConnections input_connections_;
OutputConnections output_connections_;
private slots:
void ParameterValueChanged(const olive::TimeRange &range, int element);
/**
* @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time
*/
void InvalidateFromKeyframeTimeChange();
void ParameterConnected(Node* source, int element);
/**
* @brief Slot when a keyframe's value changes to signal that the cache needs updating
*/
void InvalidateFromKeyframeValueChange();
void ParameterDisconnected(Node* source, int element);
/**
* @brief Slot when a keyframe's type changes to signal that the cache needs updating
*/
void InvalidateFromKeyframeTypeChanged();
/**
* @brief Slot when a keyframe's bezier in value changes to signal that the cache needs updating
*/
void InvalidateFromKeyframeBezierInChange();
/**
* @brief Slot when a keyframe's bezier out value changes to signal that the cache needs updating
*/
void InvalidateFromKeyframeBezierOutChange();
};
template<class T>
void Node::FindInputNodeInternal(const Node* n, QVector<T *> &list)
{
foreach (NodeInput* input, n->inputs_) {
for (auto it=input->edges().cbegin(); it!=input->edges().cend(); it++) {
Node* edge = it->second;
T* cast_test = dynamic_cast<T*>(edge);
for (auto it=n->input_connections_.cbegin(); it!=n->input_connections_.cend(); it++) {
Node* edge = it->second.node();
T* cast_test = dynamic_cast<T*>(edge);
if (cast_test) {
list.append(cast_test);
}
FindInputNodeInternal<T>(edge, list);
if (cast_test) {
list.append(cast_test);
}
FindInputNodeInternal<T>(edge, list);
}
}
@@ -589,15 +1170,17 @@ T* Node::ValueToPtr(const QVariant &ptr)
template<class T>
void Node::FindOutputNodeInternal(const Node* n, QVector<T *>& list)
{
foreach (const InputConnection& edge, n->edges()) {
Node* connected = static_cast<Node*>(edge.input->parent());
T* cast_test = dynamic_cast<T*>(connected);
foreach (const std::vector<NodeInput>& outputs, n->output_connections_) {
foreach (const NodeInput& output, outputs) {
Node* connected = output.node();
T* cast_test = dynamic_cast<T*>(connected);
if (cast_test) {
list.append(cast_test);
if (cast_test) {
list.append(cast_test);
}
FindOutputNodeInternal<T>(connected);
}
FindOutputNodeInternal<T>(connected);
}
}