diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index 8cee4b959..ba8fedb90 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -32,6 +32,7 @@ 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"); +const QString Block::kReverseInput = QStringLiteral("reverse_in"); Block::Block() : previous_(nullptr), @@ -55,6 +56,9 @@ Block::Block() : SetInputProperty(kSpeedInput, QStringLiteral("min"), 0.0); IgnoreHashingFrom(kSpeedInput); + AddInput(kReverseInput, NodeValue::kBoolean, false, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + IgnoreHashingFrom(kReverseInput); + // A block's length must be greater than 0 set_length_and_media_out(1); } @@ -77,6 +81,11 @@ void Block::set_length_and_media_out(const rational &length) return; } + if (reverse()) { + // Calculate media_in adjustment + set_media_in(SequenceToMediaTime(length - this->length(), true)); + } + set_length_internal(length); } @@ -88,8 +97,10 @@ void Block::set_length_and_media_in(const rational &length) return; } - // Calculate media_in adjustment - set_media_in(SequenceToMediaTime(this->length() - length)); + if (!reverse()) { + // Calculate media_in adjustment + set_media_in(SequenceToMediaTime(this->length() - length)); + } // Set the length without setting media out set_length_internal(length); @@ -117,7 +128,7 @@ void Block::set_enabled(bool e) emit EnabledChanged(); } -rational Block::SequenceToMediaTime(const rational &sequence_time) const +rational Block::SequenceToMediaTime(const rational &sequence_time, bool ignore_reverse) const { // These constants are not considered "values" per se, so we don't modify them if (sequence_time == RATIONAL_MIN || sequence_time == RATIONAL_MAX) { @@ -126,8 +137,7 @@ rational Block::SequenceToMediaTime(const rational &sequence_time) const rational local_time = sequence_time; - // FIXME: Doesn't handle reversing - double speed_value = GetStandardValue(kSpeedInput).toDouble(); + double speed_value = speed(); if (qIsNull(speed_value)) { // Effectively holds the frame at the in point @@ -137,7 +147,13 @@ rational Block::SequenceToMediaTime(const rational &sequence_time) const local_time = rational::fromDouble(local_time.toDouble() * speed_value); } - return local_time + media_in(); + rational media_time = local_time + media_in(); + + if (reverse() && !ignore_reverse) { + media_time = length() - media_time; + } + + return media_time; } rational Block::MediaToSequenceTime(const rational &media_time) const @@ -147,10 +163,15 @@ rational Block::MediaToSequenceTime(const rational &media_time) const return media_time; } - rational sequence_time = media_time - media_in(); + rational sequence_time = media_time; - // FIXME: Doesn't handle reversing - double speed_value = GetStandardValue(kSpeedInput).toDouble(); + if (reverse()) { + sequence_time = length() - sequence_time; + } + + sequence_time -= media_in(); + + double speed_value = speed(); if (qIsNull(speed_value)) { // Effectively holds the frame at the in point, also prevents divide by zero @@ -200,6 +221,7 @@ void Block::Retranslate() SetInputName(kMediaInInput, tr("Media In")); SetInputName(kEnabledInput, tr("Enabled")); SetInputName(kSpeedInput, tr("Speed")); + SetInputName(kReverseInput, tr("Reverse")); } void Block::Hash(const QString &, QCryptographicHash &, const rational &) const diff --git a/app/node/block/block.h b/app/node/block/block.h index 30b9e73ca..c246dfa05 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -151,12 +151,23 @@ public: return block_links_; } + double speed() const + { + return GetStandardValue(kSpeedInput).toDouble(); + } + + bool reverse() const + { + return GetStandardValue(kReverseInput).toBool(); + } + virtual void Hash(const QString& output, QCryptographicHash &hash, const rational &time) const override; static const QString kLengthInput; static const QString kMediaInInput; static const QString kEnabledInput; static const QString kSpeedInput; + static const QString kReverseInput; public slots: @@ -166,7 +177,7 @@ signals: void LengthChanged(); protected: - rational SequenceToMediaTime(const rational& sequence_time) const; + rational SequenceToMediaTime(const rational& sequence_time, bool ignore_reverse = false) const; rational MediaToSequenceTime(const rational& media_time) const; diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index c600ad43d..f41f5f25e 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -226,7 +226,6 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim continue; } - // FIXME: Doesn't handle reversing double speed_value = b->GetStandardValue(Block::kSpeedInput).toDouble(); if (qIsNull(speed_value)) { @@ -237,6 +236,10 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim samples_from_this_block->speed(speed_value); } + if (b->GetStandardValue(Block::kReverseInput).toBool()) { + samples_from_this_block->reverse(); + } + int copy_length = qMin(max_dest_sz, samples_from_this_block->sample_count()); // Copy samples into destination buffer