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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user