diff options
Diffstat (limited to 'source/blender/editors/space_clip/tracking_ops.c')
-rw-r--r-- | source/blender/editors/space_clip/tracking_ops.c | 403 |
1 files changed, 401 insertions, 2 deletions
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index f3d070452a5..e14fc8ad399 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -34,6 +34,7 @@ #include "DNA_camera_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" +#include "DNA_mask_types.h" #include "DNA_movieclip_types.h" #include "DNA_object_types.h" /* SELECT */ #include "DNA_scene_types.h" @@ -55,6 +56,8 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_library.h" +#include "BKE_mask.h" +#include "BKE_node.h" #include "BKE_sound.h" #include "WM_api.h" @@ -88,6 +91,7 @@ static bool add_marker(const bContext *C, float x, float y) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *track; int width, height; int framenr = ED_space_clip_get_clip_frame_number(sc); @@ -101,8 +105,10 @@ static bool add_marker(const bContext *C, float x, float y) track = BKE_tracking_track_add(tracking, tracksbase, x, y, framenr, width, height); BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, 0); + BKE_tracking_plane_tracks_deselect_all(plane_tracks_base); clip->tracking.act_track = track; + clip->tracking.act_plane_track = NULL; return true; } @@ -234,13 +240,31 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *track = tracksbase->first, *next; + MovieTrackingPlaneTrack *plane_track, *next_plane_track; + bool modified = false; + + /* Delete selected plane tracks. */ + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = next_plane_track) + { + next_plane_track = plane_track->next; + + if (plane_track->flag & SELECT) { + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + modified = true; + } + } + /* Remove selected point tracks (they'll also be removed from planes which uses them). */ while (track) { next = track->next; if (TRACK_VIEW_SELECTED(sc, track)) - clip_delete_track(C, clip, tracksbase, track); + clip_delete_track(C, clip, track); track = next; } @@ -248,6 +272,10 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) /* nothing selected now, unlock view so it can be scrolled nice again */ sc->flag &= ~SC_LOCK_SELECTION; + if (modified) { + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + } + return OPERATOR_FINISHED; } @@ -274,7 +302,9 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op)) SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); MovieTrackingTrack *track = tracksbase->first, *next; + MovieTrackingPlaneTrack *plane_track, *plane_track_next; int framenr = ED_space_clip_get_clip_frame_number(sc); int has_selection = 0; @@ -287,13 +317,34 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op)) if (marker) { has_selection |= track->markersnr > 1; - clip_delete_marker(C, clip, tracksbase, track, marker); + clip_delete_marker(C, clip, track, marker); } } track = next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track_next) + { + plane_track_next = plane_track->next; + + if (plane_track->flag & SELECT) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, framenr); + + if (plane_marker) { + if (plane_track->markersnr == 1) { + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + } + else { + BKE_tracking_plane_marker_delete(plane_track, framenr); + } + } + } + } + if (!has_selection) { /* nothing selected now, unlock view so it can be scrolled nice again */ sc->flag &= ~SC_LOCK_SELECTION; @@ -727,6 +778,7 @@ static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event MovieTracking *tracking = &clip->tracking; tracking->act_track = slidedata->track; + tracking->act_plane_track = NULL; op->customdata = slidedata; @@ -3670,3 +3722,350 @@ void CLIP_OT_paste_tracks(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/********************** Create plane track operator *********************/ + +static int create_plane_track_tracks_exec(bContext *C, wmOperator *op) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTracking *tracking = &clip->tracking; + MovieTrackingPlaneTrack *plane_track; + ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + plane_track = BKE_tracking_plane_track_add(tracking, plane_tracks_base, tracks_base, framenr); + + if (plane_track == NULL) { + BKE_report(op->reports, RPT_ERROR, "Need at least 4 selected point tracks to create a plane"); + return OPERATOR_CANCELLED; + } + else { + BKE_tracking_tracks_deselect_all(tracks_base); + + plane_track->flag |= SELECT; + clip->tracking.act_track = NULL; + clip->tracking.act_plane_track = plane_track; + + /* Copute homoraphies and apply them on marker's corner, so we've got + * quite nice motion from the very beginning. + */ + BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); + } + + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + + return OPERATOR_FINISHED; +} + +void CLIP_OT_create_plane_track(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Create Plane Track"; + ot->description = "Create new plane track out of selected point tracks"; + ot->idname = "CLIP_OT_create_plane_track"; + + /* api callbacks */ + ot->exec = create_plane_track_tracks_exec; + ot->poll = ED_space_clip_tracking_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************** Slide plane marker corner operator *********************/ + +typedef struct SlidePlaneMarkerData { + MovieTrackingPlaneTrack *plane_track; + MovieTrackingPlaneMarker *plane_marker; + int width, height; + int corner_index; + float *corner; + int previous_mval[2]; + float previous_corner[2]; + float old_corner[2]; + bool accurate; +} SlidePlaneMarkerData; + +static bool mouse_on_plane_slide_zone(SpaceClip *sc, float co[2], float slide_zone[2], int width, int height) +{ + const float size = 12.0f; + float dx, dy; + + dx = size / width / sc->zoom; + dy = size / height / sc->zoom; + + return IN_RANGE_INCL(co[0], slide_zone[0] - dx, slide_zone[0] + dx) && + IN_RANGE_INCL(co[1], slide_zone[1] - dy, slide_zone[1] + dy); +} + +static MovieTrackingPlaneTrack *tracking_plane_marker_check_slide(bContext *C, const wmEvent *event, int *corner_r) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + ARegion *ar = CTX_wm_region(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTrackingPlaneTrack *plane_track; + int width, height; + float co[2]; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + ED_space_clip_get_size(sc, &width, &height); + + if (width == 0 || height == 0) { + return NULL; + } + + ED_clip_mouse_pos(sc, ar, event->mval, co); + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_track->flag & SELECT) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + bool ok = false; + int i; + + for (i = 0; i < 4; i++) { + if (mouse_on_plane_slide_zone(sc, co, plane_marker->corners[i], width, height)) { + if (corner_r) { + *corner_r = i; + } + ok = true; + break; + } + } + + if (ok) { + return plane_track; + } + } + } + + return NULL; +} + +static void *slide_plane_marker_customdata(bContext *C, const wmEvent *event) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + ARegion *ar = CTX_wm_region(C); + MovieTrackingPlaneTrack *plane_track; + int width, height; + float co[2]; + SlidePlaneMarkerData *customdata = NULL; + int framenr = ED_space_clip_get_clip_frame_number(sc); + int corner; + + ED_space_clip_get_size(sc, &width, &height); + + if (width == 0 || height == 0) { + return NULL; + } + + ED_clip_mouse_pos(sc, ar, event->mval, co); + + plane_track = tracking_plane_marker_check_slide(C, event, &corner); + if (plane_track) { + MovieTrackingPlaneMarker *plane_marker; + + customdata = MEM_callocN(sizeof(SlidePlaneMarkerData), "slide plane marker data"); + + plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr); + + customdata->plane_track = plane_track; + customdata->plane_marker = plane_marker; + customdata->width = width; + customdata->height = height; + + customdata->previous_mval[0] = event->mval[0]; + customdata->previous_mval[1] = event->mval[1]; + + customdata->corner_index = corner; + customdata->corner = plane_marker->corners[corner]; + + copy_v2_v2(customdata->previous_corner, customdata->corner); + copy_v2_v2(customdata->old_corner, customdata->corner); + } + + return customdata; +} + +static int slide_plane_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + SlidePlaneMarkerData *slidedata = slide_plane_marker_customdata(C, event); + + if (slidedata) { + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTracking *tracking = &clip->tracking; + + tracking->act_plane_track = slidedata->plane_track; + tracking->act_track = NULL; + + op->customdata = slidedata; + + hide_cursor(C); + WM_event_add_modal_handler(C, op); + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); + + return OPERATOR_RUNNING_MODAL; + } + + return OPERATOR_PASS_THROUGH; +} + +static void cancel_mouse_slide_plane_marker(SlidePlaneMarkerData *data) +{ + copy_v2_v2(data->corner, data->old_corner); +} + +static void free_slide_plane_marker_data(SlidePlaneMarkerData *data) +{ + MEM_freeN(data); +} + +static void slide_plane_marker_update_homographies(SpaceClip *sc, SlidePlaneMarkerData *data) +{ + int framenr = ED_space_clip_get_clip_frame_number(sc); + + BKE_tracking_track_plane_from_existing_motion(data->plane_track, framenr); +} + +static int slide_plane_marker_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + SlidePlaneMarkerData *data = (SlidePlaneMarkerData *) op->customdata; + float dx, dy, mdelta[2]; + int next_corner_index, prev_corner_index, diag_corner_index; + float *next_corner, *prev_corner, *diag_corner; + float next_edge[2], prev_edge[2], next_diag_edge[2], prev_diag_edge[2]; + + switch (event->type) { + case LEFTCTRLKEY: + case RIGHTCTRLKEY: + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) + data->accurate = event->val == KM_PRESS; + + /* fall-through */ + case MOUSEMOVE: + mdelta[0] = event->mval[0] - data->previous_mval[0]; + mdelta[1] = event->mval[1] - data->previous_mval[1]; + + dx = mdelta[0] / data->width / sc->zoom; + dy = mdelta[1] / data->height / sc->zoom; + + if (data->accurate) { + dx /= 5.0f; + dy /= 5.0f; + } + + data->corner[0] = data->previous_corner[0] + dx; + data->corner[1] = data->previous_corner[1] + dy; + + + /* + prev_edge + (Corner 3, current) <----------------------- (Corner 2, previous) + | ^ + | | + | | + | | + next_edge | | next_diag_edge + | | + | | + | | + v | + (Corner 0, next) -----------------------> (Corner 1, diagonal) + prev_diag_edge + */ + + next_corner_index = (data->corner_index + 1) % 4; + prev_corner_index = (data->corner_index + 3) % 4; + diag_corner_index = (data->corner_index + 2) % 4; + + next_corner = data->plane_marker->corners[next_corner_index]; + prev_corner = data->plane_marker->corners[prev_corner_index]; + diag_corner = data->plane_marker->corners[diag_corner_index]; + + sub_v2_v2v2(next_edge, next_corner, data->corner); + sub_v2_v2v2(prev_edge, data->corner, prev_corner); + sub_v2_v2v2(next_diag_edge, prev_corner, diag_corner); + sub_v2_v2v2(prev_diag_edge, diag_corner, next_corner); + + if (cross_v2v2(prev_edge, next_edge) < 0.0f) { + closest_to_line_v2(data->corner, data->corner, prev_corner, next_corner); + } + + if (cross_v2v2(next_diag_edge, prev_edge) < 0.0f) { + closest_to_line_v2(data->corner, data->corner, prev_corner, diag_corner); + } + + if (cross_v2v2(next_edge, prev_diag_edge) < 0.0f) { + closest_to_line_v2(data->corner, data->corner, next_corner, diag_corner); + } + + data->previous_mval[0] = event->mval[0]; + data->previous_mval[1] = event->mval[1]; + copy_v2_v2(data->previous_corner, data->corner); + + DAG_id_tag_update(&sc->clip->id, 0); + + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL); + + break; + + case LEFTMOUSE: + if (event->val == KM_RELEASE) { + /* Marker is now keyframed. */ + data->plane_marker->flag &= ~PLANE_MARKER_TRACKED; + + slide_plane_marker_update_homographies(sc, data); + + free_slide_plane_marker_data(op->customdata); + + show_cursor(C); + + DAG_id_tag_update(&sc->clip->id, 0); + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + + return OPERATOR_FINISHED; + } + + break; + + case ESCKEY: + cancel_mouse_slide_plane_marker(op->customdata); + + free_slide_plane_marker_data(op->customdata); + + show_cursor(C); + + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + + return OPERATOR_CANCELLED; + } + + return OPERATOR_RUNNING_MODAL; +} + +void CLIP_OT_slide_plane_marker(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Slide Plane Marker"; + ot->description = "Slide plane marker areas"; + ot->idname = "CLIP_OT_slide_plane_marker"; + + /* api callbacks */ + ot->poll = ED_space_clip_tracking_poll; + ot->invoke = slide_plane_marker_invoke; + ot->modal = slide_plane_marker_modal; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING; +} |