From b713ab47eb87beedae9f06b578f242234cb5b164 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 25 Jan 2020 17:47:02 +1100 Subject: [PATCH] keyframes: only update active frames even from curve and param editor When adjusting a slider, keyframe time, or curve value, it is undesirable to re-cache the entire affected area while the user is still dragging UI objects. Since the video is unlikely to be playing, the priority must go to the currently active frame so the user gets visual feedback on the rendered image as soon as possible. This was implemented in some areas, but this commit should have that functionality in all areas. --- app/common/timerange.cpp | 4 +++- app/config/config.cpp | 2 +- app/node/block/clip/clip.cpp | 3 +++ app/node/input.cpp | 6 ++++- app/node/keyframe.cpp | 11 +++++++++ app/node/keyframe.h | 7 ++++++ app/widget/keyframeview/keyframeviewbase.cpp | 23 +++++++++++++++++-- .../timelinewidget/timelinescaledobject.cpp | 4 ++-- .../timelinewidget/timelinescaledobject.h | 4 ++-- .../timelinewidget/view/timelineviewbase.cpp | 4 ++-- .../timelinewidget/view/timelineviewbase.h | 2 +- 11 files changed, 58 insertions(+), 12 deletions(-) diff --git a/app/common/timerange.cpp b/app/common/timerange.cpp index 8ab8c65e2..f25ebc398 100644 --- a/app/common/timerange.cpp +++ b/app/common/timerange.cpp @@ -99,7 +99,9 @@ void TimeRangeList::InsertTimeRange(const TimeRange &range) for (int i=0;i(AV_CH_LAYOUT_STEREO)); // Online/offline settings config_map_["OnlinePixelFormat"] = PixelFormat::PIX_FMT_RGBA32F; diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index f9f4efb38..a6d637889 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -64,12 +64,15 @@ void ClipBlock::InvalidateCache(const rational &start_range, const rational &end rational start = MediaToSequenceTime(start_range); rational end = MediaToSequenceTime(end_range); + // Ensure range actually covers this clip's area if (!(end < in() || start > out())) { + // Limit cache invalidation to clip lengths start = qMax(start, in()); end = qMin(end, out()); Node::InvalidateCache(start, end, from); + } } else { // Otherwise, pass signal along normally diff --git a/app/node/input.cpp b/app/node/input.cpp index a401947fa..b86b01a88 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -151,6 +151,7 @@ void NodeInput::Load(QXmlStreamReader *reader, QHash& par NodeKeyframePtr key = NodeKeyframe::Create(key_time, key_value, key_type, track); key->set_bezier_control_in(key_in_handle); key->set_bezier_control_out(key_out_handle); + key->set_parent(this); keyframe_tracks_[track].append(key); } } @@ -600,6 +601,7 @@ void NodeInput::remove_keyframe(NodeKeyframePtr key) disconnect(key.get(), &NodeKeyframe::BezierControlOutChanged, this, &NodeInput::KeyframeBezierOutChanged); keyframe_tracks_[key->track()].removeOne(key); + key->set_parent(nullptr); emit KeyframeRemoved(key); emit_time_range(time_affected); @@ -618,7 +620,7 @@ void NodeInput::KeyframeTimeChanged() // This keyframe needs resorting, store it and remove it from the list NodeKeyframePtr key_shared_ptr = keyframe_tracks_.at(key->track()).at(keyframe_index); - keyframe_tracks_.removeAt(keyframe_index); + keyframe_tracks_[key->track()].removeAt(keyframe_index); // Automatically insertion sort insert_keyframe_internal(key_shared_ptr); @@ -698,6 +700,8 @@ void NodeInput::insert_keyframe_internal(NodeKeyframePtr key) { KeyframeTrack& key_track = keyframe_tracks_[key->track()]; + key->set_parent(this); + for (int i=0;i; @@ -114,6 +116,9 @@ public: */ static BezierType get_opposing_bezier_type(BezierType type); + NodeInput* parent() const; + void set_parent(NodeInput* parent); + signals: /** * @brief Signal emitted when this keyframe's time is changed @@ -141,6 +146,8 @@ signals: void BezierControlOutChanged(const QPointF& d); private: + NodeInput* parent_; + rational time_; QVariant value_; diff --git a/app/widget/keyframeview/keyframeviewbase.cpp b/app/widget/keyframeview/keyframeviewbase.cpp index dda412f3c..49f5057f2 100644 --- a/app/widget/keyframeview/keyframeviewbase.cpp +++ b/app/widget/keyframeview/keyframeviewbase.cpp @@ -5,6 +5,7 @@ #include "dialog/keyframeproperties/keyframeproperties.h" #include "keyframeviewundo.h" +#include "node/node.h" #include "widget/menu/menu.h" #include "widget/menu/menushared.h" #include "widget/nodeparamview/nodeparamviewundo.h" @@ -96,6 +97,9 @@ void KeyframeViewBase::mousePressEvent(QMouseEvent *event) for (int i=0;i(selected_items.at(i)); + // Block signals for dragging for now + key->key()->parent()->blockSignals(true); + selected_keys_.replace(i, {key, key->x(), key->key()->time(), key->key()->value().toDouble()}); } } @@ -123,12 +127,17 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event) false); } else if (!selected_keys_.isEmpty()) { foreach (const KeyframeItemAndTime& keypair, selected_keys_) { - // FIXME: Find some way to do single frame updates as the NodeParamViewWidgetBridge does? keypair.key->key()->set_time(CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x())); if (y_axis_enabled_) { keypair.key->key()->set_value(keypair.value - mouse_diff_scaled.y()); } + + // We emit a custom value changed signal while the keyframe is being dragged so only the currently viewed + // frame gets rendered in this time + keypair.key->key()->parent()->blockSignals(false); + emit keypair.key->key()->parent()->ValueChanged(GetPlayheadTime(), GetPlayheadTime()); + keypair.key->key()->parent()->blockSignals(true); } } } @@ -164,19 +173,29 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event) // Calculate the new time for this keyframe rational new_time = CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()); + + // Commit movement + + // Since we overrode the cache signalling while dragging, we simulate here precisely the change that + // occurred by first setting the keyframe to its original position, and then letting the input handle + // the signalling once the undo command is pushed. + item->key()->set_time(keypair.time); new NodeParamSetKeyframeTimeCommand(item->key(), new_time, keypair.time, command); - // Commit value if we're setting a vaule + // Commit value if we're setting a value if (y_axis_enabled_) { + item->key()->set_value(keypair.value); new NodeParamSetKeyframeValueCommand(item->key(), keypair.value - mouse_diff_scaled.y(), keypair.value, command); } + + keypair.key->key()->parent()->blockSignals(false); } Core::instance()->undo_stack()->push(command); diff --git a/app/widget/timelinewidget/timelinescaledobject.cpp b/app/widget/timelinewidget/timelinescaledobject.cpp index b92361e1e..36b91e4eb 100644 --- a/app/widget/timelinewidget/timelinescaledobject.cpp +++ b/app/widget/timelinewidget/timelinescaledobject.cpp @@ -8,12 +8,12 @@ TimelineScaledObject::TimelineScaledObject() : } -const rational &TimelineScaledObject::timebase() +const rational &TimelineScaledObject::timebase() const { return timebase_; } -const double &TimelineScaledObject::timebase_dbl() +const double &TimelineScaledObject::timebase_dbl() const { return timebase_dbl_; } diff --git a/app/widget/timelinewidget/timelinescaledobject.h b/app/widget/timelinewidget/timelinescaledobject.h index c88d2bada..7a925467e 100644 --- a/app/widget/timelinewidget/timelinescaledobject.h +++ b/app/widget/timelinewidget/timelinescaledobject.h @@ -8,8 +8,8 @@ class TimelineScaledObject public: TimelineScaledObject(); - const rational& timebase(); - const double& timebase_dbl(); + const rational& timebase() const; + const double& timebase_dbl() const; static rational SceneToTime(const double &x, const double& x_scale, const rational& timebase, bool round = false); diff --git a/app/widget/timelinewidget/view/timelineviewbase.cpp b/app/widget/timelinewidget/view/timelineviewbase.cpp index 7f204560c..3fd901855 100644 --- a/app/widget/timelinewidget/view/timelineviewbase.cpp +++ b/app/widget/timelinewidget/view/timelineviewbase.cpp @@ -97,9 +97,9 @@ void TimelineViewBase::drawForeground(QPainter *painter, const QRectF &rect) } } -rational TimelineViewBase::GetPlayheadTime() +rational TimelineViewBase::GetPlayheadTime() const { - return rational(playhead_ * timebase().numerator(), timebase().denominator()); + return Timecode::timestamp_to_time(playhead_, timebase()); } void TimelineViewBase::SetDefaultDragMode(QGraphicsView::DragMode mode) diff --git a/app/widget/timelinewidget/view/timelineviewbase.h b/app/widget/timelinewidget/view/timelineviewbase.h index dfaa12c2f..ce4663614 100644 --- a/app/widget/timelinewidget/view/timelineviewbase.h +++ b/app/widget/timelinewidget/view/timelineviewbase.h @@ -43,7 +43,7 @@ protected: void SetLimitYAxis(bool e); - rational GetPlayheadTime(); + rational GetPlayheadTime() const; void SetDefaultDragMode(DragMode mode); const DragMode& GetDefaultDragMode() const;