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.
This commit is contained in:
itsmattkc
2020-01-25 17:51:34 +11:00
parent 6f3ea35d9a
commit b713ab47eb
11 changed files with 58 additions and 12 deletions
+3 -1
View File
@@ -99,7 +99,9 @@ void TimeRangeList::InsertTimeRange(const TimeRange &range)
for (int i=0;i<size();i++) {
const TimeRange& compare = at(i);
if (range.OverlapsWith(compare)) {
if (compare == range) {
return;
} else if (range.OverlapsWith(compare)) {
replace(i, TimeRange::Combine(range, compare));
return;
}
+1 -1
View File
@@ -84,7 +84,7 @@ void Config::SetDefaults()
config_map_["DefaultSequenceHeight"] = 1080;
config_map_["DefaultSequenceFrameRate"] = QVariant::fromValue(rational(1001, 30000));
config_map_["DefaultSequenceAudioFrequency"] = 48000;
config_map_["DefaultSequenceAudioLayout"] = AV_CH_LAYOUT_STEREO;
config_map_["DefaultSequenceAudioLayout"] = QVariant::fromValue(static_cast<uint64_t>(AV_CH_LAYOUT_STEREO));
// Online/offline settings
config_map_["OnlinePixelFormat"] = PixelFormat::PIX_FMT_RGBA32F;
+3
View File
@@ -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
+5 -1
View File
@@ -151,6 +151,7 @@ void NodeInput::Load(QXmlStreamReader *reader, QHash<quintptr, NodeOutput*>& 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<key_track.size();i++) {
NodeKeyframePtr compare = key_track.at(i);
+11
View File
@@ -23,6 +23,7 @@
const NodeKeyframe::Type NodeKeyframe::kDefaultType = kLinear;
NodeKeyframe::NodeKeyframe(const rational &time, const QVariant &value, const NodeKeyframe::Type &type, const int &track) :
parent_(nullptr),
time_(time),
value_(value),
type_(type),
@@ -131,3 +132,13 @@ NodeKeyframe::BezierType NodeKeyframe::get_opposing_bezier_type(NodeKeyframe::Be
return kInHandle;
}
}
NodeInput *NodeKeyframe::parent() const
{
return parent_;
}
void NodeKeyframe::set_parent(NodeInput *parent)
{
parent_ = parent;
}
+7
View File
@@ -27,6 +27,8 @@
#include "common/rational.h"
class NodeInput;
class NodeKeyframe;
using NodeKeyframePtr = std::shared_ptr<NodeKeyframe>;
@@ -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_;
+21 -2
View File
@@ -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.size();i++) {
KeyframeViewItem* key = static_cast<KeyframeViewItem*>(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);
@@ -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_;
}
@@ -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);
@@ -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)
@@ -43,7 +43,7 @@ protected:
void SetLimitYAxis(bool e);
rational GetPlayheadTime();
rational GetPlayheadTime() const;
void SetDefaultDragMode(DragMode mode);
const DragMode& GetDefaultDragMode() const;