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:
authorSergey Sharybin <sergey.vfx@gmail.com>2016-01-15 12:02:26 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2016-01-15 13:15:56 +0300
commit585574dc301904d0a3672b1956d50c8455a0e3e6 (patch)
treeab0b07c7c0aef9deb30f16b4cc6ee021c72bbcb3 /source/blender/editors/space_clip
parentbdd79ef880ac26de4cef623518c845fa23892a90 (diff)
Tracking: Split tracking_ops into smaller files
The file started to be rather really huge and difficult to follow. Should be no functional changes.
Diffstat (limited to 'source/blender/editors/space_clip')
-rw-r--r--source/blender/editors/space_clip/CMakeLists.txt8
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c2356
-rw-r--r--source/blender/editors/space_clip/tracking_ops_detect.c171
-rw-r--r--source/blender/editors/space_clip/tracking_ops_intern.h45
-rw-r--r--source/blender/editors/space_clip/tracking_ops_orient.c860
-rw-r--r--source/blender/editors/space_clip/tracking_ops_plane.c432
-rw-r--r--source/blender/editors/space_clip/tracking_ops_solve.c351
-rw-r--r--source/blender/editors/space_clip/tracking_ops_stabilize.c242
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c579
-rw-r--r--source/blender/editors/space_clip/tracking_ops_utils.c79
10 files changed, 2778 insertions, 2345 deletions
diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt
index d17d1856502..32d48c9c564 100644
--- a/source/blender/editors/space_clip/CMakeLists.txt
+++ b/source/blender/editors/space_clip/CMakeLists.txt
@@ -53,9 +53,17 @@ set(SRC
clip_utils.c
space_clip.c
tracking_ops.c
+ tracking_ops_detect.c
+ tracking_ops_orient.c
+ tracking_ops_plane.c
+ tracking_ops_solve.c
+ tracking_ops_track.c
+ tracking_ops_stabilize.c
+ tracking_ops_utils.c
tracking_select.c
clip_intern.h
+ tracking_ops_intern.h
)
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 088c316c9ff..af1a5404ee3 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -31,28 +31,18 @@
#include "MEM_guardedalloc.h"
-#include "DNA_camera_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_object_types.h" /* SELECT */
-#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
-#include "BLI_listbase.h"
#include "BLI_blenlib.h"
-#include "BKE_main.h"
#include "BKE_context.h"
-#include "BKE_constraint.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
-#include "BKE_global.h"
#include "BKE_depsgraph.h"
-#include "BKE_object.h"
#include "BKE_report.h"
-#include "BKE_library.h"
#include "BKE_sound.h"
#include "WM_api.h"
@@ -61,19 +51,13 @@
#include "ED_screen.h"
#include "ED_clip.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-
-
#include "RNA_access.h"
#include "RNA_define.h"
#include "BLT_translation.h"
-#include "PIL_time.h"
-
-
-#include "clip_intern.h" // own include
+#include "clip_intern.h"
+#include "tracking_ops_intern.h"
/********************** add marker operator *********************/
@@ -117,7 +101,9 @@ static int add_marker_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* reset offset from locked position, so frame jumping wouldn't be so confusing */
+ /* Reset offset from locked position, so frame jumping wouldn't be so
+ * confusing.
+ */
sc->xlockof = 0;
sc->ylockof = 0;
@@ -599,20 +585,6 @@ static bool slide_check_corners(float (*corners)[2])
return true;
}
-static void hide_cursor(bContext *C)
-{
- wmWindow *win = CTX_wm_window(C);
-
- WM_cursor_set(win, CURSOR_NONE);
-}
-
-static void show_cursor(bContext *C)
-{
- wmWindow *win = CTX_wm_window(C);
-
- WM_cursor_set(win, CURSOR_STD);
-}
-
MovieTrackingTrack *tracking_marker_check_slide(bContext *C,
const wmEvent *event,
int *area_r,
@@ -816,7 +788,7 @@ static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event
op->customdata = slidedata;
- hide_cursor(C);
+ clip_tracking_hide_cursor(C);
WM_event_add_modal_handler(C, op);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
@@ -1084,7 +1056,7 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
apply_mouse_slide(C, op->customdata);
free_slide_data(op->customdata);
- show_cursor(C);
+ clip_tracking_show_cursor(C);
return OPERATOR_FINISHED;
}
@@ -1096,7 +1068,7 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
free_slide_data(op->customdata);
- show_cursor(C);
+ clip_tracking_show_cursor(C);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
@@ -1128,821 +1100,6 @@ void CLIP_OT_slide_marker(wmOperatorType *ot)
-FLT_MAX, FLT_MAX);
}
-/********************** track operator *********************/
-
-typedef struct TrackMarkersJob {
- struct AutoTrackContext *context; /* Tracking context */
- int sfra, efra, lastfra; /* Start, end and recently tracked frames */
- int backwards; /* Backwards tracking flag */
- MovieClip *clip; /* Clip which is tracking */
- float delay; /* Delay in milliseconds to allow tracking at fixed FPS */
-
- struct Main *main;
- struct Scene *scene;
- struct bScreen *screen;
-} TrackMarkersJob;
-
-static bool track_markers_testbreak(void)
-{
- return G.is_break;
-}
-
-static int track_count_markers(SpaceClip *sc,
- MovieClip *clip,
- int framenr)
-{
- int tot = 0;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- bool selected = sc ? TRACK_VIEW_SELECTED(sc, track) : TRACK_SELECTED(track);
- if (selected && (track->flag & TRACK_LOCKED) == 0) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- if (!marker || (marker->flag & MARKER_DISABLED) == 0) {
- tot++;
- }
- }
- }
- return tot;
-}
-
-static void clear_invisible_track_selection(SpaceClip *sc, MovieClip *clip)
-{
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- int hidden = 0;
- if ((sc->flag & SC_SHOW_MARKER_PATTERN) == 0) {
- hidden |= TRACK_AREA_PAT;
- }
- if ((sc->flag & SC_SHOW_MARKER_SEARCH) == 0) {
- hidden |= TRACK_AREA_SEARCH;
- }
- if (hidden) {
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- if ((track->flag & TRACK_HIDDEN) == 0) {
- BKE_tracking_track_flag_clear(track, hidden, SELECT);
- }
- }
- }
-}
-
-static void track_init_markers(SpaceClip *sc,
- MovieClip *clip,
- int framenr,
- int *frames_limit_r)
-{
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- int frames_limit = 0;
- if (sc != NULL) {
- clear_invisible_track_selection(sc, clip);
- }
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- bool selected = (sc != NULL) ? TRACK_VIEW_SELECTED(sc, track)
- : TRACK_SELECTED(track);
- if (selected) {
- if ((track->flag & TRACK_HIDDEN) == 0 &&
- (track->flag & TRACK_LOCKED) == 0)
- {
- BKE_tracking_marker_ensure(track, framenr);
- if (track->frames_limit) {
- if (frames_limit == 0) {
- frames_limit = track->frames_limit;
- }
- else {
- frames_limit = min_ii(frames_limit,
- (int)track->frames_limit);
- }
- }
- }
- }
- }
- *frames_limit_r = frames_limit;
-}
-
-static bool track_markers_check_direction(int backwards, int curfra, int efra)
-{
- if (backwards) {
- if (curfra < efra) {
- return false;
- }
- }
- else {
- if (curfra > efra) {
- return false;
- }
- }
-
- return true;
-}
-
-static int track_markers_initjob(bContext *C,
- TrackMarkersJob *tmj,
- int backwards)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- Scene *scene = CTX_data_scene(C);
- MovieTrackingSettings *settings = &clip->tracking.settings;
- int frames_limit;
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- track_init_markers(sc, clip, framenr, &frames_limit);
-
- tmj->sfra = ED_space_clip_get_clip_frame_number(sc);
- tmj->clip = clip;
- tmj->backwards = backwards;
-
- if (backwards) {
- tmj->efra = SFRA;
- }
- else {
- tmj->efra = EFRA;
- }
-
- /* Limit frames to be tracked by user setting. */
- if (frames_limit) {
- if (backwards) {
- tmj->efra = MAX2(tmj->efra, tmj->sfra - frames_limit);
- }
- else {
- tmj->efra = MIN2(tmj->efra, tmj->sfra + frames_limit);
- }
- }
-
- tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra);
-
- if (settings->speed != TRACKING_SPEED_FASTEST) {
- tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f;
-
- if (settings->speed == TRACKING_SPEED_HALF) {
- tmj->delay *= 2;
- }
- else if (settings->speed == TRACKING_SPEED_QUARTER) {
- tmj->delay *= 4;
- }
- else if (settings->speed == TRACKING_SPEED_DOUBLE) {
- tmj->delay /= 2;
- }
- }
-
- tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, 1);
-
- clip->tracking_context = tmj->context;
-
- tmj->lastfra = tmj->sfra;
-
- /* XXX: silly to store this, but this data is needed to update scene and movie-clip
- * frame numbers when tracking is finished. This introduces better feedback for artists.
- * Maybe there's another way to solve this problem, but can't think better way atm.
- * Anyway, this way isn't more unstable as animation rendering animation
- * which uses the same approach (except storing screen). */
- tmj->scene = scene;
- tmj->main = CTX_data_main(C);
- tmj->screen = CTX_wm_screen(C);
-
- return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
-}
-
-static void track_markers_startjob(void *tmv,
- short *stop,
- short *do_update,
- float *progress)
-{
- TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
- int framenr = tmj->sfra;
-
- while (framenr != tmj->efra) {
- if (tmj->delay > 0) {
- /* Tracking should happen with fixed fps. Calculate time
- * using current timer value before tracking frame and after.
- *
- * Small (and maybe unneeded optimization): do not calculate exec_time
- * for "Fastest" tracking
- */
-
- double start_time = PIL_check_seconds_timer(), exec_time;
-
- if (!BKE_autotrack_context_step(tmj->context)) {
- break;
- }
-
- exec_time = PIL_check_seconds_timer() - start_time;
- if (tmj->delay > (float)exec_time) {
- PIL_sleep_ms(tmj->delay - (float)exec_time);
- }
- }
- else if (!BKE_autotrack_context_step(tmj->context)) {
- break;
- }
-
- *do_update = true;
- *progress = (float)(framenr - tmj->sfra) / (tmj->efra - tmj->sfra);
-
- if (tmj->backwards) {
- framenr--;
- }
- else {
- framenr++;
- }
-
- tmj->lastfra = framenr;
-
- if (*stop || track_markers_testbreak()) {
- break;
- }
- }
-}
-
-static void track_markers_updatejob(void *tmv)
-{
- TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
- BKE_autotrack_context_sync(tmj->context);
-}
-
-static void track_markers_endjob(void *tmv)
-{
- TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
- wmWindowManager *wm = tmj->main->wm.first;
-
- tmj->clip->tracking_context = NULL;
- tmj->scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(tmj->clip,
- tmj->lastfra);
- if (wm != NULL) {
- ED_update_for_newframe(tmj->main, tmj->scene, 0);
- }
-
- BKE_autotrack_context_sync(tmj->context);
- BKE_autotrack_context_finish(tmj->context);
-
- WM_main_add_notifier(NC_SCENE | ND_FRAME, tmj->scene);
-}
-
-static void track_markers_freejob(void *tmv)
-{
- TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
- BKE_autotrack_context_free(tmj->context);
- MEM_freeN(tmj);
-}
-
-/* TODO(sergey): Majority of the code here can be de-duplicated with the job. */
-static int track_markers_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc;
- MovieClip *clip;
- Scene *scene = CTX_data_scene(C);
- struct AutoTrackContext *context;
- MovieClipUser *user, fake_user = {0};
- int framenr, sfra, efra;
- const bool backwards = RNA_boolean_get(op->ptr, "backwards");
- const bool sequence = RNA_boolean_get(op->ptr, "sequence");
- int frames_limit;
-
- if (RNA_struct_property_is_set(op->ptr, "clip")) {
- Main *bmain = CTX_data_main(C);
- char clip_name[MAX_ID_NAME - 2];
-
- RNA_string_get(op->ptr, "clip", clip_name);
- clip = (MovieClip *)BLI_findstring(&bmain->movieclip, clip_name, offsetof(ID, name) + 2);
- sc = NULL;
-
- if (clip == NULL) {
- return OPERATOR_CANCELLED;
- }
- framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, CFRA);
- fake_user.framenr = framenr;
- user = &fake_user;
- }
- else {
- sc = CTX_wm_space_clip(C);
-
- if (sc == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- clip = ED_space_clip_get_clip(sc);
- framenr = ED_space_clip_get_clip_frame_number(sc);
- user = &sc->user;
- }
-
- sfra = framenr;
-
- if (track_count_markers(sc, clip, framenr) == 0) {
- return OPERATOR_CANCELLED;
- }
-
- track_init_markers(sc, clip, framenr, &frames_limit);
-
- if (backwards) {
- efra = SFRA;
- }
- else {
- efra = EFRA;
- }
-
- /* Limit frames to be tracked by user setting. */
- if (frames_limit) {
- if (backwards)
- efra = MAX2(efra, sfra - frames_limit);
- else
- efra = MIN2(efra, sfra + frames_limit);
- }
-
- efra = BKE_movieclip_remap_scene_to_clip_frame(clip, efra);
-
- if (!track_markers_check_direction(backwards, framenr, efra)) {
- return OPERATOR_CANCELLED;
- }
-
- /* Do not disable tracks due to threshold when tracking frame-by-frame. */
- context = BKE_autotrack_context_new(clip, user, backwards, sequence);
- while (framenr != efra) {
- if (!BKE_autotrack_context_step(context))
- break;
-
- if (backwards) framenr--;
- else framenr++;
-
- if (!sequence)
- break;
- }
-
- BKE_autotrack_context_sync(context);
- BKE_autotrack_context_finish(context);
- BKE_autotrack_context_free(context);
-
- /* Update scene current frame to the lastes tracked frame. */
- scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
-
- return OPERATOR_FINISHED;
-}
-
-static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- TrackMarkersJob *tmj;
- ScrArea *sa = CTX_wm_area(C);
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip;
- wmJob *wm_job;
- bool backwards = RNA_boolean_get(op->ptr, "backwards");
- bool sequence = RNA_boolean_get(op->ptr, "sequence");
- int framenr;
-
- if (sc == NULL) {
- /* TODO(sergey): Support clip for invoke as well. */
- BKE_report(op->reports, RPT_ERROR,
- "Invoking this operator only supported from Clip Editor space");
- return OPERATOR_CANCELLED;
- }
-
- clip = ED_space_clip_get_clip(sc);
- BLI_assert(clip != NULL);
- framenr = ED_space_clip_get_clip_frame_number(sc);
-
- if (WM_jobs_test(CTX_wm_manager(C), sa, WM_JOB_TYPE_ANY)) {
- /* Only one tracking is allowed at a time. */
- return OPERATOR_CANCELLED;
- }
-
- if (clip->tracking_context) {
- return OPERATOR_CANCELLED;
- }
-
- if (track_count_markers(sc, clip, framenr) == 0) {
- return OPERATOR_CANCELLED;
- }
-
- if (!sequence) {
- return track_markers_exec(C, op);
- }
-
- tmj = MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
- if (!track_markers_initjob(C, tmj, backwards)) {
- track_markers_freejob(tmj);
- return OPERATOR_CANCELLED;
- }
-
- /* Setup job. */
- wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Track Markers",
- WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_TRACK_MARKERS);
- WM_jobs_customdata_set(wm_job, tmj, track_markers_freejob);
-
- /* If there's delay set in tracking job, tracking should happen
- * with fixed FPS. To deal with editor refresh we have to synchronize
- * tracks from job and tracks in clip. Do this in timer callback
- * to prevent threading conflicts. */
- if (tmj->delay > 0)
- WM_jobs_timer(wm_job, tmj->delay / 1000.0f, NC_MOVIECLIP | NA_EVALUATED, 0);
- else
- WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | NA_EVALUATED, 0);
-
- WM_jobs_callbacks(wm_job,
- track_markers_startjob,
- NULL,
- track_markers_updatejob,
- track_markers_endjob);
-
- G.is_break = false;
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- WM_cursor_wait(0);
-
- /* Add modal handler for ESC. */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
-{
- /* No running tracking, remove handler and pass through. */
- if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY)) {
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
- }
-
- /* Running tracking. */
- switch (event->type) {
- case ESCKEY:
- return OPERATOR_RUNNING_MODAL;
- }
-
- return OPERATOR_PASS_THROUGH;
-}
-
-void CLIP_OT_track_markers(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Track Markers";
- ot->description = "Track selected markers";
- ot->idname = "CLIP_OT_track_markers";
-
- /* api callbacks */
- ot->exec = track_markers_exec;
- ot->invoke = track_markers_invoke;
- ot->modal = track_markers_modal;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
- RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
- prop = RNA_def_string(ot->srna, "clip", NULL, MAX_NAME, "Movie Clip", "Movie Clip to be tracked");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-/********************** refine track position operator *********************/
-
-static int refine_marker_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- bool backwards = RNA_boolean_get(op->ptr, "backwards");
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- if (TRACK_VIEW_SELECTED(sc, track)) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- BKE_tracking_refine_marker(clip, track, marker, backwards);
- }
- }
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_refine_markers(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Refine Markers";
- ot->description = "Refine selected markers positions "
- "by running the tracker from track's reference to current frame";
- ot->idname = "CLIP_OT_refine_markers";
-
- /* api callbacks */
- ot->exec = refine_marker_exec;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
-}
-
-/********************** solve camera operator *********************/
-
-typedef struct {
- Scene *scene;
- MovieClip *clip;
- MovieClipUser user;
-
- ReportList *reports;
-
- char stats_message[256];
-
- struct MovieReconstructContext *context;
-} SolveCameraJob;
-
-static bool solve_camera_initjob(bContext *C,
- SolveCameraJob *scj,
- wmOperator *op,
- char *error_msg,
- int max_error)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- Scene *scene = CTX_data_scene(C);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- int width, height;
-
- if (!BKE_tracking_reconstruction_check(tracking,
- object,
- error_msg,
- max_error))
- {
- return false;
- }
-
- /* Could fail if footage uses images with different sizes. */
- BKE_movieclip_get_size(clip, &sc->user, &width, &height);
-
- scj->clip = clip;
- scj->scene = scene;
- scj->reports = op->reports;
- scj->user = sc->user;
-
- scj->context = BKE_tracking_reconstruction_context_new(clip,
- object,
- object->keyframe1,
- object->keyframe2,
- width,
- height);
-
- tracking->stats = MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
-
- return true;
-}
-
-static void solve_camera_updatejob(void *scv)
-{
- SolveCameraJob *scj = (SolveCameraJob *)scv;
- MovieTracking *tracking = &scj->clip->tracking;
-
- BLI_strncpy(tracking->stats->message,
- scj->stats_message,
- sizeof(tracking->stats->message));
-}
-
-static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress)
-{
- SolveCameraJob *scj = (SolveCameraJob *)scv;
- BKE_tracking_reconstruction_solve(scj->context,
- stop,
- do_update,
- progress,
- scj->stats_message,
- sizeof(scj->stats_message));
-}
-
-static void solve_camera_freejob(void *scv)
-{
- SolveCameraJob *scj = (SolveCameraJob *)scv;
- MovieTracking *tracking = &scj->clip->tracking;
- Scene *scene = scj->scene;
- MovieClip *clip = scj->clip;
- int solved;
-
- if (!scj->context) {
- /* job weren't fully initialized due to some error */
- MEM_freeN(scj);
- return;
- }
-
- solved = BKE_tracking_reconstruction_finish(scj->context, tracking);
- if (!solved) {
- BKE_report(scj->reports,
- RPT_WARNING,
- "Some data failed to reconstruct (see console for details)");
- }
- else {
- BKE_reportf(scj->reports,
- RPT_INFO,
- "Average re-projection error: %.3f",
- tracking->reconstruction.error);
- }
-
- /* Set currently solved clip as active for scene. */
- if (scene->clip != NULL) {
- id_us_min(&clip->id);
- }
- scene->clip = clip;
- id_us_plus(&clip->id);
-
- /* Set blender camera focal length so result would look fine there. */
- if (scene->camera != NULL &&
- scene->camera->data &&
- GS(((ID *) scene->camera->data)->name) == ID_CA)
- {
- Camera *camera = (Camera *)scene->camera->data;
- int width, height;
- BKE_movieclip_get_size(clip, &scj->user, &width, &height);
- BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
- WM_main_add_notifier(NC_OBJECT, camera);
- }
-
- MEM_freeN(tracking->stats);
- tracking->stats = NULL;
-
- DAG_id_tag_update(&clip->id, 0);
-
- WM_main_add_notifier(NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, NULL);
-
- /* Update active clip displayed in scene buttons. */
- WM_main_add_notifier(NC_SCENE, scene);
-
- BKE_tracking_reconstruction_context_free(scj->context);
- MEM_freeN(scj);
-}
-
-static int solve_camera_exec(bContext *C, wmOperator *op)
-{
- SolveCameraJob *scj;
- char error_msg[256] = "\0";
- scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
- if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
- if (error_msg[0]) {
- BKE_report(op->reports, RPT_ERROR, error_msg);
- }
- solve_camera_freejob(scj);
- return OPERATOR_CANCELLED;
- }
- solve_camera_startjob(scj, NULL, NULL, NULL);
- solve_camera_freejob(scj);
- return OPERATOR_FINISHED;
-}
-
-static int solve_camera_invoke(bContext *C,
- wmOperator *op,
- const wmEvent *UNUSED(event))
-{
- SolveCameraJob *scj;
- ScrArea *sa = CTX_wm_area(C);
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingReconstruction *reconstruction =
- BKE_tracking_get_active_reconstruction(tracking);
- wmJob *wm_job;
- char error_msg[256] = "\0";
-
- if (WM_jobs_test(CTX_wm_manager(C), sa, WM_JOB_TYPE_ANY)) {
- /* only one solve is allowed at a time */
- return OPERATOR_CANCELLED;
- }
-
- scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
- if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
- if (error_msg[0]) {
- BKE_report(op->reports, RPT_ERROR, error_msg);
- }
- solve_camera_freejob(scj);
- return OPERATOR_CANCELLED;
- }
-
- BLI_strncpy(tracking->stats->message,
- "Solving camera | Preparing solve",
- sizeof(tracking->stats->message));
-
- /* Hide reconstruction statistics from previous solve. */
- reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
-
- /* Setup job. */
- wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Solve Camera",
- WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_SOLVE_CAMERA);
- WM_jobs_customdata_set(wm_job, scj, solve_camera_freejob);
- WM_jobs_timer(wm_job, 0.1, NC_MOVIECLIP | NA_EVALUATED, 0);
- WM_jobs_callbacks(wm_job,
- solve_camera_startjob,
- NULL,
- solve_camera_updatejob,
- NULL);
-
- G.is_break = false;
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- WM_cursor_wait(0);
-
- /* add modal handler for ESC */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int solve_camera_modal(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *event)
-{
- /* No running solver, remove handler and pass through. */
- if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY))
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
-
- /* Running solver. */
- switch (event->type) {
- case ESCKEY:
- return OPERATOR_RUNNING_MODAL;
- }
-
- return OPERATOR_PASS_THROUGH;
-}
-
-void CLIP_OT_solve_camera(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Solve Camera";
- ot->description = "Solve camera motion from tracks";
- ot->idname = "CLIP_OT_solve_camera";
-
- /* api callbacks */
- ot->exec = solve_camera_exec;
- ot->invoke = solve_camera_invoke;
- ot->modal = solve_camera_modal;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************** clear solution operator *********************/
-
-static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- MovieTrackingReconstruction *reconstruction =
- BKE_tracking_get_active_reconstruction(tracking);
-
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- track->flag &= ~TRACK_HAS_BUNDLE;
- }
-
- if (reconstruction->cameras != NULL) {
- MEM_freeN(reconstruction->cameras);
- reconstruction->cameras = NULL;
- }
-
- reconstruction->camnr = 0;
- reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
-
- DAG_id_tag_update(&clip->id, 0);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_clear_solution(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Solution";
- ot->description = "Clear all calculated data";
- ot->idname = "CLIP_OT_clear_solution";
-
- /* api callbacks */
- ot->exec = clear_solution_exec;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/********************** clear track operator *********************/
static int clear_track_path_exec(bContext *C, wmOperator *op)
@@ -2068,807 +1225,6 @@ void CLIP_OT_disable_markers(wmOperatorType *ot)
RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
}
-/********************** set origin operator *********************/
-
-static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
-{
- Object *camera = scene->camera;
-
- if (camera != NULL &&
- BKE_object_movieclip_get(scene, camera, false) == clip)
- {
- return camera;
- }
-
- for (Base *base = scene->base.first;
- base != NULL;
- base = base->next)
- {
- if (base->object->type == OB_CAMERA) {
- if (BKE_object_movieclip_get(scene, base->object, false) == clip) {
- camera = base->object;
- break;
- }
- }
- }
-
- return camera;
-}
-
-static Object *get_orientation_object(bContext *C)
-{
- Scene *scene = CTX_data_scene(C);
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
- Object *object = NULL;
-
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- object = get_camera_with_movieclip(scene, clip);
- }
- else {
- object = OBACT;
- }
-
- if (object != NULL && object->parent != NULL) {
- object = object->parent;
- }
-
- return object;
-}
-
-static int set_orientation_poll(bContext *C)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- if (sc != NULL) {
- Scene *scene = CTX_data_scene(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- if (clip != NULL) {
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- return true;
- }
- else {
- return OBACT != NULL;
- }
- }
- }
- return false;
-}
-
-static int count_selected_bundles(bContext *C)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- int tot = 0;
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE)) {
- tot++;
- }
- }
- return tot;
-}
-
-static void object_solver_inverted_matrix(Scene *scene,
- Object *ob,
- float invmat[4][4])
-{
- bool found = false;
- for (bConstraint *con = ob->constraints.first;
- con != NULL;
- con = con->next)
- {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- if (cti == NULL) {
- continue;
- }
- if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
- if (!found) {
- Object *cam = data->camera ? data->camera : scene->camera;
- BKE_object_where_is_calc_mat4(scene, cam, invmat);
- }
- mul_m4_m4m4(invmat, invmat, data->invmat);
- found = true;
- }
- }
- if (found) {
- invert_m4(invmat);
- }
- else {
- unit_m4(invmat);
- }
-}
-
-static Object *object_solver_camera(Scene *scene, Object *ob)
-{
- for (bConstraint *con = ob->constraints.first;
- con != NULL;
- con = con->next)
- {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- if (cti == NULL) {
- continue;
- }
- if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
- return (data->camera != NULL) ? data->camera : scene->camera;
- }
- }
- return NULL;
-}
-
-static int set_origin_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- Scene *scene = CTX_data_scene(C);
- Object *camera = get_camera_with_movieclip(scene, clip);
- int selected_count = count_selected_bundles(C);
-
- if (selected_count == 0) {
- BKE_report(op->reports,
- RPT_ERROR,
- "At least one track with bundle should be selected to "
- "define origin position");
-
- return OPERATOR_CANCELLED;
- }
-
- Object *object = get_orientation_object(C);
- if (object == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
- return OPERATOR_CANCELLED;
- }
-
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
-
- float median[3] = {0.0f, 0.0f, 0.0f};
- zero_v3(median);
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- if (TRACK_VIEW_SELECTED(sc, track) &&
- (track->flag & TRACK_HAS_BUNDLE))
- {
- add_v3_v3(median, track->bundle_pos);
- }
- }
- mul_v3_fl(median, 1.0f / selected_count);
-
- float mat[4][4], vec[3];
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
- mul_v3_m4v3(vec, mat, median);
-
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- sub_v3_v3(object->loc, vec);
- }
- else {
- object_solver_inverted_matrix(scene, object, mat);
- mul_v3_m4v3(vec, mat, vec);
- copy_v3_v3(object->loc, vec);
- }
-
- DAG_id_tag_update(&clip->id, 0);
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_set_origin(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Origin";
- ot->description = "Set active marker as origin by moving camera (or its parent if present) in 3D space";
- ot->idname = "CLIP_OT_set_origin";
-
- /* api callbacks */
- ot->exec = set_origin_exec;
- ot->poll = set_orientation_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "use_median", 0, "Use Median",
- "Set origin to median point of selected bundles");
-}
-
-/********************** set floor operator *********************/
-
-static void set_axis(Scene *scene,
- Object *ob,
- MovieClip *clip,
- MovieTrackingObject *tracking_object,
- MovieTrackingTrack *track,
- char axis)
-{
- Object *camera = get_camera_with_movieclip(scene, clip);
- const bool is_camera = (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
- bool flip = false;
- float mat[4][4], vec[3], obmat[4][4], dvec[3];
-
- BKE_object_to_mat4(ob, obmat);
-
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
- mul_v3_m4v3(vec, mat, track->bundle_pos);
- copy_v3_v3(dvec, vec);
-
- if (!is_camera) {
- float imat[4][4];
-
- object_solver_inverted_matrix(scene, ob, imat);
- mul_v3_m4v3(vec, imat, vec);
-
- invert_m4_m4(imat, obmat);
- mul_v3_m4v3(dvec, imat, vec);
-
- sub_v3_v3(vec, obmat[3]);
- }
-
- if (len_squared_v2(vec) < (1e-3f * 1e-3f)) {
- return;
- }
-
- unit_m4(mat);
-
- if (axis == 'X') {
- if (fabsf(dvec[1]) < 1e-3f) {
- flip = true;
-
- mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
- mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
- mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
- }
- else {
- copy_v3_v3(mat[0], vec);
-
- if (is_camera || fabsf(vec[2]) < 1e-3f) {
- mat[0][2] = 0.0f;
- mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
- cross_v3_v3v3(mat[1], mat[2], mat[0]);
- }
- else {
- vec[2] = 0.0f;
-
- cross_v3_v3v3(mat[1], mat[0], vec);
- cross_v3_v3v3(mat[2], mat[0], mat[1]);
- }
- }
- }
- else {
- if (fabsf(dvec[0]) < 1e-3f) {
- flip = true;
-
- mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
- mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
- mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
- }
- else {
- copy_v3_v3(mat[1], vec);
-
- if (is_camera || fabsf(vec[2]) < 1e-3f) {
- mat[1][2] = 0.0f;
- mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
- cross_v3_v3v3(mat[0], mat[1], mat[2]);
- }
- else {
- vec[2] = 0.0f;
-
- cross_v3_v3v3(mat[0], vec, mat[1]);
- cross_v3_v3v3(mat[2], mat[0], mat[1]);
- }
- }
- }
-
- normalize_v3(mat[0]);
- normalize_v3(mat[1]);
- normalize_v3(mat[2]);
-
- if (is_camera) {
- invert_m4(mat);
-
- mul_m4_m4m4(mat, mat, obmat);
- }
- else {
- if (!flip) {
- float lmat[4][4], ilmat[4][4], rmat[3][3];
-
- BKE_object_rot_to_mat3(ob, rmat, true);
- invert_m3(rmat);
- mul_m4_m4m3(mat, mat, rmat);
-
- unit_m4(lmat);
- copy_v3_v3(lmat[3], obmat[3]);
- invert_m4_m4(ilmat, lmat);
-
- mul_m4_series(mat, lmat, mat, ilmat, obmat);
- }
- else {
- mul_m4_m4m4(mat, obmat, mat);
- }
- }
-
- BKE_object_apply_mat4(ob, mat, 0, 0);
-}
-
-static int set_plane_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- Scene *scene = CTX_data_scene(C);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object;
- MovieTrackingTrack *track, *axis_track = NULL, *act_track;
- ListBase *tracksbase;
- Object *object;
- Object *camera = get_camera_with_movieclip(scene, clip);
- int tot = 0;
- float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
- int plane = RNA_enum_get(op->ptr, "plane");
- float rot[4][4] = {{0.0f, 0.0f, -1.0f, 0.0f},
- {0.0f, 1.0f, 0.0f, 0.0f},
- {1.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 1.0f}}; /* 90 degrees Y-axis rotation matrix */
-
- if (count_selected_bundles(C) != 3) {
- BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
-
- return OPERATOR_CANCELLED;
- }
-
- tracking_object = BKE_tracking_object_get_active(tracking);
- tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
- act_track = BKE_tracking_track_get_active(tracking);
-
- object = get_orientation_object(C);
- if (object == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
- return OPERATOR_CANCELLED;
- }
-
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
-
- /* Get 3 bundles to use as reference. */
- track = tracksbase->first;
- while (track && tot < 3) {
- if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
- mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
- if (tot == 0 || track == act_track) {
- copy_v3_v3(orig, vec[tot]);
- }
- else {
- axis_track = track;
- }
- tot++;
- }
- track = track->next;
- }
-
- sub_v3_v3(vec[1], vec[0]);
- sub_v3_v3(vec[2], vec[0]);
-
- /* Construct ortho-normal basis. */
- unit_m4(mat);
- if (plane == 0) { /* floor */
- cross_v3_v3v3(mat[0], vec[1], vec[2]);
- copy_v3_v3(mat[1], vec[1]);
- cross_v3_v3v3(mat[2], mat[0], mat[1]);
- }
- else if (plane == 1) { /* wall */
- cross_v3_v3v3(mat[2], vec[1], vec[2]);
- copy_v3_v3(mat[1], vec[1]);
- cross_v3_v3v3(mat[0], mat[1], mat[2]);
- }
-
- normalize_v3(mat[0]);
- normalize_v3(mat[1]);
- normalize_v3(mat[2]);
-
- /* Move to origin point. */
- mat[3][0] = orig[0];
- mat[3][1] = orig[1];
- mat[3][2] = orig[2];
-
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- invert_m4(mat);
-
- BKE_object_to_mat4(object, obmat);
- mul_m4_m4m4(mat, mat, obmat);
- mul_m4_m4m4(newmat, rot, mat);
- BKE_object_apply_mat4(object, newmat, 0, 0);
-
- /* Make camera have positive z-coordinate. */
- if (object->loc[2] < 0) {
- invert_m4(rot);
- mul_m4_m4m4(newmat, rot, mat);
- BKE_object_apply_mat4(object, newmat, 0, 0);
- }
- }
- else {
- BKE_object_apply_mat4(object, mat, 0, 0);
- }
-
- BKE_object_where_is_calc(scene, object);
- set_axis(scene, object, clip, tracking_object, axis_track, 'X');
-
- DAG_id_tag_update(&clip->id, 0);
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_set_plane(wmOperatorType *ot)
-{
- static EnumPropertyItem plane_items[] = {
- {0, "FLOOR", 0, "Floor", "Set floor plane"},
- {1, "WALL", 0, "Wall", "Set wall plane"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Set Plane";
- ot->description = "Set plane based on 3 selected bundles by moving camera "
- "(or its parent if present) in 3D space";
- ot->idname = "CLIP_OT_set_plane";
-
- /* api callbacks */
- ot->exec = set_plane_exec;
- ot->poll = set_orientation_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_enum(ot->srna, "plane", plane_items, 0, "Plane",
- "Plane to be used for orientation");
-}
-
-/********************** set axis operator *********************/
-
-static int set_axis_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
- Scene *scene = CTX_data_scene(C);
- Object *object;
- int axis = RNA_enum_get(op->ptr, "axis");
-
- if (count_selected_bundles(C) != 1) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Single track with bundle should be selected to define axis");
- return OPERATOR_CANCELLED;
- }
-
- object = get_orientation_object(C);
- if (object == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
- return OPERATOR_CANCELLED;
- }
-
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking,
- tracking_object);
- MovieTrackingTrack *track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) &&
- (track->flag & TRACK_HAS_BUNDLE))
- {
- break;
- }
- track = track->next;
- }
-
- set_axis(scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');
-
- DAG_id_tag_update(&clip->id, 0);
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_set_axis(wmOperatorType *ot)
-{
- static EnumPropertyItem axis_actions[] = {
- {0, "X", 0, "X", "Align bundle align X axis"},
- {1, "Y", 0, "Y", "Align bundle align Y axis"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Set Axis";
- ot->description = "Set direction of scene axis rotating camera "
- "(or its parent if present) and assume selected track "
- "lies on real axis, joining it with the origin";
- ot->idname = "CLIP_OT_set_axis";
-
- /* api callbacks */
- ot->exec = set_axis_exec;
- ot->poll = set_orientation_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis",
- "Axis to use to align bundle along");
-}
-
-/********************** set scale operator *********************/
-
-static int do_set_scale(bContext *C,
- wmOperator *op,
- bool scale_solution,
- bool apply_scale)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
- MovieTrackingTrack *track;
- Scene *scene = CTX_data_scene(C);
- Object *object = NULL;
- Object *camera = get_camera_with_movieclip(scene, clip);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- int tot = 0;
- float vec[2][3], mat[4][4], scale;
- float dist = RNA_float_get(op->ptr, "distance");
-
- if (count_selected_bundles(C) != 2) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Two tracks with bundles should be selected to set scale");
- return OPERATOR_CANCELLED;
- }
-
- if (!scale_solution && !apply_scale) {
- object = get_orientation_object(C);
- if (object == NULL) {
- BKE_report(op->reports,
- RPT_ERROR,
- "No object to apply orientation on");
- return OPERATOR_CANCELLED;
- }
- }
-
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track)) {
- mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
- tot++;
- }
- track = track->next;
- }
-
- sub_v3_v3(vec[0], vec[1]);
-
- if (len_v3(vec[0]) > 1e-5f) {
- scale = dist / len_v3(vec[0]);
- if (apply_scale) {
- /* Apply scale on reconstructed scene itself. */
- MovieTrackingReconstruction *reconstruction =
- BKE_tracking_get_active_reconstruction(tracking);
- MovieReconstructedCamera *reconstructed_cameras;
- int i;
-
- for (track = tracksbase->first; track; track = track->next) {
- mul_v3_fl(track->bundle_pos, scale);
- }
-
- reconstructed_cameras = reconstruction->cameras;
- for (i = 0; i < reconstruction->camnr; i++) {
- mul_v3_fl(reconstructed_cameras[i].mat[3], scale);
- }
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- }
- else {
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- mul_v3_fl(object->size, scale);
- mul_v3_fl(object->loc, scale);
- }
- else if (!scale_solution) {
- Object *solver_camera = object_solver_camera(scene, object);
-
- object->size[0] = object->size[1] = object->size[2] = 1.0f / scale;
-
- if (solver_camera) {
- object->size[0] /= solver_camera->size[0];
- object->size[1] /= solver_camera->size[1];
- object->size[2] /= solver_camera->size[2];
- }
- }
- else {
- tracking_object->scale = scale;
- }
-
- DAG_id_tag_update(&clip->id, 0);
-
- if (object)
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- }
- }
-
- return OPERATOR_FINISHED;
-}
-
-static int set_scale_exec(bContext *C, wmOperator *op)
-{
- return do_set_scale(C, op, false, false);
-}
-
-static int set_scale_invoke(bContext *C,
- wmOperator *op,
- const wmEvent *UNUSED(event))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (!RNA_struct_property_is_set(op->ptr, "distance"))
- RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
-
- return set_scale_exec(C, op);
-}
-
-void CLIP_OT_set_scale(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Scale";
- ot->description = "Set scale of scene by scaling camera (or its parent if present)";
- ot->idname = "CLIP_OT_set_scale";
-
- /* api callbacks */
- ot->exec = set_scale_exec;
- ot->invoke = set_scale_invoke;
- ot->poll = set_orientation_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
- "Distance", "Distance between selected tracks", -100.0f, 100.0f);
-}
-
-/********************** set solution scale operator *********************/
-
-static int set_solution_scale_poll(bContext *C)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- if (sc != NULL) {
- MovieClip *clip = ED_space_clip_get_clip(sc);
- if (clip != NULL) {
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object =
- BKE_tracking_object_get_active(tracking);
- return (tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0;
- }
- }
- return false;
-}
-
-static int set_solution_scale_exec(bContext *C, wmOperator *op)
-{
- return do_set_scale(C, op, true, false);
-}
-
-static int set_solution_scale_invoke(bContext *C,
- wmOperator *op,
- const wmEvent *UNUSED(event))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (!RNA_struct_property_is_set(op->ptr, "distance")) {
- RNA_float_set(op->ptr,
- "distance",
- clip->tracking.settings.object_distance);
- }
-
- return set_solution_scale_exec(C, op);
-}
-
-void CLIP_OT_set_solution_scale(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Solution Scale";
- ot->description = "Set object solution scale using distance between "
- "two selected tracks";
- ot->idname = "CLIP_OT_set_solution_scale";
-
- /* api callbacks */
- ot->exec = set_solution_scale_exec;
- ot->invoke = set_solution_scale_invoke;
- ot->poll = set_solution_scale_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
- "Distance", "Distance between selected tracks",
- -100.0f, 100.0f);
-}
-
-/********************** apply solution scale operator *********************/
-
-static int apply_solution_scale_poll(bContext *C)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- if (sc != NULL) {
- MovieClip *clip = ED_space_clip_get_clip(sc);
- if (clip != NULL) {
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object =
- BKE_tracking_object_get_active(tracking);
- return (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
- }
- }
- return 0;
-}
-
-static int apply_solution_scale_exec(bContext *C, wmOperator *op)
-{
- return do_set_scale(C, op, false, true);
-}
-
-static int apply_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- if (!RNA_struct_property_is_set(op->ptr, "distance")) {
- RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
- }
- return apply_solution_scale_exec(C, op);
-}
-
-void CLIP_OT_apply_solution_scale(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Apply Solution Scale";
- ot->description = "Apply scale on solution itself to make distance between "
- "selected tracks equals to desired";
- ot->idname = "CLIP_OT_apply_solution_scale";
-
- /* api callbacks */
- ot->exec = apply_solution_scale_exec;
- ot->invoke = apply_solution_scale_invoke;
- ot->poll = apply_solution_scale_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
- "Distance", "Distance between selected tracks", -100.0f, 100.0f);
-}
-
/********************** set principal center operator *********************/
static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
@@ -3034,121 +1390,6 @@ void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** detect features operator *********************/
-
-static bGPDlayer *detect_get_layer(MovieClip *clip)
-{
- if (clip->gpd == NULL) {
- return NULL;
- }
- for (bGPDlayer *layer = clip->gpd->layers.first;
- layer != NULL;
- layer = layer->next)
- {
- if (layer->flag & GP_LAYER_ACTIVE) {
- return layer;
- }
- }
- return NULL;
-}
-
-static int detect_features_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
- ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip,
- &sc->user,
- clip_flag,
- MOVIECLIP_CACHE_SKIP);
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- int placement = RNA_enum_get(op->ptr, "placement");
- int margin = RNA_int_get(op->ptr, "margin");
- int min_distance = RNA_int_get(op->ptr, "min_distance");
- float threshold = RNA_float_get(op->ptr, "threshold");
- int place_outside_layer = 0;
- int framenr = ED_space_clip_get_clip_frame_number(sc);
- bGPDlayer *layer = NULL;
-
- if (!ibuf) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Feature detection requires valid clip frame");
- return OPERATOR_CANCELLED;
- }
-
- if (placement != 0) {
- layer = detect_get_layer(clip);
- place_outside_layer = placement == 2;
- }
-
- /* Deselect existing tracks. */
- /* TODO(sergey): Could use deselect oeprator function for this. */
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- track->flag &= ~SELECT;
- track->pat_flag &= ~SELECT;
- track->search_flag &= ~SELECT;
- }
-
- BKE_tracking_detect_harris(tracking,
- tracksbase,
- ibuf,
- framenr,
- margin,
- threshold / 100000.0f,
- min_distance,
- layer,
- place_outside_layer);
-
- IMB_freeImBuf(ibuf);
-
- BKE_tracking_dopesheet_tag_update(tracking);
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_detect_features(wmOperatorType *ot)
-{
- static EnumPropertyItem placement_items[] = {
- {0, "FRAME", 0, "Whole Frame",
- "Place markers across the whole frame"},
- {1, "INSIDE_GPENCIL", 0, "Inside grease pencil",
- "Place markers only inside areas outlined with grease pencil"},
- {2, "OUTSIDE_GPENCIL", 0, "Outside grease pencil",
- "Place markers only outside areas outlined with grease pencil"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Detect Features";
- ot->description = "Automatically detect features and place markers to track";
- ot->idname = "CLIP_OT_detect_features";
-
- /* api callbacks */
- ot->exec = detect_features_exec;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement",
- "Placement for detected features");
- RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin",
- "Only features further than margin pixels from the image "
- "edges are considered", 0, 300);
- RNA_def_float(ot->srna, "threshold", 0.5f, 0.0001f, FLT_MAX, "Threshold",
- "Threshold level to consider feature good enough for tracking",
- 0.0001f, FLT_MAX);
- RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance",
- "Minimal distance accepted between two features", 0, 300);
-}
-
/********************** frame jump operator *********************/
static int frame_jump_exec(bContext *C, wmOperator *op)
@@ -3462,200 +1703,6 @@ void CLIP_OT_track_copy_color(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************* add 2d stabilization tracks operator ********************/
-
-static int stabilize_2d_poll(bContext *C)
-{
- if (ED_space_clip_tracking_poll(C)) {
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTrackingObject *tracking_object =
- BKE_tracking_object_get_active(&clip->tracking);
- return (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
- }
- return 0;
-}
-
-static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingStabilization *stab = &tracking->stabilization;
-
- bool update = false;
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- if (TRACK_VIEW_SELECTED(sc, track) &&
- (track->flag & TRACK_USE_2D_STAB) == 0)
- {
- track->flag |= TRACK_USE_2D_STAB;
- stab->tot_track++;
- update = true;
- }
- }
-
- if (update) {
- stab->ok = 0;
- DAG_id_tag_update(&clip->id, 0);
- WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Stabilization Tracks";
- ot->description = "Add selected tracks to 2D stabilization tool";
- ot->idname = "CLIP_OT_stabilize_2d_add";
-
- /* api callbacks */
- ot->exec = stabilize_2d_add_exec;
- ot->poll = stabilize_2d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/******************* remove 2d stabilization tracks operator ******************/
-
-static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingStabilization *stab = &tracking->stabilization;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- int a = 0;
- bool update = false;
-
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- if (track->flag & TRACK_USE_2D_STAB) {
- if (a == stab->act_track) {
- track->flag &= ~TRACK_USE_2D_STAB;
- stab->act_track--;
- stab->tot_track--;
- if (stab->act_track < 0) {
- stab->act_track = 0;
- }
- update = true;
- break;
- }
- a++;
- }
- }
-
- if (update) {
- stab->ok = 0;
- DAG_id_tag_update(&clip->id, 0);
- WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Stabilization Track";
- ot->description = "Remove selected track from stabilization";
- ot->idname = "CLIP_OT_stabilize_2d_remove";
-
- /* api callbacks */
- ot->exec = stabilize_2d_remove_exec;
- ot->poll = stabilize_2d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************** select 2d stabilization tracks operator *********************/
-
-static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- bool update = false;
-
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- if (track->flag & TRACK_USE_2D_STAB) {
- BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
- update = true;
- }
- }
-
- if (update) {
- WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, clip);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Stabilization Tracks";
- ot->description = "Select tracks which are used for stabilization";
- ot->idname = "CLIP_OT_stabilize_2d_select";
-
- /* api callbacks */
- ot->exec = stabilize_2d_select_exec;
- ot->poll = stabilize_2d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/***************** set 2d stabilization rotation track operator ****************/
-
-static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
-
- if (act_track != NULL) {
- MovieTrackingStabilization *stab = &tracking->stabilization;
- stab->rot_track = act_track;
- stab->ok = 0;
-
- DAG_id_tag_update(&clip->id, 0);
- WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Rotation Track";
- ot->description = "Use active track to compensate rotation when "
- "doing 2D stabilization";
- ot->idname = "CLIP_OT_stabilize_2d_set_rotation";
-
- /* api callbacks */
- ot->exec = stabilize_2d_set_rotation_exec;
- ot->poll = stabilize_2d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/********************** clean tracks operator *********************/
static bool is_track_clean(MovieTrackingTrack *track, int frames, int del)
@@ -3971,7 +2018,7 @@ static int copy_tracks_exec(bContext *C, wmOperator *UNUSED(op))
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- clear_invisible_track_selection(sc, clip);
+ clip_tracking_clear_invisible_track_selection(sc, clip);
BKE_tracking_clipboard_copy_tracks(tracking, object);
@@ -4035,387 +2082,6 @@ void CLIP_OT_paste_tracks(wmOperatorType *ot)
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;
-
- /* Compute 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 {
- int event_type;
- 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;
-
-/* TODO(sergey): Use closest sliding zone semantic here. */
-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);
- MovieTracking *tracking = &clip->tracking;
- int width, height;
- float co[2];
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(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 (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
- plane_track != NULL;
- plane_track = plane_track->next)
- {
- if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- 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");
-
- customdata->event_type = event->type;
-
- 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;
- const 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:
- case RIGHTMOUSE:
- if (event->type == data->event_type && 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_CURSOR | OPTYPE_BLOCKING;
-}
-
/********************** Insert track keyframe operator *********************/
static void keyframe_set_flag(bContext *C, bool set)
diff --git a/source/blender/editors/space_clip/tracking_ops_detect.c b/source/blender/editors/space_clip/tracking_ops_detect.c
new file mode 100644
index 00000000000..1af6bbef0bc
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_detect.c
@@ -0,0 +1,171 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_detect.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_movieclip.h"
+#include "BKE_tracking.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_clip.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "clip_intern.h"
+
+/********************** detect features operator *********************/
+
+static bGPDlayer *detect_get_layer(MovieClip *clip)
+{
+ if (clip->gpd == NULL) {
+ return NULL;
+ }
+ for (bGPDlayer *layer = clip->gpd->layers.first;
+ layer != NULL;
+ layer = layer->next)
+ {
+ if (layer->flag & GP_LAYER_ACTIVE) {
+ return layer;
+ }
+ }
+ return NULL;
+}
+
+static int detect_features_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
+ ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip,
+ &sc->user,
+ clip_flag,
+ MOVIECLIP_CACHE_SKIP);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ int placement = RNA_enum_get(op->ptr, "placement");
+ int margin = RNA_int_get(op->ptr, "margin");
+ int min_distance = RNA_int_get(op->ptr, "min_distance");
+ float threshold = RNA_float_get(op->ptr, "threshold");
+ int place_outside_layer = 0;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+ bGPDlayer *layer = NULL;
+
+ if (!ibuf) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Feature detection requires valid clip frame");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (placement != 0) {
+ layer = detect_get_layer(clip);
+ place_outside_layer = placement == 2;
+ }
+
+ /* Deselect existing tracks. */
+ /* TODO(sergey): Could use deselect oeprator function for this. */
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ track->flag &= ~SELECT;
+ track->pat_flag &= ~SELECT;
+ track->search_flag &= ~SELECT;
+ }
+
+ BKE_tracking_detect_harris(tracking,
+ tracksbase,
+ ibuf,
+ framenr,
+ margin,
+ threshold / 100000.0f,
+ min_distance,
+ layer,
+ place_outside_layer);
+
+ IMB_freeImBuf(ibuf);
+
+ BKE_tracking_dopesheet_tag_update(tracking);
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_detect_features(wmOperatorType *ot)
+{
+ static EnumPropertyItem placement_items[] = {
+ {0, "FRAME", 0, "Whole Frame",
+ "Place markers across the whole frame"},
+ {1, "INSIDE_GPENCIL", 0, "Inside grease pencil",
+ "Place markers only inside areas outlined with grease pencil"},
+ {2, "OUTSIDE_GPENCIL", 0, "Outside grease pencil",
+ "Place markers only outside areas outlined with grease pencil"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Detect Features";
+ ot->description = "Automatically detect features and place markers to track";
+ ot->idname = "CLIP_OT_detect_features";
+
+ /* api callbacks */
+ ot->exec = detect_features_exec;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement",
+ "Placement for detected features");
+ RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin",
+ "Only features further than margin pixels from the image "
+ "edges are considered", 0, 300);
+ RNA_def_float(ot->srna, "threshold", 0.5f, 0.0001f, FLT_MAX, "Threshold",
+ "Threshold level to consider feature good enough for tracking",
+ 0.0001f, FLT_MAX);
+ RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance",
+ "Minimal distance accepted between two features", 0, 300);
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_intern.h b/source/blender/editors/space_clip/tracking_ops_intern.h
new file mode 100644
index 00000000000..d9aff100416
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_intern.h
@@ -0,0 +1,45 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_intern.h
+ * \ingroup spclip
+ */
+
+#ifndef __CLIP_TRACKING_INTERN__
+#define __CLIP_TRACKING_INTERN__
+
+struct bContext;
+struct SpaceClip;
+struct MovieClip;
+
+void clip_tracking_clear_invisible_track_selection(struct SpaceClip *sc,
+ struct MovieClip *clip);
+
+void clip_tracking_show_cursor(struct bContext *C);
+void clip_tracking_hide_cursor(struct bContext *C);
+
+#endif /* __CLIP_TRACKING_INTERN__ */ \ No newline at end of file
diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c
new file mode 100644
index 00000000000..f81180d65a9
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_orient.c
@@ -0,0 +1,860 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_orient.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h" /* SELECT */
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_constraint.h"
+#include "BKE_tracking.h"
+#include "BKE_global.h"
+#include "BKE_depsgraph.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_clip.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "clip_intern.h"
+
+/********************** set origin operator *********************/
+
+static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
+{
+ Object *camera = scene->camera;
+
+ if (camera != NULL &&
+ BKE_object_movieclip_get(scene, camera, false) == clip)
+ {
+ return camera;
+ }
+
+ for (Base *base = scene->base.first;
+ base != NULL;
+ base = base->next)
+ {
+ if (base->object->type == OB_CAMERA) {
+ if (BKE_object_movieclip_get(scene, base->object, false) == clip) {
+ camera = base->object;
+ break;
+ }
+ }
+ }
+
+ return camera;
+}
+
+static Object *get_orientation_object(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ Object *object = NULL;
+
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ object = get_camera_with_movieclip(scene, clip);
+ }
+ else {
+ object = OBACT;
+ }
+
+ if (object != NULL && object->parent != NULL) {
+ object = object->parent;
+ }
+
+ return object;
+}
+
+static int set_orientation_poll(bContext *C)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ if (sc != NULL) {
+ Scene *scene = CTX_data_scene(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (clip != NULL) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ return true;
+ }
+ else {
+ return OBACT != NULL;
+ }
+ }
+ }
+ return false;
+}
+
+static int count_selected_bundles(bContext *C)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ int tot = 0;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE)) {
+ tot++;
+ }
+ }
+ return tot;
+}
+
+static void object_solver_inverted_matrix(Scene *scene,
+ Object *ob,
+ float invmat[4][4])
+{
+ bool found = false;
+ for (bConstraint *con = ob->constraints.first;
+ con != NULL;
+ con = con->next)
+ {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ if (cti == NULL) {
+ continue;
+ }
+ if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
+ if (!found) {
+ Object *cam = data->camera ? data->camera : scene->camera;
+ BKE_object_where_is_calc_mat4(scene, cam, invmat);
+ }
+ mul_m4_m4m4(invmat, invmat, data->invmat);
+ found = true;
+ }
+ }
+ if (found) {
+ invert_m4(invmat);
+ }
+ else {
+ unit_m4(invmat);
+ }
+}
+
+static Object *object_solver_camera(Scene *scene, Object *ob)
+{
+ for (bConstraint *con = ob->constraints.first;
+ con != NULL;
+ con = con->next)
+ {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ if (cti == NULL) {
+ continue;
+ }
+ if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
+ return (data->camera != NULL) ? data->camera : scene->camera;
+ }
+ }
+ return NULL;
+}
+
+static int set_origin_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ Scene *scene = CTX_data_scene(C);
+ Object *camera = get_camera_with_movieclip(scene, clip);
+ int selected_count = count_selected_bundles(C);
+
+ if (selected_count == 0) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "At least one track with bundle should be selected to "
+ "define origin position");
+
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *object = get_orientation_object(C);
+ if (object == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
+ return OPERATOR_CANCELLED;
+ }
+
+ MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+
+ float median[3] = {0.0f, 0.0f, 0.0f};
+ zero_v3(median);
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track) &&
+ (track->flag & TRACK_HAS_BUNDLE))
+ {
+ add_v3_v3(median, track->bundle_pos);
+ }
+ }
+ mul_v3_fl(median, 1.0f / selected_count);
+
+ float mat[4][4], vec[3];
+ BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+ mul_v3_m4v3(vec, mat, median);
+
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ sub_v3_v3(object->loc, vec);
+ }
+ else {
+ object_solver_inverted_matrix(scene, object, mat);
+ mul_v3_m4v3(vec, mat, vec);
+ copy_v3_v3(object->loc, vec);
+ }
+
+ DAG_id_tag_update(&clip->id, 0);
+ DAG_id_tag_update(&object->id, OB_RECALC_OB);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_set_origin(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Origin";
+ ot->description = "Set active marker as origin by moving camera (or its parent if present) in 3D space";
+ ot->idname = "CLIP_OT_set_origin";
+
+ /* api callbacks */
+ ot->exec = set_origin_exec;
+ ot->poll = set_orientation_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "use_median", 0, "Use Median",
+ "Set origin to median point of selected bundles");
+}
+
+/********************** set floor operator *********************/
+
+static void set_axis(Scene *scene,
+ Object *ob,
+ MovieClip *clip,
+ MovieTrackingObject *tracking_object,
+ MovieTrackingTrack *track,
+ char axis)
+{
+ Object *camera = get_camera_with_movieclip(scene, clip);
+ const bool is_camera = (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
+ bool flip = false;
+ float mat[4][4], vec[3], obmat[4][4], dvec[3];
+
+ BKE_object_to_mat4(ob, obmat);
+
+ BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+ mul_v3_m4v3(vec, mat, track->bundle_pos);
+ copy_v3_v3(dvec, vec);
+
+ if (!is_camera) {
+ float imat[4][4];
+
+ object_solver_inverted_matrix(scene, ob, imat);
+ mul_v3_m4v3(vec, imat, vec);
+
+ invert_m4_m4(imat, obmat);
+ mul_v3_m4v3(dvec, imat, vec);
+
+ sub_v3_v3(vec, obmat[3]);
+ }
+
+ if (len_squared_v2(vec) < (1e-3f * 1e-3f)) {
+ return;
+ }
+
+ unit_m4(mat);
+
+ if (axis == 'X') {
+ if (fabsf(dvec[1]) < 1e-3f) {
+ flip = true;
+
+ mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
+ mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
+ mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
+ }
+ else {
+ copy_v3_v3(mat[0], vec);
+
+ if (is_camera || fabsf(vec[2]) < 1e-3f) {
+ mat[0][2] = 0.0f;
+ mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
+ cross_v3_v3v3(mat[1], mat[2], mat[0]);
+ }
+ else {
+ vec[2] = 0.0f;
+
+ cross_v3_v3v3(mat[1], mat[0], vec);
+ cross_v3_v3v3(mat[2], mat[0], mat[1]);
+ }
+ }
+ }
+ else {
+ if (fabsf(dvec[0]) < 1e-3f) {
+ flip = true;
+
+ mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
+ mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
+ mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
+ }
+ else {
+ copy_v3_v3(mat[1], vec);
+
+ if (is_camera || fabsf(vec[2]) < 1e-3f) {
+ mat[1][2] = 0.0f;
+ mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
+ cross_v3_v3v3(mat[0], mat[1], mat[2]);
+ }
+ else {
+ vec[2] = 0.0f;
+
+ cross_v3_v3v3(mat[0], vec, mat[1]);
+ cross_v3_v3v3(mat[2], mat[0], mat[1]);
+ }
+ }
+ }
+
+ normalize_v3(mat[0]);
+ normalize_v3(mat[1]);
+ normalize_v3(mat[2]);
+
+ if (is_camera) {
+ invert_m4(mat);
+
+ mul_m4_m4m4(mat, mat, obmat);
+ }
+ else {
+ if (!flip) {
+ float lmat[4][4], ilmat[4][4], rmat[3][3];
+
+ BKE_object_rot_to_mat3(ob, rmat, true);
+ invert_m3(rmat);
+ mul_m4_m4m3(mat, mat, rmat);
+
+ unit_m4(lmat);
+ copy_v3_v3(lmat[3], obmat[3]);
+ invert_m4_m4(ilmat, lmat);
+
+ mul_m4_series(mat, lmat, mat, ilmat, obmat);
+ }
+ else {
+ mul_m4_m4m4(mat, obmat, mat);
+ }
+ }
+
+ BKE_object_apply_mat4(ob, mat, 0, 0);
+}
+
+static int set_plane_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ Scene *scene = CTX_data_scene(C);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object;
+ MovieTrackingTrack *track, *axis_track = NULL, *act_track;
+ ListBase *tracksbase;
+ Object *object;
+ Object *camera = get_camera_with_movieclip(scene, clip);
+ int tot = 0;
+ float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
+ int plane = RNA_enum_get(op->ptr, "plane");
+ float rot[4][4] = {{0.0f, 0.0f, -1.0f, 0.0f},
+ {0.0f, 1.0f, 0.0f, 0.0f},
+ {1.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f}}; /* 90 degrees Y-axis rotation matrix */
+
+ if (count_selected_bundles(C) != 3) {
+ BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
+
+ return OPERATOR_CANCELLED;
+ }
+
+ tracking_object = BKE_tracking_object_get_active(tracking);
+ tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ act_track = BKE_tracking_track_get_active(tracking);
+
+ object = get_orientation_object(C);
+ if (object == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+
+ /* Get 3 bundles to use as reference. */
+ track = tracksbase->first;
+ while (track && tot < 3) {
+ if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
+ mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
+ if (tot == 0 || track == act_track) {
+ copy_v3_v3(orig, vec[tot]);
+ }
+ else {
+ axis_track = track;
+ }
+ tot++;
+ }
+ track = track->next;
+ }
+
+ sub_v3_v3(vec[1], vec[0]);
+ sub_v3_v3(vec[2], vec[0]);
+
+ /* Construct ortho-normal basis. */
+ unit_m4(mat);
+ if (plane == 0) { /* floor */
+ cross_v3_v3v3(mat[0], vec[1], vec[2]);
+ copy_v3_v3(mat[1], vec[1]);
+ cross_v3_v3v3(mat[2], mat[0], mat[1]);
+ }
+ else if (plane == 1) { /* wall */
+ cross_v3_v3v3(mat[2], vec[1], vec[2]);
+ copy_v3_v3(mat[1], vec[1]);
+ cross_v3_v3v3(mat[0], mat[1], mat[2]);
+ }
+
+ normalize_v3(mat[0]);
+ normalize_v3(mat[1]);
+ normalize_v3(mat[2]);
+
+ /* Move to origin point. */
+ mat[3][0] = orig[0];
+ mat[3][1] = orig[1];
+ mat[3][2] = orig[2];
+
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ invert_m4(mat);
+
+ BKE_object_to_mat4(object, obmat);
+ mul_m4_m4m4(mat, mat, obmat);
+ mul_m4_m4m4(newmat, rot, mat);
+ BKE_object_apply_mat4(object, newmat, 0, 0);
+
+ /* Make camera have positive z-coordinate. */
+ if (object->loc[2] < 0) {
+ invert_m4(rot);
+ mul_m4_m4m4(newmat, rot, mat);
+ BKE_object_apply_mat4(object, newmat, 0, 0);
+ }
+ }
+ else {
+ BKE_object_apply_mat4(object, mat, 0, 0);
+ }
+
+ BKE_object_where_is_calc(scene, object);
+ set_axis(scene, object, clip, tracking_object, axis_track, 'X');
+
+ DAG_id_tag_update(&clip->id, 0);
+ DAG_id_tag_update(&object->id, OB_RECALC_OB);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_set_plane(wmOperatorType *ot)
+{
+ static EnumPropertyItem plane_items[] = {
+ {0, "FLOOR", 0, "Floor", "Set floor plane"},
+ {1, "WALL", 0, "Wall", "Set wall plane"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Set Plane";
+ ot->description = "Set plane based on 3 selected bundles by moving camera "
+ "(or its parent if present) in 3D space";
+ ot->idname = "CLIP_OT_set_plane";
+
+ /* api callbacks */
+ ot->exec = set_plane_exec;
+ ot->poll = set_orientation_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "plane", plane_items, 0, "Plane",
+ "Plane to be used for orientation");
+}
+
+/********************** set axis operator *********************/
+
+static int set_axis_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ Scene *scene = CTX_data_scene(C);
+ Object *object;
+ int axis = RNA_enum_get(op->ptr, "axis");
+
+ if (count_selected_bundles(C) != 1) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Single track with bundle should be selected to define axis");
+ return OPERATOR_CANCELLED;
+ }
+
+ object = get_orientation_object(C);
+ if (object == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
+ return OPERATOR_CANCELLED;
+ }
+
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking,
+ tracking_object);
+ MovieTrackingTrack *track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) &&
+ (track->flag & TRACK_HAS_BUNDLE))
+ {
+ break;
+ }
+ track = track->next;
+ }
+
+ set_axis(scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');
+
+ DAG_id_tag_update(&clip->id, 0);
+ DAG_id_tag_update(&object->id, OB_RECALC_OB);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_set_axis(wmOperatorType *ot)
+{
+ static EnumPropertyItem axis_actions[] = {
+ {0, "X", 0, "X", "Align bundle align X axis"},
+ {1, "Y", 0, "Y", "Align bundle align Y axis"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Set Axis";
+ ot->description = "Set direction of scene axis rotating camera "
+ "(or its parent if present) and assume selected track "
+ "lies on real axis, joining it with the origin";
+ ot->idname = "CLIP_OT_set_axis";
+
+ /* api callbacks */
+ ot->exec = set_axis_exec;
+ ot->poll = set_orientation_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis",
+ "Axis to use to align bundle along");
+}
+
+/********************** set scale operator *********************/
+
+static int do_set_scale(bContext *C,
+ wmOperator *op,
+ bool scale_solution,
+ bool apply_scale)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ MovieTrackingTrack *track;
+ Scene *scene = CTX_data_scene(C);
+ Object *object = NULL;
+ Object *camera = get_camera_with_movieclip(scene, clip);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ int tot = 0;
+ float vec[2][3], mat[4][4], scale;
+ float dist = RNA_float_get(op->ptr, "distance");
+
+ if (count_selected_bundles(C) != 2) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Two tracks with bundles should be selected to set scale");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!scale_solution && !apply_scale) {
+ object = get_orientation_object(C);
+ if (object == NULL) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "No object to apply orientation on");
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track)) {
+ mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
+ tot++;
+ }
+ track = track->next;
+ }
+
+ sub_v3_v3(vec[0], vec[1]);
+
+ if (len_v3(vec[0]) > 1e-5f) {
+ scale = dist / len_v3(vec[0]);
+ if (apply_scale) {
+ /* Apply scale on reconstructed scene itself. */
+ MovieTrackingReconstruction *reconstruction =
+ BKE_tracking_get_active_reconstruction(tracking);
+ MovieReconstructedCamera *reconstructed_cameras;
+ int i;
+
+ for (track = tracksbase->first; track; track = track->next) {
+ mul_v3_fl(track->bundle_pos, scale);
+ }
+
+ reconstructed_cameras = reconstruction->cameras;
+ for (i = 0; i < reconstruction->camnr; i++) {
+ mul_v3_fl(reconstructed_cameras[i].mat[3], scale);
+ }
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ }
+ else {
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ mul_v3_fl(object->size, scale);
+ mul_v3_fl(object->loc, scale);
+ }
+ else if (!scale_solution) {
+ Object *solver_camera = object_solver_camera(scene, object);
+
+ object->size[0] = object->size[1] = object->size[2] = 1.0f / scale;
+
+ if (solver_camera) {
+ object->size[0] /= solver_camera->size[0];
+ object->size[1] /= solver_camera->size[1];
+ object->size[2] /= solver_camera->size[2];
+ }
+ }
+ else {
+ tracking_object->scale = scale;
+ }
+
+ DAG_id_tag_update(&clip->id, 0);
+
+ if (object)
+ DAG_id_tag_update(&object->id, OB_RECALC_OB);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int set_scale_exec(bContext *C, wmOperator *op)
+{
+ return do_set_scale(C, op, false, false);
+}
+
+static int set_scale_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (!RNA_struct_property_is_set(op->ptr, "distance"))
+ RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
+
+ return set_scale_exec(C, op);
+}
+
+void CLIP_OT_set_scale(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Scale";
+ ot->description = "Set scale of scene by scaling camera (or its parent if present)";
+ ot->idname = "CLIP_OT_set_scale";
+
+ /* api callbacks */
+ ot->exec = set_scale_exec;
+ ot->invoke = set_scale_invoke;
+ ot->poll = set_orientation_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
+ "Distance", "Distance between selected tracks", -100.0f, 100.0f);
+}
+
+/********************** set solution scale operator *********************/
+
+static int set_solution_scale_poll(bContext *C)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ if (sc != NULL) {
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (clip != NULL) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object =
+ BKE_tracking_object_get_active(tracking);
+ return (tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0;
+ }
+ }
+ return false;
+}
+
+static int set_solution_scale_exec(bContext *C, wmOperator *op)
+{
+ return do_set_scale(C, op, true, false);
+}
+
+static int set_solution_scale_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (!RNA_struct_property_is_set(op->ptr, "distance")) {
+ RNA_float_set(op->ptr,
+ "distance",
+ clip->tracking.settings.object_distance);
+ }
+
+ return set_solution_scale_exec(C, op);
+}
+
+void CLIP_OT_set_solution_scale(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Solution Scale";
+ ot->description = "Set object solution scale using distance between "
+ "two selected tracks";
+ ot->idname = "CLIP_OT_set_solution_scale";
+
+ /* api callbacks */
+ ot->exec = set_solution_scale_exec;
+ ot->invoke = set_solution_scale_invoke;
+ ot->poll = set_solution_scale_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
+ "Distance", "Distance between selected tracks",
+ -100.0f, 100.0f);
+}
+
+/********************** apply solution scale operator *********************/
+
+static int apply_solution_scale_poll(bContext *C)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ if (sc != NULL) {
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (clip != NULL) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object =
+ BKE_tracking_object_get_active(tracking);
+ return (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
+ }
+ }
+ return 0;
+}
+
+static int apply_solution_scale_exec(bContext *C, wmOperator *op)
+{
+ return do_set_scale(C, op, false, true);
+}
+
+static int apply_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (!RNA_struct_property_is_set(op->ptr, "distance")) {
+ RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
+ }
+ return apply_solution_scale_exec(C, op);
+}
+
+void CLIP_OT_apply_solution_scale(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Solution Scale";
+ ot->description = "Apply scale on solution itself to make distance between "
+ "selected tracks equals to desired";
+ ot->idname = "CLIP_OT_apply_solution_scale";
+
+ /* api callbacks */
+ ot->exec = apply_solution_scale_exec;
+ ot->invoke = apply_solution_scale_invoke;
+ ot->poll = apply_solution_scale_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
+ "Distance", "Distance between selected tracks",
+ -100.0f, 100.0f);
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_plane.c b/source/blender/editors/space_clip/tracking_ops_plane.c
new file mode 100644
index 00000000000..c5dc1c14dea
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_plane.c
@@ -0,0 +1,432 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_plane.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_tracking.h"
+#include "BKE_depsgraph.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_clip.h"
+
+#include "clip_intern.h"
+#include "tracking_ops_intern.h"
+
+/********************** 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;
+
+ /* Compute 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 {
+ int event_type;
+ 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;
+
+/* TODO(sergey): Use closest sliding zone semantic here. */
+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);
+ MovieTracking *tracking = &clip->tracking;
+ int width, height;
+ float co[2];
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(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 (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
+ plane_track != NULL;
+ plane_track = plane_track->next)
+ {
+ if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
+ 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");
+
+ customdata->event_type = event->type;
+
+ 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;
+
+ clip_tracking_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;
+ const 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:
+ case RIGHTMOUSE:
+ if (event->type == data->event_type && 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);
+
+ clip_tracking_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);
+
+ clip_tracking_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_CURSOR | OPTYPE_BLOCKING;
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c
new file mode 100644
index 00000000000..5c74c1947e3
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_solve.c
@@ -0,0 +1,351 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_solve.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_object_types.h" /* SELECT */
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_movieclip.h"
+#include "BKE_tracking.h"
+#include "BKE_global.h"
+#include "BKE_depsgraph.h"
+#include "BKE_report.h"
+#include "BKE_library.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_clip.h"
+
+
+#include "clip_intern.h"
+
+/********************** solve camera operator *********************/
+
+typedef struct {
+ Scene *scene;
+ MovieClip *clip;
+ MovieClipUser user;
+
+ ReportList *reports;
+
+ char stats_message[256];
+
+ struct MovieReconstructContext *context;
+} SolveCameraJob;
+
+static bool solve_camera_initjob(bContext *C,
+ SolveCameraJob *scj,
+ wmOperator *op,
+ char *error_msg,
+ int max_error)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ Scene *scene = CTX_data_scene(C);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
+ int width, height;
+
+ if (!BKE_tracking_reconstruction_check(tracking,
+ object,
+ error_msg,
+ max_error))
+ {
+ return false;
+ }
+
+ /* Could fail if footage uses images with different sizes. */
+ BKE_movieclip_get_size(clip, &sc->user, &width, &height);
+
+ scj->clip = clip;
+ scj->scene = scene;
+ scj->reports = op->reports;
+ scj->user = sc->user;
+
+ scj->context = BKE_tracking_reconstruction_context_new(clip,
+ object,
+ object->keyframe1,
+ object->keyframe2,
+ width,
+ height);
+
+ tracking->stats = MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
+
+ return true;
+}
+
+static void solve_camera_updatejob(void *scv)
+{
+ SolveCameraJob *scj = (SolveCameraJob *)scv;
+ MovieTracking *tracking = &scj->clip->tracking;
+
+ BLI_strncpy(tracking->stats->message,
+ scj->stats_message,
+ sizeof(tracking->stats->message));
+}
+
+static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress)
+{
+ SolveCameraJob *scj = (SolveCameraJob *)scv;
+ BKE_tracking_reconstruction_solve(scj->context,
+ stop,
+ do_update,
+ progress,
+ scj->stats_message,
+ sizeof(scj->stats_message));
+}
+
+static void solve_camera_freejob(void *scv)
+{
+ SolveCameraJob *scj = (SolveCameraJob *)scv;
+ MovieTracking *tracking = &scj->clip->tracking;
+ Scene *scene = scj->scene;
+ MovieClip *clip = scj->clip;
+ int solved;
+
+ if (!scj->context) {
+ /* job weren't fully initialized due to some error */
+ MEM_freeN(scj);
+ return;
+ }
+
+ solved = BKE_tracking_reconstruction_finish(scj->context, tracking);
+ if (!solved) {
+ BKE_report(scj->reports,
+ RPT_WARNING,
+ "Some data failed to reconstruct (see console for details)");
+ }
+ else {
+ BKE_reportf(scj->reports,
+ RPT_INFO,
+ "Average re-projection error: %.3f",
+ tracking->reconstruction.error);
+ }
+
+ /* Set currently solved clip as active for scene. */
+ if (scene->clip != NULL) {
+ id_us_min(&clip->id);
+ }
+ scene->clip = clip;
+ id_us_plus(&clip->id);
+
+ /* Set blender camera focal length so result would look fine there. */
+ if (scene->camera != NULL &&
+ scene->camera->data &&
+ GS(((ID *) scene->camera->data)->name) == ID_CA)
+ {
+ Camera *camera = (Camera *)scene->camera->data;
+ int width, height;
+ BKE_movieclip_get_size(clip, &scj->user, &width, &height);
+ BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
+ WM_main_add_notifier(NC_OBJECT, camera);
+ }
+
+ MEM_freeN(tracking->stats);
+ tracking->stats = NULL;
+
+ DAG_id_tag_update(&clip->id, 0);
+
+ WM_main_add_notifier(NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, NULL);
+
+ /* Update active clip displayed in scene buttons. */
+ WM_main_add_notifier(NC_SCENE, scene);
+
+ BKE_tracking_reconstruction_context_free(scj->context);
+ MEM_freeN(scj);
+}
+
+static int solve_camera_exec(bContext *C, wmOperator *op)
+{
+ SolveCameraJob *scj;
+ char error_msg[256] = "\0";
+ scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
+ if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
+ }
+ solve_camera_freejob(scj);
+ return OPERATOR_CANCELLED;
+ }
+ solve_camera_startjob(scj, NULL, NULL, NULL);
+ solve_camera_freejob(scj);
+ return OPERATOR_FINISHED;
+}
+
+static int solve_camera_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ SolveCameraJob *scj;
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingReconstruction *reconstruction =
+ BKE_tracking_get_active_reconstruction(tracking);
+ wmJob *wm_job;
+ char error_msg[256] = "\0";
+
+ if (WM_jobs_test(CTX_wm_manager(C), sa, WM_JOB_TYPE_ANY)) {
+ /* only one solve is allowed at a time */
+ return OPERATOR_CANCELLED;
+ }
+
+ scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
+ if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
+ }
+ solve_camera_freejob(scj);
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_strncpy(tracking->stats->message,
+ "Solving camera | Preparing solve",
+ sizeof(tracking->stats->message));
+
+ /* Hide reconstruction statistics from previous solve. */
+ reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+
+ /* Setup job. */
+ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Solve Camera",
+ WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_SOLVE_CAMERA);
+ WM_jobs_customdata_set(wm_job, scj, solve_camera_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_MOVIECLIP | NA_EVALUATED, 0);
+ WM_jobs_callbacks(wm_job,
+ solve_camera_startjob,
+ NULL,
+ solve_camera_updatejob,
+ NULL);
+
+ G.is_break = false;
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ WM_cursor_wait(0);
+
+ /* add modal handler for ESC */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int solve_camera_modal(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *event)
+{
+ /* No running solver, remove handler and pass through. */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY))
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+
+ /* Running solver. */
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void CLIP_OT_solve_camera(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Solve Camera";
+ ot->description = "Solve camera motion from tracks";
+ ot->idname = "CLIP_OT_solve_camera";
+
+ /* api callbacks */
+ ot->exec = solve_camera_exec;
+ ot->invoke = solve_camera_invoke;
+ ot->modal = solve_camera_modal;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************** clear solution operator *********************/
+
+static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ MovieTrackingReconstruction *reconstruction =
+ BKE_tracking_get_active_reconstruction(tracking);
+
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ track->flag &= ~TRACK_HAS_BUNDLE;
+ }
+
+ if (reconstruction->cameras != NULL) {
+ MEM_freeN(reconstruction->cameras);
+ reconstruction->cameras = NULL;
+ }
+
+ reconstruction->camnr = 0;
+ reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
+
+ DAG_id_tag_update(&clip->id, 0);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_clear_solution(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Solution";
+ ot->description = "Clear all calculated data";
+ ot->idname = "CLIP_OT_clear_solution";
+
+ /* api callbacks */
+ ot->exec = clear_solution_exec;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_stabilize.c b/source/blender/editors/space_clip/tracking_ops_stabilize.c
new file mode 100644
index 00000000000..8d6173e1cea
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_stabilize.c
@@ -0,0 +1,242 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_stabilize.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_tracking.h"
+#include "BKE_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_clip.h"
+
+#include "clip_intern.h"
+
+/********************* add 2d stabilization tracks operator ********************/
+
+static int stabilize_2d_poll(bContext *C)
+{
+ if (ED_space_clip_tracking_poll(C)) {
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTrackingObject *tracking_object =
+ BKE_tracking_object_get_active(&clip->tracking);
+ return (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
+ }
+ return 0;
+}
+
+static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+
+ bool update = false;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track) &&
+ (track->flag & TRACK_USE_2D_STAB) == 0)
+ {
+ track->flag |= TRACK_USE_2D_STAB;
+ stab->tot_track++;
+ update = true;
+ }
+ }
+
+ if (update) {
+ stab->ok = 0;
+ DAG_id_tag_update(&clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Stabilization Tracks";
+ ot->description = "Add selected tracks to 2D stabilization tool";
+ ot->idname = "CLIP_OT_stabilize_2d_add";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_add_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/******************* remove 2d stabilization tracks operator ******************/
+
+static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ int a = 0;
+ bool update = false;
+
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (track->flag & TRACK_USE_2D_STAB) {
+ if (a == stab->act_track) {
+ track->flag &= ~TRACK_USE_2D_STAB;
+ stab->act_track--;
+ stab->tot_track--;
+ if (stab->act_track < 0) {
+ stab->act_track = 0;
+ }
+ update = true;
+ break;
+ }
+ a++;
+ }
+ }
+
+ if (update) {
+ stab->ok = 0;
+ DAG_id_tag_update(&clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Stabilization Track";
+ ot->description = "Remove selected track from stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_remove";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_remove_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/******************* select 2d stabilization tracks operator ******************/
+
+static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ bool update = false;
+
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (track->flag & TRACK_USE_2D_STAB) {
+ BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
+ update = true;
+ }
+ }
+
+ if (update) {
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Stabilization Tracks";
+ ot->description = "Select tracks which are used for stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_select";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_select_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/***************** set 2d stabilization rotation track operator ****************/
+
+static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
+
+ if (act_track != NULL) {
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+ stab->rot_track = act_track;
+ stab->ok = 0;
+
+ DAG_id_tag_update(&clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Rotation Track";
+ ot->description = "Use active track to compensate rotation when "
+ "doing 2D stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_set_rotation";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_set_rotation_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
new file mode 100644
index 00000000000..580eff08e2c
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -0,0 +1,579 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_track.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+
+#include "BKE_main.h"
+#include "BKE_context.h"
+#include "BKE_movieclip.h"
+#include "BKE_tracking.h"
+#include "BKE_global.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_clip.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "PIL_time.h"
+
+#include "clip_intern.h" // own include
+#include "tracking_ops_intern.h"
+
+/********************** Track operator *********************/
+
+typedef struct TrackMarkersJob {
+ struct AutoTrackContext *context; /* Tracking context */
+ int sfra, efra, lastfra; /* Start, end and recently tracked frames */
+ int backwards; /* Backwards tracking flag */
+ MovieClip *clip; /* Clip which is tracking */
+ float delay; /* Delay in milliseconds to allow
+ * tracking at fixed FPS */
+
+ struct Main *main;
+ struct Scene *scene;
+ struct bScreen *screen;
+} TrackMarkersJob;
+
+static bool track_markers_testbreak(void)
+{
+ return G.is_break;
+}
+
+static int track_count_markers(SpaceClip *sc,
+ MovieClip *clip,
+ int framenr)
+{
+ int tot = 0;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ bool selected = (sc != NULL) ? TRACK_VIEW_SELECTED(sc, track)
+ : TRACK_SELECTED(track);
+ if (selected && (track->flag & TRACK_LOCKED) == 0) {
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track,
+ framenr);
+ if (!marker || (marker->flag & MARKER_DISABLED) == 0) {
+ tot++;
+ }
+ }
+ }
+ return tot;
+}
+
+static void track_init_markers(SpaceClip *sc,
+ MovieClip *clip,
+ int framenr,
+ int *frames_limit_r)
+{
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ int frames_limit = 0;
+ if (sc != NULL) {
+ clip_tracking_clear_invisible_track_selection(sc, clip);
+ }
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ bool selected = (sc != NULL) ? TRACK_VIEW_SELECTED(sc, track)
+ : TRACK_SELECTED(track);
+ if (selected) {
+ if ((track->flag & TRACK_HIDDEN) == 0 &&
+ (track->flag & TRACK_LOCKED) == 0)
+ {
+ BKE_tracking_marker_ensure(track, framenr);
+ if (track->frames_limit) {
+ if (frames_limit == 0) {
+ frames_limit = track->frames_limit;
+ }
+ else {
+ frames_limit = min_ii(frames_limit,
+ (int)track->frames_limit);
+ }
+ }
+ }
+ }
+ }
+ *frames_limit_r = frames_limit;
+}
+
+static bool track_markers_check_direction(int backwards, int curfra, int efra)
+{
+ if (backwards) {
+ if (curfra < efra) {
+ return false;
+ }
+ }
+ else {
+ if (curfra > efra) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int track_markers_initjob(bContext *C,
+ TrackMarkersJob *tmj,
+ int backwards)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ Scene *scene = CTX_data_scene(C);
+ MovieTrackingSettings *settings = &clip->tracking.settings;
+ int frames_limit;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ track_init_markers(sc, clip, framenr, &frames_limit);
+
+ tmj->sfra = ED_space_clip_get_clip_frame_number(sc);
+ tmj->clip = clip;
+ tmj->backwards = backwards;
+
+ if (backwards) {
+ tmj->efra = SFRA;
+ }
+ else {
+ tmj->efra = EFRA;
+ }
+
+ /* Limit frames to be tracked by user setting. */
+ if (frames_limit) {
+ if (backwards) {
+ tmj->efra = MAX2(tmj->efra, tmj->sfra - frames_limit);
+ }
+ else {
+ tmj->efra = MIN2(tmj->efra, tmj->sfra + frames_limit);
+ }
+ }
+
+ tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra);
+
+ if (settings->speed != TRACKING_SPEED_FASTEST) {
+ tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f;
+
+ if (settings->speed == TRACKING_SPEED_HALF) {
+ tmj->delay *= 2;
+ }
+ else if (settings->speed == TRACKING_SPEED_QUARTER) {
+ tmj->delay *= 4;
+ }
+ else if (settings->speed == TRACKING_SPEED_DOUBLE) {
+ tmj->delay /= 2;
+ }
+ }
+
+ tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, 1);
+
+ clip->tracking_context = tmj->context;
+
+ tmj->lastfra = tmj->sfra;
+
+ /* XXX: silly to store this, but this data is needed to update scene and
+ * movie-clip numbers when tracking is finished. This introduces
+ * better feedback for artists.
+ * Maybe there's another way to solve this problem, but can't think
+ * better way atm.
+ * Anyway, this way isn't more unstable as animation rendering
+ * animation which uses the same approach (except storing screen).
+ */
+ tmj->scene = scene;
+ tmj->main = CTX_data_main(C);
+ tmj->screen = CTX_wm_screen(C);
+
+ return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
+}
+
+static void track_markers_startjob(void *tmv,
+ short *stop,
+ short *do_update,
+ float *progress)
+{
+ TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
+ int framenr = tmj->sfra;
+
+ while (framenr != tmj->efra) {
+ if (tmj->delay > 0) {
+ /* Tracking should happen with fixed fps. Calculate time
+ * using current timer value before tracking frame and after.
+ *
+ * Small (and maybe unneeded optimization): do not calculate
+ * exec_time for "Fastest" tracking
+ */
+
+ double start_time = PIL_check_seconds_timer(), exec_time;
+
+ if (!BKE_autotrack_context_step(tmj->context)) {
+ break;
+ }
+
+ exec_time = PIL_check_seconds_timer() - start_time;
+ if (tmj->delay > (float)exec_time) {
+ PIL_sleep_ms(tmj->delay - (float)exec_time);
+ }
+ }
+ else if (!BKE_autotrack_context_step(tmj->context)) {
+ break;
+ }
+
+ *do_update = true;
+ *progress = (float)(framenr - tmj->sfra) / (tmj->efra - tmj->sfra);
+
+ if (tmj->backwards) {
+ framenr--;
+ }
+ else {
+ framenr++;
+ }
+
+ tmj->lastfra = framenr;
+
+ if (*stop || track_markers_testbreak()) {
+ break;
+ }
+ }
+}
+
+static void track_markers_updatejob(void *tmv)
+{
+ TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
+ BKE_autotrack_context_sync(tmj->context);
+}
+
+static void track_markers_endjob(void *tmv)
+{
+ TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
+ wmWindowManager *wm = tmj->main->wm.first;
+
+ tmj->clip->tracking_context = NULL;
+ tmj->scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(tmj->clip,
+ tmj->lastfra);
+ if (wm != NULL) {
+ ED_update_for_newframe(tmj->main, tmj->scene, 0);
+ }
+
+ BKE_autotrack_context_sync(tmj->context);
+ BKE_autotrack_context_finish(tmj->context);
+
+ WM_main_add_notifier(NC_SCENE | ND_FRAME, tmj->scene);
+}
+
+static void track_markers_freejob(void *tmv)
+{
+ TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
+ BKE_autotrack_context_free(tmj->context);
+ MEM_freeN(tmj);
+}
+
+/* TODO(sergey): Majority of the code here can be de-duplicated with the job. */
+static int track_markers_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc;
+ MovieClip *clip;
+ Scene *scene = CTX_data_scene(C);
+ struct AutoTrackContext *context;
+ MovieClipUser *user, fake_user = {0};
+ int framenr, sfra, efra;
+ const bool backwards = RNA_boolean_get(op->ptr, "backwards");
+ const bool sequence = RNA_boolean_get(op->ptr, "sequence");
+ int frames_limit;
+
+ if (RNA_struct_property_is_set(op->ptr, "clip")) {
+ Main *bmain = CTX_data_main(C);
+ char clip_name[MAX_ID_NAME - 2];
+
+ RNA_string_get(op->ptr, "clip", clip_name);
+ clip = (MovieClip *)BLI_findstring(&bmain->movieclip,
+ clip_name,
+ offsetof(ID, name) + 2);
+ sc = NULL;
+
+ if (clip == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, CFRA);
+ fake_user.framenr = framenr;
+ user = &fake_user;
+ }
+ else {
+ sc = CTX_wm_space_clip(C);
+
+ if (sc == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ clip = ED_space_clip_get_clip(sc);
+ framenr = ED_space_clip_get_clip_frame_number(sc);
+ user = &sc->user;
+ }
+
+ sfra = framenr;
+
+ if (track_count_markers(sc, clip, framenr) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ track_init_markers(sc, clip, framenr, &frames_limit);
+
+ if (backwards) {
+ efra = SFRA;
+ }
+ else {
+ efra = EFRA;
+ }
+
+ /* Limit frames to be tracked by user setting. */
+ if (frames_limit) {
+ if (backwards)
+ efra = MAX2(efra, sfra - frames_limit);
+ else
+ efra = MIN2(efra, sfra + frames_limit);
+ }
+
+ efra = BKE_movieclip_remap_scene_to_clip_frame(clip, efra);
+
+ if (!track_markers_check_direction(backwards, framenr, efra)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Do not disable tracks due to threshold when tracking frame-by-frame. */
+ context = BKE_autotrack_context_new(clip, user, backwards, sequence);
+ while (framenr != efra) {
+ if (!BKE_autotrack_context_step(context))
+ break;
+
+ if (backwards) framenr--;
+ else framenr++;
+
+ if (!sequence)
+ break;
+ }
+
+ BKE_autotrack_context_sync(context);
+ BKE_autotrack_context_finish(context);
+ BKE_autotrack_context_free(context);
+
+ /* Update scene current frame to the lastes tracked frame. */
+ scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+static int track_markers_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ TrackMarkersJob *tmj;
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip;
+ wmJob *wm_job;
+ bool backwards = RNA_boolean_get(op->ptr, "backwards");
+ bool sequence = RNA_boolean_get(op->ptr, "sequence");
+ int framenr;
+
+ if (sc == NULL) {
+ /* TODO(sergey): Support clip for invoke as well. */
+ BKE_report(op->reports, RPT_ERROR,
+ "Invoking this operator only supported from "
+ "Clip Editor space");
+ return OPERATOR_CANCELLED;
+ }
+
+ clip = ED_space_clip_get_clip(sc);
+ BLI_assert(clip != NULL);
+ framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ if (WM_jobs_test(CTX_wm_manager(C), sa, WM_JOB_TYPE_ANY)) {
+ /* Only one tracking is allowed at a time. */
+ return OPERATOR_CANCELLED;
+ }
+
+ if (clip->tracking_context) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (track_count_markers(sc, clip, framenr) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!sequence) {
+ return track_markers_exec(C, op);
+ }
+
+ tmj = MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
+ if (!track_markers_initjob(C, tmj, backwards)) {
+ track_markers_freejob(tmj);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Setup job. */
+ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa,
+ "Track Markers",
+ WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_TRACK_MARKERS);
+ WM_jobs_customdata_set(wm_job, tmj, track_markers_freejob);
+
+ /* If there's delay set in tracking job, tracking should happen
+ * with fixed FPS. To deal with editor refresh we have to synchronize
+ * tracks from job and tracks in clip. Do this in timer callback
+ * to prevent threading conflicts. */
+ if (tmj->delay > 0) {
+ WM_jobs_timer(wm_job,
+ tmj->delay / 1000.0f, NC_MOVIECLIP | NA_EVALUATED, 0);
+ }
+ else {
+ WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | NA_EVALUATED, 0);
+ }
+
+ WM_jobs_callbacks(wm_job,
+ track_markers_startjob,
+ NULL,
+ track_markers_updatejob,
+ track_markers_endjob);
+
+ G.is_break = false;
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ WM_cursor_wait(0);
+
+ /* Add modal handler for ESC. */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int track_markers_modal(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *event)
+{
+ /* No running tracking, remove handler and pass through. */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY)) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ }
+
+ /* Running tracking. */
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void CLIP_OT_track_markers(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Track Markers";
+ ot->description = "Track selected markers";
+ ot->idname = "CLIP_OT_track_markers";
+
+ /* api callbacks */
+ ot->exec = track_markers_exec;
+ ot->invoke = track_markers_invoke;
+ ot->modal = track_markers_modal;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "backwards", 0, "Backwards",
+ "Do backwards tracking");
+ RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence",
+ "Track marker during image sequence rather than "
+ "single image");
+ prop = RNA_def_string(ot->srna, "clip", NULL, MAX_NAME, "Movie Clip",
+ "Movie Clip to be tracked");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/********************** Refine track position operator *********************/
+
+static int refine_marker_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ bool backwards = RNA_boolean_get(op->ptr, "backwards");
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track)) {
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track,
+ framenr);
+ BKE_tracking_refine_marker(clip, track, marker, backwards);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_refine_markers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Refine Markers";
+ ot->description = "Refine selected markers positions "
+ "by running the tracker from track's reference "
+ "to current frame";
+ ot->idname = "CLIP_OT_refine_markers";
+
+ /* api callbacks */
+ ot->exec = refine_marker_exec;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "backwards", 0, "Backwards",
+ "Do backwards tracking");
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_utils.c b/source/blender/editors/space_clip/tracking_ops_utils.c
new file mode 100644
index 00000000000..4fbee51407d
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_utils.c
@@ -0,0 +1,79 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_utils.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_tracking.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "tracking_ops_intern.h" // own include
+
+void clip_tracking_clear_invisible_track_selection(SpaceClip *sc,
+ MovieClip *clip)
+{
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ int hidden = 0;
+ if ((sc->flag & SC_SHOW_MARKER_PATTERN) == 0) {
+ hidden |= TRACK_AREA_PAT;
+ }
+ if ((sc->flag & SC_SHOW_MARKER_SEARCH) == 0) {
+ hidden |= TRACK_AREA_SEARCH;
+ }
+ if (hidden) {
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if ((track->flag & TRACK_HIDDEN) == 0) {
+ BKE_tracking_track_flag_clear(track, hidden, SELECT);
+ }
+ }
+ }
+}
+
+void clip_tracking_hide_cursor(bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, CURSOR_NONE);
+}
+
+void clip_tracking_show_cursor(bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, CURSOR_STD);
+}