Rename the flags from `SEQ_TYPE_*` to `STRIP_TYPE_*`. Pull Request: https://projects.blender.org/blender/blender/pulls/132753
218 lines
6.6 KiB
C++
218 lines
6.6 KiB
C++
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup sequencer
|
|
*/
|
|
|
|
#include "BKE_fcurve.hh"
|
|
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_sequence_types.h"
|
|
|
|
#include "IMB_imbuf.hh"
|
|
|
|
#include "RNA_prototypes.hh"
|
|
|
|
#include "SEQ_render.hh"
|
|
#include "SEQ_time.hh"
|
|
|
|
#include "effects.hh"
|
|
#include "render.hh"
|
|
|
|
static void init_speed_effect(Strip *strip)
|
|
{
|
|
if (strip->effectdata) {
|
|
MEM_freeN(strip->effectdata);
|
|
}
|
|
|
|
strip->effectdata = MEM_callocN(sizeof(SpeedControlVars), "speedcontrolvars");
|
|
|
|
SpeedControlVars *v = (SpeedControlVars *)strip->effectdata;
|
|
v->speed_control_type = SEQ_SPEED_STRETCH;
|
|
v->speed_fader = 1.0f;
|
|
v->speed_fader_length = 0.0f;
|
|
v->speed_fader_frame_number = 0.0f;
|
|
}
|
|
|
|
static void load_speed_effect(Strip *strip)
|
|
{
|
|
SpeedControlVars *v = (SpeedControlVars *)strip->effectdata;
|
|
v->frameMap = nullptr;
|
|
}
|
|
|
|
static int num_inputs_speed()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static void free_speed_effect(Strip *strip, const bool /*do_id_user*/)
|
|
{
|
|
SpeedControlVars *v = (SpeedControlVars *)strip->effectdata;
|
|
if (v->frameMap) {
|
|
MEM_freeN(v->frameMap);
|
|
}
|
|
MEM_SAFE_FREE(strip->effectdata);
|
|
}
|
|
|
|
static void copy_speed_effect(Strip *dst, const Strip *src, const int /*flag*/)
|
|
{
|
|
SpeedControlVars *v;
|
|
dst->effectdata = MEM_dupallocN(src->effectdata);
|
|
v = (SpeedControlVars *)dst->effectdata;
|
|
v->frameMap = nullptr;
|
|
}
|
|
|
|
static StripEarlyOut early_out_speed(const Strip * /*strip*/, float /*fac*/)
|
|
{
|
|
return StripEarlyOut::DoEffect;
|
|
}
|
|
|
|
static FCurve *strip_effect_speed_speed_factor_curve_get(Scene *scene, Strip *strip)
|
|
{
|
|
return id_data_find_fcurve(&scene->id, strip, &RNA_Strip, "speed_factor", 0, nullptr);
|
|
}
|
|
|
|
void strip_effect_speed_rebuild_map(Scene *scene, Strip *strip)
|
|
{
|
|
const int effect_strip_length = SEQ_time_right_handle_frame_get(scene, strip) -
|
|
SEQ_time_left_handle_frame_get(scene, strip);
|
|
|
|
if ((strip->seq1 == nullptr) || (effect_strip_length < 1)) {
|
|
return; /* Make COVERITY happy and check for (CID 598) input strip. */
|
|
}
|
|
|
|
const FCurve *fcu = strip_effect_speed_speed_factor_curve_get(scene, strip);
|
|
if (fcu == nullptr) {
|
|
return;
|
|
}
|
|
|
|
SpeedControlVars *v = (SpeedControlVars *)strip->effectdata;
|
|
if (v->frameMap) {
|
|
MEM_freeN(v->frameMap);
|
|
}
|
|
|
|
v->frameMap = static_cast<float *>(MEM_mallocN(sizeof(float) * effect_strip_length, __func__));
|
|
v->frameMap[0] = 0.0f;
|
|
|
|
float target_frame = 0;
|
|
for (int frame_index = 1; frame_index < effect_strip_length; frame_index++) {
|
|
target_frame += evaluate_fcurve(fcu,
|
|
SEQ_time_left_handle_frame_get(scene, strip) + frame_index);
|
|
const int target_frame_max = SEQ_time_strip_length_get(scene, strip->seq1);
|
|
CLAMP(target_frame, 0, target_frame_max);
|
|
v->frameMap[frame_index] = target_frame;
|
|
}
|
|
}
|
|
|
|
static void strip_effect_speed_frame_map_ensure(Scene *scene, Strip *strip)
|
|
{
|
|
const SpeedControlVars *v = (SpeedControlVars *)strip->effectdata;
|
|
if (v->frameMap != nullptr) {
|
|
return;
|
|
}
|
|
|
|
strip_effect_speed_rebuild_map(scene, strip);
|
|
}
|
|
|
|
float strip_speed_effect_target_frame_get(Scene *scene,
|
|
Strip *strip_speed,
|
|
float timeline_frame,
|
|
int input)
|
|
{
|
|
if (strip_speed->seq1 == nullptr) {
|
|
return 0.0f;
|
|
}
|
|
|
|
SEQ_effect_handle_get(strip_speed); /* Ensure, that data are initialized. */
|
|
int frame_index = round_fl_to_int(SEQ_give_frame_index(scene, strip_speed, timeline_frame));
|
|
SpeedControlVars *s = (SpeedControlVars *)strip_speed->effectdata;
|
|
const Strip *source = strip_speed->seq1;
|
|
|
|
float target_frame = 0.0f;
|
|
switch (s->speed_control_type) {
|
|
case SEQ_SPEED_STRETCH: {
|
|
/* Only right handle controls effect speed! */
|
|
const float target_content_length = SEQ_time_strip_length_get(scene, source) -
|
|
source->startofs;
|
|
const float speed_effetct_length = SEQ_time_right_handle_frame_get(scene, strip_speed) -
|
|
SEQ_time_left_handle_frame_get(scene, strip_speed);
|
|
const float ratio = frame_index / speed_effetct_length;
|
|
target_frame = target_content_length * ratio;
|
|
break;
|
|
}
|
|
case SEQ_SPEED_MULTIPLY: {
|
|
const FCurve *fcu = strip_effect_speed_speed_factor_curve_get(scene, strip_speed);
|
|
if (fcu != nullptr) {
|
|
strip_effect_speed_frame_map_ensure(scene, strip_speed);
|
|
target_frame = s->frameMap[frame_index];
|
|
}
|
|
else {
|
|
target_frame = frame_index * s->speed_fader;
|
|
}
|
|
break;
|
|
}
|
|
case SEQ_SPEED_LENGTH:
|
|
target_frame = SEQ_time_strip_length_get(scene, source) * (s->speed_fader_length / 100.0f);
|
|
break;
|
|
case SEQ_SPEED_FRAME_NUMBER:
|
|
target_frame = s->speed_fader_frame_number;
|
|
break;
|
|
}
|
|
|
|
CLAMP(target_frame, 0, SEQ_time_strip_length_get(scene, source));
|
|
target_frame += strip_speed->start;
|
|
|
|
/* No interpolation. */
|
|
if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) {
|
|
return target_frame;
|
|
}
|
|
|
|
/* Interpolation is used, switch between current and next frame based on which input is
|
|
* requested. */
|
|
return input == 0 ? target_frame : ceil(target_frame);
|
|
}
|
|
|
|
static float speed_effect_interpolation_ratio_get(Scene *scene,
|
|
Strip *strip_speed,
|
|
float timeline_frame)
|
|
{
|
|
const float target_frame = strip_speed_effect_target_frame_get(
|
|
scene, strip_speed, timeline_frame, 0);
|
|
return target_frame - floor(target_frame);
|
|
}
|
|
|
|
static ImBuf *do_speed_effect(const SeqRenderData *context,
|
|
Strip *strip,
|
|
float timeline_frame,
|
|
float fac,
|
|
ImBuf *ibuf1,
|
|
ImBuf *ibuf2)
|
|
{
|
|
const SpeedControlVars *s = (SpeedControlVars *)strip->effectdata;
|
|
SeqEffectHandle cross_effect = get_sequence_effect_impl(STRIP_TYPE_CROSS);
|
|
ImBuf *out;
|
|
|
|
if (s->flags & SEQ_SPEED_USE_INTERPOLATION) {
|
|
fac = speed_effect_interpolation_ratio_get(context->scene, strip, timeline_frame);
|
|
/* Current frame is ibuf1, next frame is ibuf2. */
|
|
out = cross_effect.execute(context, nullptr, timeline_frame, fac, ibuf1, ibuf2);
|
|
return out;
|
|
}
|
|
|
|
/* No interpolation. */
|
|
return IMB_dupImBuf(ibuf1);
|
|
}
|
|
|
|
void speed_effect_get_handle(SeqEffectHandle &rval)
|
|
{
|
|
rval.init = init_speed_effect;
|
|
rval.num_inputs = num_inputs_speed;
|
|
rval.load = load_speed_effect;
|
|
rval.free = free_speed_effect;
|
|
rval.copy = copy_speed_effect;
|
|
rval.execute = do_speed_effect;
|
|
rval.early_out = early_out_speed;
|
|
}
|