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
+37 -39
View File
@@ -28,6 +28,11 @@
namespace olive {
const QString Block::kLengthInput = QStringLiteral("length_in");
const QString Block::kMediaInInput = QStringLiteral("media_in_in");
const QString Block::kEnabledInput = QStringLiteral("enabled_in");
const QString Block::kSpeedInput = QStringLiteral("speed_in");
Block::Block() :
previous_(nullptr),
next_(nullptr),
@@ -36,24 +41,18 @@ Block::Block() :
in_transition_(nullptr),
out_transition_(nullptr)
{
length_input_ = new NodeInput(this, QStringLiteral("length_in"), NodeValue::kRational);
length_input_->SetConnectable(false);
length_input_->SetKeyframable(false);
IgnoreInvalidationsFrom(length_input_);
connect(length_input_, &NodeInput::ValueChanged, this, &Block::LengthChanged);
AddInput(kLengthInput, NodeValue::kRational, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
IgnoreInvalidationsFrom(kLengthInput);
IgnoreHashingFrom(kLengthInput);
media_in_input_ = new NodeInput(this, QStringLiteral("media_in_in"), NodeValue::kRational);
media_in_input_->SetConnectable(false);
media_in_input_->SetKeyframable(false);
AddInput(kMediaInInput, NodeValue::kRational, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
IgnoreHashingFrom(kMediaInInput);
enabled_input_ = new NodeInput(this, QStringLiteral("enabled_in"), NodeValue::kBoolean);
enabled_input_->SetConnectable(false);
enabled_input_->SetKeyframable(false);
enabled_input_->SetStandardValue(true);
AddInput(kEnabledInput, NodeValue::kBoolean, true, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
speed_input_ = new NodeInput(this, QStringLiteral("speed_in"), NodeValue::kFloat);
speed_input_->SetStandardValue(1.0);
speed_input_->setProperty("view", FloatSlider::kPercentage);
AddInput(kSpeedInput, NodeValue::kFloat, 1.0);
SetInputProperty(kSpeedInput, QStringLiteral("view"), FloatSlider::kPercentage);
IgnoreHashingFrom(kSpeedInput);
// A block's length must be greater than 0
set_length_and_media_out(1);
@@ -66,7 +65,7 @@ QVector<Node::CategoryID> Block::Category() const
rational Block::length() const
{
return length_input_->GetStandardValue().value<rational>();
return GetStandardValue(kLengthInput).value<rational>();
}
void Block::set_length_and_media_out(const rational &length)
@@ -97,22 +96,22 @@ void Block::set_length_and_media_in(const rational &length)
rational Block::media_in() const
{
return media_in_input_->GetStandardValue().value<rational>();
return GetStandardValue(kMediaInInput).value<rational>();
}
void Block::set_media_in(const rational &media_in)
{
media_in_input_->SetStandardValue(QVariant::fromValue(media_in));
SetStandardValue(kMediaInInput, QVariant::fromValue(media_in));
}
bool Block::is_enabled() const
{
return enabled_input_->GetStandardValue().toBool();
return GetStandardValue(kEnabledInput).toBool();
}
void Block::set_enabled(bool e)
{
enabled_input_->SetStandardValue(e);
SetStandardValue(kEnabledInput, e);
emit EnabledChanged();
}
@@ -127,10 +126,8 @@ rational Block::SequenceToMediaTime(const rational &sequence_time) const
rational local_time = sequence_time;
// FIXME: Doesn't handle reversing
if (speed_input_->IsKeyframing() || speed_input_->IsConnected()) {
// FIXME: We'll need to calculate the speed hoo boy
} else {
double speed_value = speed_input_->GetStandardValue().toDouble();
if (IsInputStatic(kSpeedInput)) {
double speed_value = GetStandardValue(kSpeedInput).toDouble();
if (qIsNull(speed_value)) {
// Effectively holds the frame at the in point
@@ -139,6 +136,8 @@ rational Block::SequenceToMediaTime(const rational &sequence_time) const
// Multiply time
local_time = rational::fromDouble(local_time.toDouble() * speed_value);
}
} else {
// FIXME: We'll need to calculate the speed hoo boy
}
return local_time + media_in();
@@ -154,10 +153,10 @@ rational Block::MediaToSequenceTime(const rational &media_time) const
rational sequence_time = media_time - media_in();
// FIXME: Doesn't handle reversing
if (speed_input_->IsKeyframing() || speed_input_->IsConnected()) {
if (IsInputKeyframing(kSpeedInput) || IsInputConnected(kSpeedInput)) {
// FIXME: We'll need to calculate the speed hoo boy
} else {
double speed_value = speed_input_->GetStandardValue().toDouble();
double speed_value = GetStandardValue(kSpeedInput).toDouble();
if (qIsNull(speed_value)) {
// Effectively holds the frame at the in point, also prevents divide by zero
@@ -171,16 +170,15 @@ rational Block::MediaToSequenceTime(const rational &media_time) const
return sequence_time;
}
QVector<NodeInput *> Block::GetInputsToHash() const
void Block::InputValueChangedEvent(const QString &input, int element)
{
QVector<NodeInput*> inputs = Node::GetInputsToHash();
Q_UNUSED(element)
// Ignore these inputs
inputs.removeOne(media_in_input_);
inputs.removeOne(speed_input_);
inputs.removeOne(length_input_);
return inputs;
if (input == kLengthInput) {
emit LengthChanged();
} else if (input == kEnabledInput) {
emit EnabledChanged();
}
}
void Block::LinkChangeEvent()
@@ -198,17 +196,17 @@ void Block::LinkChangeEvent()
void Block::set_length_internal(const rational &length)
{
length_input_->SetStandardValue(QVariant::fromValue(length));
SetStandardValue(kLengthInput, QVariant::fromValue(length));
}
void Block::Retranslate()
{
Node::Retranslate();
length_input_->set_name(tr("Length"));
media_in_input_->set_name(tr("Media In"));
enabled_input_->set_name(tr("Enabled"));
speed_input_->set_name(tr("Speed"));
SetInputName(kLengthInput, tr("Length"));
SetInputName(kMediaInInput, tr("Media In"));
SetInputName(kEnabledInput, tr("Enabled"));
SetInputName(kSpeedInput, tr("Speed"));
}
void Block::Hash(QCryptographicHash &, const rational &) const
+6 -21
View File
@@ -114,21 +114,6 @@ public:
virtual void Retranslate() override;
NodeInput* length_input() const
{
return length_input_;
}
NodeInput* media_in_input() const
{
return media_in_input_;
}
NodeInput* speed_input() const
{
return speed_input_;
}
TransitionBlock* in_transition()
{
return in_transition_;
@@ -166,6 +151,11 @@ public:
virtual void Hash(QCryptographicHash &hash, const rational &time) const override;
static const QString kLengthInput;
static const QString kMediaInInput;
static const QString kEnabledInput;
static const QString kSpeedInput;
public slots:
signals:
@@ -178,7 +168,7 @@ protected:
rational MediaToSequenceTime(const rational& media_time) const;
virtual QVector<NodeInput*> GetInputsToHash() const override;
virtual void InputValueChangedEvent(const QString& input, int element) override;
virtual void LinkChangeEvent() override;
@@ -188,11 +178,6 @@ protected:
private:
void set_length_internal(const rational &length);
NodeInput* length_input_;
NodeInput* media_in_input_;
NodeInput* speed_input_;
NodeInput* enabled_input_;
rational in_point_;
rational out_point_;
Track* track_;
+18 -18
View File
@@ -22,10 +22,11 @@
namespace olive {
const QString ClipBlock::kBufferIn = QStringLiteral("buffer_in");
ClipBlock::ClipBlock()
{
texture_input_ = new NodeInput(this, QStringLiteral("buffer_in"), NodeValue::kNone);
texture_input_->SetKeyframable(false);
AddInput(kBufferIn, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable));
}
Node *ClipBlock::copy() const
@@ -53,15 +54,12 @@ QString ClipBlock::Description() const
return tr("A time-based node that represents a media source.");
}
NodeInput *ClipBlock::texture_input() const
void ClipBlock::InvalidateCache(const TimeRange& range, const QString& from, int element)
{
return texture_input_;
}
Q_UNUSED(element)
void ClipBlock::InvalidateCache(const TimeRange& range, const InputConnection& from)
{
// If signal is from texture input, transform all times from media time to sequence time
if (from.input == texture_input_) {
if (from == kBufferIn) {
// Adjust range from media time to sequence time
rational start = MediaToSequenceTime(range.in());
rational end = MediaToSequenceTime(range.out());
@@ -73,32 +71,34 @@ void ClipBlock::InvalidateCache(const TimeRange& range, const InputConnection& f
}
}
TimeRange ClipBlock::InputTimeAdjustment(NodeInput *input, int element, const TimeRange &input_time) const
TimeRange ClipBlock::InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const
{
Q_UNUSED(element)
if (input == texture_input_) {
if (input == kBufferIn) {
return TimeRange(SequenceToMediaTime(input_time.in()), SequenceToMediaTime(input_time.out()));
}
return Block::InputTimeAdjustment(input, element, input_time);
}
TimeRange ClipBlock::OutputTimeAdjustment(NodeInput *input, int element, const TimeRange &input_time) const
TimeRange ClipBlock::OutputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const
{
Q_UNUSED(element)
if (input == texture_input_) {
if (input == kBufferIn) {
return TimeRange(MediaToSequenceTime(input_time.in()), MediaToSequenceTime(input_time.out()));
}
return Block::OutputTimeAdjustment(input, element, input_time);
}
NodeValueTable ClipBlock::Value(NodeValueDatabase &value) const
NodeValueTable ClipBlock::Value(const QString &output, NodeValueDatabase &value) const
{
Q_UNUSED(output)
// We discard most values here except for the buffer we received
NodeValue data = value[texture_input()].GetWithMeta(NodeValue::kBuffer);
NodeValue data = value[kBufferIn].GetWithMeta(NodeValue::kBuffer);
NodeValueTable table;
if (data.type() != NodeValue::kNone) {
@@ -111,15 +111,15 @@ void ClipBlock::Retranslate()
{
Block::Retranslate();
texture_input_->set_name(tr("Buffer"));
SetInputName(kBufferIn, tr("Buffer"));
}
void ClipBlock::Hash(QCryptographicHash &hash, const rational &time) const
{
if (texture_input_->IsConnected()) {
rational t = InputTimeAdjustment(texture_input_, -1, TimeRange(time, time)).in();
if (IsInputConnected(kBufferIn)) {
rational t = InputTimeAdjustment(kBufferIn, -1, TimeRange(time, time)).in();
texture_input_->GetConnectedNode()->Hash(hash, t);
GetConnectedNode(kBufferIn)->Hash(hash, t);
}
}
+5 -8
View File
@@ -42,22 +42,19 @@ public:
virtual QString id() const override;
virtual QString Description() const override;
NodeInput* texture_input() const;
virtual void InvalidateCache(const TimeRange& range, const QString& from, int element = -1) override;
virtual void InvalidateCache(const TimeRange& range, const InputConnection& from) override;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
virtual TimeRange InputTimeAdjustment(NodeInput* input, int element, const TimeRange& input_time) const override;
virtual TimeRange OutputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
virtual TimeRange OutputTimeAdjustment(NodeInput* input, int element, const TimeRange& input_time) const override;
virtual NodeValueTable Value(NodeValueDatabase& value) const override;
virtual NodeValueTable Value(const QString& output, NodeValueDatabase& value) const override;
virtual void Retranslate() override;
virtual void Hash(QCryptographicHash &hash, const rational &time) const override;
private:
NodeInput* texture_input_;
static const QString kBufferIn;
};
-2
View File
@@ -42,8 +42,6 @@ public:
virtual QString id() const override;
virtual QString Description() const override;
private:
};
}
@@ -61,6 +61,8 @@ ShaderCode CrossDissolveTransition::GetShaderCode(const QString &shader_id) cons
void CrossDissolveTransition::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &job) const
{
Q_UNUSED(value)
job.SetAlphaChannelRequired(true);
}
@@ -22,9 +22,11 @@
namespace olive {
const QString DipToColorTransition::kColorInput = QStringLiteral("color_in");
DipToColorTransition::DipToColorTransition()
{
color_input_ = new NodeInput(this, QStringLiteral("color_in"), NodeValue::kColor, QVariant::fromValue(Color(0, 0, 0)));
AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(0, 0, 0)));
}
Node *DipToColorTransition::copy() const
@@ -61,7 +63,7 @@ ShaderCode DipToColorTransition::GetShaderCode(const QString &shader_id) const
void DipToColorTransition::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &job) const
{
job.InsertValue(color_input_, value);
job.InsertValue(this, kColorInput, value);
}
}
@@ -40,12 +40,11 @@ public:
virtual ShaderCode GetShaderCode(const QString& shader_id) const override;
static const QString kColorInput;
protected:
virtual void ShaderJobEvent(NodeValueDatabase &value, ShaderJob& job) const override;
private:
NodeInput* color_input_;
};
}
+68 -77
View File
@@ -24,23 +24,19 @@
namespace olive {
const QString TransitionBlock::kOutBlockInput = QStringLiteral("out_block_in");
const QString TransitionBlock::kInBlockInput = QStringLiteral("in_block_in");
const QString TransitionBlock::kCurveInput = QStringLiteral("curve_in");
TransitionBlock::TransitionBlock() :
connected_out_block_(nullptr),
connected_in_block_(nullptr)
{
out_block_input_ = new NodeInput(this, QStringLiteral("out_block_in"), NodeValue::kNone);
out_block_input_->SetKeyframable(false);
connect(out_block_input_, &NodeInput::InputConnected, this, &TransitionBlock::InBlockConnected);
connect(out_block_input_, &NodeInput::InputDisconnected, this, &TransitionBlock::InBlockDisconnected);
AddInput(kOutBlockInput, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable));
in_block_input_ = new NodeInput(this, QStringLiteral("in_block_in"), NodeValue::kNone);
in_block_input_->SetKeyframable(false);
connect(in_block_input_, &NodeInput::InputConnected, this, &TransitionBlock::OutBlockConnected);
connect(in_block_input_, &NodeInput::InputDisconnected, this, &TransitionBlock::OutBlockDisconnected);
AddInput(kInBlockInput, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable));
curve_input_ = new NodeInput(this, QStringLiteral("curve_in"), NodeValue::kCombo);
curve_input_->SetKeyframable(false);
curve_input_->SetConnectable(false);
AddInput(kCurveInput, NodeValue::kCombo, InputFlags(kInputFlagNotKeyframable | kInputFlagNotConnectable));
}
Block::Type TransitionBlock::type() const
@@ -48,26 +44,16 @@ Block::Type TransitionBlock::type() const
return kTransition;
}
NodeInput *TransitionBlock::out_block_input() const
{
return out_block_input_;
}
NodeInput *TransitionBlock::in_block_input() const
{
return in_block_input_;
}
void TransitionBlock::Retranslate()
{
Block::Retranslate();
out_block_input_->set_name(tr("From"));
in_block_input_->set_name(tr("To"));
curve_input_->set_name(tr("Curve"));
SetInputName(kOutBlockInput, tr("From"));
SetInputName(kInBlockInput, tr("To"));
SetInputName(kCurveInput, tr("Curve"));
// These must correspond to the CurveType enum
curve_input_->set_combobox_strings({ tr("Linear"), tr("Exponential"), tr("Logarithmic") });
SetComboBoxStrings(kCurveInput, { tr("Linear"), tr("Exponential"), tr("Logarithmic") });
}
rational TransitionBlock::in_offset() const
@@ -169,56 +155,16 @@ void TransitionBlock::InsertTransitionTimes(AcceleratedJob *job, const double &t
NodeValue(NodeValue::kFloat, GetInProgress(time), this));
}
void TransitionBlock::OutBlockConnected(Node *node)
NodeValueTable TransitionBlock::Value(const QString &output, NodeValueDatabase &value) const
{
// If node is not a block, this will just be null
if ((connected_out_block_ = dynamic_cast<Block*>(node))) {
Q_UNUSED(output)
Q_ASSERT(connected_out_block_->type() != Block::kTransition
&& !connected_out_block_->out_transition()
&& connected_out_block_ == this->previous());
connected_out_block_->set_out_transition(this);
}
}
void TransitionBlock::OutBlockDisconnected()
{
if (connected_out_block_) {
connected_out_block_->set_in_transition(nullptr);
connected_out_block_ = nullptr;
}
}
void TransitionBlock::InBlockConnected(Node *node)
{
// If node is not a block, this will just be null
if ((connected_in_block_ = dynamic_cast<Block*>(node))) {
Q_ASSERT(connected_in_block_->type() != Block::kTransition
&& !connected_in_block_->in_transition()
&& connected_in_block_ == this->next());
connected_in_block_->set_in_transition(this);
}
}
void TransitionBlock::InBlockDisconnected()
{
if (connected_in_block_) {
connected_in_block_->set_in_transition(nullptr);
connected_in_block_ = nullptr;
}
}
NodeValueTable TransitionBlock::Value(NodeValueDatabase &value) const
{
NodeValue::Type data_type;
if (out_block_input()->IsConnected()) {
data_type = value[out_block_input()].GetWithMeta(NodeValue::kBuffer).type();
} else if (in_block_input()->IsConnected()) {
data_type = value[in_block_input()].GetWithMeta(NodeValue::kBuffer).type();
if (IsInputConnected(kOutBlockInput)) {
data_type = value[kOutBlockInput].GetWithMeta(NodeValue::kBuffer).type();
} else if (IsInputConnected(kInBlockInput)) {
data_type = value[kInBlockInput].GetWithMeta(NodeValue::kBuffer).type();
} else {
data_type = NodeValue::kNone;
}
@@ -230,9 +176,9 @@ NodeValueTable TransitionBlock::Value(NodeValueDatabase &value) const
// This must be a visual transition
ShaderJob job;
job.InsertValue(out_block_input(), value);
job.InsertValue(in_block_input(), value);
job.InsertValue(curve_input_, value);
job.InsertValue(this, kOutBlockInput, value);
job.InsertValue(this, kInBlockInput, value);
job.InsertValue(this, kCurveInput, value);
double time = value[QStringLiteral("global")].Get(NodeValue::kFloat, QStringLiteral("time_in")).toDouble();
InsertTransitionTimes(&job, time);
@@ -243,8 +189,8 @@ NodeValueTable TransitionBlock::Value(NodeValueDatabase &value) const
push_job = QVariant::fromValue(job);
} else if (data_type == NodeValue::kSamples) {
// This must be an audio transition
SampleBufferPtr from_samples = value[out_block_input()].Take(NodeValue::kSamples).value<SampleBufferPtr>();
SampleBufferPtr to_samples = value[in_block_input()].Take(NodeValue::kSamples).value<SampleBufferPtr>();
SampleBufferPtr from_samples = value[kOutBlockInput].Take(NodeValue::kSamples).value<SampleBufferPtr>();
SampleBufferPtr to_samples = value[kInBlockInput].Take(NodeValue::kSamples).value<SampleBufferPtr>();
if (from_samples || to_samples) {
double time_in = value[QStringLiteral("global")].Get(NodeValue::kFloat, QStringLiteral("time_in")).toDouble();
@@ -287,7 +233,7 @@ void TransitionBlock::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferP
double TransitionBlock::TransformCurve(double linear) const
{
switch (static_cast<CurveType>(curve_input_->GetStandardValue().toInt())) {
switch (static_cast<CurveType>(GetStandardValue(kCurveInput).toInt())) {
case kLinear:
break;
case kExponential:
@@ -301,4 +247,49 @@ double TransitionBlock::TransformCurve(double linear) const
return linear;
}
void TransitionBlock::InputConnectedEvent(const QString &input, int element, const NodeOutput &output)
{
Q_UNUSED(element)
if (input == kOutBlockInput) {
// If node is not a block, this will just be null
if ((connected_out_block_ = dynamic_cast<Block*>(output.node()))) {
Q_ASSERT(connected_out_block_->type() != Block::kTransition
&& !connected_out_block_->out_transition()
&& connected_out_block_ == this->previous());
connected_out_block_->set_out_transition(this);
}
} else if (input == kInBlockInput) {
// If node is not a block, this will just be null
if ((connected_in_block_ = dynamic_cast<Block*>(output.node()))) {
Q_ASSERT(connected_in_block_->type() != Block::kTransition
&& !connected_in_block_->in_transition()
&& connected_in_block_ == this->next());
connected_in_block_->set_in_transition(this);
}
}
}
void TransitionBlock::InputDisconnectedEvent(const QString &input, int element, const NodeOutput &output)
{
Q_UNUSED(element)
Q_UNUSED(output)
if (input == kOutBlockInput) {
if (connected_out_block_) {
connected_out_block_->set_in_transition(nullptr);
connected_out_block_ = nullptr;
}
} else if (input == kInBlockInput) {
if (connected_in_block_) {
connected_in_block_->set_in_transition(nullptr);
connected_in_block_ = nullptr;
}
}
}
}
+9 -19
View File
@@ -33,9 +33,6 @@ public:
virtual Type type() const override;
NodeInput* out_block_input() const;
NodeInput* in_block_input() const;
virtual void Retranslate() override;
rational in_offset() const;
@@ -50,7 +47,11 @@ public:
virtual void Hash(QCryptographicHash& hash, const rational &time) const override;
virtual NodeValueTable Value(NodeValueDatabase &value) const override;
virtual NodeValueTable Value(const QString& output, NodeValueDatabase &value) const override;
static const QString kOutBlockInput;
static const QString kInBlockInput;
static const QString kCurveInput;
protected:
virtual void ShaderJobEvent(NodeValueDatabase &value, ShaderJob& job) const;
@@ -59,6 +60,10 @@ protected:
double TransformCurve(double linear) const;
virtual void InputConnectedEvent(const QString& input, int element, const NodeOutput& output) override;
virtual void InputDisconnectedEvent(const QString& input, int element, const NodeOutput& output) override;
private:
enum CurveType {
kLinear,
@@ -70,25 +75,10 @@ private:
void InsertTransitionTimes(AcceleratedJob* job, const double& time) const;
NodeInput* out_block_input_;
NodeInput* in_block_input_;
NodeInput* curve_input_;
Block* connected_out_block_;
Block* connected_in_block_;
private slots:
void OutBlockConnected(Node* node);
void OutBlockDisconnected();
void InBlockConnected(Node* node);
void InBlockDisconnected();
};
}