updated NodeInputs to use a standard value as well as keyframed values

Previously the non-keyframed value was stored as a static keyframe but this
introduced issues when an input was in a state of keyframes being enabled but
0 keyframes existing. Having a standard value makes much more sense.
This commit is contained in:
itsmattkc
2019-12-27 02:06:41 +11:00
parent 7a512cc540
commit e32376a8b7
9 changed files with 142 additions and 73 deletions
+6 -6
View File
@@ -75,7 +75,7 @@ void Block::set_out(const rational &out)
rational Block::length() const
{
return length_input_->get_value_at_time(0).value<rational>();
return length_input_->get_standard_value().value<rational>();
}
void Block::set_length(const rational &length)
@@ -86,7 +86,7 @@ void Block::set_length(const rational &length)
return;
}
length_input_->set_override_value(QVariant::fromValue(length));
length_input_->set_standard_value(QVariant::fromValue(length));
}
void Block::set_length_and_media_out(const rational &length)
@@ -153,22 +153,22 @@ void Block::set_next(Block *next)
rational Block::media_in() const
{
return media_in_input_->get_value_at_time(0).value<rational>();
return media_in_input_->get_standard_value().value<rational>();
}
void Block::set_media_in(const rational &media_in)
{
media_in_input_->set_override_value(QVariant::fromValue(media_in));
media_in_input_->set_standard_value(QVariant::fromValue(media_in));
}
rational Block::media_out() const
{
return media_out_input_->get_value_at_time(0).value<rational>();
return media_out_input_->get_standard_value().value<rational>();
}
void Block::set_media_out(const rational &media_out)
{
media_out_input_->set_override_value(QVariant::fromValue(media_out));
media_out_input_->set_standard_value(QVariant::fromValue(media_out));
}
rational Block::media_length() const
+62 -40
View File
@@ -29,13 +29,12 @@ NodeInput::NodeInput(const QString& id, const DataType &type, const QVariant &de
NodeParam(id),
data_type_(type),
keyframable_(true),
standard_value_(default_value),
keyframing_(false),
dependent_(true),
has_minimum_(false),
has_maximum_(false)
{
// Have at least one keyframe/value active at any time
insert_keyframe(std::make_shared<NodeKeyframe>(0, default_value, NodeKeyframe::kLinear));
}
bool NodeInput::IsArray()
@@ -84,50 +83,52 @@ Node *NodeInput::get_connected_node() const
QVariant NodeInput::get_value_at_time(const rational &time) const
{
if (is_keyframing()) {
if (keyframes_.first()->time() >= time) {
// This time precedes any keyframe, so we just return the first value
return keyframes_.first()->value();
}
if (!is_keyframing() || keyframes_.isEmpty()) {
return standard_value_;
}
if (keyframes_.last()->time() <= time) {
// This time is after any keyframes so we return the last value
return keyframes_.last()->value();
}
if (keyframes_.first()->time() >= time) {
// This time precedes any keyframe, so we just return the first value
return keyframes_.first()->value();
}
// If we're here, the time must be somewhere in between the keyframes
for (int i=0;i<keyframes_.size()-1;i++) {
NodeKeyframePtr before = keyframes_.at(i);
NodeKeyframePtr after = keyframes_.at(i+1);
if (keyframes_.last()->time() <= time) {
// This time is after any keyframes so we return the last value
return keyframes_.last()->value();
}
if (before->time() == time
|| data_type() != kFloat // FIXME: Expand this to other types that can be interpolated
|| (before->time() < time && before->type() == NodeKeyframe::kHold)) {
// If we're here, the time must be somewhere in between the keyframes
for (int i=0;i<keyframes_.size()-1;i++) {
NodeKeyframePtr before = keyframes_.at(i);
NodeKeyframePtr after = keyframes_.at(i+1);
// Time == keyframe time, so value is precise
return before->value();
if (before->time() == time
|| data_type() != kFloat // FIXME: Expand this to other types that can be interpolated
|| (before->time() < time && before->type() == NodeKeyframe::kHold)) {
} else if (before->time() < time && after->time() > time) {
// We must interpolate between these keyframes
// Time == keyframe time, so value is precise
return before->value();
if (before->type() == NodeKeyframe::kBezier && after->type() == NodeKeyframe::kBezier) {
// FIXME: Perform a cubic bezier interpolation
} else if (before->type() == NodeKeyframe::kLinear && after->type() == NodeKeyframe::kBezier) {
// FIXME: Perform a quadratic bezier interpolation with anchors from the AFTER keyframe
} else if (before->type() == NodeKeyframe::kLinear && after->type() == NodeKeyframe::kBezier) {
// FIXME: Perform a quadratic bezier interpolation with anchors from the BEFORE keyframe
} else {
// To have arrived here, the keyframes must both be linear
qreal period_progress = (time.toDouble() - before->time().toDouble()) / (after->time().toDouble() - before->time().toDouble());
qreal interpolated_value = lerp(before->value().toDouble(), after->value().toDouble(), period_progress);
} else if (before->time() < time && after->time() > time) {
// We must interpolate between these keyframes
return interpolated_value;
}
if (before->type() == NodeKeyframe::kBezier && after->type() == NodeKeyframe::kBezier) {
// FIXME: Perform a cubic bezier interpolation
} else if (before->type() == NodeKeyframe::kLinear && after->type() == NodeKeyframe::kBezier) {
// FIXME: Perform a quadratic bezier interpolation with anchors from the AFTER keyframe
} else if (before->type() == NodeKeyframe::kLinear && after->type() == NodeKeyframe::kBezier) {
// FIXME: Perform a quadratic bezier interpolation with anchors from the BEFORE keyframe
} else {
// To have arrived here, the keyframes must both be linear
qreal period_progress = (time.toDouble() - before->time().toDouble()) / (after->time().toDouble() - before->time().toDouble());
qreal interpolated_value = lerp(before->value().toDouble(), after->value().toDouble(), period_progress);
return interpolated_value;
}
}
}
return keyframes_.first()->value();
return standard_value_;
}
NodeKeyframePtr NodeInput::get_keyframe_at_time(const rational &time) const
@@ -147,7 +148,7 @@ NodeKeyframePtr NodeInput::get_keyframe_at_time(const rational &time) const
NodeKeyframePtr NodeInput::get_closest_keyframe_to_time(const rational &time) const
{
if (!is_keyframing()) {
if (!is_keyframing() || keyframes_.isEmpty()) {
return nullptr;
}
@@ -179,6 +180,17 @@ NodeKeyframePtr NodeInput::get_closest_keyframe_to_time(const rational &time) co
return nullptr;
}
NodeKeyframe::Type NodeInput::get_best_keyframe_type_for_time(const rational &time) const
{
NodeKeyframePtr closest_key = get_closest_keyframe_to_time(time);
if (closest_key) {
return closest_key->type();
}
return NodeKeyframe::kDefaultType;
}
void NodeInput::insert_keyframe(NodeKeyframePtr key)
{
Q_ASSERT(is_keyframable() || keyframes_.isEmpty());
@@ -293,11 +305,18 @@ bool NodeInput::is_keyframable() const
return keyframable_;
}
void NodeInput::set_override_value(const QVariant &value)
const QVariant &NodeInput::get_standard_value() const
{
Q_ASSERT(!is_keyframable());
return standard_value_;
}
keyframes_.first()->set_value(value);
void NodeInput::set_standard_value(const QVariant &value)
{
standard_value_ = value;
if (!is_keyframing()) {
emit ValueChanged(RATIONAL_MIN, RATIONAL_MAX);
}
}
const QList<NodeKeyframePtr> &NodeInput::keyframes() const
@@ -346,7 +365,10 @@ void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_conn
{
Q_ASSERT(source->id() == dest->id());
// Copy values
// Copy standard value
dest->standard_value_ = source->standard_value_;
// Copy keyframes
dest->keyframes_.clear();
foreach (NodeKeyframePtr key, source->keyframes_) {
NodeKeyframePtr copy = std::make_shared<NodeKeyframe>(key->time(), key->value(), key->type());
+19 -7
View File
@@ -94,10 +94,15 @@ public:
/**
* @brief Gets the closest keyframe to a time
*
* If is_keyframing() is false, this will return nullptr. Otherwise, this is guaranteed to return a keyframe.
* If is_keyframing() is false or keyframes_ is empty, this will return nullptr.
*/
NodeKeyframePtr get_closest_keyframe_to_time(const rational& time) const;
/**
* @brief A heuristic to determine what type a keyframe should be if it's inserted at a certain time (between keyframes)
*/
NodeKeyframe::Type get_best_keyframe_type_for_time(const rational& time) const;
/**
* @brief Inserts a keyframe at the given time and returns a reference to it
*/
@@ -131,11 +136,14 @@ public:
bool is_keyframable() const;
/**
* @brief Replaces all values with this value
*
* This can only be used on inputs where keyframing is disabled.
* @brief Get non-keyframed value
*/
void set_override_value(const QVariant& value);
const QVariant& get_standard_value() const;
/**
* @brief Set non-keyframed value
*/
void set_standard_value(const QVariant& value);
/**
* @brief Return list of keyframes in this parameter
@@ -193,11 +201,15 @@ private:
*/
bool keyframable_;
/**
* @brief Non-keyframed value
*/
QVariant standard_value_;
/**
* @brief Internal keyframe array
*
* All internal/user-defined data is stored in this array. Even if keyframing is not enabled, this array will contain
* one entry which will be used, and its time value will be ignored.
* If keyframing is enabled, this data is used instead of standard_value.
*/
QList<NodeKeyframePtr> keyframes_;
+3 -3
View File
@@ -32,12 +32,12 @@ MediaInput::MediaInput() :
StreamPtr MediaInput::footage()
{
return footage_input_->get_value_at_time(0).value<StreamPtr>();
return footage_input_->get_standard_value().value<StreamPtr>();
}
void MediaInput::SetFootage(StreamPtr f)
{
footage_input_->set_override_value(QVariant::fromValue(f));
footage_input_->set_standard_value(QVariant::fromValue(f));
}
void MediaInput::Retranslate()
@@ -47,7 +47,7 @@ void MediaInput::Retranslate()
void MediaInput::FootageChanged()
{
StreamPtr new_footage = footage_input_->get_value_at_time(0).value<StreamPtr>();
StreamPtr new_footage = footage_input_->get_standard_value().value<StreamPtr>();
if (new_footage == connected_footage_) {
return;
+2 -2
View File
@@ -350,7 +350,7 @@ QString TrackOutput::GetDefaultTrackName(TrackType type, int index)
bool TrackOutput::IsMuted() const
{
return muted_input_->get_value_at_time(0).toBool();
return muted_input_->get_standard_value().toBool();
}
bool TrackOutput::IsLocked() const
@@ -365,7 +365,7 @@ void TrackOutput::SetTrackName(const QString &name)
void TrackOutput::SetMuted(bool e)
{
muted_input_->set_override_value(e);
muted_input_->set_standard_value(e);
InvalidateCache(0, track_length());
}