Files
test2/source/blender/sequencer/intern/effects/vse_effect_speed.cc
Falk David ff91c27481 Cleanup: VSE: Rename SequenceType to StripType as well as flags
Rename the flags from `SEQ_TYPE_*` to `STRIP_TYPE_*`.

Pull Request: https://projects.blender.org/blender/blender/pulls/132753
2025-01-07 16:10:36 +01:00

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;
}