nodes: use much smarter time transform function

Fixes #2042
This commit is contained in:
itsmattkc
2022-10-23 12:15:36 -07:00
parent 86a5a0fcfd
commit 5096278e60
12 changed files with 64 additions and 78 deletions
+36 -52
View File
@@ -1712,42 +1712,33 @@ QString Node::GetCategoryName(const CategoryID &c)
return tr("Uncategorized");
}
QVector<TimeRange> Node::TransformTimeTo(const TimeRange &time, Node *target, bool input_dir)
TimeRange Node::TransformTimeTo(TimeRange time, Node *target, TransformTimeDirection dir, int path_index)
{
QVector<TimeRange> 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);
std::list<NodeInput> 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 {
// We did NOT find the target, traverse this
paths_found.append(connected->TransformTimeTo(input_adjustment, target, input_dir));
}
}
} 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));
// 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<Node *> &vec, Node *to, int &path_index)
bool FindPathInternal(std::list<NodeInput> &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
if (FindPathInternal(vec, next.node(), to, path_index)) {
return true;
}
vec.pop_back();
}
}
return false;
}
std::list<Node *> Node::FindPath(Node *from, Node *to, int path_index)
std::list<NodeInput> Node::FindPath(Node *from, Node *to, int path_index)
{
std::list<Node *> v;
std::list<NodeInput> 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;
}
+10 -2
View File
@@ -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<TimeRange> 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<Node*> FindPath(Node *from, Node *to, int path_index = 0);
/**
* @brief Find path starting at `from` that outputs to arrive at `to`
*/
static std::list<NodeInput> FindPath(Node *from, Node *to, int path_index);
static const QString kEnabledInput;
+1 -1
View File
@@ -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);
+3 -3
View File
@@ -228,7 +228,7 @@ bool KeyframeView::Paste(std::function<Node *(const QString &)> 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)
@@ -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)
@@ -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)
@@ -216,7 +216,7 @@ public:
if (time_target_) {
for (size_t i=0; i<copy.size(); i++) {
if (Node *parent = time_targets_[i]) {
copy[i] = time_target_->GetAdjustedTime(parent, time_target_->GetTimeTarget(), copy[i], false);
copy[i] = time_target_->GetAdjustedTime(parent, time_target_->GetTimeTarget(), copy[i], Node::kTransformTowardsOutput);
}
}
}
+1 -1
View File
@@ -868,7 +868,7 @@ bool TimeBasedWidget::SnapPoint(const std::vector<rational> &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);
}
}
+1 -1
View File
@@ -1470,7 +1470,7 @@ void TimelineWidget::CacheClipsInOut()
for (Block *b : qAsConst(selected_blocks_)) {
if (ClipBlock *clip = dynamic_cast<ClipBlock*>(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);
}
}
+4 -10
View File
@@ -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<TimeRange> 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
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -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