diff options
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/include/ED_clip.h | 24 | ||||
-rw-r--r-- | source/blender/editors/include/ED_mask.h | 5 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_add.c | 10 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_edit.c | 36 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_intern.h | 15 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_ops.c | 39 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_query.c | 13 | ||||
-rw-r--r-- | source/blender/editors/mask/mask_select.c | 13 | ||||
-rw-r--r-- | source/blender/editors/space_clip/clip_editor.c | 160 | ||||
-rw-r--r-- | source/blender/editors/space_clip/clip_intern.h | 5 | ||||
-rw-r--r-- | source/blender/editors/space_clip/clip_ops.c | 8 | ||||
-rw-r--r-- | source/blender/editors/space_clip/clip_utils.c | 147 | ||||
-rw-r--r-- | source/blender/editors/space_clip/tracking_ops.c | 9 | ||||
-rw-r--r-- | source/blender/editors/space_clip/tracking_select.c | 17 | ||||
-rw-r--r-- | source/blender/editors/space_image/image_ops.c | 2 |
15 files changed, 374 insertions, 129 deletions
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h index 0a66c439f79..56494f87bfe 100644 --- a/source/blender/editors/include/ED_clip.h +++ b/source/blender/editors/include/ED_clip.h @@ -99,6 +99,30 @@ void ED_space_clip_set_clip(struct bContext *C, struct Mask *ED_space_clip_get_mask(struct SpaceClip *sc); void ED_space_clip_set_mask(struct bContext *C, struct SpaceClip *sc, struct Mask *mask); +/* Locked state is used to preserve current clip editor viewport upon changes. Example usage: + * + * ... + * + * ClipViewLockState lock_state; + * ED_clip_view_lock_state_store(C, &lock_state); + * + * <change selection> + * + * ED_clip_view_lock_state_restore_no_jump(C, &lock_state); + * + * These function are to be used from space clip editor context only. Otherwise debug builds will + * assert, release builds will crash. */ + +typedef struct ClipViewLockState { + float offset_x, offset_y; + float lock_offset_x, lock_offset_y; + float zoom; +} ClipViewLockState; + +void ED_clip_view_lock_state_store(const struct bContext *C, ClipViewLockState *state); +void ED_clip_view_lock_state_restore_no_jump(const struct bContext *C, + const ClipViewLockState *state); + /* ** clip_ops.c ** */ void ED_operatormacros_clip(void); diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index bcf52da3f69..b20dae694fc 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -63,7 +63,10 @@ void ED_mask_point_pos__reverse( struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr); void ED_mask_cursor_location_get(struct ScrArea *area, float cursor[2]); -bool ED_mask_selected_minmax(const struct bContext *C, float min[2], float max[2]); +bool ED_mask_selected_minmax(const struct bContext *C, + float min[2], + float max[2], + bool include_handles); /* mask_draw.c */ void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type); diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index d7b3d74bc7e..1226cc57359 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -507,6 +507,9 @@ static int add_vertex_handle_cyclic( static int add_vertex_exec(bContext *C, wmOperator *op) { + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + Mask *mask = CTX_data_edit_mask(C); if (mask == NULL) { /* if there's no active mask, create one */ @@ -548,6 +551,8 @@ static int add_vertex_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } @@ -690,6 +695,9 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot) static int create_primitive_from_points( bContext *C, wmOperator *op, const float (*points)[2], int num_points, char handle_type) { + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ScrArea *area = CTX_wm_area(C); int size = RNA_float_get(op->ptr, "size"); @@ -752,6 +760,8 @@ static int create_primitive_from_points( DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index 663ae0097ad..e6c6424e5f0 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -184,3 +184,39 @@ void ED_operatormacros_mask(void) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Lock-to-selection viewport preservation + * \{ */ + +void ED_mask_view_lock_state_store(const bContext *C, MaskViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + if (space_clip != NULL) { + ED_clip_view_lock_state_store(C, &state->space_clip_state); + } +} + +void ED_mask_view_lock_state_restore_no_jump(const bContext *C, const MaskViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + if (space_clip != NULL) { + if ((space_clip->flag & SC_LOCK_SELECTION) == 0) { + /* Early output if the editor is not locked to selection. + * Avoids forced dependency graph evaluation here. */ + return; + } + + /* Mask's lock-to-selection requres deformed splines to be evaluated to calculate bounds of + * points after animation has been evaluated. The restore-no-jump type of function does + * calculation of new offset for the view for an updated state of mask to cancel the offset out + * by modifying locked offset. In order to do such calculation mask needs to be evaluated after + * modification by an operator. */ + struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + (void)depsgraph; + + ED_clip_view_lock_state_restore_no_jump(C, &state->space_clip_state); + } +} + +/** \} */ diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index f6990583383..ee1784011ea 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -23,6 +23,8 @@ #pragma once +#include "ED_clip.h" + struct Mask; struct bContext; struct wmOperatorType; @@ -92,6 +94,19 @@ void ED_mask_select_flush_all(struct Mask *mask); bool ED_maskedit_poll(struct bContext *C); bool ED_maskedit_mask_poll(struct bContext *C); +/* Generalized solution for preserving editor viewport when making changes while lock-to-selection + * is enabled. + * Any mask operator can use this API, without worrying that some editors do not have an idea of + * lock-to-selection. */ + +typedef struct MaskViewLockState { + ClipViewLockState space_clip_state; +} MaskViewLockState; + +void ED_mask_view_lock_state_store(const struct bContext *C, MaskViewLockState *state); +void ED_mask_view_lock_state_restore_no_jump(const struct bContext *C, + const MaskViewLockState *state); + /* mask_query.c */ bool ED_mask_find_nearest_diff_point(const struct bContext *C, struct Mask *mask, diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index 25cc39bf9a0..00a1dfb7d87 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -226,6 +226,12 @@ typedef struct SlidePointData { int width, height; float prev_mouse_coord[2]; + + /* Previous clip coordinate which was resolved from mouse position (0, 0). + * Is used to compansate for view offste moving in-between of mouse events when + * lock-to-selection is enabled. */ + float prev_zero_coord[2]; + float no[2]; bool is_curvature_only, is_accurate, is_initial_feather, is_overall_feather; @@ -431,6 +437,9 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * const float threshold = 19; eMaskWhichHandle which_handle; + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ED_mask_mouse_pos(area, region, event->mval, co); ED_mask_get_size(area, &width, &height); @@ -530,7 +539,15 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * } customdata->which_handle = which_handle; + { + WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + DEG_id_tag_update(&mask->id, 0); + + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + } + ED_mask_mouse_pos(area, region, event->mval, customdata->prev_mouse_coord); + ED_mask_mouse_pos(area, region, (int[2]){0, 0}, customdata->prev_zero_coord); } return customdata; @@ -655,10 +672,24 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_mask_mouse_pos(area, region, event->mval, co); sub_v2_v2v2(delta, co, data->prev_mouse_coord); + copy_v2_v2(data->prev_mouse_coord, co); + + /* Compensate for possibly moved view offset since the last event. + * The idea is to see how mapping of a fixed and known position did change. */ + { + float zero_coord[2]; + ED_mask_mouse_pos(area, region, (int[2]){0, 0}, zero_coord); + + float zero_delta[2]; + sub_v2_v2v2(zero_delta, zero_coord, data->prev_zero_coord); + sub_v2_v2(delta, zero_delta); + + copy_v2_v2(data->prev_zero_coord, zero_coord); + } + if (data->is_accurate) { mul_v2_fl(delta, 0.2f); } - copy_v2_v2(data->prev_mouse_coord, co); if (data->action == SLIDE_ACTION_HANDLE) { float new_handle[2]; @@ -966,6 +997,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C, float u, co[2]; BezTriple *next_bezt; + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co); if (!ED_mask_find_nearest_diff_point(C, @@ -1047,6 +1081,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C, mask_layer->act_point = point; ED_mask_select_flush_all(mask); + DEG_id_tag_update(&mask->id, 0); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return slide_data; } diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c index cfd57ca3477..8f4f14a1ba8 100644 --- a/source/blender/editors/mask/mask_query.c +++ b/source/blender/editors/mask/mask_query.c @@ -604,7 +604,7 @@ void ED_mask_point_pos__reverse( *yr = co[1]; } -bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2]) +bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2], bool include_handles) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Mask *mask = CTX_data_edit_mask(C); @@ -638,22 +638,29 @@ bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2]) } if (bezt->f2 & SELECT) { minmax_v2v2_v2(min, max, deform_point->bezt.vec[1]); + ok = true; } - if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { + + if (!include_handles) { + /* Ignore handles. */ + } + else if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_STICK, handle); minmax_v2v2_v2(min, max, handle); + ok = true; } else { if ((bezt->f1 & SELECT) && (bezt->h1 != HD_VECT)) { BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_LEFT, handle); minmax_v2v2_v2(min, max, handle); + ok = true; } if ((bezt->f3 & SELECT) && (bezt->h2 != HD_VECT)) { BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_RIGHT, handle); minmax_v2v2_v2(min, max, handle); + ok = true; } } - ok = true; } } } diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index cdc6ece1e84..5c369afc4cd 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -214,12 +214,17 @@ static int select_all_exec(bContext *C, wmOperator *op) Mask *mask = CTX_data_edit_mask(C); int action = RNA_enum_get(op->ptr, "action"); + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ED_mask_select_toggle_all(mask, action); ED_mask_select_flush_all(mask); DEG_id_tag_update(&mask->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } @@ -261,6 +266,9 @@ static int select_exec(bContext *C, wmOperator *op) eMaskWhichHandle which_handle; const float threshold = 19; + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + RNA_float_get_array(op->ptr, "location", co); point = ED_mask_point_find_nearest( @@ -324,6 +332,8 @@ static int select_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&mask->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } @@ -364,12 +374,15 @@ static int select_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&mask->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } if (deselect_all) { /* For clip editor tracks, leave deselect all to clip editor. */ if (!ED_clip_can_select(C)) { ED_mask_deselect_all(C); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); return OPERATOR_FINISHED; } } diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index bd11a746e11..af1d082d317 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -327,118 +327,18 @@ void ED_clip_update_frame(const Main *mainp, int cfra) } } -static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2]) +bool ED_clip_view_selection(const bContext *C, ARegion *UNUSED(region), bool fit) { - MovieClip *clip = ED_space_clip_get_clip(sc); - MovieTrackingTrack *track; - int width, height; - bool ok = false; - ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); - int framenr = ED_space_clip_get_clip_frame_number(sc); - - INIT_MINMAX2(min, max); - - ED_space_clip_get_size(sc, &width, &height); - - track = tracksbase->first; - while (track) { - if (TRACK_VIEW_SELECTED(sc, track)) { - MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - - if (marker) { - float pos[3]; - - pos[0] = marker->pos[0] + track->offset[0]; - pos[1] = marker->pos[1] + track->offset[1]; - pos[2] = 0.0f; - - /* undistortion happens for normalized coords */ - if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) { - /* undistortion happens for normalized coords */ - ED_clip_point_undistorted_pos(sc, pos, pos); - } - - pos[0] *= width; - pos[1] *= height; - - mul_v3_m4v3(pos, sc->stabmat, pos); - - minmax_v2v2_v2(min, max, pos); - - ok = true; - } - } - - track = track->next; - } - - return ok; -} - -static bool selected_boundbox(const bContext *C, float min[2], float max[2]) -{ - SpaceClip *sc = CTX_wm_space_clip(C); - if (sc->mode == SC_MODE_TRACKING) { - return selected_tracking_boundbox(sc, min, max); - } - - if (ED_mask_selected_minmax(C, min, max)) { - MovieClip *clip = ED_space_clip_get_clip(sc); - int width, height; - ED_space_clip_get_size(sc, &width, &height); - BKE_mask_coord_to_movieclip(clip, &sc->user, min, min); - BKE_mask_coord_to_movieclip(clip, &sc->user, max, max); - min[0] *= width; - min[1] *= height; - max[0] *= width; - max[1] *= height; - return true; - } - return false; -} - -bool ED_clip_view_selection(const bContext *C, ARegion *region, bool fit) -{ - SpaceClip *sc = CTX_wm_space_clip(C); - int w, h, frame_width, frame_height; - float min[2], max[2]; - - ED_space_clip_get_size(sc, &frame_width, &frame_height); - - if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) { + float offset_x, offset_y; + float zoom; + if (!clip_view_calculate_view_selection(C, fit, &offset_x, &offset_y, &zoom)) { return false; } - if (!selected_boundbox(C, min, max)) { - return false; - } - - /* center view */ - clip_view_center_to_point( - sc, (max[0] + min[0]) / (2 * frame_width), (max[1] + min[1]) / (2 * frame_height)); - - w = max[0] - min[0]; - h = max[1] - min[1]; - - /* set zoom to see all selection */ - if (w > 0 && h > 0) { - int width, height; - float zoomx, zoomy, newzoom, aspx, aspy; - - ED_space_clip_get_aspect(sc, &aspx, &aspy); - - width = BLI_rcti_size_x(®ion->winrct) + 1; - height = BLI_rcti_size_y(®ion->winrct) + 1; - - zoomx = (float)width / w / aspx; - zoomy = (float)height / h / aspy; - - newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)); - - if (fit || sc->zoom > newzoom) { - sc->zoom = newzoom; - } - } + SpaceClip *sc = CTX_wm_space_clip(C); + sc->xof = offset_x; + sc->yof = offset_y; + sc->zoom = zoom; return true; } @@ -1177,3 +1077,47 @@ void clip_start_prefetch_job(const bContext *C) /* and finally start the job */ WM_jobs_start(CTX_wm_manager(C), wm_job); } + +void ED_clip_view_lock_state_store(const bContext *C, ClipViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + BLI_assert(space_clip != NULL); + + state->offset_x = space_clip->xof; + state->offset_y = space_clip->yof; + state->zoom = space_clip->zoom; + + state->lock_offset_x = 0.0f; + state->lock_offset_y = 0.0f; + + if ((space_clip->flag & SC_LOCK_SELECTION) == 0) { + return; + } + + if (!clip_view_calculate_view_selection( + C, false, &state->offset_x, &state->offset_y, &state->zoom)) { + return; + } + + state->lock_offset_x = space_clip->xlockof; + state->lock_offset_y = space_clip->ylockof; +} + +void ED_clip_view_lock_state_restore_no_jump(const bContext *C, const ClipViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + BLI_assert(space_clip != NULL); + + if ((space_clip->flag & SC_LOCK_SELECTION) == 0) { + return; + } + + float offset_x, offset_y; + float zoom; + if (!clip_view_calculate_view_selection(C, false, &offset_x, &offset_y, &zoom)) { + return; + } + + space_clip->xlockof = state->offset_x + state->lock_offset_x - offset_x; + space_clip->ylockof = state->offset_y + state->lock_offset_y - offset_y; +} diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 81df8cc8ecd..b9a69204281 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -171,8 +171,13 @@ void clip_delete_plane_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingPlaneTrack *plane_track); +void clip_view_offset_for_center_to_point( + SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y); void clip_view_center_to_point(SpaceClip *sc, float x, float y); +bool clip_view_calculate_view_selection( + const struct bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom); + void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene); /* tracking_ops.c */ diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index cd4a1ffb526..cb84ea6571c 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1840,8 +1840,16 @@ void CLIP_OT_cursor_set(wmOperatorType *ot) static int lock_selection_togglee_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceClip *space_clip = CTX_wm_space_clip(C); + + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); + space_clip->flag ^= SC_LOCK_SELECTION; + + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index c7f2a027ba8..faa3f18e8c1 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -27,10 +27,12 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_rect.h" #include "BLI_utildefines.h" #include "BKE_animsys.h" #include "BKE_context.h" +#include "BKE_mask.h" #include "BKE_movieclip.h" #include "BKE_tracking.h" @@ -44,6 +46,7 @@ #include "WM_types.h" #include "ED_clip.h" +#include "ED_mask.h" #include "ED_screen.h" #include "UI_interface.h" @@ -395,16 +398,152 @@ void clip_delete_plane_track(bContext *C, MovieClip *clip, MovieTrackingPlaneTra DEG_id_tag_update(&clip->id, 0); } -void clip_view_center_to_point(SpaceClip *sc, float x, float y) +/* Calculate space clip offset to be centered at the given point. */ +void clip_view_offset_for_center_to_point( + SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y) { int width, height; + ED_space_clip_get_size(sc, &width, &height); + float aspx, aspy; + ED_space_clip_get_aspect(sc, &aspx, &aspy); + + *r_offset_x = (x - 0.5f) * width * aspx; + *r_offset_y = (y - 0.5f) * height * aspy; +} + +void clip_view_center_to_point(SpaceClip *sc, float x, float y) +{ + clip_view_offset_for_center_to_point(sc, x, y, &sc->xof, &sc->yof); +} + +static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2]) +{ + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTrackingTrack *track; + int width, height; + bool ok = false; + ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + INIT_MINMAX2(min, max); ED_space_clip_get_size(sc, &width, &height); - ED_space_clip_get_aspect(sc, &aspx, &aspy); - sc->xof = (x - 0.5f) * width * aspx; - sc->yof = (y - 0.5f) * height * aspy; + track = tracksbase->first; + while (track) { + if (TRACK_VIEW_SELECTED(sc, track)) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); + + if (marker) { + float pos[3]; + + pos[0] = marker->pos[0] + track->offset[0]; + pos[1] = marker->pos[1] + track->offset[1]; + pos[2] = 0.0f; + + /* undistortion happens for normalized coords */ + if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) { + /* undistortion happens for normalized coords */ + ED_clip_point_undistorted_pos(sc, pos, pos); + } + + pos[0] *= width; + pos[1] *= height; + + mul_v3_m4v3(pos, sc->stabmat, pos); + + minmax_v2v2_v2(min, max, pos); + + ok = true; + } + } + + track = track->next; + } + + return ok; +} + +static bool selected_boundbox(const bContext *C, float min[2], float max[2], bool include_handles) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + if (sc->mode == SC_MODE_TRACKING) { + return selected_tracking_boundbox(sc, min, max); + } + + if (ED_mask_selected_minmax(C, min, max, include_handles)) { + MovieClip *clip = ED_space_clip_get_clip(sc); + int width, height; + ED_space_clip_get_size(sc, &width, &height); + BKE_mask_coord_to_movieclip(clip, &sc->user, min, min); + BKE_mask_coord_to_movieclip(clip, &sc->user, max, max); + min[0] *= width; + min[1] *= height; + max[0] *= width; + max[1] *= height; + return true; + } + return false; +} + +bool clip_view_calculate_view_selection( + const bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + + int frame_width, frame_height; + ED_space_clip_get_size(sc, &frame_width, &frame_height); + + if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) { + return false; + } + + /* NOTE: The `fit` argment is set to truth when doing "View to Selected" operator, and it set to + * false when this function is used for Lock-to-Selection functionality. When locking to + * selection the handles are to be ignored. So we can deriver the `include_handles` from `fit`. + * + * TODO(sergey): Make such decision more explicit. Maybe pass usecase for the calculation to tell + * operator from lock-to-selection apart. */ + float min[2], max[2]; + if (!selected_boundbox(C, min, max, fit)) { + return false; + } + + /* center view */ + clip_view_offset_for_center_to_point(sc, + (max[0] + min[0]) / (2 * frame_width), + (max[1] + min[1]) / (2 * frame_height), + r_offset_x, + r_offset_y); + + const int w = max[0] - min[0]; + const int h = max[1] - min[1]; + + /* set zoom to see all selection */ + *r_zoom = sc->zoom; + if (w > 0 && h > 0) { + ARegion *region = CTX_wm_region(C); + + int width, height; + float zoomx, zoomy, newzoom, aspx, aspy; + + ED_space_clip_get_aspect(sc, &aspx, &aspy); + + width = BLI_rcti_size_x(®ion->winrct) + 1; + height = BLI_rcti_size_y(®ion->winrct) + 1; + + zoomx = (float)width / w / aspx; + zoomy = (float)height / h / aspy; + + newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)); + + if (fit) { + *r_zoom = newzoom; + } + } + + return true; } void clip_draw_sfra_efra(View2D *v2d, Scene *scene) diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 10574063ebd..0f4fc2a2160 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -88,17 +88,16 @@ static int add_marker_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); float pos[2]; + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); + RNA_float_get_array(op->ptr, "location", pos); if (!add_marker(C, pos[0], pos[1])) { return OPERATOR_CANCELLED; } - /* Reset offset from locked position, so frame jumping wouldn't be so - * confusing. - */ - sc->xlockof = 0; - sc->ylockof = 0; + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index 063ea9592aa..ecd73f82e22 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -304,6 +304,9 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const track = find_nearest_track(sc, tracksbase, co, &distance_to_track); plane_track = find_nearest_plane_track(sc, plane_tracks_base, co, &distance_to_plane_track); + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); + /* Do not select beyond some reasonable distance, that is useless and * prevents the 'deselect on nothing' behavior. */ if (distance_to_track > 0.05f) { @@ -377,10 +380,7 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const ED_mask_deselect_all(C); } - if (!extend) { - sc->xlockof = 0.0f; - sc->ylockof = 0.0f; - } + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); BKE_tracking_dopesheet_tag_update(tracking); @@ -867,15 +867,20 @@ static int select_all_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; - int action = RNA_enum_get(op->ptr, "action"); + const int action = RNA_enum_get(op->ptr, "action"); - bool has_selection = false; + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); + bool has_selection = false; ED_clip_select_all(sc, action, &has_selection); if (!has_selection) { sc->flag &= ~SC_LOCK_SELECTION; } + else { + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); + } BKE_tracking_dopesheet_tag_update(tracking); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 86e52814d6f..097e304c893 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -900,7 +900,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) } } else if (ED_space_image_check_show_maskedit(sima, obedit)) { - if (!ED_mask_selected_minmax(C, min, max)) { + if (!ED_mask_selected_minmax(C, min, max, true)) { return OPERATOR_CANCELLED; } } |