transitions: extended transition logic

General code and functionality improvements. Moved more code out of the
OpenGL backend for portability. Implemented audio transitions.
Implemented basic transition animation curve settings.
This commit is contained in:
itsmattkc
2020-07-16 00:36:21 +10:00
parent de74adeb5e
commit 662d66ad10
10 changed files with 224 additions and 52 deletions
+111 -16
View File
@@ -28,17 +28,22 @@ TransitionBlock::TransitionBlock() :
connected_out_block_(nullptr),
connected_in_block_(nullptr)
{
out_block_input_ = new NodeInput("out_block_in", NodeParam::kBuffer);
out_block_input_ = new NodeInput(QStringLiteral("out_block_in"), NodeParam::kBuffer);
out_block_input_->set_is_keyframable(false);
connect(out_block_input_, &NodeParam::EdgeAdded, this, &TransitionBlock::BlockConnected);
connect(out_block_input_, &NodeParam::EdgeRemoved, this, &TransitionBlock::BlockDisconnected);
AddInput(out_block_input_);
in_block_input_ = new NodeInput("in_block_in", NodeParam::kBuffer);
in_block_input_ = new NodeInput(QStringLiteral("in_block_in"), NodeParam::kBuffer);
in_block_input_->set_is_keyframable(false);
connect(in_block_input_, &NodeParam::EdgeAdded, this, &TransitionBlock::BlockConnected);
connect(in_block_input_, &NodeParam::EdgeRemoved, this, &TransitionBlock::BlockDisconnected);
AddInput(in_block_input_);
curve_input_ = new NodeInput(QStringLiteral("curve_in"), NodeParam::kCombo);
curve_input_->set_is_keyframable(false);
curve_input_->set_connectable(false);
AddInput(curve_input_);
}
Block::Type TransitionBlock::type() const
@@ -62,6 +67,10 @@ void TransitionBlock::Retranslate()
out_block_input_->set_name(tr("From"));
in_block_input_->set_name(tr("To"));
curve_input_->set_name(tr("Curve"));
// These must correspond to the CurveType enum
curve_input_->set_combobox_strings({ tr("Linear"), tr("Exponential"), tr("Logarithmic") });
}
rational TransitionBlock::in_offset() const
@@ -106,12 +115,12 @@ Block *TransitionBlock::connected_in_block() const
return connected_in_block_;
}
double TransitionBlock::GetTotalProgress(const rational &time) const
double TransitionBlock::GetTotalProgress(const double &time) const
{
return GetInternalTransitionTime(time) / length().toDouble();
}
double TransitionBlock::GetOutProgress(const rational &time) const
double TransitionBlock::GetOutProgress(const double &time) const
{
if (out_offset() == 0) {
return 0;
@@ -120,7 +129,7 @@ double TransitionBlock::GetOutProgress(const rational &time) const
return clamp(1.0 - (GetInternalTransitionTime(time) / out_offset().toDouble()), 0.0, 1.0);
}
double TransitionBlock::GetInProgress(const rational &time) const
double TransitionBlock::GetInProgress(const double &time) const
{
if (in_offset() == 0) {
return 0;
@@ -133,18 +142,34 @@ void TransitionBlock::Hash(QCryptographicHash &hash, const rational &time) const
{
Node::Hash(hash, time);
double all_prog = GetTotalProgress(time);
double in_prog = GetInProgress(time);
double out_prog = GetOutProgress(time);
double time_dbl = time.toDouble();
double all_prog = GetTotalProgress(time_dbl);
double in_prog = GetInProgress(time_dbl);
double out_prog = GetOutProgress(time_dbl);
hash.addData(reinterpret_cast<const char*>(&all_prog), sizeof(double));
hash.addData(reinterpret_cast<const char*>(&in_prog), sizeof(double));
hash.addData(reinterpret_cast<const char*>(&out_prog), sizeof(double));
}
double TransitionBlock::GetInternalTransitionTime(const rational &time) const
double TransitionBlock::GetInternalTransitionTime(const double &time) const
{
return time.toDouble() - in().toDouble();
return time - in().toDouble();
}
void TransitionBlock::InsertTransitionTimes(AcceleratedJob *job, const double &time) const
{
// Provides total transition progress from 0.0 (start) - 1.0 (end)
job->InsertValue(QStringLiteral("ove_tprog_all"),
NodeValue(NodeParam::kFloat, GetTotalProgress(time), this));
// Provides progress of out section from 1.0 (start) - 0.0 (end)
job->InsertValue(QStringLiteral("ove_tprog_out"),
NodeValue(NodeParam::kFloat, GetOutProgress(time), this));
// Provides progress of in section from 0.0 (start) - 1.0 (end)
job->InsertValue(QStringLiteral("ove_tprog_in"),
NodeValue(NodeParam::kFloat, GetInProgress(time), this));
}
void TransitionBlock::BlockConnected(NodeEdgePtr edge)
@@ -173,16 +198,62 @@ void TransitionBlock::BlockDisconnected(NodeEdgePtr edge)
NodeValueTable TransitionBlock::Value(NodeValueDatabase &value) const
{
ShaderJob job;
NodeParam::DataType data_type;
job.InsertValue(out_block_input(), value);
job.InsertValue(in_block_input(), value);
job.SetAlphaChannelRequired(true);
if (out_block_input()->is_connected()) {
data_type = value[out_block_input()].GetWithMeta(NodeParam::kBuffer).type();
} else if (in_block_input()->is_connected()) {
data_type = value[in_block_input()].GetWithMeta(NodeParam::kBuffer).type();
} else {
data_type = NodeParam::kNone;
}
ShaderJobEvent(value, job);
NodeParam::DataType job_type;
QVariant push_job;
if (data_type == NodeParam::kTexture) {
// This must be a visual transition
ShaderJob job;
job.InsertValue(out_block_input(), value);
job.InsertValue(in_block_input(), value);
job.InsertValue(curve_input_, value);
job.SetAlphaChannelRequired(true);
double time = value[QStringLiteral("global")].Get(NodeParam::kFloat, QStringLiteral("time_in")).toDouble();
InsertTransitionTimes(&job, time);
ShaderJobEvent(value, job);
job_type = NodeParam::kShaderJob;
push_job = QVariant::fromValue(job);
} else if (data_type == NodeParam::kSamples) {
// This must be an audio transition
SampleBufferPtr from_samples = value[out_block_input()].Take(NodeParam::kBuffer).value<SampleBufferPtr>();
SampleBufferPtr to_samples = value[in_block_input()].Take(NodeParam::kBuffer).value<SampleBufferPtr>();
if (from_samples || to_samples) {
double time_in = value[QStringLiteral("global")].Get(NodeParam::kFloat, QStringLiteral("time_in")).toDouble();
double time_out = value[QStringLiteral("global")].Get(NodeParam::kFloat, QStringLiteral("time_out")).toDouble();
const AudioParams& params = (from_samples) ? from_samples->audio_params() : to_samples->audio_params();
int nb_samples = params.time_to_samples(time_out - time_in);
SampleBufferPtr out_samples = SampleBuffer::CreateAllocated(params, nb_samples);
SampleJobEvent(from_samples, to_samples, out_samples, time_in);
job_type = NodeParam::kSamples;
push_job = QVariant::fromValue(out_samples);
}
}
NodeValueTable table = value.Merge();
table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this);
if (!push_job.isNull()) {
table.Push(job_type, push_job, this);
}
return table;
}
@@ -192,4 +263,28 @@ void TransitionBlock::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &job) c
Q_UNUSED(job)
}
void TransitionBlock::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const
{
Q_UNUSED(from_samples)
Q_UNUSED(to_samples)
Q_UNUSED(out_samples)
Q_UNUSED(time_in)
}
double TransitionBlock::TransformCurve(double linear) const
{
switch (static_cast<CurveType>(curve_input_->get_standard_value().toInt())) {
case kLinear:
break;
case kExponential:
linear *= linear;
break;
case kLogarithmic:
linear = qSqrt(linear);
break;
}
return linear;
}
OLIVE_NAMESPACE_EXIT