From 5096278e600f95dd294f6765c31e8811b3c018ac Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 23 Oct 2022 12:15:36 -0700 Subject: [PATCH] nodes: use much smarter time transform function Fixes #2042 --- app/node/node.cpp | 90 ++++++++----------- app/node/node.h | 12 ++- app/widget/curvewidget/curveview.cpp | 2 +- app/widget/keyframeview/keyframeview.cpp | 6 +- .../nodeparamviewkeyframecontrol.cpp | 4 +- .../nodeparamviewwidgetbridge.cpp | 2 +- .../timebased/timebasedviewselectionmanager.h | 2 +- app/widget/timebased/timebasedwidget.cpp | 2 +- app/widget/timelinewidget/timelinewidget.cpp | 2 +- app/widget/timetarget/timetarget.cpp | 14 +-- app/widget/timetarget/timetarget.h | 4 +- app/widget/viewer/viewerdisplay.cpp | 2 +- 12 files changed, 64 insertions(+), 78 deletions(-) diff --git a/app/node/node.cpp b/app/node/node.cpp index 1d8cb3f4c..d843a460a 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -1712,42 +1712,33 @@ QString Node::GetCategoryName(const CategoryID &c) return tr("Uncategorized"); } -QVector Node::TransformTimeTo(const TimeRange &time, Node *target, bool input_dir) +TimeRange Node::TransformTimeTo(TimeRange time, Node *target, TransformTimeDirection dir, int path_index) { - QVector paths_found; + Node *from = this; + Node *to = target; - if (input_dir) { - // If this input is connected, traverse it to see if we stumble across the specified `node` - for (auto it=input_connections_.cbegin(); it!=input_connections_.cend(); it++) { - TimeRange input_adjustment = InputTimeAdjustment(it->first.input(), it->first.element(), time); - Node* connected = it->second; + if (dir == kTransformTowardsInput) { + std::swap(from, to); + } - if (connected == target) { - // We found the target, no need to keep traversing - if (!paths_found.contains(input_adjustment)) { - paths_found.append(input_adjustment); - } - } else { - // We did NOT find the target, traverse this - paths_found.append(connected->TransformTimeTo(input_adjustment, target, input_dir)); + std::list path = FindPath(from, to, path_index); + + if (!path.empty()) { + if (dir == kTransformTowardsInput) { + for (auto it=path.crbegin(); it!=path.crend(); it++) { + const NodeInput &i = (*it); + time = i.node()->InputTimeAdjustment(i.input(), i.element(), time); } - } - } else { - // If this input is connected, traverse it to see if we stumble across the specified `node` - foreach (const OutputConnection& conn, output_connections_) { - Node* connected_node = conn.second.node(); - - TimeRange output_adjustment = connected_node->OutputTimeAdjustment(conn.second.input(), conn.second.element(), time); - - if (connected_node == target) { - paths_found.append(output_adjustment); - } else { - paths_found.append(connected_node->TransformTimeTo(output_adjustment, target, input_dir)); + } else { + // Traverse in output direction + for (auto it=path.cbegin(); it!=path.cend(); it++) { + const NodeInput &i = (*it); + time = i.node()->OutputTimeAdjustment(i.input(), i.element(), time); } } } - return paths_found; + return time; } QVariant Node::PtrToValue(void *ptr) @@ -2011,46 +2002,39 @@ void Node::SetValueAtTime(const NodeInput &input, const rational &time, const QV } } -void FindPathInternal(std::list &vec, Node *to, int &path_index) +bool FindPathInternal(std::list &vec, Node *from, Node *to, int &path_index) { - Node *from = vec.back(); + for (auto it=from->output_connections().cbegin(); it!=from->output_connections().cend(); it++) { + const NodeInput &next = it->second; - for (auto it=from->input_connections().cbegin(); it!=from->input_connections().cend(); it++) { - vec.push_back(it->second); - if (it->second == to) { - // Found a path, determine if it's the one we want + vec.push_back(next); + + if (next.node() == to) { + // Found a path! Determine if it's the index we want if (path_index == 0) { // It is! - break; + return true; } else { + // It isn't, keep looking... path_index--; } } - // Recurse to see if we can find it here - FindPathInternal(vec, to, path_index); - if (vec.back() == to) { - // Found through recursion - break; - } else { - // Must not be available through this path - vec.pop_back(); + if (FindPathInternal(vec, next.node(), to, path_index)) { + return true; } + + vec.pop_back(); } + + return false; } -std::list Node::FindPath(Node *from, Node *to, int path_index) +std::list Node::FindPath(Node *from, Node *to, int path_index) { - std::list v; + std::list v; - v.push_back(from); - - FindPathInternal(v, to, path_index); - - if (v.size() == 1) { - // Failed to find path, return empty list - v.pop_back(); - } + FindPathInternal(v, from, to, path_index); return v; } diff --git a/app/node/node.h b/app/node/node.h index 0dbfdaa3e..253788cbe 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -844,10 +844,15 @@ public: */ static QString GetCategoryName(const CategoryID &c); + enum TransformTimeDirection { + kTransformTowardsInput, + kTransformTowardsOutput + }; + /** * @brief Transforms time from this node through the connections it takes to get to the specified node */ - QVector TransformTimeTo(const TimeRange& time, Node* target, bool input_dir); + TimeRange TransformTimeTo(TimeRange time, Node* target, TransformTimeDirection dir, int path_index); /** * @brief Find nodes of a certain type that this Node takes inputs from @@ -1147,7 +1152,10 @@ public: static void SetValueAtTime(const NodeInput &input, const rational &time, const QVariant &value, int track, MultiUndoCommand *command, bool insert_on_all_tracks_if_no_key); - static std::list FindPath(Node *from, Node *to, int path_index = 0); + /** + * @brief Find path starting at `from` that outputs to arrive at `to` + */ + static std::list FindPath(Node *from, Node *to, int path_index); static const QString kEnabledInput; diff --git a/app/widget/curvewidget/curveview.cpp b/app/widget/curvewidget/curveview.cpp index 10300b7ff..6f105a22d 100644 --- a/app/widget/curvewidget/curveview.cpp +++ b/app/widget/curvewidget/curveview.cpp @@ -519,7 +519,7 @@ void CurveView::ZoomToFitInternal(bool selected_only) rational transformed_time = GetAdjustedTime(key->parent(), GetTimeTarget(), key->time(), - false); + Node::kTransformTowardsOutput); qreal key_y = GetUnscaledItemYFromKeyframeValue(key); diff --git a/app/widget/keyframeview/keyframeview.cpp b/app/widget/keyframeview/keyframeview.cpp index 9fead0fe1..abc2b1015 100644 --- a/app/widget/keyframeview/keyframeview.cpp +++ b/app/widget/keyframeview/keyframeview.cpp @@ -228,7 +228,7 @@ bool KeyframeView::Paste(std::function find_node_functi for (NodeKeyframe *key : it.value()) { // Adjust sequence time to node's time rational t = key->time() - min; - t = GetAdjustedTime(GetTimeTarget(), node_with_id, t, true); + t = GetAdjustedTime(GetTimeTarget(), node_with_id, t, Node::kTransformTowardsInput); key->set_time(t); if (NodeKeyframe *existing = node_with_id->GetKeyframeAtTimeOnTrack(key->input(), key->time(), key->track(), key->element())) { @@ -491,12 +491,12 @@ void KeyframeView::DeselectKeyframe(NodeKeyframe *key) rational KeyframeView::GetUnadjustedKeyframeTime(NodeKeyframe *key, const rational &time) { - return GetAdjustedTime(GetTimeTarget(), key->parent(), time, true); + return GetAdjustedTime(GetTimeTarget(), key->parent(), time, Node::kTransformTowardsInput); } rational KeyframeView::GetAdjustedKeyframeTime(NodeKeyframe *key) { - return GetAdjustedTime(key->parent(), GetTimeTarget(), key->time(), false); + return GetAdjustedTime(key->parent(), GetTimeTarget(), key->time(), Node::kTransformTowardsOutput); } double KeyframeView::GetKeyframeSceneX(NodeKeyframe *key) diff --git a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp index c431966a8..ea29b036e 100644 --- a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp +++ b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp @@ -122,12 +122,12 @@ void NodeParamViewKeyframeControl::SetButtonsEnabled(bool e) rational NodeParamViewKeyframeControl::GetCurrentTimeAsNodeTime() const { - return GetAdjustedTime(GetTimeTarget(), input_.node(), time_, true); + return GetAdjustedTime(GetTimeTarget(), input_.node(), time_, Node::kTransformTowardsInput); } rational NodeParamViewKeyframeControl::ConvertToViewerTime(const rational &r) const { - return GetAdjustedTime(input_.node(), GetTimeTarget(), r, false); + return GetAdjustedTime(input_.node(), GetTimeTarget(), r, Node::kTransformTowardsOutput); } void NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable(bool e) diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index dd33a7659..b5b4db823 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -528,7 +528,7 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() rational NodeParamViewWidgetBridge::GetCurrentTimeAsNodeTime() const { - return GetAdjustedTime(GetTimeTarget(), GetInnerInput().node(), time_, true); + return GetAdjustedTime(GetTimeTarget(), GetInnerInput().node(), time_, Node::kTransformTowardsInput); } void NodeParamViewWidgetBridge::SetTimebase(const rational& timebase) diff --git a/app/widget/timebased/timebasedviewselectionmanager.h b/app/widget/timebased/timebasedviewselectionmanager.h index 6d9e6962f..f9ac6faf9 100644 --- a/app/widget/timebased/timebasedviewselectionmanager.h +++ b/app/widget/timebased/timebasedviewselectionmanager.h @@ -216,7 +216,7 @@ public: if (time_target_) { for (size_t i=0; iGetAdjustedTime(parent, time_target_->GetTimeTarget(), copy[i], false); + copy[i] = time_target_->GetAdjustedTime(parent, time_target_->GetTimeTarget(), copy[i], Node::kTransformTowardsOutput); } } } diff --git a/app/widget/timebased/timebasedwidget.cpp b/app/widget/timebased/timebasedwidget.cpp index a4beb3bfa..b97521b47 100644 --- a/app/widget/timebased/timebasedwidget.cpp +++ b/app/widget/timebased/timebasedwidget.cpp @@ -868,7 +868,7 @@ bool TimeBasedWidget::SnapPoint(const std::vector &start_times, ration rational time = key->time(); if (const TimeTargetObject *target = GetKeyframeTimeTarget()) { if (Node *parent = key->parent()) { - time = target->GetAdjustedTime(parent, target->GetTimeTarget(), time, false); + time = target->GetAdjustedTime(parent, target->GetTimeTarget(), time, Node::kTransformTowardsOutput); } } diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 943242ee8..1bfea94a2 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -1470,7 +1470,7 @@ void TimelineWidget::CacheClipsInOut() for (Block *b : qAsConst(selected_blocks_)) { if (ClipBlock *clip = dynamic_cast(b)) { if (Node *connected = clip->GetConnectedOutput(clip->kBufferIn)) { - TimeRange adjusted = tto.GetAdjustedTime(this->sequence(), connected, r, true); + TimeRange adjusted = tto.GetAdjustedTime(this->sequence(), connected, r, Node::kTransformTowardsInput); clip->RequestInvalidatedFromConnected(true, adjusted); } } diff --git a/app/widget/timetarget/timetarget.cpp b/app/widget/timetarget/timetarget.cpp index 8662999e5..3c98aa7df 100644 --- a/app/widget/timetarget/timetarget.cpp +++ b/app/widget/timetarget/timetarget.cpp @@ -45,28 +45,22 @@ void TimeTargetObject::SetPathIndex(int index) path_index_ = index; } -rational TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const rational &r, bool input_direction) const +rational TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const rational &r, Node::TransformTimeDirection dir) const { if (!from || !to) { return r; } - return GetAdjustedTime(from, to, TimeRange(r, r), input_direction).in(); + return GetAdjustedTime(from, to, TimeRange(r, r), dir).in(); } -TimeRange TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const TimeRange &r, bool input_direction) const +TimeRange TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const TimeRange &r, Node::TransformTimeDirection dir) const { if (!from || !to) { return r; } - QVector adjusted = from->TransformTimeTo(r, to, input_direction); - - if (adjusted.isEmpty()) { - return r; - } - - return adjusted.at(path_index_); + return from->TransformTimeTo(r, to, dir, path_index_); } /*int TimeTargetObject::GetNumberOfPathAdjustments(Node* from, NodeParam::Type direction) const diff --git a/app/widget/timetarget/timetarget.h b/app/widget/timetarget/timetarget.h index f1b2aa285..c561f58b0 100644 --- a/app/widget/timetarget/timetarget.h +++ b/app/widget/timetarget/timetarget.h @@ -35,8 +35,8 @@ public: void SetPathIndex(int index); - rational GetAdjustedTime(Node* from, Node* to, const rational& r, bool input_direction) const; - TimeRange GetAdjustedTime(Node* from, Node* to, const TimeRange& r, bool input_direction) const; + rational GetAdjustedTime(Node* from, Node* to, const rational& r, Node::TransformTimeDirection dir) const; + TimeRange GetAdjustedTime(Node* from, Node* to, const TimeRange& r, Node::TransformTimeDirection dir) const; //int GetNumberOfPathAdjustments(Node* from, NodeParam::Type direction) const; diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index e7ec99fb5..aea700d51 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -596,7 +596,7 @@ void ViewerDisplayWidget::DrawTextWithCrudeShadow(QPainter *painter, const QRect rational ViewerDisplayWidget::GetGizmoTime() { - return GetAdjustedTime(GetTimeTarget(), gizmos_, time_, true); + return GetAdjustedTime(GetTimeTarget(), gizmos_, time_, Node::kTransformTowardsInput); } bool ViewerDisplayWidget::IsHandDrag(QMouseEvent *event) const