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--source/blender/editors/include/ED_clip.h24
-rw-r--r--source/blender/editors/include/ED_mask.h5
-rw-r--r--source/blender/editors/mask/mask_add.c10
-rw-r--r--source/blender/editors/mask/mask_edit.c36
-rw-r--r--source/blender/editors/mask/mask_intern.h15
-rw-r--r--source/blender/editors/mask/mask_ops.c39
-rw-r--r--source/blender/editors/mask/mask_query.c13
-rw-r--r--source/blender/editors/mask/mask_select.c13
-rw-r--r--source/blender/editors/space_clip/clip_editor.c160
-rw-r--r--source/blender/editors/space_clip/clip_intern.h5
-rw-r--r--source/blender/editors/space_clip/clip_ops.c8
-rw-r--r--source/blender/editors/space_clip/clip_utils.c147
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c9
-rw-r--r--source/blender/editors/space_clip/tracking_select.c17
-rw-r--r--source/blender/editors/space_image/image_ops.c2
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(&region->winrct) + 1;
- height = BLI_rcti_size_y(&region->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(&region->winrct) + 1;
+ height = BLI_rcti_size_y(&region->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;
}
}