|
|
|
|
@@ -3069,8 +3069,6 @@ static void init_speed_effect(Sequence *seq)
|
|
|
|
|
seq->effectdata = MEM_callocN(sizeof(SpeedControlVars), "speedcontrolvars");
|
|
|
|
|
|
|
|
|
|
v = (SpeedControlVars *)seq->effectdata;
|
|
|
|
|
v->frameMap = NULL;
|
|
|
|
|
v->length = 0;
|
|
|
|
|
v->speed_control_type = SEQ_SPEED_STRETCH;
|
|
|
|
|
v->speed_fader = 1.0f;
|
|
|
|
|
v->speed_fader_length = 0.0f;
|
|
|
|
|
@@ -3080,9 +3078,7 @@ static void init_speed_effect(Sequence *seq)
|
|
|
|
|
static void load_speed_effect(Sequence *seq)
|
|
|
|
|
{
|
|
|
|
|
SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
|
|
|
|
|
|
|
|
|
|
v->frameMap = NULL;
|
|
|
|
|
v->length = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int num_inputs_speed(void)
|
|
|
|
|
@@ -3105,7 +3101,6 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla
|
|
|
|
|
dst->effectdata = MEM_dupallocN(src->effectdata);
|
|
|
|
|
v = (SpeedControlVars *)dst->effectdata;
|
|
|
|
|
v->frameMap = NULL;
|
|
|
|
|
v->length = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
|
|
|
|
|
@@ -3127,164 +3122,112 @@ static int seq_effect_speed_get_strip_content_length(const Sequence *seq)
|
|
|
|
|
return seq->len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force)
|
|
|
|
|
static FCurve *seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *seq)
|
|
|
|
|
{
|
|
|
|
|
int timeline_frame;
|
|
|
|
|
float fallback_fac = 1.0f;
|
|
|
|
|
SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
|
|
|
|
|
FCurve *fcu = NULL;
|
|
|
|
|
return id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if not already done, load / initialize data */
|
|
|
|
|
SEQ_effect_handle_get(seq);
|
|
|
|
|
|
|
|
|
|
if ((force == false) && (seq->len == v->length) && (v->frameMap != NULL)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated.
|
|
|
|
|
* This is, because `target_frame` value is integrated over time. */
|
|
|
|
|
void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq)
|
|
|
|
|
{
|
|
|
|
|
if ((seq->seq1 == NULL) || (seq->len < 1)) {
|
|
|
|
|
/* make coverity happy and check for (CID 598) input strip ... */
|
|
|
|
|
return; /* Make coverity happy and check for (CID 598) input strip... */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FCurve *fcu = seq_effect_speed_speed_factor_curve_get(scene, seq);
|
|
|
|
|
if (fcu == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* XXX(campbell): new in 2.5x. should we use the animation system this way?
|
|
|
|
|
* The fcurve is needed because many frames need evaluating at once. */
|
|
|
|
|
switch (v->speed_control_type) {
|
|
|
|
|
case SEQ_SPEED_MULTIPLY: {
|
|
|
|
|
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SEQ_SPEED_FRAME_NUMBER: {
|
|
|
|
|
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_frame_number", 0, NULL);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SEQ_SPEED_LENGTH: {
|
|
|
|
|
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_length", 0, NULL);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!v->frameMap || v->length != seq->len) {
|
|
|
|
|
if (v->frameMap) {
|
|
|
|
|
MEM_freeN(v->frameMap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v->length = seq->len;
|
|
|
|
|
|
|
|
|
|
v->frameMap = MEM_callocN(sizeof(float) * v->length, "speedcontrol frameMap");
|
|
|
|
|
SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
|
|
|
|
|
if (v->frameMap) {
|
|
|
|
|
MEM_freeN(v->frameMap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fallback_fac = 1.0;
|
|
|
|
|
const int effect_strip_length = seq->enddisp - seq->startdisp;
|
|
|
|
|
v->frameMap = MEM_mallocN(sizeof(float) * effect_strip_length, __func__);
|
|
|
|
|
v->frameMap[0] = 0.0f;
|
|
|
|
|
|
|
|
|
|
const int target_strip_length = seq_effect_speed_get_strip_content_length(seq->seq1);
|
|
|
|
|
|
|
|
|
|
if (v->speed_control_type == SEQ_SPEED_STRETCH) {
|
|
|
|
|
if ((seq->seq1->enddisp != seq->seq1->start) && (target_strip_length != 0)) {
|
|
|
|
|
fallback_fac = (float)target_strip_length / (float)(seq->seq1->enddisp - seq->seq1->start);
|
|
|
|
|
fcu = NULL;
|
|
|
|
|
}
|
|
|
|
|
float target_frame = 0;
|
|
|
|
|
for (int frame_index = 1; frame_index < effect_strip_length; frame_index++) {
|
|
|
|
|
target_frame += evaluate_fcurve(fcu, seq->startdisp + frame_index);
|
|
|
|
|
v->frameMap[frame_index] = target_frame;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* if there is no fcurve, use value as simple multiplier */
|
|
|
|
|
if (!fcu) {
|
|
|
|
|
switch (v->speed_control_type) {
|
|
|
|
|
case SEQ_SPEED_MULTIPLY: {
|
|
|
|
|
fallback_fac = v->speed_fader;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SEQ_SPEED_FRAME_NUMBER: {
|
|
|
|
|
fallback_fac = v->speed_fader_frame_number;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SEQ_SPEED_LENGTH: {
|
|
|
|
|
fallback_fac = v->speed_fader_length;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void seq_effect_speed_frame_map_ensure(Scene *scene, Sequence *seq, FCurve *fcu)
|
|
|
|
|
{
|
|
|
|
|
SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
|
|
|
|
|
if (v->frameMap != NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ELEM(v->speed_control_type, SEQ_SPEED_MULTIPLY, SEQ_SPEED_STRETCH)) {
|
|
|
|
|
float cursor = 0;
|
|
|
|
|
float facf;
|
|
|
|
|
|
|
|
|
|
v->frameMap[0] = 0;
|
|
|
|
|
v->lastValidFrame = 0;
|
|
|
|
|
|
|
|
|
|
for (timeline_frame = 1; timeline_frame < v->length; timeline_frame++) {
|
|
|
|
|
if (fcu) {
|
|
|
|
|
facf = evaluate_fcurve(fcu, seq->startdisp + timeline_frame);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
facf = fallback_fac;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cursor += facf;
|
|
|
|
|
|
|
|
|
|
if (cursor >= target_strip_length) {
|
|
|
|
|
v->frameMap[timeline_frame] = target_strip_length - 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
v->frameMap[timeline_frame] = cursor;
|
|
|
|
|
v->lastValidFrame = timeline_frame;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
float facf;
|
|
|
|
|
|
|
|
|
|
v->lastValidFrame = 0;
|
|
|
|
|
for (timeline_frame = 0; timeline_frame < v->length; timeline_frame++) {
|
|
|
|
|
|
|
|
|
|
if (fcu) {
|
|
|
|
|
facf = evaluate_fcurve(fcu, seq->startdisp + timeline_frame);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
facf = fallback_fac;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (v->speed_control_type == SEQ_SPEED_LENGTH) {
|
|
|
|
|
facf *= target_strip_length;
|
|
|
|
|
facf /= 100.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (facf >= target_strip_length) {
|
|
|
|
|
facf = target_strip_length - 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
v->lastValidFrame = timeline_frame;
|
|
|
|
|
}
|
|
|
|
|
v->frameMap[timeline_frame] = facf;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
seq_effect_speed_rebuild_map(scene, seq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Override timeline_frame when rendering speed effect input. */
|
|
|
|
|
float seq_speed_effect_target_frame_get(const SeqRenderData *context,
|
|
|
|
|
Sequence *seq,
|
|
|
|
|
float seq_speed_effect_target_frame_get(Scene *scene,
|
|
|
|
|
Sequence *seq_speed,
|
|
|
|
|
float timeline_frame,
|
|
|
|
|
int input)
|
|
|
|
|
{
|
|
|
|
|
int frame_index = seq_give_frame_index(seq, timeline_frame);
|
|
|
|
|
SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
|
|
|
|
|
seq_effect_speed_rebuild_map(context->scene, seq, false);
|
|
|
|
|
if (seq_speed->seq1 == NULL) {
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SEQ_effect_handle_get(seq_speed); /* Ensure, that data are initialized. */
|
|
|
|
|
int frame_index = seq_give_frame_index(seq_speed, timeline_frame);
|
|
|
|
|
SpeedControlVars *s = (SpeedControlVars *)seq_speed->effectdata;
|
|
|
|
|
const Sequence *source = seq_speed->seq1;
|
|
|
|
|
|
|
|
|
|
float target_frame = 0.0f;
|
|
|
|
|
switch (s->speed_control_type) {
|
|
|
|
|
case SEQ_SPEED_STRETCH:
|
|
|
|
|
const float target_content_length = seq_effect_speed_get_strip_content_length(source);
|
|
|
|
|
const float target_strip_length = source->enddisp - source->startdisp;
|
|
|
|
|
const float ratio = target_content_length / target_strip_length;
|
|
|
|
|
target_frame = frame_index * ratio;
|
|
|
|
|
break;
|
|
|
|
|
case SEQ_SPEED_MULTIPLY:
|
|
|
|
|
FCurve *fcu = seq_effect_speed_speed_factor_curve_get(scene, seq_speed);
|
|
|
|
|
if (fcu != NULL) {
|
|
|
|
|
seq_effect_speed_frame_map_ensure(scene, seq_speed, fcu);
|
|
|
|
|
target_frame = s->frameMap[frame_index];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
target_frame = frame_index * s->speed_fader;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SEQ_SPEED_LENGTH:
|
|
|
|
|
target_frame = seq_effect_speed_get_strip_content_length(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_effect_speed_get_strip_content_length(source));
|
|
|
|
|
target_frame += seq_speed->start;
|
|
|
|
|
|
|
|
|
|
/* No interpolation. */
|
|
|
|
|
if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) {
|
|
|
|
|
return seq->start + s->frameMap[frame_index];
|
|
|
|
|
return target_frame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We need to provide current and next image for interpolation. */
|
|
|
|
|
if (input == 0) { /* Current frame. */
|
|
|
|
|
return floor(seq->start + s->frameMap[frame_index]);
|
|
|
|
|
}
|
|
|
|
|
/* Next frame. */
|
|
|
|
|
return ceil(seq->start + s->frameMap[frame_index]);
|
|
|
|
|
/* 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(SpeedControlVars *s,
|
|
|
|
|
Sequence *seq,
|
|
|
|
|
static float speed_effect_interpolation_ratio_get(Scene *scene,
|
|
|
|
|
Sequence *seq_speed,
|
|
|
|
|
float timeline_frame)
|
|
|
|
|
{
|
|
|
|
|
int frame_index = seq_give_frame_index(seq, timeline_frame);
|
|
|
|
|
return s->frameMap[frame_index] - floor(s->frameMap[frame_index]);
|
|
|
|
|
const float target_frame = seq_speed_effect_target_frame_get(
|
|
|
|
|
scene, seq_speed, timeline_frame, 0);
|
|
|
|
|
return target_frame - floor(target_frame);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ImBuf *do_speed_effect(const SeqRenderData *context,
|
|
|
|
|
@@ -3302,7 +3245,7 @@ static ImBuf *do_speed_effect(const SeqRenderData *context,
|
|
|
|
|
|
|
|
|
|
if (s->flags & SEQ_SPEED_USE_INTERPOLATION) {
|
|
|
|
|
out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
|
|
|
|
|
facf0 = facf1 = speed_effect_interpolation_ratio_get(s, seq, timeline_frame);
|
|
|
|
|
facf0 = facf1 = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame);
|
|
|
|
|
/* Current frame is ibuf1, next frame is ibuf2. */
|
|
|
|
|
out = seq_render_effect_execute_threaded(
|
|
|
|
|
&cross_effect, context, NULL, timeline_frame, facf0, facf1, ibuf1, ibuf2, ibuf3);
|
|
|
|
|
|