Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py19
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c227
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c5
-rw-r--r--source/blender/editors/transform/transform.c19
-rw-r--r--source/blender/editors/transform/transform_constraints.c12
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c30
-rw-r--r--source/blender/editors/transform/transform_generics.c52
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c322
-rw-r--r--source/blender/editors/transform/transform_mode.c12
-rw-r--r--source/blender/editors/transform/transform_mode.h2
-rw-r--r--source/blender/editors/transform/transform_mode_resize.c35
-rw-r--r--source/blender/editors/transform/transform_mode_shrink_fatten.c4
-rw-r--r--source/blender/editors/transform/transform_ops.c14
-rw-r--r--source/blender/editors/transform/transform_orientations.c13
-rw-r--r--source/blender/sequencer/SEQ_transform.h4
-rw-r--r--source/blender/sequencer/intern/strip_transform.c54
16 files changed, 467 insertions, 357 deletions
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 008129cd389..9b1b401bc5b 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -2515,6 +2515,18 @@ class _defs_sequencer_generic:
keymap="Sequencer Tool: Scale",
)
+ @ToolDef.from_fn
+ def transform():
+ return dict(
+ idname="builtin.transform",
+ label="Transform",
+ description=(
+ "Supports any combination of grab, rotate, and scale at once"
+ ),
+ icon="ops.transform.transform",
+ widget="SEQUENCER_GGT_gizmo2d",
+ # No keymap default action, only for gizmo!
+ )
class _defs_sequencer_select:
@ToolDef.from_fn
@@ -3112,6 +3124,8 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_sequencer_generic.translate,
_defs_sequencer_generic.rotate,
_defs_sequencer_generic.scale,
+ _defs_sequencer_generic.transform,
+ None,
_defs_sequencer_generic.sample,
*_tools_annotate,
],
@@ -3126,9 +3140,12 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_sequencer_generic.translate,
_defs_sequencer_generic.rotate,
_defs_sequencer_generic.scale,
- _defs_sequencer_generic.blade,
+ _defs_sequencer_generic.transform,
+ None,
_defs_sequencer_generic.sample,
*_tools_annotate,
+ None,
+ _defs_sequencer_generic.blade,
],
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
index 6fd06b47656..08dbdd021d3 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -98,65 +98,13 @@ static bool gizmo_calc_rect_view_margin(const wmGizmo *gz, const float dims[2],
zero_v2(margin);
return false;
}
+
margin[0] = ((handle_size * scale_xy[0]));
margin[1] = ((handle_size * scale_xy[1]));
return true;
}
/* -------------------------------------------------------------------- */
-
-static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[2], bool r_constrain_axis[2])
-{
- bool x = true, y = true;
- switch (part) {
- case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X: {
- ARRAY_SET_ITEMS(r_pt, 0.5, 0.0);
- x = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X: {
- ARRAY_SET_ITEMS(r_pt, -0.5, 0.0);
- x = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y: {
- ARRAY_SET_ITEMS(r_pt, 0.0, 0.5);
- y = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y: {
- ARRAY_SET_ITEMS(r_pt, 0.0, -0.5);
- y = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y: {
- ARRAY_SET_ITEMS(r_pt, 0.5, 0.5);
- x = y = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y: {
- ARRAY_SET_ITEMS(r_pt, 0.5, -0.5);
- x = y = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y: {
- ARRAY_SET_ITEMS(r_pt, -0.5, 0.5);
- x = y = false;
- break;
- }
- case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y: {
- ARRAY_SET_ITEMS(r_pt, -0.5, -0.5);
- x = y = false;
- break;
- }
- default:
- BLI_assert(0);
- }
- r_constrain_axis[0] = x;
- r_constrain_axis[1] = y;
-}
-
-/* -------------------------------------------------------------------- */
/** \name Box Draw Style
*
* Useful for 3D views, see: #ED_GIZMO_CAGE2D_STYLE_BOX
@@ -400,6 +348,7 @@ static void cage2d_draw_box_interaction(const float color[4],
ARRAY_SET_ITEMS(verts[1], r_rotate.xmin, r_rotate.ymax);
ARRAY_SET_ITEMS(verts[2], r_rotate.xmax, r_rotate.ymax);
ARRAY_SET_ITEMS(verts[3], r_rotate.xmax, r_rotate.ymin);
+
verts_len = 4;
if (is_solid) {
prim_type = GPU_PRIM_TRI_FAN;
@@ -769,10 +718,10 @@ static int gizmo_cage2d_get_cursor(wmGizmo *gz)
return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X:
- return WM_CURSOR_X_MOVE;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y:
- return WM_CURSOR_Y_MOVE;
+ return WM_CURSOR_NSEW_SCROLL;
/* TODO: diagonal cursor. */
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y:
@@ -937,173 +886,11 @@ static int gizmo_cage2d_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static int gizmo_cage2d_modal(bContext *C,
- wmGizmo *gz,
- const wmEvent *event,
+static int gizmo_cage2d_modal(bContext *UNUSED(C),
+ wmGizmo *UNUSED(gz),
+ const wmEvent *UNUSED(event),
eWM_GizmoFlagTweak UNUSED(tweak_flag))
{
- if (event->type != MOUSEMOVE) {
- return OPERATOR_RUNNING_MODAL;
- }
- /* For transform logic to be manageable we operate in -0.5..0.5 2D space,
- * no matter the size of the rectangle, mouse coords are scaled to unit space.
- * The mouse coords have been projected into the matrix
- * so we don't need to worry about axis alignment.
- *
- * - The cursor offset are multiplied by 'dims'.
- * - Matrix translation is also multiplied by 'dims'.
- */
- RectTransformInteraction *data = gz->interaction_data;
- float point_local[2];
-
- float dims[2];
- RNA_float_get_array(gz->ptr, "dimensions", dims);
-
- {
- float matrix_back[4][4];
- copy_m4_m4(matrix_back, gz->matrix_offset);
- copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
-
- bool ok = gizmo_window_project_2d(
- C, gz, (const float[2]){UNPACK2(event->mval)}, 2, false, point_local);
- copy_m4_m4(gz->matrix_offset, matrix_back);
- if (!ok) {
- return OPERATOR_RUNNING_MODAL;
- }
- }
-
- const int transform_flag = RNA_enum_get(gz->ptr, "transform");
- wmGizmoProperty *gz_prop;
-
- gz_prop = WM_gizmo_target_property_find(gz, "matrix");
- if (gz_prop->type != NULL) {
- WM_gizmo_target_property_float_get_array(gz, gz_prop, &gz->matrix_offset[0][0]);
- }
-
- if (gz->highlight_part == ED_GIZMO_CAGE2D_PART_TRANSLATE) {
- /* do this to prevent clamping from changing size */
- copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
- gz->matrix_offset[3][0] = data->orig_matrix_offset[3][0] +
- (point_local[0] - data->orig_mouse[0]);
- gz->matrix_offset[3][1] = data->orig_matrix_offset[3][1] +
- (point_local[1] - data->orig_mouse[1]);
- }
- else if (gz->highlight_part == ED_GIZMO_CAGE2D_PART_ROTATE) {
-
-#define MUL_V2_V3_M4_FINAL(test_co, mouse_co) \
- mul_v3_m4v3( \
- test_co, data->orig_matrix_final_no_offset, ((const float[3]){UNPACK2(mouse_co), 0.0}))
-
- float test_co[3];
-
- if (data->dial == NULL) {
- MUL_V2_V3_M4_FINAL(test_co, data->orig_matrix_offset[3]);
-
- data->dial = BLI_dial_init(test_co, FLT_EPSILON);
-
- MUL_V2_V3_M4_FINAL(test_co, data->orig_mouse);
- BLI_dial_angle(data->dial, test_co);
- }
-
- /* rotate */
- MUL_V2_V3_M4_FINAL(test_co, point_local);
- const float angle = BLI_dial_angle(data->dial, test_co);
-
- float matrix_space_inv[4][4];
- float matrix_rotate[4][4];
- float pivot[3];
-
- copy_v3_v3(pivot, data->orig_matrix_offset[3]);
-
- invert_m4_m4(matrix_space_inv, gz->matrix_space);
-
- unit_m4(matrix_rotate);
- mul_m4_m4m4(matrix_rotate, matrix_rotate, matrix_space_inv);
- rotate_m4(matrix_rotate, 'Z', -angle);
- mul_m4_m4m4(matrix_rotate, matrix_rotate, gz->matrix_space);
-
- zero_v3(matrix_rotate[3]);
- transform_pivot_set_m4(matrix_rotate, pivot);
-
- mul_m4_m4m4(gz->matrix_offset, matrix_rotate, data->orig_matrix_offset);
-
-#undef MUL_V2_V3_M4_FINAL
- }
- else {
- /* scale */
- copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
- float pivot[2];
- bool constrain_axis[2] = {false};
-
- if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE) {
- gizmo_rect_pivot_from_scale_part(gz->highlight_part, pivot, constrain_axis);
- }
- else {
- zero_v2(pivot);
- }
-
- /* Cursor deltas scaled to (-0.5..0.5). */
- float delta_orig[2], delta_curr[2];
- for (int i = 0; i < 2; i++) {
- delta_orig[i] = ((data->orig_mouse[i] - data->orig_matrix_offset[3][i]) / dims[i]) -
- pivot[i];
- delta_curr[i] = ((point_local[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i];
- }
-
- float scale[2] = {1.0f, 1.0f};
- for (int i = 0; i < 2; i++) {
- if (constrain_axis[i] == false) {
- if (delta_orig[i] < 0.0f) {
- delta_orig[i] *= -1.0f;
- delta_curr[i] *= -1.0f;
- }
- const int sign = signum_i(scale[i]);
-
- scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i]));
-
- if ((transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_SIGNED) == 0) {
- if (sign != signum_i(scale[i])) {
- scale[i] = 0.0f;
- }
- }
- }
- }
-
- if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM) {
- if (constrain_axis[0] == false && constrain_axis[1] == false) {
- scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f;
- }
- else if (constrain_axis[0] == false) {
- scale[1] = scale[0];
- }
- else if (constrain_axis[1] == false) {
- scale[0] = scale[1];
- }
- else {
- BLI_assert(0);
- }
- }
-
- /* scale around pivot */
- float matrix_scale[4][4];
- unit_m4(matrix_scale);
-
- mul_v3_fl(matrix_scale[0], scale[0]);
- mul_v3_fl(matrix_scale[1], scale[1]);
-
- transform_pivot_set_m4(matrix_scale,
- (const float[3]){pivot[0] * dims[0], pivot[1] * dims[1], 0.0f});
- mul_m4_m4m4(gz->matrix_offset, data->orig_matrix_offset, matrix_scale);
- }
-
- if (gz_prop->type != NULL) {
- WM_gizmo_target_property_float_set_array(C, gz, gz_prop, &gz->matrix_offset[0][0]);
- }
-
- /* tag the region for redraw */
- ED_region_tag_redraw_editor_overlays(CTX_wm_region(C));
- WM_event_add_mousemove(CTX_wm_window(C));
-
return OPERATOR_RUNNING_MODAL;
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index e5e241c8b7e..6e4c3c774a2 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2250,6 +2250,11 @@ void sequencer_draw_preview(const bContext *C,
sequencer_draw_maskedit(C, scene, region, sseq);
#endif
+ /* Draw registered callbacks. */
+ GPU_framebuffer_bind(framebuffer_overlay);
+ ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
+ GPU_framebuffer_bind_no_srgb(framebuffer_overlay);
+
/* Scope is freed in sequencer_check_scopes when `ibuf` changes and redraw is needed. */
if (ibuf) {
IMB_freeImBuf(ibuf);
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 9dcd3a3e510..ec3847acbce 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -797,6 +797,25 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
if (constraint_new == CON_AXIS2) {
return false;
}
+
+ if (t->data_type == TC_SEQ_IMAGE_DATA) {
+ /* Setup the 2d msg string so it writes out the transform space. */
+ msg_2d = msg_3d;
+
+ short orient_index = 1;
+ if (t->orient_curr == O_DEFAULT || ELEM(constraint_curr, -1, constraint_new)) {
+ /* Successive presses on existing axis, cycle orientation modes. */
+ orient_index = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient));
+ }
+
+ transform_orientations_current_set(t, orient_index);
+ if (orient_index != 0) {
+ /* Make sure that we don't stop the constraint unless we are looped back around to
+ * "no constraint". */
+ constraint_curr = -1;
+ }
+ }
+
if (constraint_curr == constraint_new) {
stopConstraint(t);
}
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index e2ad89e0dbc..23ba335476c 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -755,7 +755,7 @@ void drawConstraint(TransInfo *t)
{
TransCon *tc = &(t->con);
- if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) {
+ if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) {
return;
}
if (!(tc->mode & CON_APPLY)) {
@@ -921,6 +921,16 @@ static void drawObjectConstraint(TransInfo *t)
}
}
+ if (t->options & CTX_SEQUENCER_IMAGE) {
+ /* Because we construct an "L" shape to deform the sequence, we should skip
+ * all points except the first vertex. Otherwise we will draw the same axis constraint line
+ * 3 times for each strip.
+ */
+ if (i % 3 != 0) {
+ continue;
+ }
+ }
+
if (t->flag & T_EDIT) {
mul_v3_m4v3(co, tc->mat, td->center);
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index 6e3f12de472..2b5ed268504 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -64,12 +64,16 @@ static TransData *SeqToTransData(const Scene *scene,
SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, origin);
float vertex[2] = {origin[0], origin[1]};
- /* Add control vertex, so rotation and scale can be calculated. */
+ /* Add control vertex, so rotation and scale can be calculated.
+ * All three vertices will form a "L" shape that is aligned to the local strip axis.
+ */
if (vert_index == 1) {
- vertex[0] += 1.0f;
+ vertex[0] += cosf(transform->rotation);
+ vertex[1] += sinf(transform->rotation);
}
else if (vert_index == 2) {
- vertex[1] += 1.0f;
+ vertex[0] -= sinf(transform->rotation);
+ vertex[1] += cosf(transform->rotation);
}
td2d->loc[0] = vertex[0];
@@ -81,10 +85,12 @@ static TransData *SeqToTransData(const Scene *scene,
td->center[0] = origin[0];
td->center[1] = origin[1];
- memset(td->axismtx, 0, sizeof(td->axismtx));
- td->axismtx[2][2] = 1.0f;
unit_m3(td->mtx);
unit_m3(td->smtx);
+ unit_m3(td->axismtx);
+
+ rotate_m3(td->axismtx, transform->rotation);
+ normalize_m3(td->axismtx);
tdseq->seq = seq;
copy_v2_v2(tdseq->orig_origin_position, origin);
@@ -159,18 +165,18 @@ void recalcData_sequencer_image(TransInfo *t)
for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
/* Origin. */
- float loc[2];
- copy_v2_v2(loc, td2d->loc);
+ float origin[2];
+ copy_v2_v2(origin, td2d->loc);
i++, td++, td2d++;
/* X and Y control points used to read scale and rotation. */
float handle_x[2];
copy_v2_v2(handle_x, td2d->loc);
- sub_v2_v2(handle_x, loc);
+ sub_v2_v2(handle_x, origin);
i++, td++, td2d++;
float handle_y[2];
copy_v2_v2(handle_y, td2d->loc);
- sub_v2_v2(handle_y, loc);
+ sub_v2_v2(handle_y, origin);
TransDataSeq *tdseq = td->extra;
Sequence *seq = tdseq->seq;
@@ -181,8 +187,9 @@ void recalcData_sequencer_image(TransInfo *t)
/* Calculate translation. */
float translation[2];
copy_v2_v2(translation, tdseq->orig_origin_position);
- sub_v2_v2(translation, loc);
+ sub_v2_v2(translation, origin);
mul_v2_v2(translation, mirror);
+
transform->xofs = tdseq->orig_translation[0] - translation[0];
transform->yofs = tdseq->orig_translation[1] - translation[1];
@@ -192,7 +199,8 @@ void recalcData_sequencer_image(TransInfo *t)
/* Rotation. Scaling can cause negative rotation. */
if (t->mode == TFM_ROTATION) {
- float rotation = angle_signed_v2v2(handle_x, (float[]){1, 0}) * mirror[0] * mirror[1];
+ const float orig_dir[2] = {cosf(tdseq->orig_rotation), sinf(tdseq->orig_rotation)};
+ float rotation = angle_signed_v2v2(handle_x, orig_dir) * mirror[0] * mirror[1];
transform->rotation = tdseq->orig_rotation + rotation;
transform->rotation += DEG2RAD(360.0);
transform->rotation = fmod(transform->rotation, DEG2RAD(360.0));
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 09c338046ed..8effb82173b 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -73,42 +73,56 @@
void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options)
{
+ if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_SEQ)) {
+ return;
+ }
+
float v1[3], v2[3], v3[3];
uchar col[3], col2[3];
if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = t->view;
- GPU_matrix_push();
-
copy_v3_v3(v3, dir);
mul_v3_fl(v3, v3d->clip_end);
sub_v3_v3v3(v2, center, v3);
add_v3_v3v3(v1, center, v3);
+ }
+ else if (t->spacetype == SPACE_SEQ) {
+ View2D *v2d = t->view;
- if (options & DRAWLIGHT) {
- col[0] = col[1] = col[2] = 220;
- }
- else {
- UI_GetThemeColor3ubv(TH_GRID, col);
- }
- UI_make_axis_color(col, col2, axis);
+ copy_v3_v3(v3, dir);
+ float max_dist = max_ff(BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur));
+ mul_v3_fl(v3, max_dist);
+
+ sub_v3_v3v3(v2, center, v3);
+ add_v3_v3v3(v1, center, v3);
+ }
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_matrix_push();
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- immUniformColor3ubv(col2);
+ if (options & DRAWLIGHT) {
+ col[0] = col[1] = col[2] = 220;
+ }
+ else {
+ UI_GetThemeColor3ubv(TH_GRID, col);
+ }
+ UI_make_axis_color(col, col2, axis);
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(pos, v1);
- immVertex3fv(pos, v2);
- immEnd();
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immUnbindProgram();
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ubv(col2);
- GPU_matrix_pop();
- }
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
}
/**
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 61119c72ad6..7ba52ec823d 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -173,6 +173,7 @@ typedef struct GizmoGroup2D {
float origin[2];
float min[2];
float max[2];
+ float rotation;
bool no_cage;
@@ -241,7 +242,7 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
}
ScrArea *area = CTX_wm_area(C);
- bool changed = false;
+ bool has_select = false;
if (area->spacetype == SPACE_IMAGE) {
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -249,18 +250,75 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, NULL, &objects_len);
if (ED_uvedit_minmax_multi(scene, objects, objects_len, r_min, r_max)) {
- changed = true;
+ has_select = true;
}
MEM_freeN(objects);
}
+ else if (area->spacetype == SPACE_SEQ) {
+ Scene *scene = CTX_data_scene(C);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+ int selected_strips = SEQ_collection_len(strips);
+ if (selected_strips > 0) {
+ INIT_MINMAX2(r_min, r_max);
+ has_select = true;
- if (changed == false) {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ float quad[4][2];
+ SEQ_image_transform_quad_get(scene, seq, selected_strips != 1, quad);
+ for (int i = 0; i < 4; i++) {
+ minmax_v2v2_v2(r_min, r_max, quad[i]);
+ }
+ }
+ }
+ SEQ_collection_free(strips);
+ if (selected_strips > 1) {
+ /* Don't draw the cage as transforming multiple strips isn't currently very useful as it
+ * doesn't behave as one would expect.
+ *
+ * This is because our current transform system doesn't support shearing which would make the
+ * scaling transforms of the bounding box behave weirdly.
+ * In addition to this, the rotation of the bounding box can not currently be hooked up
+ * properly to read the result from the transform system (when transforming multiple strips).
+ */
+ mid_v2_v2v2(r_center, r_min, r_max);
+ zero_v2(r_min);
+ zero_v2(r_max);
+ return has_select;
+ }
+ }
+
+ if (has_select == false) {
zero_v2(r_min);
zero_v2(r_max);
}
mid_v2_v2v2(r_center, r_min, r_max);
- return changed;
+ return has_select;
+}
+
+static int gizmo2d_calc_transform_orientation(const bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+ if (area->spacetype != SPACE_SEQ) {
+ return V3D_ORIENT_GLOBAL;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(ed);
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
+ SEQ_filter_selected_strips(strips);
+
+ bool use_local_orient = SEQ_collection_len(strips) == 1;
+ SEQ_collection_free(strips);
+
+ if (use_local_orient) {
+ return V3D_ORIENT_LOCAL;
+ }
+ return V3D_ORIENT_GLOBAL;
}
static float gizmo2d_calc_rotation(const bContext *C)
@@ -276,9 +334,10 @@ static float gizmo2d_calc_rotation(const bContext *C)
SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips) {
- if (seq == ed->act_seq) {
+ if (SEQ_collection_len(strips) == 1) {
+ /* Only return the strip rotation if only one is selected. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
StripTransform *transform = seq->strip->transform;
float mirror[2];
SEQ_image_transform_mirror_factor_get(seq, mirror);
@@ -436,17 +495,17 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup
ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X, ot_resize, NULL);
PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
- RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
RNA_property_boolean_set(ptr, prop_release_confirm, true);
- ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL);
RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL);
RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y, ot_resize, NULL);
- RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
RNA_property_boolean_set(ptr, prop_release_confirm, true);
- ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL);
RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL);
RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
ptr = WM_gizmo_operator_set(
ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, NULL);
@@ -465,87 +524,51 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup
}
}
-static void gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
+static void rotate_around_center_v2(float point[2], const float center[2], const float angle)
{
- gizmo2d_xform_setup(C, gzgroup);
- GizmoGroup2D *ggd = gzgroup->customdata;
- ggd->no_cage = true;
+ float tmp[2];
+
+ sub_v2_v2v2(tmp, point, center);
+ rotate_v2_v2fl(point, tmp, angle);
+ add_v2_v2(point, center);
}
static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup2D *ggd = gzgroup->customdata;
- float origin[3];
bool has_select;
if (ggd->no_cage) {
- has_select = gizmo2d_calc_center(C, origin);
+ has_select = gizmo2d_calc_center(C, ggd->origin);
}
else {
- has_select = gizmo2d_calc_bounds(C, origin, ggd->min, ggd->max);
+ has_select = gizmo2d_calc_bounds(C, ggd->origin, ggd->min, ggd->max);
+ ggd->rotation = gizmo2d_calc_rotation(C);
}
- copy_v2_v2(ggd->origin, origin);
+
bool show_cage = !ggd->no_cage && !equals_v2v2(ggd->min, ggd->max);
if (has_select == false) {
+ /* Nothing selected. Disable gizmo drawing and return. */
+ ggd->cage->flag |= WM_GIZMO_HIDDEN;
for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
ggd->translate_xy[i]->flag |= WM_GIZMO_HIDDEN;
}
- ggd->cage->flag |= WM_GIZMO_HIDDEN;
+ return;
}
- else {
- if (show_cage) {
- ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
- for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
- wmGizmo *gz = ggd->translate_xy[i];
- gz->flag |= WM_GIZMO_HIDDEN;
- }
- }
- else {
- ggd->cage->flag |= WM_GIZMO_HIDDEN;
- for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
- wmGizmo *gz = ggd->translate_xy[i];
- gz->flag &= ~WM_GIZMO_HIDDEN;
- }
- }
- if (show_cage) {
- wmGizmoOpElem *gzop;
- float mid[2];
- const float *min = ggd->min;
- const float *max = ggd->max;
- mid_v2_v2v2(mid, min, max);
-
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X);
- PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f});
-
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f});
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f});
-
- gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE);
- RNA_property_float_set_array(
- &gzop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f});
+ if (!show_cage) {
+ /* Disable cage gizmo drawing and return. */
+ ggd->cage->flag |= WM_GIZMO_HIDDEN;
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ ggd->translate_xy[i]->flag &= ~WM_GIZMO_HIDDEN;
}
+ return;
+ }
+
+ /* We will show the cage gizmo! Setup all necessary data. */
+ ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
+ for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
+ ggd->translate_xy[i]->flag |= WM_GIZMO_HIDDEN;
}
}
@@ -554,7 +577,6 @@ static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
ARegion *region = CTX_wm_region(C);
GizmoGroup2D *ggd = gzgroup->customdata;
float origin[3] = {UNPACK2(ggd->origin), 0.0f};
- const float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f};
gizmo2d_origin_to_region(region, origin);
@@ -564,19 +586,128 @@ static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
}
UI_view2d_view_to_region_m4(&region->v2d, ggd->cage->matrix_space);
- WM_gizmo_set_matrix_offset_location(ggd->cage, origin_aa);
+ /* Define the bounding box of the gizmo in the offset transform matrix. */
+ unit_m4(ggd->cage->matrix_offset);
ggd->cage->matrix_offset[0][0] = (ggd->max[0] - ggd->min[0]);
ggd->cage->matrix_offset[1][1] = (ggd->max[1] - ggd->min[1]);
+
+ ScrArea *area = CTX_wm_area(C);
+
+ if (area->spacetype == SPACE_SEQ) {
+ gizmo2d_calc_center(C, origin);
+
+ float matrix_rotate[4][4];
+ unit_m4(matrix_rotate);
+ copy_v3_v3(matrix_rotate[3], origin);
+ rotate_m4(matrix_rotate, 'Z', ggd->rotation);
+ unit_m4(ggd->cage->matrix_basis);
+ mul_m4_m4m4(ggd->cage->matrix_basis, matrix_rotate, ggd->cage->matrix_basis);
+
+ float mid[2];
+ sub_v2_v2v2(mid, origin, ggd->origin);
+ mul_v2_fl(mid, -1.0f);
+ copy_v2_v2(ggd->cage->matrix_offset[3], mid);
+ }
+ else {
+ const float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f};
+ WM_gizmo_set_matrix_offset_location(ggd->cage, origin_aa);
+ }
}
-static void gizmo2d_xform_no_cage_message_subscribe(const struct bContext *C,
- struct wmGizmoGroup *gzgroup,
- struct wmMsgBus *mbus)
+static void gizmo2d_xform_invoke_prepare(const bContext *C,
+ wmGizmoGroup *gzgroup,
+ wmGizmo *UNUSED(gz),
+ const wmEvent *UNUSED(event))
{
- bScreen *screen = CTX_wm_screen(C);
+ GizmoGroup2D *ggd = gzgroup->customdata;
+ wmGizmoOpElem *gzop;
+ const float *mid = ggd->origin;
+ const float *min = ggd->min;
+ const float *max = ggd->max;
+
+ /* Define the different transform center points that will be used when grabbing the corners or
+ * rotating with the gizmo.
+ *
+ * The coordinates are referred to as their cardinal directions:
+ * N
+ * o
+ *NW | NE
+ * x-----------x
+ * | |
+ *W| C |E
+ * | |
+ * x-----------x
+ *SW S SE
+ */
+ float n[3] = {mid[0], max[1], 0.0f};
+ float w[3] = {min[0], mid[1], 0.0f};
+ float e[3] = {max[0], mid[1], 0.0f};
+ float s[3] = {mid[0], min[1], 0.0f};
+
+ float nw[3] = {min[0], max[1], 0.0f};
+ float ne[3] = {max[0], max[1], 0.0f};
+ float sw[3] = {min[0], min[1], 0.0f};
+ float se[3] = {max[0], min[1], 0.0f};
+
+ float c[3] = {mid[0], mid[1], 0.0f};
+
+ float orient_matrix[3][3];
+ unit_m3(orient_matrix);
+
ScrArea *area = CTX_wm_area(C);
- ARegion *region = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
+
+ if (ggd->rotation != 0.0f && area->spacetype == SPACE_SEQ) {
+ float origin[3];
+ gizmo2d_calc_center(C, origin);
+ /* We need to rotate the cardinal points so they align with the rotated bounding box. */
+
+ rotate_around_center_v2(n, origin, ggd->rotation);
+ rotate_around_center_v2(w, origin, ggd->rotation);
+ rotate_around_center_v2(e, origin, ggd->rotation);
+ rotate_around_center_v2(s, origin, ggd->rotation);
+
+ rotate_around_center_v2(nw, origin, ggd->rotation);
+ rotate_around_center_v2(ne, origin, ggd->rotation);
+ rotate_around_center_v2(sw, origin, ggd->rotation);
+ rotate_around_center_v2(se, origin, ggd->rotation);
+
+ rotate_around_center_v2(c, origin, ggd->rotation);
+
+ rotate_m3(orient_matrix, ggd->rotation);
+ }
+
+ int orient_type = gizmo2d_calc_transform_orientation(C);
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X);
+ PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
+ PropertyRNA *prop_mouse_dir = RNA_struct_find_property(&gzop->ptr, "mouse_dir_constraint");
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, e);
+ RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[0]);
+ RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, w);
+ RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[0]);
+ RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, n);
+ RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[1]);
+ RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, s);
+ RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[1]);
+ RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, ne);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, se);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, nw);
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, sw);
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, c);
}
void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
@@ -586,6 +717,24 @@ void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = gizmo2d_xform_refresh;
gzgt->draw_prepare = gizmo2d_xform_draw_prepare;
+ gzgt->invoke_prepare = gizmo2d_xform_invoke_prepare;
+}
+
+static void gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ gizmo2d_xform_setup(C, gzgroup);
+ GizmoGroup2D *ggd = gzgroup->customdata;
+ ggd->no_cage = true;
+}
+
+static void gizmo2d_xform_no_cage_message_subscribe(const struct bContext *C,
+ struct wmGizmoGroup *gzgroup,
+ struct wmMsgBus *mbus)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(wmGizmoGroupType *gzgt)
@@ -726,6 +875,18 @@ static void gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou
}
}
+static void gizmo2d_resize_invoke_prepare(const bContext *C,
+ wmGizmoGroup *UNUSED(gzgroup),
+ wmGizmo *gz,
+ const wmEvent *UNUSED(event))
+{
+ wmGizmoOpElem *gzop;
+ int orient_type = gizmo2d_calc_transform_orientation(C);
+
+ gzop = WM_gizmo_operator_get(gz, 0);
+ RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
+}
+
static void gizmo2d_resize_message_subscribe(const struct bContext *C,
struct wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus)
@@ -743,6 +904,7 @@ void ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType *gzgt)
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
gzgt->refresh = gizmo2d_resize_refresh;
gzgt->draw_prepare = gizmo2d_resize_draw_prepare;
+ gzgt->invoke_prepare = gizmo2d_resize_invoke_prepare;
gzgt->message_subscribe = gizmo2d_resize_message_subscribe;
}
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index b14d499cb66..7f92c96d25f 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -1082,9 +1082,17 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
case TFM_ROTATION:
initRotation(t);
break;
- case TFM_RESIZE:
- initResize(t);
+ case TFM_RESIZE: {
+ float mouse_dir_constraint[3];
+ if (op) {
+ RNA_float_get_array(op->ptr, "mouse_dir_constraint", mouse_dir_constraint);
+ }
+ else {
+ zero_v3(mouse_dir_constraint);
+ }
+ initResize(t, mouse_dir_constraint);
break;
+ }
case TFM_SKIN_RESIZE:
initSkinResize(t);
break;
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index d8601000ddb..c561d1c8a4f 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -121,7 +121,7 @@ void initMirror(TransInfo *t);
void initPushPull(TransInfo *t);
/* transform_mode_resize.c */
-void initResize(TransInfo *t);
+void initResize(TransInfo *t, float mouse_dir_constraint[3]);
/* transform_mode_rotate.c */
void initRotation(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c
index 65f4623b3be..28323460626 100644
--- a/source/blender/editors/transform/transform_mode_resize.c
+++ b/source/blender/editors/transform/transform_mode_resize.c
@@ -201,14 +201,45 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
-void initResize(TransInfo *t)
+void initResize(TransInfo *t, float mouse_dir_constraint[3])
{
t->mode = TFM_RESIZE;
t->transform = applyResize;
t->tsnap.applySnap = ApplySnapResize;
t->tsnap.distance = ResizeBetween;
- initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
+ if (is_zero_v3(mouse_dir_constraint)) {
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
+ }
+ else {
+ int mval_start[2], mval_end[2];
+ float mval_dir[3], t_mval[2];
+ float viewmat[3][3];
+
+ copy_m3_m4(viewmat, t->viewmat);
+ mul_v3_m3v3(mval_dir, viewmat, mouse_dir_constraint);
+ normalize_v2(mval_dir);
+ if (is_zero_v2(mval_dir)) {
+ /* The screen space direction is orthogonal to the view.
+ * Fall back to constraining on the Y axis. */
+ mval_dir[0] = 0;
+ mval_dir[1] = 1;
+ }
+
+ mval_start[0] = t->center2d[0];
+ mval_start[1] = t->center2d[1];
+
+ t_mval[0] = t->mval[0] - mval_start[0];
+ t_mval[1] = t->mval[1] - mval_start[1];
+ project_v2_v2v2(mval_dir, t_mval, mval_dir);
+
+ mval_end[0] = t->center2d[0] + mval_dir[0];
+ mval_end[1] = t->center2d[1] + mval_dir[1];
+
+ setCustomPoints(t, &t->mouse, mval_end, mval_start);
+
+ initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
+ }
t->flag |= T_NULL_ONE;
t->num.val_flag[0] |= NUM_NULL_ONE;
diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c
index b96b8103392..b18e0aa0c7f 100644
--- a/source/blender/editors/transform/transform_mode_shrink_fatten.c
+++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c
@@ -188,7 +188,9 @@ void initShrinkFatten(TransInfo *t)
{
/* If not in mesh edit mode, fallback to Resize. */
if ((t->flag & T_EDIT) == 0 || (t->obedit_type != OB_MESH)) {
- initResize(t);
+ float no_mouse_dir_constraint[3];
+ zero_v3(no_mouse_dir_constraint);
+ initResize(t, no_mouse_dir_constraint);
}
else {
t->mode = TFM_SHRINKFATTEN;
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 3a4a9342e18..5ed340abf97 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -59,6 +59,7 @@ typedef struct TransformModeItem {
void (*opfunc)(wmOperatorType *);
} TransformModeItem;
+static const float VecZero[3] = {0, 0, 0};
static const float VecOne[3] = {1, 1, 1};
static const char OP_TRANSLATION[] = "TRANSFORM_OT_translate";
@@ -783,6 +784,19 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
RNA_def_float_vector(
ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Scale", "", -FLT_MAX, FLT_MAX);
+ PropertyRNA *prop;
+ prop = RNA_def_float_vector(ot->srna,
+ "mouse_dir_constraint",
+ 3,
+ VecZero,
+ -FLT_MAX,
+ FLT_MAX,
+ "Mouse Directional Constraint",
+ "",
+ -FLT_MAX,
+ FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
WM_operatortype_props_advanced_begin(ot);
Transform_Properties(ot,
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 1e3acdf1071..298cd00bb46 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -30,6 +30,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
@@ -52,6 +53,8 @@
#include "ED_armature.h"
+#include "SEQ_select.h"
+
#include "transform.h"
#include "transform_orientations.h"
@@ -602,6 +605,16 @@ short transform_orientation_matrix_get(bContext *C,
return V3D_ORIENT_CUSTOM_MATRIX;
}
+ if (t->spacetype == SPACE_SEQ && t->options & CTX_SEQUENCER_IMAGE) {
+ Scene *scene = t->scene;
+ Sequence *seq = SEQ_select_active_get(scene);
+ if (seq && seq->strip->transform && orient_index == V3D_ORIENT_LOCAL) {
+ unit_m3(r_spacemtx);
+ rotate_m3(r_spacemtx, seq->strip->transform->rotation);
+ return orient_index;
+ }
+ }
+
Object *ob = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = t->scene;
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index 69db21d4c63..18437680731 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -66,6 +66,10 @@ void SEQ_image_transform_mirror_factor_get(const struct Sequence *seq, float r_m
void SEQ_image_transform_origin_offset_pixelspace_get(const struct Scene *scene,
const struct Sequence *seq,
float r_origin[2]);
+void SEQ_image_transform_quad_get(const struct Scene *scene,
+ const struct Sequence *seq,
+ bool apply_rotation,
+ float r_quad[4][2]);
void SEQ_image_transform_final_quad_get(const struct Scene *scene,
const struct Sequence *seq,
float r_quad[4][2]);
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index f014c7a312a..ec504c0c9b6 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -473,40 +473,41 @@ void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
*
* \param scene: Scene in which strips are located
* \param seq: Sequence to calculate image transform origin
+ * \param apply_rotation: Apply sequence rotation transform to the quad
* \param r_origin: return value
*/
-
-void SEQ_image_transform_final_quad_get(const Scene *scene,
- const Sequence *seq,
- float r_quad[4][2])
+static void seq_image_transform_quad_get_ex(const Scene *scene,
+ const Sequence *seq,
+ bool apply_rotation,
+ float r_quad[4][2])
{
StripTransform *transform = seq->strip->transform;
StripCrop *crop = seq->strip->crop;
- int imgage_size[2] = {scene->r.xsch, scene->r.ysch};
+ int image_size[2] = {scene->r.xsch, scene->r.ysch};
if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) {
- imgage_size[0] = seq->strip->stripdata->orig_width;
- imgage_size[1] = seq->strip->stripdata->orig_height;
+ image_size[0] = seq->strip->stripdata->orig_width;
+ image_size[1] = seq->strip->stripdata->orig_height;
}
float transform_matrix[3][3];
loc_rot_size_to_mat3(transform_matrix,
(const float[]){transform->xofs, transform->yofs},
- transform->rotation,
+ apply_rotation ? transform->rotation : 0.0f,
(const float[]){transform->scale_x, transform->scale_y});
- const float origin[2] = {imgage_size[0] * transform->origin[0],
- imgage_size[1] * transform->origin[1]};
- const float pivot[2] = {origin[0] - (imgage_size[0] / 2), origin[1] - (imgage_size[1] / 2)};
+ const float origin[2] = {image_size[0] * transform->origin[0],
+ image_size[1] * transform->origin[1]};
+ const float pivot[2] = {origin[0] - (image_size[0] / 2), origin[1] - (image_size[1] / 2)};
transform_pivot_set_m3(transform_matrix, pivot);
- r_quad[0][0] = (imgage_size[0] / 2) - crop->right;
- r_quad[0][1] = (imgage_size[1] / 2) - crop->top;
- r_quad[1][0] = (imgage_size[0] / 2) - crop->right;
- r_quad[1][1] = (-imgage_size[1] / 2) + crop->bottom;
- r_quad[2][0] = (-imgage_size[0] / 2) + crop->left;
- r_quad[2][1] = (-imgage_size[1] / 2) + crop->bottom;
- r_quad[3][0] = (-imgage_size[0] / 2) + crop->left;
- r_quad[3][1] = (imgage_size[1] / 2) - crop->top;
+ r_quad[0][0] = (image_size[0] / 2) - crop->right;
+ r_quad[0][1] = (image_size[1] / 2) - crop->top;
+ r_quad[1][0] = (image_size[0] / 2) - crop->right;
+ r_quad[1][1] = (-image_size[1] / 2) + crop->bottom;
+ r_quad[2][0] = (-image_size[0] / 2) + crop->left;
+ r_quad[2][1] = (-image_size[1] / 2) + crop->bottom;
+ r_quad[3][0] = (-image_size[0] / 2) + crop->left;
+ r_quad[3][1] = (image_size[1] / 2) - crop->top;
mul_m3_v2(transform_matrix, r_quad[0]);
mul_m3_v2(transform_matrix, r_quad[1]);
@@ -521,6 +522,21 @@ void SEQ_image_transform_final_quad_get(const Scene *scene,
mul_v2_v2(r_quad[3], mirror);
}
+void SEQ_image_transform_quad_get(const Scene *scene,
+ const Sequence *seq,
+ bool apply_rotation,
+ float r_quad[4][2])
+{
+ seq_image_transform_quad_get_ex(scene, seq, apply_rotation, r_quad);
+}
+
+void SEQ_image_transform_final_quad_get(const Scene *scene,
+ const Sequence *seq,
+ float r_quad[4][2])
+{
+ seq_image_transform_quad_get_ex(scene, seq, true, r_quad);
+}
+
void SEQ_image_preview_unit_to_px(const Scene *scene, const float co_src[2], float co_dst[2])
{
co_dst[0] = co_src[0] * scene->r.xsch;