diff options
Diffstat (limited to 'source/blender/editors/space_clip/clip_utils.c')
-rw-r--r-- | source/blender/editors/space_clip/clip_utils.c | 226 |
1 files changed, 222 insertions, 4 deletions
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index c7f2a027ba8..271ec219809 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,231 @@ 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 tracking_has_selection(SpaceClip *space_clip) +{ + MovieClip *clip = ED_space_clip_get_clip(space_clip); + ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); + const int framenr = ED_space_clip_get_clip_frame_number(space_clip); + + LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { + if (!TRACK_VIEW_SELECTED(space_clip, track)) { + continue; + } + const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); + if (marker != NULL) { + return true; + } + } + + return false; +} + +static bool mask_has_selection(const bContext *C, bool include_handles) +{ + Mask *mask = CTX_data_edit_mask(C); + if (mask == NULL) { + return false; + } + + LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) { + if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) { + continue; + } + LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) { + for (int i = 0; i < spline->tot_point; i++) { + const MaskSplinePoint *point = &spline->points[i]; + const BezTriple *bezt = &point->bezt; + if (!MASKPOINT_ISSEL_ANY(point)) { + continue; + } + if (bezt->f2 & SELECT) { + return true; + } + + if (!include_handles) { + /* Ignore handles. */ + } + else if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { + return true; + } + else { + if ((bezt->f1 & SELECT) && (bezt->h1 != HD_VECT)) { + return true; + } + if ((bezt->f3 & SELECT) && (bezt->h2 != HD_VECT)) { + return true; + } + } + } + } + } + + return false; +} + +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` argument 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 derive the `include_handles` from `fit`. + * + * TODO(sergey): Make such decision more explicit. Maybe pass use-case 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; +} + +/* Returns truth if lock-to-selection is enabled and possible. + * Locking to selection is not possible if there is no selection. */ +bool clip_view_has_locked_selection(const bContext *C) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + + if ((space_clip->flag & SC_LOCK_SELECTION) == 0) { + return false; + } + + if (space_clip->mode == SC_MODE_TRACKING) { + return tracking_has_selection(space_clip); + } + + return mask_has_selection(C, false); } void clip_draw_sfra_efra(View2D *v2d, Scene *scene) |