diff options
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(®ion->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; |