VSE: Make mirror operator work in VSE preview

By default, the Ctrl-M shortcut is not working in the VSE preview.

This PR aims to address the issue and provide a working iteration of
the feature.

In my view, it would be preferable for this operator to not only flip
the `flip_x` and `flip_y` values, but also manipulate the transform and
rotation of the strips in a way that keeps the strip in the same
location on the screen, rather than flipping them to the other side.

I decided to implement the feature with this correction functionality,
as it seems more coherent with how the mirror works in other areas of
Blender.

Pull Request: https://projects.blender.org/blender/blender/pulls/136343
This commit is contained in:
Ramon Klauck
2025-04-22 17:28:29 +02:00
committed by Richard Antalik
parent b59b4d87a8
commit 12f5ce7c85
3 changed files with 61 additions and 4 deletions

View File

@@ -40,6 +40,9 @@ struct TransDataSeq {
float orig_translation[2];
float orig_scale[2];
float orig_rotation;
int orig_flag;
float active_seq_orig_rotation;
float2 orig_mirror;
};
} // namespace
@@ -54,6 +57,7 @@ static TransData *SeqToTransData(const Scene *scene,
const StripTransform *transform = strip->data->transform;
const float2 origin = seq::image_transform_origin_offset_pixelspace_get(scene, strip);
const float2 mirror = seq::image_transform_mirror_factor_get(strip);
Editing *ed = seq::editing_get(scene);
float vertex[2] = {origin[0], origin[1]};
/* Add control vertex, so rotation and scale can be calculated.
@@ -90,6 +94,9 @@ static TransData *SeqToTransData(const Scene *scene,
tdseq->orig_scale[0] = transform->scale_x;
tdseq->orig_scale[1] = transform->scale_y;
tdseq->orig_rotation = transform->rotation;
tdseq->orig_flag = strip->flag;
tdseq->orig_mirror = mirror;
tdseq->active_seq_orig_rotation = ed->act_seq->data->transform->rotation;
td->extra = (void *)tdseq;
td->ext = nullptr;
@@ -197,6 +204,7 @@ static void recalcData_sequencer_image(TransInfo *t)
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
TransData *td = nullptr;
TransData2D *td2d = nullptr;
Editing *ed = seq::editing_get(t->scene);
int i;
for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
@@ -222,13 +230,12 @@ static void recalcData_sequencer_image(TransInfo *t)
TransDataSeq *tdseq = static_cast<TransDataSeq *>(td->extra);
Strip *strip = tdseq->strip;
StripTransform *transform = strip->data->transform;
const float2 mirror = seq::image_transform_mirror_factor_get(strip);
/* Calculate translation. */
float translation[2];
copy_v2_v2(translation, tdseq->orig_origin_position);
sub_v2_v2(translation, origin);
mul_v2_v2(translation, mirror);
mul_v2_v2(translation, tdseq->orig_mirror);
translation[0] *= t->scene->r.yasp / t->scene->r.xasp;
/* Round resulting position to integer pixels. Resulting strip
@@ -245,7 +252,33 @@ static void recalcData_sequencer_image(TransInfo *t)
/* Rotation. Scaling can cause negative rotation. */
if (t->mode == TFM_ROTATION) {
transform->rotation = tdseq->orig_rotation - (t->values_final[0] * mirror[0] * mirror[1]);
transform->rotation = tdseq->orig_rotation -
(t->values_final[0] * tdseq->orig_mirror[0] * tdseq->orig_mirror[1]);
}
if (t->mode == TFM_MIRROR) {
transform->xofs *= t->values_final[0];
transform->yofs *= t->values_final[1];
if (t->orient_curr == O_SET) {
if (strip == ed->act_seq) {
transform->rotation = -tdseq->orig_rotation;
}
else {
transform->rotation = tdseq->orig_rotation + (2 * -tdseq->active_seq_orig_rotation);
}
}
else {
strip->flag = tdseq->orig_flag;
if (t->values_final[0] == -1) {
strip->flag ^= SEQ_FLIPX;
}
if (t->values_final[1] == -1) {
strip->flag ^= SEQ_FLIPY;
}
transform->rotation = tdseq->orig_rotation;
}
}
if ((t->animtimer) && animrig::is_autokey_on(t->scene)) {
@@ -273,6 +306,12 @@ static void special_aftertrans_update__sequencer_image(bContext * /*C*/, TransIn
if (t->mode == TFM_ROTATION) {
transform->rotation = tdseq->orig_rotation;
}
if (t->mode == TFM_MIRROR) {
transform->xofs = tdseq->orig_translation[0];
transform->yofs = tdseq->orig_translation[1];
transform->rotation = tdseq->orig_rotation;
strip->flag = tdseq->orig_flag;
}
continue;
}

View File

@@ -178,6 +178,17 @@ static void applyMirror(TransInfo *t)
SNPRINTF(str, IFACE_("Mirror%s"), t->con.text);
if (t->options & CTX_SEQUENCER_IMAGE) {
if (axis_bitmap == 1) {
t->values_final[0] = -1;
t->values_final[1] = 1;
}
if (axis_bitmap == 2) {
t->values_final[0] = 1;
t->values_final[1] = -1;
}
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
@@ -194,6 +205,10 @@ static void applyMirror(TransInfo *t)
ED_area_status_text(t->area, str);
}
else {
if (t->options & CTX_SEQUENCER_IMAGE) {
t->values_final[0] = 1.0f;
t->values_final[1] = 1.0f;
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {

View File

@@ -48,6 +48,7 @@
#include "SEQ_select.hh"
#include "SEQ_transform.hh"
#include "transform.hh"
#include "transform_orientations.hh"
@@ -764,7 +765,9 @@ short transform_orientation_matrix_get(bContext *C,
Scene *scene = t->scene;
Strip *strip = seq::select_active_get(scene);
if (strip && strip->data->transform && orient_index == V3D_ORIENT_LOCAL) {
axis_angle_to_mat3_single(r_spacemtx, 'Z', strip->data->transform->rotation);
const float2 mirror = seq::image_transform_mirror_factor_get(strip);
axis_angle_to_mat3_single(
r_spacemtx, 'Z', strip->data->transform->rotation * mirror[0] * mirror[1]);
return orient_index;
}
}