Blender V2.61 - r43446

tracking_ops.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2011 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  *
00022  * Contributor(s): Blender Foundation,
00023  *                 Sergey Sharybin
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00032 #include "MEM_guardedalloc.h"
00033 
00034 #include "DNA_camera_types.h"
00035 #include "DNA_constraint_types.h"
00036 #include "DNA_gpencil_types.h"
00037 #include "DNA_movieclip_types.h"
00038 #include "DNA_object_types.h"   /* SELECT */
00039 #include "DNA_scene_types.h"
00040 
00041 #include "BLI_utildefines.h"
00042 #include "BLI_math.h"
00043 #include "BLI_listbase.h"
00044 #include "BLI_rect.h"
00045 #include "BLI_blenlib.h"
00046 
00047 #include "BKE_main.h"
00048 #include "BKE_context.h"
00049 #include "BKE_constraint.h"
00050 #include "BKE_movieclip.h"
00051 #include "BKE_tracking.h"
00052 #include "BKE_global.h"
00053 #include "BKE_depsgraph.h"
00054 #include "BKE_object.h"
00055 #include "BKE_report.h"
00056 #include "BKE_scene.h"
00057 #include "BKE_library.h"
00058 #include "BKE_sound.h"
00059 
00060 #include "WM_api.h"
00061 #include "WM_types.h"
00062 
00063 #include "ED_screen.h"
00064 #include "ED_clip.h"
00065 #include "ED_keyframing.h"
00066 
00067 #include "IMB_imbuf_types.h"
00068 #include "IMB_imbuf.h"
00069 
00070 #include "UI_interface.h"
00071 
00072 #include "RNA_access.h"
00073 #include "RNA_define.h"
00074 
00075 #include "PIL_time.h"
00076 
00077 #include "UI_view2d.h"
00078 
00079 #include "clip_intern.h"    // own include
00080 
00081 static int space_clip_frame_poll(bContext *C)
00082 {
00083     SpaceClip *sc= CTX_wm_space_clip(C);
00084 
00085     if(sc) {
00086         MovieClip *clip= ED_space_clip(sc);
00087 
00088         if(clip)
00089             return BKE_movieclip_has_frame(clip, &sc->user);
00090     }
00091 
00092     return 0;
00093 }
00094 
00095 /********************** add marker operator *********************/
00096 
00097 static void add_marker(SpaceClip *sc, float x, float y)
00098 {
00099     MovieClip *clip= ED_space_clip(sc);
00100     MovieTracking *tracking= &clip->tracking;
00101     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
00102     MovieTrackingTrack *track;
00103     int width, height;
00104     
00105     ED_space_clip_size(sc, &width, &height);
00106 
00107     track= BKE_tracking_add_track(tracking, tracksbase, x, y, sc->user.framenr, width, height);
00108 
00109     BKE_tracking_select_track(tracksbase, track, TRACK_AREA_ALL, 0);
00110 
00111     clip->tracking.act_track= track;
00112 }
00113 
00114 static int add_marker_exec(bContext *C, wmOperator *op)
00115 {
00116     SpaceClip *sc= CTX_wm_space_clip(C);
00117     MovieClip *clip= ED_space_clip(sc);
00118     float pos[2];
00119     int width, height;
00120 
00121     ED_space_clip_size(sc, &width, &height);
00122     if(!width || !height)
00123         return OPERATOR_CANCELLED;
00124 
00125     RNA_float_get_array(op->ptr, "location", pos);
00126 
00127     add_marker(sc, pos[0], pos[1]);
00128 
00129     /* reset offset from locked position, so frame jumping wouldn't be so confusing */
00130     sc->xlockof= 0;
00131     sc->ylockof= 0;
00132 
00133     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
00134 
00135     return OPERATOR_FINISHED;
00136 }
00137 
00138 static int add_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
00139 {
00140     float co[2];
00141 
00142     ED_clip_mouse_pos(C, event, co);
00143 
00144     RNA_float_set_array(op->ptr, "location", co);
00145 
00146     return add_marker_exec(C, op);
00147 }
00148 
00149 void CLIP_OT_add_marker(wmOperatorType *ot)
00150 {
00151     /* identifiers */
00152     ot->name= "Add Marker";
00153     ot->idname= "CLIP_OT_add_marker";
00154     ot->description= "Place new marker at specified location";
00155 
00156     /* api callbacks */
00157     ot->invoke= add_marker_invoke;
00158     ot->exec= add_marker_exec;
00159     ot->poll= space_clip_frame_poll;
00160 
00161     /* flags */
00162     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00163 
00164     /* properties */
00165     RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
00166         "Location", "Location of marker on frame", -1.0f, 1.0f);
00167 }
00168 
00169 /********************** delete track operator *********************/
00170 
00171 static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
00172 {
00173     SpaceClip *sc= CTX_wm_space_clip(C);
00174     MovieClip *clip= ED_space_clip(sc);
00175     MovieTracking *tracking= &clip->tracking;
00176     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
00177     MovieTrackingTrack *track= tracksbase->first, *next;
00178 
00179     while(track) {
00180         next= track->next;
00181 
00182         if(TRACK_VIEW_SELECTED(sc, track))
00183             clip_delete_track(C, clip, tracksbase, track);
00184 
00185         track= next;
00186     }
00187 
00188     /* nothing selected now, unlock view so it can be scrolled nice again */
00189     sc->flag&= ~SC_LOCK_SELECTION;
00190 
00191     return OPERATOR_FINISHED;
00192 }
00193 
00194 void CLIP_OT_delete_track(wmOperatorType *ot)
00195 {
00196     /* identifiers */
00197     ot->name= "Delete Track";
00198     ot->idname= "CLIP_OT_delete_track";
00199     ot->description= "Delete selected tracks";
00200 
00201     /* api callbacks */
00202     ot->invoke= WM_operator_confirm;
00203     ot->exec= delete_track_exec;
00204     ot->poll= ED_space_clip_poll;
00205 
00206     /* flags */
00207     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00208 }
00209 
00210 /********************** delete marker operator *********************/
00211 
00212 static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
00213 {
00214     SpaceClip *sc= CTX_wm_space_clip(C);
00215     MovieClip *clip= ED_space_clip(sc);
00216     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
00217     MovieTrackingTrack *track= tracksbase->first, *next;
00218     int framenr= sc->user.framenr;
00219     int has_selection= 0;
00220 
00221     while(track) {
00222         next= track->next;
00223 
00224         if(TRACK_VIEW_SELECTED(sc, track)) {
00225             MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, framenr);
00226 
00227             if(marker) {
00228                 has_selection|= track->markersnr>1;
00229 
00230                 clip_delete_marker(C, clip, tracksbase, track, marker);
00231             }
00232         }
00233 
00234         track= next;
00235     }
00236 
00237     if(!has_selection) {
00238         /* nothing selected now, unlock view so it can be scrolled nice again */
00239         sc->flag&= ~SC_LOCK_SELECTION;
00240     }
00241 
00242     return OPERATOR_FINISHED;
00243 }
00244 
00245 void CLIP_OT_delete_marker(wmOperatorType *ot)
00246 {
00247     /* identifiers */
00248     ot->name= "Delete Marker";
00249     ot->idname= "CLIP_OT_delete_marker";
00250     ot->description= "Delete marker for current frame from selected tracks";
00251 
00252     /* api callbacks */
00253     ot->invoke= WM_operator_confirm;
00254     ot->exec= delete_marker_exec;
00255     ot->poll= ED_space_clip_poll;
00256 
00257     /* flags */
00258     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00259 }
00260 
00261 /********************** slide marker operator *********************/
00262 
00263 #define SLIDE_ACTION_POS    0
00264 #define SLIDE_ACTION_SIZE   1
00265 #define SLIDE_ACTION_OFFSET 2
00266 
00267 typedef struct {
00268     int area, action;
00269     MovieTrackingTrack *track;
00270     MovieTrackingMarker *marker;
00271 
00272     int mval[2];
00273     int width, height;
00274     float *min, *max, *pos, *offset;
00275     float smin[2], smax[2], spos[2], soff[2];
00276     float (*smarkers)[2];
00277 
00278     int lock, accurate;
00279 } SlideMarkerData;
00280 
00281 static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTrack *track,
00282             MovieTrackingMarker *marker, wmEvent *event, int area, int action, int width, int height)
00283 {
00284     SlideMarkerData *data= MEM_callocN(sizeof(SlideMarkerData), "slide marker data");
00285 
00286     marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
00287 
00288     data->area= area;
00289     data->action= action;
00290     data->track= track;
00291     data->marker= marker;
00292 
00293     if(area==TRACK_AREA_POINT) {
00294         data->pos= marker->pos;
00295         data->offset= track->offset;
00296         copy_v2_v2(data->spos, marker->pos);
00297         copy_v2_v2(data->soff, track->offset);
00298     } else if(area==TRACK_AREA_PAT) {
00299         if(action==SLIDE_ACTION_SIZE) {
00300             data->min= track->pat_min;
00301             data->max= track->pat_max;
00302         } else {
00303             int a;
00304 
00305             data->pos= marker->pos;
00306             data->offset= track->offset;
00307 
00308             copy_v2_v2(data->soff, track->offset);
00309 
00310             data->smarkers= MEM_callocN(sizeof(*data->smarkers)*track->markersnr, "slide marekrs");
00311             for(a= 0; a<track->markersnr; a++)
00312                 copy_v2_v2(data->smarkers[a], track->markers[a].pos);
00313         }
00314     } else if(area==TRACK_AREA_SEARCH) {
00315         data->min= track->search_min;
00316         data->max= track->search_max;
00317     }
00318 
00319     if(area==TRACK_AREA_SEARCH || (area==TRACK_AREA_PAT && action!=SLIDE_ACTION_OFFSET)) {
00320         copy_v2_v2(data->smin, data->min);
00321         copy_v2_v2(data->smax, data->max);
00322     }
00323 
00324     data->mval[0]= event->mval[0];
00325     data->mval[1]= event->mval[1];
00326 
00327     data->width= width;
00328     data->height= height;
00329 
00330     if(action==SLIDE_ACTION_SIZE)
00331         data->lock= 1;
00332 
00333     return data;
00334 }
00335 
00336 /* corner = 0: right-bottom corner,
00337    corner = 1: left-top corner */
00338 static int mouse_on_corner(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
00339             int area, float co[2], int corner, int width, int height)
00340 {
00341     int inside= 0;
00342     float size= 12.0f;
00343     float min[2], max[2];
00344     float crn[2], dx, dy, tdx, tdy;
00345 
00346     if(area==TRACK_AREA_SEARCH) {
00347         copy_v2_v2(min, track->search_min);
00348         copy_v2_v2(max, track->search_max);
00349     } else {
00350         copy_v2_v2(min, track->pat_min);
00351         copy_v2_v2(max, track->pat_max);
00352     }
00353 
00354     dx= size/width/sc->zoom;
00355     dy= size/height/sc->zoom;
00356 
00357     tdx= 5.0f/width/sc->zoom;
00358     tdy= 5.0f/height/sc->zoom;
00359 
00360     dx= MIN2(dx, (max[0]-min[0])/6.0f) + tdx;
00361     dy= MIN2(dy, (max[1]-min[1])/6.0f) + tdy;
00362 
00363     if(corner==0) {
00364         crn[0]= marker->pos[0]+max[0];
00365         crn[1]= marker->pos[1]+min[1];
00366 
00367         inside= co[0]>=crn[0]-dx && co[0]<=crn[0]+tdx && co[1]>=crn[1]-tdy && co[1]<=crn[1]+dy;
00368     } else {
00369         crn[0]= marker->pos[0]+min[0];
00370         crn[1]= marker->pos[1]+max[1];
00371 
00372         inside= co[0]>=crn[0]-dx && co[0]<=crn[0]+dx && co[1]>=crn[1]-dy && co[1]<=crn[1]+dy;
00373     }
00374 
00375     return inside;
00376 }
00377 
00378 static int mouse_on_offset(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
00379             float co[2], int width, int height)
00380 {
00381     float pos[2], dx, dy;
00382 
00383     add_v2_v2v2(pos, marker->pos, track->offset);
00384 
00385     dx= 12.0f/width/sc->zoom;
00386     dy= 12.0f/height/sc->zoom;
00387 
00388     dx=MIN2(dx, (track->pat_max[0]-track->pat_min[0])/2.0f);
00389     dy=MIN2(dy, (track->pat_max[1]-track->pat_min[1])/2.0f);
00390 
00391     return co[0]>=pos[0]-dx && co[0]<=pos[0]+dx && co[1]>=pos[1]-dy && co[1]<=pos[1]+dy;
00392 }
00393 
00394 static void hide_cursor(bContext *C)
00395 {
00396     wmWindow *win= CTX_wm_window(C);
00397 
00398     WM_cursor_set(win, CURSOR_NONE);
00399 }
00400 
00401 static void show_cursor(bContext *C)
00402 {
00403     wmWindow *win= CTX_wm_window(C);
00404 
00405     WM_cursor_set(win, CURSOR_STD);
00406 }
00407 
00408 static void *slide_marker_customdata(bContext *C, wmEvent *event)
00409 {
00410     SpaceClip *sc= CTX_wm_space_clip(C);
00411     MovieClip *clip= ED_space_clip(sc);
00412     MovieTrackingTrack *track;
00413     int width, height;
00414     float co[2];
00415     void *customdata= NULL;
00416     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
00417 
00418     ED_space_clip_size(sc, &width, &height);
00419 
00420     if(width==0 || height==0)
00421         return NULL;
00422 
00423     ED_clip_mouse_pos(C, event, co);
00424 
00425     track= tracksbase->first;
00426     while(track) {
00427         if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
00428             MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
00429 
00430             if((marker->flag&MARKER_DISABLED)==0) {
00431                 if(!customdata)
00432                     if(mouse_on_offset(sc, track, marker, co, width, height))
00433                         customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_POINT, SLIDE_ACTION_POS, width, height);
00434 
00435                 if(sc->flag&SC_SHOW_MARKER_SEARCH) {
00436                     if(mouse_on_corner(sc, track, marker, TRACK_AREA_SEARCH, co, 1, width, height))
00437                         customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, SLIDE_ACTION_OFFSET, width, height);
00438                     else if(mouse_on_corner(sc, track, marker, TRACK_AREA_SEARCH, co, 0, width, height))
00439                         customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, SLIDE_ACTION_SIZE, width, height);
00440                 }
00441 
00442                 if(!customdata && sc->flag&SC_SHOW_MARKER_PATTERN) {
00443                     if(mouse_on_corner(sc, track, marker, TRACK_AREA_PAT, co, 1,  width, height))
00444                         customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, SLIDE_ACTION_OFFSET, width, height);
00445 
00446                     if(!customdata && mouse_on_corner(sc, track, marker, TRACK_AREA_PAT, co, 0, width, height))
00447                         customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, SLIDE_ACTION_SIZE, width, height);
00448                 }
00449 
00450                 if(customdata)
00451                     break;
00452             }
00453         }
00454 
00455         track= track->next;
00456     }
00457 
00458     return customdata;
00459 }
00460 
00461 static int slide_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
00462 {
00463     SlideMarkerData *slidedata= slide_marker_customdata(C, event);
00464 
00465     if(slidedata) {
00466         SpaceClip *sc= CTX_wm_space_clip(C);
00467         MovieClip *clip= ED_space_clip(sc);
00468         MovieTracking *tracking= &clip->tracking;
00469 
00470         tracking->act_track= slidedata->track;
00471 
00472         op->customdata= slidedata;
00473 
00474         hide_cursor(C);
00475         WM_event_add_modal_handler(C, op);
00476 
00477         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
00478 
00479         return OPERATOR_RUNNING_MODAL;
00480     }
00481 
00482     return OPERATOR_PASS_THROUGH;
00483 }
00484 
00485 static void cancel_mouse_slide(SlideMarkerData *data)
00486 {
00487     /* cancel sliding */
00488     if(data->area == TRACK_AREA_POINT) {
00489         if(data->action==SLIDE_ACTION_OFFSET)
00490             copy_v2_v2(data->offset, data->soff);
00491         else
00492             copy_v2_v2(data->pos, data->spos);
00493     } else {
00494         if(data->action==SLIDE_ACTION_SIZE) {
00495             copy_v2_v2(data->min, data->smin);
00496             copy_v2_v2(data->max, data->smax);
00497         } else {
00498             int a;
00499 
00500             for(a= 0; a<data->track->markersnr; a++)
00501                 copy_v2_v2(data->track->markers[a].pos, data->smarkers[a]);
00502 
00503             copy_v2_v2(data->offset, data->soff);
00504         }
00505     }
00506 }
00507 
00508 static void free_slide_data(SlideMarkerData *data)
00509 {
00510     if(data->smarkers) MEM_freeN(data->smarkers);
00511     MEM_freeN(data);
00512 }
00513 
00514 static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
00515 {
00516     SpaceClip *sc= CTX_wm_space_clip(C);
00517     SlideMarkerData *data= (SlideMarkerData *)op->customdata;
00518     float dx, dy, mdelta[2];
00519 
00520     switch(event->type) {
00521         case LEFTCTRLKEY:
00522         case RIGHTCTRLKEY:
00523         case LEFTSHIFTKEY:
00524         case RIGHTSHIFTKEY:
00525             if(data->action==SLIDE_ACTION_SIZE)
00526                 if(ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY))
00527                     data->lock= event->val==KM_RELEASE;
00528 
00529             if(ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
00530                 data->accurate= event->val==KM_PRESS;
00531 
00532             /* no break! update area size */
00533 
00534         case MOUSEMOVE:
00535             mdelta[0]= event->mval[0]-data->mval[0];
00536             mdelta[1]= event->mval[1]-data->mval[1];
00537 
00538             dx= mdelta[0]/data->width/sc->zoom;
00539 
00540             if(data->lock) dy= -dx/data->height*data->width;
00541             else dy= mdelta[1]/data->height/sc->zoom;
00542 
00543             if(data->accurate) {
00544                 dx/= 5;
00545                 dy/= 5;
00546             }
00547 
00548             if(data->area==TRACK_AREA_POINT) {
00549                 if(data->action==SLIDE_ACTION_OFFSET) {
00550                     data->offset[0]= data->soff[0]+dx;
00551                     data->offset[1]= data->soff[1]+dy;
00552                 } else {
00553                     data->pos[0]= data->spos[0]+dx;
00554                     data->pos[1]= data->spos[1]+dy;
00555 
00556                     data->marker->flag&= ~MARKER_TRACKED;
00557                 }
00558 
00559                 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00560                 DAG_id_tag_update(&sc->clip->id, 0);
00561             } else {
00562                 if(data->action==SLIDE_ACTION_SIZE) {
00563                     data->min[0]= data->smin[0]-dx;
00564                     data->max[0]= data->smax[0]+dx;
00565 
00566                     data->min[1]= data->smin[1]+dy;
00567                     data->max[1]= data->smax[1]-dy;
00568 
00569                     if(data->area==TRACK_AREA_SEARCH) BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_DIM);
00570                     else BKE_tracking_clamp_track(data->track, CLAMP_PAT_DIM);
00571                 } else {
00572                     float d[2]={dx, dy};
00573 
00574                     if(data->area==TRACK_AREA_SEARCH) {
00575                         add_v2_v2v2(data->min, data->smin, d);
00576                         add_v2_v2v2(data->max, data->smax, d);
00577                     } else {
00578                         int a;
00579 
00580                         for(a= 0; a<data->track->markersnr; a++)
00581                             add_v2_v2v2(data->track->markers[a].pos, data->smarkers[a], d);
00582 
00583                         sub_v2_v2v2(data->offset, data->soff, d);
00584                     }
00585 
00586                     if(data->area==TRACK_AREA_SEARCH)
00587                         BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_POS);
00588                 }
00589             }
00590 
00591             WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
00592 
00593             break;
00594 
00595         case LEFTMOUSE:
00596             if(event->val==KM_RELEASE) {
00597                 free_slide_data(op->customdata);
00598 
00599                 show_cursor(C);
00600 
00601                 return OPERATOR_FINISHED;
00602             }
00603 
00604             break;
00605 
00606         case ESCKEY:
00607             cancel_mouse_slide(op->customdata);
00608 
00609             free_slide_data(op->customdata);
00610 
00611             show_cursor(C);
00612 
00613             WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
00614 
00615             return OPERATOR_CANCELLED;
00616     }
00617 
00618     return OPERATOR_RUNNING_MODAL;
00619 }
00620 
00621 void CLIP_OT_slide_marker(wmOperatorType *ot)
00622 {
00623     /* identifiers */
00624     ot->name= "Slide Marker";
00625     ot->description= "Slide marker areas";
00626     ot->idname= "CLIP_OT_slide_marker";
00627 
00628     /* api callbacks */
00629     ot->poll= space_clip_frame_poll;
00630     ot->invoke= slide_marker_invoke;
00631     ot->modal= slide_marker_modal;
00632 
00633     /* flags */
00634     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_GRAB_POINTER|OPTYPE_BLOCKING;
00635 
00636     /* properties */
00637     RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
00638         "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX);
00639 }
00640 
00641 /********************** mouse select operator *********************/
00642 
00643 static int mouse_on_side(float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
00644 {
00645     if(x1>x2) SWAP(float, x1, x2);
00646     if(y1>y2) SWAP(float, y1, y2);
00647 
00648     return (co[0]>=x1-epsx && co[0]<=x2+epsx) && (co[1]>=y1-epsy && co[1]<=y2+epsy);
00649 }
00650 
00651 static int mouse_on_rect(float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
00652 {
00653     return mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+max[0], pos[1]+min[1], epsx, epsy) ||
00654            mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+min[0], pos[1]+max[1], epsx, epsy) ||
00655            mouse_on_side(co, pos[0]+min[0], pos[1]+max[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy) ||
00656            mouse_on_side(co, pos[0]+max[0], pos[1]+min[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy);
00657 }
00658 
00659 static int track_mouse_area(SpaceClip *sc, float co[2], MovieTrackingTrack *track)
00660 {
00661     MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
00662     float epsx, epsy;
00663     int width, height;
00664 
00665     ED_space_clip_size(sc, &width, &height);
00666 
00667     epsx= MIN4(track->pat_min[0]-track->search_min[0], track->search_max[0]-track->pat_max[0],
00668                fabsf(track->pat_min[0]), fabsf(track->pat_max[0])) / 2;
00669     epsy= MIN4(track->pat_min[1]-track->search_min[1], track->search_max[1]-track->pat_max[1],
00670                fabsf(track->pat_min[1]), fabsf(track->pat_max[1])) / 2;
00671 
00672     epsx= MAX2(epsx, 2.0f / width);
00673     epsy= MAX2(epsy, 2.0f / height);
00674 
00675     if(sc->flag&SC_SHOW_MARKER_SEARCH)
00676         if(mouse_on_rect(co, marker->pos, track->search_min, track->search_max, epsx, epsy))
00677             return TRACK_AREA_SEARCH;
00678 
00679     if((marker->flag&MARKER_DISABLED)==0) {
00680         if(sc->flag&SC_SHOW_MARKER_PATTERN)
00681             if(mouse_on_rect(co, marker->pos, track->pat_min, track->pat_max, epsx, epsy))
00682                 return TRACK_AREA_PAT;
00683 
00684         epsx= 12.0f/width;
00685         epsy= 12.0f/height;
00686 
00687         if(fabsf(co[0]-marker->pos[0]-track->offset[0])< epsx && fabsf(co[1]-marker->pos[1]-track->offset[1])<=epsy)
00688             return TRACK_AREA_POINT;
00689     }
00690 
00691     return TRACK_AREA_NONE;
00692 }
00693 
00694 static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
00695 {
00696     float d1, d2, d3, d4;
00697     float p[2]= {co[0]-pos[0], co[1]-pos[1]};
00698     float v1[2]= {min[0], min[1]}, v2[2]= {max[0], min[1]},
00699           v3[2]= {max[0], max[1]}, v4[2]= {min[0], max[1]};
00700 
00701     d1= dist_to_line_segment_v2(p, v1, v2);
00702     d2= dist_to_line_segment_v2(p, v2, v3);
00703     d3= dist_to_line_segment_v2(p, v3, v4);
00704     d4= dist_to_line_segment_v2(p, v4, v1);
00705 
00706     return MIN4(d1, d2, d3, d4);
00707 }
00708 
00709 static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2])
00710 {
00711     MovieTrackingTrack *track= NULL, *cur;
00712     float mindist= 0.0f;
00713 
00714     cur= tracksbase->first;
00715     while(cur) {
00716         MovieTrackingMarker *marker= BKE_tracking_get_marker(cur, sc->user.framenr);
00717 
00718         if(((cur->flag&TRACK_HIDDEN)==0) && MARKER_VISIBLE(sc, marker)) {
00719             float dist, d1, d2=FLT_MAX, d3=FLT_MAX;
00720 
00721             d1= sqrtf((co[0]-marker->pos[0]-cur->offset[0])*(co[0]-marker->pos[0]-cur->offset[0])+
00722                       (co[1]-marker->pos[1]-cur->offset[1])*(co[1]-marker->pos[1]-cur->offset[1])); /* distance to marker point */
00723 
00724             /* distance to pattern boundbox */
00725             if(sc->flag&SC_SHOW_MARKER_PATTERN)
00726                 d2= dist_to_rect(co, marker->pos, cur->pat_min, cur->pat_max);
00727 
00728             /* distance to search boundbox */
00729             if(sc->flag&SC_SHOW_MARKER_SEARCH && TRACK_VIEW_SELECTED(sc, cur))
00730                 d3= dist_to_rect(co, marker->pos, cur->search_min, cur->search_max);
00731 
00732             /* choose minimal distance. useful for cases of overlapped markers. */
00733             dist= MIN3(d1, d2, d3);
00734 
00735             if(track==NULL || dist<mindist) {
00736                 track= cur;
00737                 mindist= dist;
00738             }
00739         }
00740 
00741         cur= cur->next;
00742     }
00743 
00744     return track;
00745 }
00746 
00747 static int mouse_select(bContext *C, float co[2], int extend)
00748 {
00749     SpaceClip *sc= CTX_wm_space_clip(C);
00750     MovieClip *clip= ED_space_clip(sc);
00751     MovieTracking *tracking= &clip->tracking;
00752     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
00753     MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
00754     MovieTrackingTrack *track= NULL;    /* selected marker */
00755 
00756     track= find_nearest_track(sc, tracksbase, co);
00757 
00758     if(track) {
00759         int area= track_mouse_area(sc, co, track);
00760 
00761         if(!extend || !TRACK_VIEW_SELECTED(sc, track))
00762             area= TRACK_AREA_ALL;
00763 
00764         if(extend && TRACK_AREA_SELECTED(track, area)) {
00765             if(track==act_track)
00766                 BKE_tracking_deselect_track(track, area);
00767             else
00768                 clip->tracking.act_track= track;
00769         } else {
00770             if(area==TRACK_AREA_POINT)
00771                 area= TRACK_AREA_ALL;
00772 
00773             BKE_tracking_select_track(tracksbase, track, area, extend);
00774             clip->tracking.act_track= track;
00775         }
00776     }
00777 
00778     if(!extend) {
00779         sc->xlockof= 0.0f;
00780         sc->ylockof= 0.0f;
00781     }
00782 
00783     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
00784 
00785     return OPERATOR_FINISHED;
00786 }
00787 
00788 static int select_exec(bContext *C, wmOperator *op)
00789 {
00790     float co[2];
00791     int extend;
00792 
00793     RNA_float_get_array(op->ptr, "location", co);
00794     extend= RNA_boolean_get(op->ptr, "extend");
00795 
00796     return mouse_select(C, co, extend);
00797 }
00798 
00799 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
00800 {
00801     float co[2];
00802     int extend= RNA_boolean_get(op->ptr, "extend");
00803 
00804     if(!extend) {
00805         SlideMarkerData *slidedata= slide_marker_customdata(C, event);
00806 
00807         if(slidedata) {
00808             SpaceClip *sc= CTX_wm_space_clip(C);
00809             MovieClip *clip= ED_space_clip(sc);
00810 
00811             clip->tracking.act_track= slidedata->track;
00812 
00813             WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
00814 
00815             MEM_freeN(slidedata);
00816 
00817             return OPERATOR_PASS_THROUGH;
00818         }
00819     }
00820 
00821     ED_clip_mouse_pos(C, event, co);
00822     RNA_float_set_array(op->ptr, "location", co);
00823 
00824     return select_exec(C, op);
00825 }
00826 
00827 void CLIP_OT_select(wmOperatorType *ot)
00828 {
00829     /* identifiers */
00830     ot->name= "Select";
00831     ot->description= "Select tracking markers";
00832     ot->idname= "CLIP_OT_select";
00833 
00834     /* api callbacks */
00835     ot->exec= select_exec;
00836     ot->invoke= select_invoke;
00837     ot->poll= ED_space_clip_poll;
00838 
00839     /* flags */
00840     ot->flag= OPTYPE_UNDO;
00841 
00842     /* properties */
00843     RNA_def_boolean(ot->srna, "extend", 0,
00844         "Extend", "Extend selection rather than clearing the existing selection");
00845     RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
00846         "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
00847 }
00848 
00849 /********************** border select operator *********************/
00850 
00851 static int border_select_exec(bContext *C, wmOperator *op)
00852 {
00853     SpaceClip *sc= CTX_wm_space_clip(C);
00854     MovieClip *clip= ED_space_clip(sc);
00855     MovieTrackingTrack *track;
00856     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
00857     rcti rect;
00858     rctf rectf;
00859     int change= 0, mode, extend;
00860 
00861     /* get rectangle from operator */
00862     rect.xmin= RNA_int_get(op->ptr, "xmin");
00863     rect.ymin= RNA_int_get(op->ptr, "ymin");
00864     rect.xmax= RNA_int_get(op->ptr, "xmax");
00865     rect.ymax= RNA_int_get(op->ptr, "ymax");
00866 
00867     ED_clip_point_stable_pos(C, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
00868     ED_clip_point_stable_pos(C, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
00869 
00870     mode= RNA_int_get(op->ptr, "gesture_mode");
00871     extend= RNA_boolean_get(op->ptr, "extend");
00872 
00873     /* do actual selection */
00874     track= tracksbase->first;
00875     while(track) {
00876         if((track->flag&TRACK_HIDDEN)==0) {
00877             MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
00878 
00879             if(MARKER_VISIBLE(sc, marker)) {
00880                 if(BLI_in_rctf(&rectf, marker->pos[0], marker->pos[1])) {
00881                     BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
00882                 }
00883                 else if(!extend) {
00884                     BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 1);
00885                 }
00886 
00887                 change= 1;
00888             }
00889         }
00890 
00891         track= track->next;
00892     }
00893 
00894     if(change) {
00895         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
00896 
00897         return OPERATOR_FINISHED;
00898     }
00899 
00900     return OPERATOR_CANCELLED;
00901 }
00902 
00903 void CLIP_OT_select_border(wmOperatorType *ot)
00904 {
00905     /* identifiers */
00906     ot->name= "Border Select";
00907     ot->description= "Select markers using border selection";
00908     ot->idname= "CLIP_OT_select_border";
00909 
00910     /* api callbacks */
00911     ot->invoke= WM_border_select_invoke;
00912     ot->exec= border_select_exec;
00913     ot->modal= WM_border_select_modal;
00914     ot->poll= ED_space_clip_poll;
00915 
00916     /* flags */
00917     ot->flag= OPTYPE_UNDO;
00918 
00919     /* properties */
00920     WM_operator_properties_gesture_border(ot, TRUE);
00921 }
00922 
00923 /********************** circle select operator *********************/
00924 
00925 static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
00926 {
00927     /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
00928     float x, y;
00929 
00930     x= (marker->pos[0] - offset[0])*ellipse[0];
00931     y= (marker->pos[1] - offset[1])*ellipse[1];
00932 
00933     return x*x + y*y < 1.0f;
00934 }
00935 
00936 static int circle_select_exec(bContext *C, wmOperator *op)
00937 {
00938     SpaceClip *sc= CTX_wm_space_clip(C);
00939     MovieClip *clip= ED_space_clip(sc);
00940     ARegion *ar= CTX_wm_region(C);
00941     MovieTrackingTrack *track;
00942     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
00943     int x, y, radius, width, height, mode, change= 0;
00944     float zoomx, zoomy, offset[2], ellipse[2];
00945 
00946     /* get operator properties */
00947     x= RNA_int_get(op->ptr, "x");
00948     y= RNA_int_get(op->ptr, "y");
00949     radius= RNA_int_get(op->ptr, "radius");
00950 
00951     mode= RNA_int_get(op->ptr, "gesture_mode");
00952 
00953     /* compute ellipse and position in unified coordinates */
00954     ED_space_clip_size(sc, &width, &height);
00955     ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
00956 
00957     ellipse[0]= width*zoomx/radius;
00958     ellipse[1]= height*zoomy/radius;
00959 
00960     ED_clip_point_stable_pos(C, x, y, &offset[0], &offset[1]);
00961 
00962     /* do selection */
00963     track= tracksbase->first;
00964     while(track) {
00965         if((track->flag&TRACK_HIDDEN)==0) {
00966             MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
00967 
00968             if(MARKER_VISIBLE(sc, marker) && marker_inside_ellipse(marker, offset, ellipse)) {
00969                 BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
00970 
00971                 change= 1;
00972             }
00973         }
00974 
00975         track= track->next;
00976     }
00977 
00978     if(change) {
00979         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
00980 
00981         return OPERATOR_FINISHED;
00982     }
00983 
00984     return OPERATOR_CANCELLED;
00985 }
00986 
00987 void CLIP_OT_select_circle(wmOperatorType *ot)
00988 {
00989     /* identifiers */
00990     ot->name= "Circle Select";
00991     ot->description= "Select markers using circle selection";
00992     ot->idname= "CLIP_OT_select_circle";
00993 
00994     /* api callbacks */
00995     ot->invoke= WM_gesture_circle_invoke;
00996     ot->modal= WM_gesture_circle_modal;
00997     ot->exec= circle_select_exec;
00998     ot->poll= ED_space_clip_poll;
00999 
01000     /* flags */
01001     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01002 
01003     /* properties */
01004     RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
01005     RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
01006     RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
01007     RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
01008 }
01009 
01010 /********************** select all operator *********************/
01011 
01012 static int select_all_exec(bContext *C, wmOperator *op)
01013 {
01014     SpaceClip *sc= CTX_wm_space_clip(C);
01015     MovieClip *clip= ED_space_clip(sc);
01016     MovieTrackingTrack *track= NULL;    /* selected track */
01017     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
01018     int action= RNA_enum_get(op->ptr, "action");
01019     int framenr= sc->user.framenr;
01020     int has_selection= 0;
01021 
01022     if(action == SEL_TOGGLE){
01023         action= SEL_SELECT;
01024         track= tracksbase->first;
01025         while(track) {
01026             if(TRACK_VIEW_SELECTED(sc, track)) {
01027                 action= SEL_DESELECT;
01028                 break;
01029             }
01030 
01031             track= track->next;
01032         }
01033     }
01034 
01035     track= tracksbase->first;
01036     while(track) {
01037         if((track->flag&TRACK_HIDDEN)==0) {
01038             MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
01039 
01040             if(marker && MARKER_VISIBLE(sc, marker)) {
01041                 switch (action) {
01042                     case SEL_SELECT:
01043                         track->flag|= SELECT;
01044                         track->pat_flag|= SELECT;
01045                         track->search_flag|= SELECT;
01046                         break;
01047                     case SEL_DESELECT:
01048                         track->flag&= ~SELECT;
01049                         track->pat_flag&= ~SELECT;
01050                         track->search_flag&= ~SELECT;
01051                         break;
01052                     case SEL_INVERT:
01053                         track->flag^= SELECT;
01054                         track->pat_flag^= SELECT;
01055                         track->search_flag^= SELECT;
01056                         break;
01057                 }
01058             }
01059         }
01060 
01061         if(TRACK_VIEW_SELECTED(sc, track))
01062             has_selection= 1;
01063 
01064         track= track->next;
01065     }
01066 
01067     if(!has_selection)
01068         sc->flag&= ~SC_LOCK_SELECTION;
01069 
01070     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
01071 
01072     return OPERATOR_FINISHED;
01073 }
01074 
01075 void CLIP_OT_select_all(wmOperatorType *ot)
01076 {
01077     /* identifiers */
01078     ot->name= "Select or Deselect All";
01079     ot->description= "Change selection of all tracking markers";
01080     ot->idname= "CLIP_OT_select_all";
01081 
01082     /* api callbacks */
01083     ot->exec= select_all_exec;
01084     ot->poll= ED_space_clip_poll;
01085 
01086     /* flags */
01087     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01088 
01089     WM_operator_properties_select_all(ot);
01090 }
01091 
01092 /********************** select grouped operator *********************/
01093 
01094 static int select_groped_exec(bContext *C, wmOperator *op)
01095 {
01096     SpaceClip *sc= CTX_wm_space_clip(C);
01097     MovieClip *clip= ED_space_clip(sc);
01098     MovieTrackingTrack *track;
01099     MovieTrackingMarker *marker;
01100     MovieTracking *tracking= &clip->tracking;
01101     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
01102     int group= RNA_enum_get(op->ptr, "group");
01103 
01104     track= tracksbase->first;
01105     while(track) {
01106         int ok= 0;
01107 
01108         marker= BKE_tracking_get_marker(track, sc->user.framenr);
01109 
01110         if(group==0) { /* Keyframed */
01111             ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED)==0;
01112         }
01113         else if(group==1) { /* Estimated */
01114             ok= marker->framenr!=sc->user.framenr;
01115         }
01116         else if(group==2) { /* tracked */
01117             ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED);
01118         }
01119         else if(group==3) { /* locked */
01120             ok= track->flag&TRACK_LOCKED;
01121         }
01122         else if(group==4) { /* disabled */
01123             ok= marker->flag&MARKER_DISABLED;
01124         }
01125         else if(group==5) { /* color */
01126             MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
01127 
01128             if(act_track) {
01129                 ok= (track->flag&TRACK_CUSTOMCOLOR) == (act_track->flag&TRACK_CUSTOMCOLOR);
01130 
01131                 if(ok && track->flag&TRACK_CUSTOMCOLOR)
01132                     ok= equals_v3v3(track->color, act_track->color);
01133             }
01134         }
01135         else if(group==6) { /* failed */
01136             ok= (track->flag&TRACK_HAS_BUNDLE) == 0;
01137         }
01138 
01139         if(ok) {
01140             track->flag|= SELECT;
01141             if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag|= SELECT;;
01142             if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag|= SELECT;;
01143         }
01144 
01145         track= track->next;
01146     }
01147 
01148     WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
01149 
01150     return OPERATOR_FINISHED;
01151 }
01152 
01153 void CLIP_OT_select_grouped(wmOperatorType *ot)
01154 {
01155     static EnumPropertyItem select_group_items[] = {
01156             {0, "KEYFRAMED", 0, "Keyframed tracks", "Select all keyframed tracks"},
01157             {1, "ESTIMATED", 0, "Estimated tracks", "Select all estimated tracks"},
01158             {2, "TRACKED", 0, "Tracked tracks", "Select all tracked tracks"},
01159             {3, "LOCKED", 0, "Locked tracks", "Select all locked tracks"},
01160             {4, "DISABLED", 0, "Disabled tracks", "Select all disabled tracks"},
01161             {5, "COLOR", 0, "Tracks with same color", "Select all tracks with same color as active track"},
01162             {6, "FAILED", 0, "Failed Tracks", "Select all tracks which failed to be reconstructed"},
01163             {0, NULL, 0, NULL, NULL}
01164     };
01165 
01166     /* identifiers */
01167     ot->name= "Select Grouped";
01168     ot->description= "Joint Selected Tracks";
01169     ot->idname= "CLIP_OT_select_grouped";
01170 
01171     /* api callbacks */
01172     ot->exec= select_groped_exec;
01173     ot->poll= space_clip_frame_poll;
01174 
01175     /* flags */
01176     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01177 
01178     /* proeprties */
01179     RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
01180 }
01181 
01182 /********************** track operator *********************/
01183 
01184 typedef struct TrackMarkersJob {
01185     struct MovieTrackingContext *context;   /* tracking context */
01186     int sfra, efra, lastfra;    /* Start, end and recently tracked frames */
01187     int backwards;              /* Backwards tracking flag */
01188     MovieClip *clip;            /* Clip which is tracking */
01189     float delay;                /* Delay in milliseconds to allow tracking at fixed FPS */
01190 
01191     struct Main *main;
01192     struct Scene *scene;
01193     struct bScreen *screen;
01194 } TrackMarkersJob;
01195 
01196 static int track_markers_testbreak(void)
01197 {
01198     return G.afbreek;
01199 }
01200 
01201 static int track_count_markers(SpaceClip *sc, MovieClip *clip)
01202 {
01203     int tot= 0;
01204     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
01205     MovieTrackingTrack *track;
01206     int framenr= sc->user.framenr;
01207 
01208     track= tracksbase->first;
01209     while(track) {
01210         if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
01211             MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, framenr);
01212 
01213             if (!marker || (marker->flag&MARKER_DISABLED) == 0)
01214                 tot++;
01215         }
01216 
01217         track= track->next;
01218     }
01219 
01220     return tot;
01221 }
01222 
01223 static void clear_invisible_track_selection(SpaceClip *sc, MovieClip *clip)
01224 {
01225     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
01226     int hidden = 0;
01227 
01228     if ((sc->flag&SC_SHOW_MARKER_PATTERN)==0)
01229         hidden |= TRACK_AREA_PAT;
01230 
01231     if ((sc->flag&SC_SHOW_MARKER_SEARCH)==0)
01232         hidden |= TRACK_AREA_SEARCH;
01233 
01234     if (hidden) {
01235         MovieTrackingTrack *track = tracksbase->first;
01236 
01237         while(track) {
01238             BKE_tracking_track_flag(track, hidden, SELECT, 1);
01239 
01240             track = track->next;
01241         }
01242     }
01243 }
01244 
01245 static void track_init_markers(SpaceClip *sc, MovieClip *clip, int *frames_limit_r)
01246 {
01247     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
01248     MovieTrackingTrack *track;
01249     int framenr= sc->user.framenr;
01250     int frames_limit= 0;
01251 
01252     clear_invisible_track_selection(sc, clip);
01253 
01254     track= tracksbase->first;
01255     while(track) {
01256         if(TRACK_SELECTED(track)) {
01257             if((track->flag&TRACK_HIDDEN)==0 && (track->flag&TRACK_LOCKED)==0) {
01258                 BKE_tracking_ensure_marker(track, framenr);
01259 
01260                 if(track->frames_limit) {
01261                     if(frames_limit==0)
01262                         frames_limit= track->frames_limit;
01263                     else
01264                         frames_limit= MIN2(frames_limit, track->frames_limit);
01265                 }
01266             }
01267         }
01268 
01269         track= track->next;
01270     }
01271 
01272     *frames_limit_r= frames_limit;
01273 }
01274 
01275 static int track_markers_check_direction(int backwards, int curfra, int efra)
01276 {
01277     if(backwards) {
01278         if(curfra<efra) return 0;
01279     }
01280     else {
01281         if(curfra>efra) return 0;
01282     }
01283 
01284     return 1;
01285 }
01286 
01287 static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
01288 {
01289     SpaceClip *sc= CTX_wm_space_clip(C);
01290     MovieClip *clip= ED_space_clip(sc);
01291     Scene *scene= CTX_data_scene(C);
01292     MovieTrackingSettings *settings= &clip->tracking.settings;
01293     int frames_limit;
01294 
01295     track_init_markers(sc, clip, &frames_limit);
01296 
01297     tmj->sfra= sc->user.framenr;
01298     tmj->clip= clip;
01299     tmj->backwards= backwards;
01300 
01301     if(backwards) tmj->efra= SFRA;
01302     else tmj->efra= EFRA;
01303 
01304     /* limit frames to be tracked by user setting */
01305     if(frames_limit) {
01306         if(backwards) tmj->efra= MAX2(tmj->efra, tmj->sfra-frames_limit);
01307         else tmj->efra= MIN2(tmj->efra, tmj->sfra+frames_limit);
01308     }
01309 
01310     if(settings->speed!=TRACKING_SPEED_FASTEST) {
01311         tmj->delay= 1.0f/scene->r.frs_sec*1000.0f;
01312 
01313         if(settings->speed==TRACKING_SPEED_HALF) tmj->delay*= 2;
01314         else if(settings->speed==TRACKING_SPEED_QUARTER) tmj->delay*= 4;
01315         else if(settings->speed==TRACKING_SPEED_DOUBLE) tmj->delay/= 2;
01316     }
01317 
01318     tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards, 1);
01319 
01320     clip->tracking_context= tmj->context;
01321 
01322     tmj->lastfra= tmj->sfra;
01323 
01324     /* XXX: silly to store this, but this data is needed to update scene and movieclip
01325             frame numbers when tracking is finished. This introduces better feedback for artists.
01326             Maybe there's another way to solve this problem, but can't think better way atm.
01327             Anyway, this way isn't more unstable as animation rendering animation
01328             which uses the same approach (except storing screen). */
01329     tmj->scene= scene;
01330     tmj->main= CTX_data_main(C);
01331     tmj->screen= CTX_wm_screen(C);
01332 
01333     return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
01334 }
01335 
01336 static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
01337 {
01338     TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
01339     int framenr= tmj->sfra;
01340     //double t= PIL_check_seconds_timer();
01341 
01342     while(framenr != tmj->efra) {
01343         if(tmj->delay>0) {
01344             /* tracking should happen with fixed fps. Calculate time
01345                using current timer value before tracking frame and after.
01346 
01347                Small (and maybe unneeded optimization): do not calculate exec_time
01348                for "Fastest" tracking */
01349 
01350             double start_time= PIL_check_seconds_timer(), exec_time;
01351 
01352             if(!BKE_tracking_next(tmj->context))
01353                 break;
01354 
01355             exec_time= PIL_check_seconds_timer()-start_time;
01356             if(tmj->delay > (float)exec_time)
01357                 PIL_sleep_ms(tmj->delay-(float)exec_time);
01358         } else if(!BKE_tracking_next(tmj->context))
01359                 break;
01360 
01361         *do_update= 1;
01362         *progress=(float)(framenr-tmj->sfra) / (tmj->efra-tmj->sfra);
01363 
01364         if(tmj->backwards) framenr--;
01365         else framenr++;
01366 
01367         tmj->lastfra= framenr;
01368 
01369         if(*stop || track_markers_testbreak())
01370             break;
01371     }
01372 
01373     //printf("Tracking time: %lf\n", PIL_check_seconds_timer()-t);
01374 }
01375 
01376 static void track_markers_updatejob(void *tmv)
01377 {
01378     TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
01379 
01380     BKE_tracking_sync(tmj->context);
01381 }
01382 
01383 static void track_markers_freejob(void *tmv)
01384 {
01385     TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
01386 
01387     tmj->clip->tracking_context= NULL;
01388     tmj->scene->r.cfra= tmj->lastfra;
01389     ED_update_for_newframe(tmj->main, tmj->scene, tmj->screen, 0);
01390 
01391     BKE_tracking_sync(tmj->context);
01392     BKE_tracking_context_free(tmj->context);
01393 
01394     MEM_freeN(tmj);
01395 
01396     WM_main_add_notifier(NC_SCENE|ND_FRAME, tmj->scene);
01397 }
01398 
01399 static int track_markers_exec(bContext *C, wmOperator *op)
01400 {
01401     SpaceClip *sc= CTX_wm_space_clip(C);
01402     MovieClip *clip= ED_space_clip(sc);
01403     Scene *scene= CTX_data_scene(C);
01404     struct MovieTrackingContext *context;
01405     int framenr= sc->user.framenr;
01406     int sfra= framenr, efra;
01407     int backwards= RNA_boolean_get(op->ptr, "backwards");
01408     int sequence= RNA_boolean_get(op->ptr, "sequence");
01409     int frames_limit;
01410 
01411     if(track_count_markers(sc, clip)==0)
01412         return OPERATOR_CANCELLED;
01413 
01414     track_init_markers(sc, clip, &frames_limit);
01415 
01416     if(backwards) efra= SFRA;
01417     else efra= EFRA;
01418 
01419     /* limit frames to be tracked by user setting */
01420     if(frames_limit) {
01421         if(backwards) efra= MAX2(efra, sfra-frames_limit);
01422         else efra= MIN2(efra, sfra+frames_limit);
01423     }
01424 
01425     if(!track_markers_check_direction(backwards, framenr, efra))
01426         return OPERATOR_CANCELLED;
01427 
01428     /* do not disable tracks due to threshold when tracking frame-by-frame */
01429     context= BKE_tracking_context_new(clip, &sc->user, backwards, sequence);
01430 
01431     while(framenr != efra) {
01432         if(!BKE_tracking_next(context))
01433             break;
01434 
01435         if(backwards) framenr--;
01436         else framenr++;
01437 
01438         if(!sequence)
01439             break;
01440     }
01441 
01442     BKE_tracking_sync(context);
01443     BKE_tracking_context_free(context);
01444 
01445     /* update scene current frame to the lastes tracked frame */
01446     scene->r.cfra= framenr;
01447 
01448     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
01449     WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
01450 
01451     return OPERATOR_FINISHED;
01452 }
01453 
01454 static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
01455 {
01456     TrackMarkersJob *tmj;
01457     ScrArea *sa= CTX_wm_area(C);
01458     SpaceClip *sc= CTX_wm_space_clip(C);
01459     MovieClip *clip= ED_space_clip(sc);
01460     wmJob *steve;
01461     int backwards= RNA_boolean_get(op->ptr, "backwards");
01462     int sequence= RNA_boolean_get(op->ptr, "sequence");
01463 
01464     if(WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
01465         /* only one tracking is allowed at a time */
01466         return OPERATOR_CANCELLED;
01467     }
01468 
01469     if(clip->tracking_context)
01470         return OPERATOR_CANCELLED;
01471 
01472     if(track_count_markers(sc, clip)==0)
01473         return OPERATOR_CANCELLED;
01474 
01475     if(!sequence)
01476         return track_markers_exec(C, op);
01477 
01478     tmj= MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
01479     if(!track_markers_initjob(C, tmj, backwards)) {
01480         track_markers_freejob(tmj);
01481 
01482         return OPERATOR_CANCELLED;
01483     }
01484 
01485     /* setup job */
01486     steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Track Markers", WM_JOB_PROGRESS);
01487     WM_jobs_customdata(steve, tmj, track_markers_freejob);
01488 
01489     /* if there's delay set in tracking job, tracking should happen
01490        with fixed FPS. To deal with editor refresh we have to syncronize
01491        tracks from job and tracks in clip. Do this in timer callback
01492        to prevent threading conflicts. */
01493     if(tmj->delay>0) WM_jobs_timer(steve, tmj->delay/1000.0f, NC_MOVIECLIP|NA_EVALUATED, 0);
01494     else WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|NA_EVALUATED, 0);
01495 
01496     WM_jobs_callbacks(steve, track_markers_startjob, NULL, track_markers_updatejob, NULL);
01497 
01498     G.afbreek= 0;
01499 
01500     WM_jobs_start(CTX_wm_manager(C), steve);
01501     WM_cursor_wait(0);
01502 
01503     /* add modal handler for ESC */
01504     WM_event_add_modal_handler(C, op);
01505 
01506     return OPERATOR_RUNNING_MODAL;
01507 }
01508 
01509 static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
01510 {
01511     /* no running tracking, remove handler and pass through */
01512     if(0==WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
01513         return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
01514 
01515     /* running tracking */
01516     switch (event->type) {
01517         case ESCKEY:
01518             return OPERATOR_RUNNING_MODAL;
01519             break;
01520     }
01521 
01522     return OPERATOR_PASS_THROUGH;
01523 }
01524 
01525 void CLIP_OT_track_markers(wmOperatorType *ot)
01526 {
01527     /* identifiers */
01528     ot->name= "Track Markers";
01529     ot->description= "Track selected markers";
01530     ot->idname= "CLIP_OT_track_markers";
01531 
01532     /* api callbacks */
01533     ot->exec= track_markers_exec;
01534     ot->invoke= track_markers_invoke;
01535     ot->poll= space_clip_frame_poll;
01536     ot->modal= track_markers_modal;
01537 
01538     /* flags */
01539     ot->flag= OPTYPE_UNDO;
01540 
01541     /* properties */
01542     RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
01543     RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
01544 }
01545 
01546 /********************** solve camera operator *********************/
01547 
01548 typedef struct {
01549     Scene *scene;
01550     MovieClip *clip;
01551     MovieClipUser user;
01552 
01553     ReportList *reports;
01554 
01555     char stats_message[256];
01556 
01557     struct MovieReconstructContext *context;
01558 } SolveCameraJob;
01559 
01560 static int solve_camera_initjob(bContext *C, SolveCameraJob *scj, wmOperator *op, char *error_msg, int max_error)
01561 {
01562     SpaceClip *sc= CTX_wm_space_clip(C);
01563     MovieClip *clip= ED_space_clip(sc);
01564     Scene *scene= CTX_data_scene(C);
01565     MovieTracking *tracking= &clip->tracking;
01566     MovieTrackingSettings *settings= &clip->tracking.settings;
01567     MovieTrackingObject *object= BKE_tracking_active_object(tracking);
01568     int width, height;
01569 
01570     if(!BKE_tracking_can_reconstruct(tracking, object, error_msg, max_error))
01571         return 0;
01572 
01573     /* could fail if footage uses images with different sizes */
01574     BKE_movieclip_get_size(clip, &sc->user, &width, &height);
01575 
01576     scj->clip= clip;
01577     scj->scene= scene;
01578     scj->reports= op->reports;
01579     scj->user= sc->user;
01580 
01581     scj->context= BKE_tracking_reconstruction_context_new(tracking, object,
01582             settings->keyframe1, settings->keyframe2, width, height);
01583 
01584     tracking->stats= MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
01585 
01586     return 1;
01587 }
01588 
01589 static void solve_camera_updatejob(void *scv)
01590 {
01591     SolveCameraJob *scj= (SolveCameraJob *)scv;
01592     MovieTracking *tracking= &scj->clip->tracking;
01593 
01594     BLI_strncpy(tracking->stats->message, scj->stats_message, sizeof(tracking->stats->message));
01595 }
01596 
01597 static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress)
01598 {
01599     SolveCameraJob *scj= (SolveCameraJob *)scv;
01600 
01601     BKE_tracking_solve_reconstruction(scj->context, stop, do_update, progress,
01602             scj->stats_message, sizeof(scj->stats_message));
01603 }
01604 
01605 static void solve_camera_freejob(void *scv)
01606 {
01607     SolveCameraJob *scj= (SolveCameraJob *)scv;
01608     MovieTracking *tracking= &scj->clip->tracking;
01609     Scene *scene= scj->scene;
01610     MovieClip *clip= scj->clip;
01611     int solved;
01612 
01613     if(!scj->context) {
01614         /* job weren't fully initialized due to some error */
01615         MEM_freeN(scj);
01616         return;
01617     }
01618 
01619     solved= BKE_tracking_finish_reconstruction(scj->context, tracking);
01620 
01621     if(!solved)
01622         BKE_report(scj->reports, RPT_WARNING, "Some data failed to reconstruct, see console for details");
01623     else
01624         BKE_reportf(scj->reports, RPT_INFO, "Average reprojection error %.3f", tracking->reconstruction.error);
01625 
01626     /* set currently solved clip as active for scene */
01627     if(scene->clip)
01628         id_us_min(&clip->id);
01629 
01630     scene->clip= clip;
01631     id_us_plus(&clip->id);
01632 
01633     /* set blender camera focal length so result would look fine there */
01634     if(scene->camera) {
01635         Camera *camera= (Camera*)scene->camera->data;
01636         int width, height;
01637 
01638         BKE_movieclip_get_size(clip, &scj->user, &width, &height);
01639 
01640         BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
01641 
01642         WM_main_add_notifier(NC_OBJECT, camera);
01643     }
01644 
01645     MEM_freeN(tracking->stats);
01646     tracking->stats= NULL;
01647 
01648     DAG_id_tag_update(&clip->id, 0);
01649 
01650     WM_main_add_notifier(NC_MOVIECLIP|NA_EVALUATED, clip);
01651     WM_main_add_notifier(NC_OBJECT|ND_TRANSFORM, NULL);
01652 
01653     /* update active clip displayed in scene buttons */
01654     WM_main_add_notifier(NC_SCENE, scene);
01655 
01656     BKE_tracking_reconstruction_context_free(scj->context);
01657     MEM_freeN(scj);
01658 }
01659 
01660 static int solve_camera_exec(bContext *C, wmOperator *op)
01661 {
01662     SolveCameraJob *scj;
01663     char error_msg[256]= "\0";
01664 
01665     scj= MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
01666     if(!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
01667         if(error_msg[0])
01668             BKE_report(op->reports, RPT_ERROR, error_msg);
01669 
01670         solve_camera_freejob(scj);
01671 
01672         return OPERATOR_CANCELLED;
01673     }
01674 
01675     solve_camera_startjob(scj, NULL, NULL, NULL);
01676 
01677     solve_camera_freejob(scj);
01678 
01679     return OPERATOR_FINISHED;
01680 }
01681 
01682 static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
01683 {
01684     SolveCameraJob *scj;
01685     ScrArea *sa= CTX_wm_area(C);
01686     SpaceClip *sc= CTX_wm_space_clip(C);
01687     MovieClip *clip= ED_space_clip(sc);
01688     MovieTracking *tracking= &clip->tracking;
01689     MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(tracking);
01690     wmJob *steve;
01691     char error_msg[256]= "\0";
01692 
01693     if(WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
01694         /* only one solve is allowed at a time */
01695         return OPERATOR_CANCELLED;
01696     }
01697 
01698     scj= MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
01699     if(!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
01700         if(error_msg[0])
01701             BKE_report(op->reports, RPT_ERROR, error_msg);
01702 
01703         solve_camera_freejob(scj);
01704 
01705         return OPERATOR_CANCELLED;
01706     }
01707 
01708     BLI_strncpy(tracking->stats->message, "Solving camera | Preparing solve", sizeof(tracking->stats->message));
01709 
01710     /* hide reconstruction statistics from previous solve */
01711     reconstruction->flag&= ~TRACKING_RECONSTRUCTED;
01712     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
01713 
01714     /* setup job */
01715     steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Solve Camera", WM_JOB_PROGRESS);
01716     WM_jobs_customdata(steve, scj, solve_camera_freejob);
01717     WM_jobs_timer(steve, 0.1, NC_MOVIECLIP|NA_EVALUATED, 0);
01718     WM_jobs_callbacks(steve, solve_camera_startjob, NULL, solve_camera_updatejob, NULL);
01719 
01720     G.afbreek= 0;
01721 
01722     WM_jobs_start(CTX_wm_manager(C), steve);
01723     WM_cursor_wait(0);
01724 
01725     /* add modal handler for ESC */
01726     WM_event_add_modal_handler(C, op);
01727 
01728     return OPERATOR_RUNNING_MODAL;
01729 }
01730 
01731 static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
01732 {
01733     /* no running solver, remove handler and pass through */
01734     if(0==WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C)))
01735         return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
01736 
01737     /* running tracking */
01738     switch (event->type) {
01739         case ESCKEY:
01740             return OPERATOR_RUNNING_MODAL;
01741             break;
01742     }
01743 
01744     return OPERATOR_PASS_THROUGH;
01745 }
01746 
01747 void CLIP_OT_solve_camera(wmOperatorType *ot)
01748 {
01749     /* identifiers */
01750     ot->name= "Solve Camera";
01751     ot->description= "Solve camera motion from tracks";
01752     ot->idname= "CLIP_OT_solve_camera";
01753 
01754     /* api callbacks */
01755     ot->exec= solve_camera_exec;
01756     ot->invoke= solve_camera_invoke;
01757     ot->modal= solve_camera_modal;
01758     ot->poll= ED_space_clip_poll;
01759 
01760     /* flags */
01761     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01762 }
01763 
01764 /********************** clear solution operator *********************/
01765 
01766 static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
01767 {
01768     SpaceClip *sc= CTX_wm_space_clip(C);
01769     MovieClip *clip= ED_space_clip(sc);
01770     MovieTracking *tracking= &clip->tracking;
01771     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
01772     MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(tracking);
01773     MovieTrackingTrack *track= tracksbase->first;
01774 
01775     while(track) {
01776         track->flag&= ~TRACK_HAS_BUNDLE;
01777 
01778         track= track->next;
01779     }
01780 
01781     if(reconstruction->cameras)
01782         MEM_freeN(reconstruction->cameras);
01783 
01784     reconstruction->cameras= NULL;
01785     reconstruction->camnr= 0;
01786 
01787     reconstruction->flag&= ~TRACKING_RECONSTRUCTED;
01788 
01789     DAG_id_tag_update(&clip->id, 0);
01790 
01791     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
01792     WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
01793 
01794     return OPERATOR_FINISHED;
01795 }
01796 
01797 void CLIP_OT_clear_solution(wmOperatorType *ot)
01798 {
01799     /* identifiers */
01800     ot->name= "Clear Solution";
01801     ot->description= "Clear all calculated data";
01802     ot->idname= "CLIP_OT_clear_solution";
01803 
01804     /* api callbacks */
01805     ot->exec= clear_solution_exec;
01806     ot->poll= ED_space_clip_poll;
01807 
01808     /* flags */
01809     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01810 }
01811 
01812 /********************** clear track operator *********************/
01813 
01814 static int clear_track_path_exec(bContext *C, wmOperator *op)
01815 {
01816     SpaceClip *sc= CTX_wm_space_clip(C);
01817     MovieClip *clip= ED_space_clip(sc);
01818     MovieTrackingTrack *track;
01819     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
01820     int action= RNA_enum_get(op->ptr, "action");
01821 
01822     track= tracksbase->first;
01823     while(track) {
01824         if(TRACK_VIEW_SELECTED(sc, track))
01825             BKE_tracking_clear_path(track, sc->user.framenr, action);
01826 
01827         track= track->next;
01828     }
01829 
01830     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
01831 
01832     return OPERATOR_FINISHED;
01833 }
01834 
01835 void CLIP_OT_clear_track_path(wmOperatorType *ot)
01836 {
01837     static EnumPropertyItem clear_path_actions[] = {
01838             {TRACK_CLEAR_UPTO, "UPTO", 0, "Clear up-to", "Clear path up to current frame"},
01839             {TRACK_CLEAR_REMAINED, "REMAINED", 0, "Clear remained", "Clear path at remaining frames (after current)"},
01840             {TRACK_CLEAR_ALL, "ALL", 0, "Clear all", "Clear the whole path"},
01841             {0, NULL, 0, NULL, NULL}
01842     };
01843 
01844     /* identifiers */
01845     ot->name= "Clear Track Path";
01846     ot->description= "Clear tracks after/before current position or clear the whole track";
01847     ot->idname= "CLIP_OT_clear_track_path";
01848 
01849     /* api callbacks */
01850     ot->exec= clear_track_path_exec;
01851     ot->poll= ED_space_clip_poll;
01852 
01853     /* flags */
01854     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01855 
01856     /* proeprties */
01857     RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
01858 }
01859 
01860 /********************** disable markers operator *********************/
01861 
01862 static int disable_markers_exec(bContext *C, wmOperator *op)
01863 {
01864     SpaceClip *sc= CTX_wm_space_clip(C);
01865     MovieClip *clip= ED_space_clip(sc);
01866     MovieTracking *tracking= &clip->tracking;
01867     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
01868     MovieTrackingTrack *track= tracksbase->first;
01869     int action= RNA_enum_get(op->ptr, "action");
01870 
01871     while(track) {
01872         if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
01873             MovieTrackingMarker *marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
01874 
01875             if(action==0) marker->flag|= MARKER_DISABLED;
01876             else if(action==1) marker->flag&= ~MARKER_DISABLED;
01877             else marker->flag^= MARKER_DISABLED;
01878         }
01879 
01880         track= track->next;
01881     }
01882 
01883     DAG_id_tag_update(&clip->id, 0);
01884 
01885     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
01886 
01887     return OPERATOR_FINISHED;
01888 }
01889 
01890 void CLIP_OT_disable_markers(wmOperatorType *ot)
01891 {
01892     static EnumPropertyItem actions_items[] = {
01893             {0, "DISABLE", 0, "Disable", "Disable selected markers"},
01894             {1, "ENABLE", 0, "Enable", "Enable selected markers"},
01895             {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
01896             {0, NULL, 0, NULL, NULL}
01897     };
01898 
01899     /* identifiers */
01900     ot->name= "Disable Markers";
01901     ot->description= "Disable/enable selected markers";
01902     ot->idname= "CLIP_OT_disable_markers";
01903 
01904     /* api callbacks */
01905     ot->exec= disable_markers_exec;
01906     ot->poll= ED_space_clip_poll;
01907 
01908     /* flags */
01909     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01910 
01911     /* properties */
01912     RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
01913 }
01914 
01915 /********************** set origin operator *********************/
01916 
01917 static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
01918 {
01919     Object *camera= scene->camera;
01920     Base *base;
01921 
01922     if(camera && object_get_movieclip(scene, camera, 0)==clip)
01923         return camera;
01924 
01925     base= scene->base.first;
01926     while(base) {
01927         if(base->object->type == OB_CAMERA) {
01928             if(object_get_movieclip(scene, base->object, 0)==clip) {
01929                 camera= base->object;
01930                 break;
01931             }
01932         }
01933 
01934         base= base->next;
01935     }
01936 
01937     return camera;
01938 }
01939 
01940 static Object *get_orientation_object(bContext *C)
01941 {
01942     Scene *scene= CTX_data_scene(C);
01943     SpaceClip *sc= CTX_wm_space_clip(C);
01944     MovieClip *clip= ED_space_clip(sc);
01945     MovieTracking *tracking= &clip->tracking;
01946     MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
01947     Object *object= NULL;
01948 
01949     if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
01950         object= get_camera_with_movieclip(scene, clip);
01951     }
01952     else {
01953         object= OBACT;
01954     }
01955 
01956     if(object && object->parent)
01957         object= object->parent;
01958 
01959     return object;
01960 }
01961 
01962 static int set_orientation_poll(bContext *C)
01963 {
01964     if(space_clip_frame_poll(C)) {
01965         Scene *scene= CTX_data_scene(C);
01966         SpaceClip *sc= CTX_wm_space_clip(C);
01967         MovieClip *clip= ED_space_clip(sc);
01968         MovieTracking *tracking= &clip->tracking;
01969         MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
01970 
01971         if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
01972             return 1;
01973         }
01974         else {
01975             return OBACT != NULL;
01976         }
01977     }
01978 
01979     return 0;
01980 }
01981 
01982 static int count_selected_bundles(bContext *C)
01983 {
01984     SpaceClip *sc= CTX_wm_space_clip(C);
01985     MovieClip *clip= ED_space_clip(sc);
01986     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
01987     MovieTrackingTrack *track;
01988     int tot= 0;
01989 
01990     track= tracksbase->first;
01991     while(track) {
01992         if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE))
01993             tot++;
01994 
01995         track= track->next;
01996     }
01997 
01998     return tot;
01999 }
02000 
02001 static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4])
02002 {
02003     bConstraint *con;
02004     int found= 0;
02005 
02006     for (con= ob->constraints.first; con; con=con->next) {
02007         bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
02008 
02009         if(!cti)
02010             continue;
02011 
02012         if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
02013             bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
02014 
02015             if(!found) {
02016                 Object *cam= data->camera ? data->camera : scene->camera;
02017 
02018                 where_is_object_mat(scene, cam, invmat);
02019             }
02020 
02021             mult_m4_m4m4(invmat, invmat, data->invmat);
02022 
02023             found= 1;
02024         }
02025     }
02026 
02027     if(found)
02028         invert_m4(invmat);
02029     else
02030         unit_m4(invmat);
02031 }
02032 
02033 static Object *object_solver_camera(Scene *scene, Object *ob)
02034 {
02035     bConstraint *con;
02036 
02037     for (con= ob->constraints.first; con; con=con->next) {
02038         bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
02039 
02040         if(!cti)
02041             continue;
02042 
02043         if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
02044             bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
02045 
02046             return data->camera ? data->camera : scene->camera;
02047         }
02048     }
02049 
02050     return NULL;
02051 }
02052 
02053 static int set_origin_exec(bContext *C, wmOperator *op)
02054 {
02055     SpaceClip *sc= CTX_wm_space_clip(C);
02056     MovieClip *clip= ED_space_clip(sc);
02057     MovieTracking *tracking= &clip->tracking;
02058     MovieTrackingTrack *track;
02059     MovieTrackingObject *tracking_object;
02060     Scene *scene= CTX_data_scene(C);
02061     Object *object;
02062     Object *camera= get_camera_with_movieclip(scene, clip);
02063     ListBase *tracksbase;
02064     float mat[4][4], vec[3], median[3];
02065     int selected_count= count_selected_bundles(C);
02066 
02067     if(selected_count==0) {
02068         BKE_report(op->reports, RPT_ERROR, "At least one track with bundle should be selected to define origin position");
02069 
02070         return OPERATOR_CANCELLED;
02071     }
02072 
02073     object= get_orientation_object(C);
02074     if(!object) {
02075         BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
02076 
02077         return OPERATOR_CANCELLED;
02078     }
02079 
02080     tracking_object= BKE_tracking_active_object(tracking);
02081 
02082     tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
02083 
02084     track= tracksbase->first;
02085     zero_v3(median);
02086     while(track) {
02087         if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE)) {
02088             add_v3_v3(median, track->bundle_pos);
02089         }
02090 
02091         track= track->next;
02092     }
02093     mul_v3_fl(median, 1.0f/selected_count);
02094 
02095     BKE_get_tracking_mat(scene, camera, mat);
02096 
02097     mul_v3_m4v3(vec, mat, median);
02098 
02099     if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
02100         sub_v3_v3(object->loc, vec);
02101     }
02102     else {
02103         object_solver_inverted_matrix(scene, object, mat);
02104         mul_v3_m4v3(vec, mat, vec);
02105         copy_v3_v3(object->loc, vec);
02106     }
02107 
02108     DAG_id_tag_update(&clip->id, 0);
02109     DAG_id_tag_update(&object->id, OB_RECALC_OB);
02110 
02111     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
02112     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
02113 
02114     return OPERATOR_FINISHED;
02115 }
02116 
02117 void CLIP_OT_set_origin(wmOperatorType *ot)
02118 {
02119     /* identifiers */
02120     ot->name= "Set Origin";
02121     ot->description= "Set active marker as origin by moving camera (or it's parent if present) in 3D space";
02122     ot->idname= "CLIP_OT_set_origin";
02123 
02124     /* api callbacks */
02125     ot->exec= set_origin_exec;
02126     ot->poll= set_orientation_poll;
02127 
02128     /* flags */
02129     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02130 
02131     /* properties */
02132     RNA_def_boolean(ot->srna, "use_median", 0, "Use Median", "Set origin to median point of selected bundles");
02133 }
02134 
02135 /********************** set floor operator *********************/
02136 
02137 static void set_axis(Scene *scene,  Object *ob, MovieClip *clip, MovieTrackingObject *tracking_object,
02138             MovieTrackingTrack *track, char axis)
02139 {
02140     Object *camera= get_camera_with_movieclip(scene, clip);
02141     int is_camera= tracking_object->flag&TRACKING_OBJECT_CAMERA;
02142     int  flip= 0;
02143     float mat[4][4], vec[3], obmat[4][4], dvec[3];
02144 
02145     object_to_mat4(ob, obmat);
02146 
02147     BKE_get_tracking_mat(scene, camera, mat);
02148     mul_v3_m4v3(vec, mat, track->bundle_pos);
02149     copy_v3_v3(dvec, vec);
02150 
02151     if(!is_camera) {
02152         float imat[4][4];
02153 
02154         object_solver_inverted_matrix(scene, ob, imat);
02155         mul_v3_m4v3(vec, imat, vec);
02156 
02157         invert_m4_m4(imat, obmat);
02158         mul_v3_m4v3(dvec, imat, vec);
02159 
02160         sub_v3_v3(vec, obmat[3]);
02161     }
02162 
02163     if(len_v2(vec) < 1e-3f)
02164         return;
02165 
02166     unit_m4(mat);
02167 
02168     if(axis=='X') {
02169         if(fabsf(dvec[1])<1e-3f) {
02170             flip= 1;
02171 
02172             mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
02173             mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
02174             mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
02175         } else {
02176             copy_v3_v3(mat[0], vec);
02177 
02178             if(is_camera || fabsf(vec[2])<1e-3f) {
02179                 mat[0][2]= 0.0f;
02180                 mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
02181                 cross_v3_v3v3(mat[1], mat[2], mat[0]);
02182             }
02183             else {
02184                 vec[2]= 0.0f;
02185 
02186                 cross_v3_v3v3(mat[1], mat[0], vec);
02187                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
02188             }
02189         }
02190     } else {
02191         if(fabsf(dvec[0])<1e-3f) {
02192             flip= 1;
02193 
02194             mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
02195             mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
02196             mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
02197         } else {
02198             copy_v3_v3(mat[1], vec);
02199 
02200             if(is_camera || fabsf(vec[2])<1e-3f) {
02201                 mat[1][2]= 0.0f;
02202                 mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
02203                 cross_v3_v3v3(mat[0], mat[1], mat[2]);
02204             }
02205             else {
02206                 vec[2]= 0.0f;
02207 
02208                 cross_v3_v3v3(mat[0], vec, mat[1]);
02209                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
02210             }
02211         }
02212     }
02213 
02214     normalize_v3(mat[0]);
02215     normalize_v3(mat[1]);
02216     normalize_v3(mat[2]);
02217 
02218     if(is_camera) {
02219         invert_m4(mat);
02220 
02221         mult_m4_m4m4(mat, mat, obmat);
02222     }
02223     else {
02224         if(!flip) {
02225             float lmat[4][4], ilmat[4][4], rmat[3][3];
02226 
02227             object_rot_to_mat3(ob, rmat);
02228             invert_m3(rmat);
02229             mul_m4_m4m3(mat, mat, rmat);
02230 
02231             unit_m4(lmat);
02232             copy_v3_v3(lmat[3], obmat[3]);
02233             invert_m4_m4(ilmat, lmat);
02234 
02235             mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
02236         }
02237         else {
02238             mult_m4_m4m4(mat, obmat, mat);
02239         }
02240     }
02241 
02242     object_apply_mat4(ob, mat, 0, 0);
02243 }
02244 
02245 static int set_floor_exec(bContext *C, wmOperator *op)
02246 {
02247     SpaceClip *sc= CTX_wm_space_clip(C);
02248     MovieClip *clip= ED_space_clip(sc);
02249     Scene *scene= CTX_data_scene(C);
02250     MovieTracking *tracking= &clip->tracking;
02251     MovieTrackingObject *tracking_object;
02252     MovieTrackingTrack *track, *axis_track= NULL, *act_track;
02253     ListBase *tracksbase;
02254     Object *object;
02255     Object *camera= get_camera_with_movieclip(scene, clip);
02256     int tot= 0;
02257     float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3]= {0.0f, 0.0f, 0.0f};
02258     float rot[4][4]={{0.0f, 0.0f, -1.0f, 0.0f},
02259                      {0.0f, 1.0f, 0.0f, 0.0f},
02260                      {1.0f, 0.0f, 0.0f, 0.0f},
02261                      {0.0f, 0.0f, 0.0f, 1.0f}}; /* 90 degrees Y-axis rotation matrix */
02262 
02263     if(count_selected_bundles(C)!=3) {
02264         BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
02265 
02266         return OPERATOR_CANCELLED;
02267     }
02268 
02269     tracking_object= BKE_tracking_active_object(tracking);
02270     tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
02271     act_track= BKE_tracking_active_track(tracking);
02272 
02273     object= get_orientation_object(C);
02274     if(!object) {
02275         BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
02276 
02277         return OPERATOR_CANCELLED;
02278     }
02279 
02280     BKE_get_tracking_mat(scene, camera, mat);
02281 
02282     /* get 3 bundles to use as reference */
02283     track= tracksbase->first;
02284     while(track && tot<3) {
02285         if(track->flag&TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
02286             mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
02287 
02288             if(tot==0 || track==act_track)
02289                 copy_v3_v3(orig, vec[tot]);
02290             else
02291                 axis_track= track;
02292 
02293             tot++;
02294         }
02295 
02296         track= track->next;
02297     }
02298 
02299     sub_v3_v3(vec[1], vec[0]);
02300     sub_v3_v3(vec[2], vec[0]);
02301 
02302     /* construct ortho-normal basis */
02303     unit_m4(mat);
02304 
02305     cross_v3_v3v3(mat[0], vec[1], vec[2]);
02306     copy_v3_v3(mat[1], vec[1]);
02307     cross_v3_v3v3(mat[2], mat[0], mat[1]);
02308 
02309     normalize_v3(mat[0]);
02310     normalize_v3(mat[1]);
02311     normalize_v3(mat[2]);
02312 
02313     /* move to origin point */
02314     mat[3][0]= orig[0];
02315     mat[3][1]= orig[1];
02316     mat[3][2]= orig[2];
02317 
02318     if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
02319         invert_m4(mat);
02320 
02321         object_to_mat4(object, obmat);
02322         mult_m4_m4m4(mat, mat, obmat);
02323         mult_m4_m4m4(newmat, rot, mat);
02324         object_apply_mat4(object, newmat, 0, 0);
02325 
02326         /* make camera have positive z-coordinate */
02327         if(object->loc[2]<0) {
02328             invert_m4(rot);
02329             mult_m4_m4m4(newmat, rot, mat);
02330             object_apply_mat4(object, newmat, 0, 0);
02331         }
02332     }
02333     else {
02334         object_apply_mat4(object, mat, 0, 0);
02335     }
02336 
02337     where_is_object(scene, object);
02338     set_axis(scene, object, clip, tracking_object, axis_track, 'X');
02339 
02340     DAG_id_tag_update(&clip->id, 0);
02341     DAG_id_tag_update(&object->id, OB_RECALC_OB);
02342 
02343     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
02344     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
02345 
02346     return OPERATOR_FINISHED;
02347 }
02348 
02349 void CLIP_OT_set_floor(wmOperatorType *ot)
02350 {
02351     /* identifiers */
02352     ot->name= "Set Floor";
02353     ot->description= "Set floor based on 3 selected bundles by moving camera (or it's parent if present) in 3D space";
02354     ot->idname= "CLIP_OT_set_floor";
02355 
02356     /* api callbacks */
02357     ot->exec= set_floor_exec;
02358     ot->poll= set_orientation_poll;
02359 
02360     /* flags */
02361     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02362 }
02363 
02364 /********************** set axis operator *********************/
02365 
02366 static int set_axis_exec(bContext *C, wmOperator *op)
02367 {
02368     SpaceClip *sc= CTX_wm_space_clip(C);
02369     MovieClip *clip= ED_space_clip(sc);
02370     MovieTracking *tracking= &clip->tracking;
02371     MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
02372     MovieTrackingTrack *track;
02373     Scene *scene= CTX_data_scene(C);
02374     Object *object;
02375     ListBase *tracksbase;
02376     int axis= RNA_enum_get(op->ptr, "axis");
02377 
02378     if(count_selected_bundles(C)!=1) {
02379         BKE_report(op->reports, RPT_ERROR, "Single track with bundle should be selected to define axis");
02380 
02381         return OPERATOR_CANCELLED;
02382     }
02383 
02384     object= get_orientation_object(C);
02385     if(!object) {
02386         BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
02387 
02388         return OPERATOR_CANCELLED;
02389     }
02390 
02391     tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
02392 
02393     track=tracksbase->first;
02394     while(track) {
02395         if(TRACK_VIEW_SELECTED(sc, track))
02396             break;
02397 
02398         track= track->next;
02399     }
02400 
02401     set_axis(scene, object, clip, tracking_object, track, axis==0?'X':'Y');
02402 
02403     DAG_id_tag_update(&clip->id, 0);
02404     DAG_id_tag_update(&object->id, OB_RECALC_OB);
02405 
02406     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
02407     WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
02408 
02409     return OPERATOR_FINISHED;
02410 }
02411 
02412 void CLIP_OT_set_axis(wmOperatorType *ot)
02413 {
02414     static EnumPropertyItem axis_actions[] = {
02415             {0, "X", 0, "X", "Align bundle align X axis"},
02416             {1, "Y", 0, "Y", "Align bundle align Y axis"},
02417             {0, NULL, 0, NULL, NULL}
02418     };
02419 
02420     /* identifiers */
02421     ot->name= "Set Axis";
02422     ot->description= "Set direction of scene axis rotating camera (or it's parent if present) and assuming selected track lies on real axis joining it with the origin";
02423     ot->idname= "CLIP_OT_set_axis";
02424 
02425     /* api callbacks */
02426     ot->exec= set_axis_exec;
02427     ot->poll= set_orientation_poll;
02428 
02429     /* flags */
02430     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02431 
02432     /* properties */
02433     RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
02434 }
02435 
02436 /********************** set scale operator *********************/
02437 
02438 static int do_set_scale(bContext *C, wmOperator *op, int scale_solution)
02439 {
02440     SpaceClip *sc= CTX_wm_space_clip(C);
02441     MovieClip *clip= ED_space_clip(sc);
02442     MovieTracking *tracking= &clip->tracking;
02443     MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
02444     MovieTrackingTrack *track;
02445     Scene *scene= CTX_data_scene(C);
02446     Object *object= NULL;
02447     Object *camera= get_camera_with_movieclip(scene, clip);
02448     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
02449     int tot= 0;
02450     float vec[2][3], mat[4][4], scale;
02451     float dist= RNA_float_get(op->ptr, "distance");
02452 
02453     if(count_selected_bundles(C)!=2) {
02454         BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to set scale");
02455 
02456         return OPERATOR_CANCELLED;
02457     }
02458 
02459     object= get_orientation_object(C);
02460     if(!object) {
02461         BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
02462 
02463         return OPERATOR_CANCELLED;
02464     }
02465 
02466     BKE_get_tracking_mat(scene, camera, mat);
02467 
02468     track= tracksbase->first;
02469     while(track) {
02470         if(TRACK_VIEW_SELECTED(sc, track)) {
02471             mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
02472             tot++;
02473         }
02474 
02475         track= track->next;
02476     }
02477 
02478     sub_v3_v3(vec[0], vec[1]);
02479 
02480     if(len_v3(vec[0])>1e-5f) {
02481         scale= dist / len_v3(vec[0]);
02482 
02483         if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
02484             mul_v3_fl(object->size, scale);
02485             mul_v3_fl(object->loc, scale);
02486         }
02487         else if(!scale_solution){
02488             Object *solver_camera= object_solver_camera(scene, object);
02489 
02490             object->size[0]= object->size[1]= object->size[2]= 1.0f/scale;
02491 
02492             if(solver_camera) {
02493                 object->size[0]/= solver_camera->size[0];
02494                 object->size[1]/= solver_camera->size[1];
02495                 object->size[2]/= solver_camera->size[2];
02496             }
02497         }
02498         else {
02499             tracking_object->scale= scale;
02500         }
02501 
02502         DAG_id_tag_update(&clip->id, 0);
02503 
02504         if(object)
02505             DAG_id_tag_update(&object->id, OB_RECALC_OB);
02506 
02507         WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
02508         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
02509     }
02510 
02511     return OPERATOR_FINISHED;
02512 }
02513 
02514 static int set_scale_exec(bContext *C, wmOperator *op)
02515 {
02516     return do_set_scale(C, op, 0);
02517 }
02518 
02519 static int set_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
02520 {
02521     SpaceClip *sc= CTX_wm_space_clip(C);
02522     MovieClip *clip= ED_space_clip(sc);
02523     float dist= RNA_float_get(op->ptr, "distance");
02524 
02525     if(dist==0.0f)
02526         RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
02527 
02528     return set_scale_exec(C, op);
02529 }
02530 
02531 void CLIP_OT_set_scale(wmOperatorType *ot)
02532 {
02533     /* identifiers */
02534     ot->name= "Set Scale";
02535     ot->description= "Set scale of scene by scaling camera (or it's parent if present)";
02536     ot->idname= "CLIP_OT_set_scale";
02537 
02538     /* api callbacks */
02539     ot->exec= set_scale_exec;
02540     ot->invoke= set_scale_invoke;
02541     ot->poll= set_orientation_poll;
02542 
02543     /* flags */
02544     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02545 
02546     /* properties */
02547     RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
02548         "Distance", "Distance between selected tracks", -100.0f, 100.0f);
02549 }
02550 
02551 /********************** set solution scale operator *********************/
02552 
02553 static int set_solution_scale_poll(bContext *C)
02554 {
02555     if(space_clip_frame_poll(C)) {
02556         SpaceClip *sc= CTX_wm_space_clip(C);
02557         MovieClip *clip= ED_space_clip(sc);
02558         MovieTracking *tracking= &clip->tracking;
02559         MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
02560 
02561         return (tracking_object->flag&TRACKING_OBJECT_CAMERA) == 0;
02562     }
02563 
02564     return 0;
02565 }
02566 
02567 static int set_solution_scale_exec(bContext *C, wmOperator *op)
02568 {
02569     return do_set_scale(C, op, 1);
02570 }
02571 
02572 static int set_solution_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
02573 {
02574     SpaceClip *sc= CTX_wm_space_clip(C);
02575     MovieClip *clip= ED_space_clip(sc);
02576     float dist= RNA_float_get(op->ptr, "distance");
02577 
02578     if(dist==0.0f)
02579         RNA_float_set(op->ptr, "distance", clip->tracking.settings.object_distance);
02580 
02581     return set_solution_scale_exec(C, op);
02582 }
02583 
02584 void CLIP_OT_set_solution_scale(wmOperatorType *ot)
02585 {
02586     /* identifiers */
02587     ot->name= "Set Solution Scale";
02588     ot->description= "Set object solution scale using distance between two selected tracks";
02589     ot->idname= "CLIP_OT_set_solution_scale";
02590 
02591     /* api callbacks */
02592     ot->exec= set_solution_scale_exec;
02593     ot->invoke= set_solution_scale_invoke;
02594     ot->poll= set_solution_scale_poll;
02595 
02596     /* flags */
02597     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02598 
02599     /* properties */
02600     RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
02601         "Distance", "Distance between selected tracks", -100.0f, 100.0f);
02602 }
02603 
02604 /********************** set principal center operator *********************/
02605 
02606 static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
02607 {
02608     SpaceClip *sc= CTX_wm_space_clip(C);
02609     MovieClip *clip= ED_space_clip(sc);
02610     int width, height;
02611 
02612     BKE_movieclip_get_size(clip, &sc->user, &width, &height);
02613 
02614     if(width==0 || height==0)
02615         return OPERATOR_CANCELLED;
02616 
02617     clip->tracking.camera.principal[0]= ((float)width)/2.0f;
02618     clip->tracking.camera.principal[1]= ((float)height)/2.0f;
02619 
02620     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
02621 
02622     return OPERATOR_FINISHED;
02623 }
02624 
02625 void CLIP_OT_set_center_principal(wmOperatorType *ot)
02626 {
02627     /* identifiers */
02628     ot->name= "Set Principal to Center";
02629     ot->description= "Set optical center to center of footage";
02630     ot->idname= "CLIP_OT_set_center_principal";
02631 
02632     /* api callbacks */
02633     ot->exec= set_center_principal_exec;
02634     ot->poll= ED_space_clip_poll;
02635 
02636     /* flags */
02637     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02638 }
02639 
02640 /********************** hide tracks operator *********************/
02641 
02642 static int hide_tracks_exec(bContext *C, wmOperator *op)
02643 {
02644     SpaceClip *sc= CTX_wm_space_clip(C);
02645     MovieClip *clip= ED_space_clip(sc);
02646     MovieTrackingTrack *track;
02647     MovieTracking *tracking= &clip->tracking;
02648     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
02649     MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
02650     int unselected;
02651 
02652     unselected= RNA_boolean_get(op->ptr, "unselected");
02653 
02654     track= tracksbase->first;
02655     while(track) {
02656         if(unselected==0 && TRACK_VIEW_SELECTED(sc, track)) {
02657             track->flag|= TRACK_HIDDEN;
02658         } else if(unselected==1 && !TRACK_VIEW_SELECTED(sc, track)) {
02659             track->flag|= TRACK_HIDDEN;
02660         }
02661 
02662         track= track->next;
02663     }
02664 
02665     if(act_track && act_track->flag&TRACK_HIDDEN)
02666         clip->tracking.act_track= NULL;
02667 
02668     if(unselected==0) {
02669         /* no selection on screen now, unlock view so it can be scrolled nice again */
02670         sc->flag&= ~SC_LOCK_SELECTION;
02671     }
02672 
02673     WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
02674 
02675     return OPERATOR_FINISHED;
02676 }
02677 
02678 void CLIP_OT_hide_tracks(wmOperatorType *ot)
02679 {
02680     /* identifiers */
02681     ot->name= "Hide Tracks";
02682     ot->description= "Hide selected tracks";
02683     ot->idname= "CLIP_OT_hide_tracks";
02684 
02685     /* api callbacks */
02686     ot->exec= hide_tracks_exec;
02687     ot->poll= ED_space_clip_poll;
02688 
02689     /* flags */
02690     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02691 
02692     /* properties */
02693     RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
02694 }
02695 
02696 /********************** hide tracks clear operator *********************/
02697 
02698 static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
02699 {
02700     SpaceClip *sc= CTX_wm_space_clip(C);
02701     MovieClip *clip= ED_space_clip(sc);
02702     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
02703     MovieTrackingTrack *track;
02704 
02705     track= tracksbase->first;
02706     while(track) {
02707         track->flag&= ~TRACK_HIDDEN;
02708 
02709         track= track->next;
02710     }
02711 
02712     WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
02713 
02714     return OPERATOR_FINISHED;
02715 }
02716 
02717 void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
02718 {
02719     /* identifiers */
02720     ot->name= "Hide Tracks Clear";
02721     ot->description= "Clear hide selected tracks";
02722     ot->idname= "CLIP_OT_hide_tracks_clear";
02723 
02724     /* api callbacks */
02725     ot->exec= hide_tracks_clear_exec;
02726     ot->poll= ED_space_clip_poll;
02727 
02728     /* flags */
02729     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02730 }
02731 
02732 /********************** detect features operator *********************/
02733 
02734 static bGPDlayer *detect_get_layer(MovieClip *clip)
02735 {
02736     bGPDlayer *layer;
02737 
02738     if(!clip->gpd)
02739         return NULL;
02740 
02741     layer= clip->gpd->layers.first;
02742     while(layer) {
02743         if(layer->flag&GP_LAYER_ACTIVE)
02744             return layer;
02745 
02746         layer= layer->next;
02747     }
02748 
02749     return NULL;
02750 }
02751 
02752 static int detect_features_exec(bContext *C, wmOperator *op)
02753 {
02754     SpaceClip *sc= CTX_wm_space_clip(C);
02755     MovieClip *clip= ED_space_clip(sc);
02756     int clip_flag= clip->flag&MCLIP_TIMECODE_FLAGS;
02757     ImBuf *ibuf= BKE_movieclip_get_ibuf_flag(clip, &sc->user, clip_flag);
02758     MovieTracking *tracking= &clip->tracking;
02759     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
02760     MovieTrackingTrack *track= tracksbase->first;
02761     int placement= RNA_enum_get(op->ptr, "placement");
02762     int margin= RNA_int_get(op->ptr, "margin");
02763     int min_trackability= RNA_int_get(op->ptr, "min_trackability");
02764     int min_distance= RNA_int_get(op->ptr, "min_distance");
02765     int place_outside_layer= 0;
02766     bGPDlayer *layer= NULL;
02767 
02768     if(placement!=0) {
02769         layer= detect_get_layer(clip);
02770         place_outside_layer= placement==2;
02771     }
02772 
02773     /* deselect existing tracks */
02774     while(track) {
02775         track->flag&= ~SELECT;
02776         track->pat_flag&= ~SELECT;
02777         track->search_flag&= ~SELECT;
02778 
02779         track= track->next;
02780     }
02781 
02782     BKE_tracking_detect_fast(tracking, tracksbase, ibuf, sc->user.framenr, margin,
02783                 min_trackability, min_distance, layer, place_outside_layer);
02784 
02785     IMB_freeImBuf(ibuf);
02786 
02787     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
02788 
02789     return OPERATOR_FINISHED;
02790 }
02791 
02792 void CLIP_OT_detect_features(wmOperatorType *ot)
02793 {
02794     static EnumPropertyItem placement_items[] = {
02795             {0, "FRAME",            0, "Whole Frame",           "Place markers across the whole frame"},
02796             {1, "INSIDE_GPENCIL",   0, "Inside grease pencil",  "Place markers only inside areas outlined with grease pencil"},
02797             {2, "OUTSIDE_GPENCIL",  0, "Outside grease pencil", "Place markers only outside areas outlined with grease pencil"},
02798             {0, NULL, 0, NULL, NULL}
02799     };
02800 
02801     /* identifiers */
02802     ot->name= "Detect Features";
02803     ot->description= "Automatically detect features and place markers to track";
02804     ot->idname= "CLIP_OT_detect_features";
02805 
02806     /* api callbacks */
02807     ot->exec= detect_features_exec;
02808     ot->poll= space_clip_frame_poll;
02809 
02810     /* flags */
02811     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02812 
02813     /* properties */
02814     RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features");
02815     RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin", "Only corners further than margin pixels from the image edges are considered", 0, 300);
02816     RNA_def_int(ot->srna, "min_trackability", 16, 0, INT_MAX, "Trackability", "Minimum trackability score to add a corner", 0, 300);
02817     RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two corners", 0, 300);
02818 }
02819 
02820 /********************** frame jump operator *********************/
02821 
02822 static int frame_jump_exec(bContext *C, wmOperator *op)
02823 {
02824     Scene *scene= CTX_data_scene(C);
02825     SpaceClip *sc= CTX_wm_space_clip(C);
02826     MovieClip *clip= ED_space_clip(sc);
02827     MovieTrackingTrack *track;
02828     int pos= RNA_enum_get(op->ptr, "position");
02829     int delta;
02830 
02831     if(pos<=1) {    /* jump to path */
02832         track= BKE_tracking_active_track(&clip->tracking);
02833 
02834         if(!track)
02835             return OPERATOR_CANCELLED;
02836 
02837         delta= pos == 1 ? 1 : -1;
02838 
02839         while(sc->user.framenr+delta >= SFRA && sc->user.framenr+delta <= EFRA) {
02840             MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, sc->user.framenr+delta);
02841 
02842             if(!marker || marker->flag&MARKER_DISABLED)
02843                 break;
02844 
02845             sc->user.framenr+= delta;
02846         }
02847     }
02848     else {  /* to to failed frame */
02849         if(clip->tracking.reconstruction.flag&TRACKING_RECONSTRUCTED) {
02850             int a= sc->user.framenr;
02851             MovieTracking *tracking= &clip->tracking;
02852             MovieTrackingObject *object= BKE_tracking_active_object(tracking);
02853 
02854             delta= pos == 3 ? 1 : -1;
02855 
02856             a+= delta;
02857 
02858             while(a+delta >= SFRA && a+delta <= EFRA) {
02859                 MovieReconstructedCamera *cam;
02860 
02861                 cam= BKE_tracking_get_reconstructed_camera(tracking, object, a);
02862 
02863                 if(!cam) {
02864                     sc->user.framenr= a;
02865 
02866                     break;
02867                 }
02868 
02869                 a+= delta;
02870             }
02871         }
02872     }
02873 
02874     if(CFRA!=sc->user.framenr) {
02875         CFRA= sc->user.framenr;
02876         sound_seek_scene(CTX_data_main(C), CTX_data_scene(C));
02877 
02878         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
02879     }
02880 
02881     WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
02882 
02883     return OPERATOR_FINISHED;
02884 }
02885 
02886 void CLIP_OT_frame_jump(wmOperatorType *ot)
02887 {
02888     static EnumPropertyItem position_items[] = {
02889             {0, "PATHSTART",    0, "Path Start",        "Jump to start of current path"},
02890             {1, "PATHEND",      0, "Path End",          "Jump to end of current path"},
02891             {2, "FAILEDPREV",   0, "Previous Failed",   "Jump to previous failed frame"},
02892             {2, "FAILNEXT",     0, "Next Failed",       "Jump to next failed frame"},
02893             {0, NULL, 0, NULL, NULL}
02894     };
02895 
02896     /* identifiers */
02897     ot->name= "Jump to Frame";
02898     ot->description= "Jump to special frame";
02899     ot->idname= "CLIP_OT_frame_jump";
02900 
02901     /* api callbacks */
02902     ot->exec= frame_jump_exec;
02903     ot->poll= space_clip_frame_poll;
02904 
02905     /* flags */
02906     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02907 
02908     /* properties */
02909     RNA_def_enum(ot->srna, "position", position_items, 0, "Position", "Position to jumo to");
02910 }
02911 
02912 /********************** join tracks operator *********************/
02913 
02914 static int join_tracks_exec(bContext *C, wmOperator *op)
02915 {
02916     SpaceClip *sc= CTX_wm_space_clip(C);
02917     MovieClip *clip= ED_space_clip(sc);
02918     MovieTracking *tracking= &clip->tracking;
02919     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
02920     MovieTrackingTrack *act_track, *track, *next;
02921 
02922     act_track= BKE_tracking_active_track(tracking);
02923 
02924     if(!act_track) {
02925         BKE_report(op->reports, RPT_ERROR, "No active track to join to");
02926         return OPERATOR_CANCELLED;
02927     }
02928 
02929     track= tracksbase->first;
02930     while(track) {
02931         if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
02932             if(!BKE_tracking_test_join_tracks(act_track, track)) {
02933                 BKE_report(op->reports, RPT_ERROR, "Some selected tracks have got keyframed markers to the same frame");
02934                 return OPERATOR_CANCELLED;
02935             }
02936         }
02937 
02938         track= track->next;
02939     }
02940 
02941     track= tracksbase->first;
02942     while(track) {
02943         next= track->next;
02944 
02945         if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
02946             BKE_tracking_join_tracks(act_track, track);
02947 
02948             BKE_tracking_free_track(track);
02949             BLI_freelinkN(tracksbase, track);
02950         }
02951 
02952         track= next;
02953     }
02954 
02955     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
02956 
02957     return OPERATOR_FINISHED;
02958 }
02959 
02960 void CLIP_OT_join_tracks(wmOperatorType *ot)
02961 {
02962     /* identifiers */
02963     ot->name= "Join Tracks";
02964     ot->description= "Join selected tracks";
02965     ot->idname= "CLIP_OT_join_tracks";
02966 
02967     /* api callbacks */
02968     ot->exec= join_tracks_exec;
02969     ot->poll= space_clip_frame_poll;
02970 
02971     /* flags */
02972     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02973 }
02974 
02975 /********************** lock tracks operator *********************/
02976 
02977 static int lock_tracks_exec(bContext *C, wmOperator *op)
02978 {
02979     SpaceClip *sc= CTX_wm_space_clip(C);
02980     MovieClip *clip= ED_space_clip(sc);
02981     MovieTracking *tracking= &clip->tracking;
02982     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
02983     MovieTrackingTrack *track= tracksbase->first;
02984     int action= RNA_enum_get(op->ptr, "action");
02985 
02986     while(track) {
02987         if(TRACK_VIEW_SELECTED(sc, track)) {
02988             if(action==0) track->flag|= TRACK_LOCKED;
02989             else if(action==1) track->flag&= ~TRACK_LOCKED;
02990             else track->flag^= TRACK_LOCKED;
02991         }
02992 
02993         track= track->next;
02994     }
02995 
02996     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
02997 
02998     return OPERATOR_FINISHED;
02999 }
03000 
03001 void CLIP_OT_lock_tracks(wmOperatorType *ot)
03002 {
03003     static EnumPropertyItem actions_items[] = {
03004             {0, "LOCK", 0, "Lock", "Lock selected tracks"},
03005             {1, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
03006             {2, "TOGGLE", 0, "Toggle", "Toggle locked flag for selected tracks"},
03007             {0, NULL, 0, NULL, NULL}
03008     };
03009 
03010     /* identifiers */
03011     ot->name= "Lock Tracks";
03012     ot->description= "Lock/unlock selected tracks";
03013     ot->idname= "CLIP_OT_lock_tracks";
03014 
03015     /* api callbacks */
03016     ot->exec= lock_tracks_exec;
03017     ot->poll= ED_space_clip_poll;
03018 
03019     /* flags */
03020     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03021 
03022     /* properties */
03023     RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
03024 }
03025 
03026 /********************** track copy color operator *********************/
03027 
03028 static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
03029 {
03030     SpaceClip *sc= CTX_wm_space_clip(C);
03031     MovieClip *clip= ED_space_clip(sc);
03032     MovieTracking *tracking= &clip->tracking;
03033     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
03034     MovieTrackingTrack *track, *act_track= BKE_tracking_active_track(tracking);
03035 
03036     if(!act_track)
03037         return OPERATOR_CANCELLED;
03038 
03039     track= tracksbase->first;
03040     while(track) {
03041         if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
03042             track->flag&= ~TRACK_CUSTOMCOLOR;
03043 
03044             if(act_track->flag&TRACK_CUSTOMCOLOR) {
03045                 copy_v3_v3(track->color, act_track->color);
03046                 track->flag|= TRACK_CUSTOMCOLOR;
03047             }
03048         }
03049 
03050         track= track->next;
03051     }
03052 
03053     WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
03054 
03055     return OPERATOR_FINISHED;
03056 }
03057 
03058 void CLIP_OT_track_copy_color(wmOperatorType *ot)
03059 {
03060     /* identifiers */
03061     ot->name= "Copy Color";
03062     ot->description= "Copy color to all selected tracks";
03063     ot->idname= "CLIP_OT_track_copy_color";
03064 
03065     /* api callbacks */
03066     ot->exec= track_copy_color_exec;
03067     ot->poll= ED_space_clip_poll;
03068 
03069     /* flags */
03070     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03071 }
03072 
03073 /********************** add 2d stabilization tracks operator *********************/
03074 
03075 static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
03076 {
03077     SpaceClip *sc= CTX_wm_space_clip(C);
03078     MovieClip *clip= ED_space_clip(sc);
03079     MovieTracking *tracking= &clip->tracking;
03080     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
03081     MovieTrackingTrack *track;
03082     MovieTrackingStabilization *stab= &tracking->stabilization;
03083     int update= 0;
03084 
03085     track= tracksbase->first;
03086     while(track) {
03087         if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_USE_2D_STAB)==0) {
03088             track->flag|= TRACK_USE_2D_STAB;
03089             stab->tot_track++;
03090 
03091             update= 1;
03092         }
03093 
03094         track= track->next;
03095     }
03096 
03097     if(update) {
03098         stab->ok= 0;
03099 
03100         DAG_id_tag_update(&clip->id, 0);
03101         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
03102     }
03103 
03104     return OPERATOR_FINISHED;
03105 }
03106 
03107 void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
03108 {
03109     /* identifiers */
03110     ot->name= "Add Stabilization Tracks";
03111     ot->description= "Add selected tracks to 2D stabilization tool";
03112     ot->idname= "CLIP_OT_stabilize_2d_add";
03113 
03114     /* api callbacks */
03115     ot->exec= stabilize_2d_add_exec;
03116     ot->poll= ED_space_clip_poll;
03117 
03118     /* flags */
03119     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03120 }
03121 
03122 /********************** remove 2d stabilization tracks operator *********************/
03123 
03124 static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
03125 {
03126     SpaceClip *sc= CTX_wm_space_clip(C);
03127     MovieClip *clip= ED_space_clip(sc);
03128     MovieTracking *tracking= &clip->tracking;
03129     MovieTrackingStabilization *stab= &tracking->stabilization;
03130     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
03131     MovieTrackingTrack *track;
03132     int a= 0, update= 0;
03133 
03134     track= tracksbase->first;
03135     while(track) {
03136         if(track->flag&TRACK_USE_2D_STAB) {
03137             if(a==stab->act_track) {
03138                 track->flag&= ~TRACK_USE_2D_STAB;
03139 
03140                 stab->act_track--;
03141                 stab->tot_track--;
03142 
03143                 if(stab->act_track<0)
03144                     stab->act_track= 0;
03145 
03146                 update= 1;
03147 
03148                 break;
03149             }
03150 
03151             a++;
03152         }
03153 
03154         track= track->next;
03155     }
03156 
03157     if(update) {
03158         stab->ok= 0;
03159 
03160         DAG_id_tag_update(&clip->id, 0);
03161         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
03162     }
03163 
03164     return OPERATOR_FINISHED;
03165 }
03166 
03167 void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
03168 {
03169     /* identifiers */
03170     ot->name= "Remove Stabilization Track";
03171     ot->description= "Remove selected track from stabilization";
03172     ot->idname= "CLIP_OT_stabilize_2d_remove";
03173 
03174     /* api callbacks */
03175     ot->exec= stabilize_2d_remove_exec;
03176     ot->poll= ED_space_clip_poll;
03177 
03178     /* flags */
03179     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03180 }
03181 
03182 /********************** select 2d stabilization tracks operator *********************/
03183 
03184 static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
03185 {
03186     SpaceClip *sc= CTX_wm_space_clip(C);
03187     MovieClip *clip= ED_space_clip(sc);
03188     MovieTracking *tracking= &clip->tracking;
03189     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
03190     MovieTrackingTrack *track;
03191     int update= 0;
03192 
03193     track= tracksbase->first;
03194     while(track) {
03195         if(track->flag&TRACK_USE_2D_STAB) {
03196             BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 0);
03197 
03198             update= 1;
03199         }
03200 
03201         track= track->next;
03202     }
03203 
03204     if(update)
03205         WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, clip);
03206 
03207     return OPERATOR_FINISHED;
03208 }
03209 
03210 void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
03211 {
03212     /* identifiers */
03213     ot->name= "Select Stabilization Tracks";
03214     ot->description= "Select track which are used for stabilization";
03215     ot->idname= "CLIP_OT_stabilize_2d_select";
03216 
03217     /* api callbacks */
03218     ot->exec= stabilize_2d_select_exec;
03219     ot->poll= ED_space_clip_poll;
03220 
03221     /* flags */
03222     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03223 }
03224 
03225 /********************** set 2d stabilization rotation track operator *********************/
03226 
03227 static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
03228 {
03229     SpaceClip *sc= CTX_wm_space_clip(C);
03230     MovieClip *clip= ED_space_clip(sc);
03231     MovieTracking *tracking= &clip->tracking;
03232     MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
03233 
03234     if(act_track) {
03235         MovieTrackingStabilization *stab= &tracking->stabilization;
03236 
03237         stab->rot_track= act_track;
03238         stab->ok= 0;
03239 
03240         DAG_id_tag_update(&clip->id, 0);
03241         WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
03242     }
03243 
03244     return OPERATOR_FINISHED;
03245 }
03246 
03247 void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
03248 {
03249     /* identifiers */
03250     ot->name= "Set Rotation Track";
03251     ot->description= "Use active track to compensate rotation when doing 2D stabilization";
03252     ot->idname= "CLIP_OT_stabilize_2d_set_rotation";
03253 
03254     /* api callbacks */
03255     ot->exec= stabilize_2d_set_rotation_exec;
03256     ot->poll= ED_space_clip_poll;
03257 
03258     /* flags */
03259     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03260 }
03261 
03262 /********************** clean tracks operator *********************/
03263 
03264 static int is_track_clean(MovieTrackingTrack *track, int frames, int del)
03265 {
03266     int ok= 1, a, prev= -1, count= 0;
03267     MovieTrackingMarker *markers= track->markers, *new_markers= NULL;
03268     int start_disabled= 0;
03269     int markersnr= track->markersnr;
03270 
03271     if(del)
03272         new_markers= MEM_callocN(markersnr*sizeof(MovieTrackingMarker), "track cleaned markers");
03273 
03274     for(a= 0; a<markersnr; a++) {
03275         int end= 0;
03276 
03277         if(prev==-1) {
03278             if((markers[a].flag&MARKER_DISABLED)==0)
03279                 prev= a;
03280             else
03281                 start_disabled= 1;
03282         }
03283 
03284         if(prev >= 0) {
03285             end=  a == markersnr-1;
03286             end|= (a < markersnr-1) && (markers[a].framenr != markers[a+1].framenr-1 ||
03287                                         markers[a].flag&MARKER_DISABLED);
03288         }
03289 
03290         if(end) {
03291             int segok= 1, len= 0;
03292 
03293             if(a != prev && markers[a].framenr != markers[a-1].framenr+1)
03294                 len= a-prev;
03295             else if(markers[a].flag&MARKER_DISABLED)
03296                 len= a-prev;
03297             else len= a-prev+1;
03298 
03299             if(frames) {
03300                 if(len < frames) {
03301                     segok= 0;
03302                     ok= 0;
03303 
03304                     if(!del)
03305                         break;
03306                 }
03307             }
03308 
03309             if(del) {
03310                 if(segok) {
03311                     int t= len;
03312 
03313                     if(markers[a].flag&MARKER_DISABLED)
03314                         t++;
03315 
03316                     /* place disabled marker in front of current segment */
03317                     if(start_disabled) {
03318                         memcpy(new_markers+count, markers+prev, sizeof(MovieTrackingMarker));
03319                         new_markers[count].framenr--;
03320                         new_markers[count].flag|= MARKER_DISABLED;
03321 
03322                         count++;
03323                         start_disabled= 0;
03324                     }
03325 
03326                     memcpy(new_markers+count, markers+prev, t*sizeof(MovieTrackingMarker));
03327                     count+= t;
03328                 }
03329                 else if(markers[a].flag&MARKER_DISABLED) {
03330                     /* current segment which would be deleted was finished by disabled marker,
03331                        so next segment should be started from disabled marker */
03332                     start_disabled= 1;
03333                 }
03334             }
03335 
03336             prev= -1;
03337         }
03338     }
03339 
03340     if(del) {
03341         MEM_freeN(track->markers);
03342 
03343         if(count) {
03344             track->markers= new_markers;
03345         }
03346         else {
03347             track->markers= NULL;
03348             MEM_freeN(new_markers);
03349         }
03350 
03351         track->markersnr= count;
03352     }
03353 
03354     return ok;
03355 }
03356 
03357 static int clean_tracks_exec(bContext *C, wmOperator *op)
03358 {
03359     SpaceClip *sc= CTX_wm_space_clip(C);
03360     MovieClip *clip= ED_space_clip(sc);
03361     MovieTracking *tracking= &clip->tracking;
03362     ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
03363     MovieTrackingTrack *track, *next, *act_track= BKE_tracking_active_track(tracking);
03364     int frames= RNA_int_get(op->ptr, "frames");
03365     int action= RNA_enum_get(op->ptr, "action");
03366     float error= RNA_float_get(op->ptr, "error");
03367 
03368     if(error && action==TRACKING_CLEAN_DELETE_SEGMENT)
03369         action= TRACKING_CLEAN_DELETE_TRACK;
03370 
03371     track= tracksbase->first;
03372     while(track) {
03373         next= track->next;
03374 
03375         if((track->flag&TRACK_HIDDEN)==0 && (track->flag&TRACK_LOCKED)==0) {
03376             int ok= 1;
03377 
03378             ok= (is_track_clean(track, frames, action==TRACKING_CLEAN_DELETE_SEGMENT)) &&
03379                 (error == 0.0f || (track->flag&TRACK_HAS_BUNDLE)==0  || track->error < error);
03380 
03381             if(!ok) {
03382                 if(action==TRACKING_CLEAN_SELECT) {
03383                     BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 0);
03384                 }
03385                 else if(action==TRACKING_CLEAN_DELETE_TRACK) {
03386                     if(track==act_track)
03387                         clip->tracking.act_track= NULL;
03388 
03389                     BKE_tracking_free_track(track);
03390                     BLI_freelinkN(tracksbase, track);
03391                     track= NULL;
03392                 }
03393 
03394                 /* happens when all tracking segments are not long enough */
03395                 if(track && track->markersnr==0) {
03396                     if(track==act_track)
03397                         clip->tracking.act_track= NULL;
03398 
03399                     BKE_tracking_free_track(track);
03400                     BLI_freelinkN(tracksbase, track);
03401                 }
03402             }
03403         }
03404 
03405         track= next;
03406     }
03407 
03408     WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, clip);
03409 
03410     return OPERATOR_FINISHED;
03411 }
03412 
03413 static int clean_tracks_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
03414 {
03415     SpaceClip *sc= CTX_wm_space_clip(C);
03416     MovieClip *clip= ED_space_clip(sc);
03417     int frames= RNA_int_get(op->ptr, "frames");
03418     float error= RNA_float_get(op->ptr, "error");
03419     int action= RNA_enum_get(op->ptr, "action");
03420 
03421     if(frames==0 && error==0 && action==0) {
03422         RNA_int_set(op->ptr, "frames", clip->tracking.settings.clean_frames);
03423         RNA_float_set(op->ptr, "error", clip->tracking.settings.clean_error);
03424         RNA_enum_set(op->ptr, "action", clip->tracking.settings.clean_action);
03425     }
03426 
03427     return clean_tracks_exec(C, op);
03428 }
03429 
03430 void CLIP_OT_clean_tracks(wmOperatorType *ot)
03431 {
03432     static EnumPropertyItem actions_items[] = {
03433             {TRACKING_CLEAN_SELECT, "SELECT", 0, "Select", "Select unclean tracks"},
03434             {TRACKING_CLEAN_DELETE_TRACK, "DELETE_TRACK", 0, "Delete Track", "Delete unclean tracks"},
03435             {TRACKING_CLEAN_DELETE_SEGMENT, "DELETE_SEGMENTS", 0, "Delete Segments", "Delete unclean segments of tracks"},
03436             {0, NULL, 0, NULL, NULL}
03437     };
03438 
03439     /* identifiers */
03440     ot->name= "Clean Tracks";
03441     ot->description= "Clean tracks with high error values or few frames";
03442     ot->idname= "CLIP_OT_clean_tracks";
03443 
03444     /* api callbacks */
03445     ot->exec= clean_tracks_exec;
03446     ot->invoke= clean_tracks_invoke;
03447     ot->poll= ED_space_clip_poll;
03448 
03449     /* flags */
03450     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03451 
03452     /* properties */
03453     RNA_def_int(ot->srna, "frames", 0, 0, INT_MAX, "Tracked Frames", "Effect on tracks which are tracked less than specified amount of frames", 0, INT_MAX);
03454     RNA_def_float(ot->srna, "error", 0.0f, 0.0f, FLT_MAX, "Reprojection Error", "Effect on tracks with have got larger reprojection error", 0.0f, 100.0f);
03455     RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Cleanup action to execute");
03456 }
03457 
03458 /********************** add tracking object *********************/
03459 
03460 static int tracking_object_new_exec(bContext *C, wmOperator *UNUSED(op))
03461 {
03462     SpaceClip *sc= CTX_wm_space_clip(C);
03463     MovieClip *clip= ED_space_clip(sc);
03464     MovieTracking *tracking= &clip->tracking;
03465 
03466     BKE_tracking_new_object(tracking, "Object");
03467 
03468     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
03469 
03470     return OPERATOR_FINISHED;
03471 }
03472 
03473 void CLIP_OT_tracking_object_new(wmOperatorType *ot)
03474 {
03475     /* identifiers */
03476     ot->name= "Add Tracking Object";
03477     ot->description= "Add new object for tracking";
03478     ot->idname= "CLIP_OT_tracking_object_new";
03479 
03480     /* api callbacks */
03481     ot->exec= tracking_object_new_exec;
03482     ot->poll= ED_space_clip_poll;
03483 
03484     /* flags */
03485     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03486 }
03487 
03488 /********************** remove tracking object *********************/
03489 
03490 static int tracking_object_remove_exec(bContext *C, wmOperator *op)
03491 {
03492     SpaceClip *sc= CTX_wm_space_clip(C);
03493     MovieClip *clip= ED_space_clip(sc);
03494     MovieTracking *tracking= &clip->tracking;
03495     MovieTrackingObject *object;
03496 
03497     object= BKE_tracking_active_object(tracking);
03498 
03499     if(object->flag&TRACKING_OBJECT_CAMERA) {
03500         BKE_report(op->reports, RPT_WARNING, "Object used for camera tracking can't be deleted");
03501         return OPERATOR_CANCELLED;
03502     }
03503 
03504     BKE_tracking_remove_object(tracking, object);
03505 
03506     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
03507 
03508     return OPERATOR_FINISHED;
03509 }
03510 
03511 void CLIP_OT_tracking_object_remove(wmOperatorType *ot)
03512 {
03513     /* identifiers */
03514     ot->name= "Movie Tracking Object";
03515     ot->description= "Remove object for tracking";
03516     ot->idname= "CLIP_OT_tracking_object_remove";
03517 
03518     /* api callbacks */
03519     ot->exec= tracking_object_remove_exec;
03520     ot->poll= ED_space_clip_poll;
03521 
03522     /* flags */
03523     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03524 }
03525 
03526 /********************** copy tracks to clipboard operator *********************/
03527 
03528 static int copy_tracks_exec(bContext *C, wmOperator *UNUSED(op))
03529 {
03530     SpaceClip *sc = CTX_wm_space_clip(C);
03531     MovieClip *clip = ED_space_clip(sc);
03532     MovieTracking *tracking = &clip->tracking;
03533     MovieTrackingObject *object = BKE_tracking_active_object(tracking);
03534 
03535     clear_invisible_track_selection(sc, clip);
03536 
03537     BKE_tracking_clipboard_copy_tracks(tracking, object);
03538 
03539     return OPERATOR_FINISHED;
03540 }
03541 
03542 void CLIP_OT_copy_tracks(wmOperatorType *ot)
03543 {
03544     /* identifiers */
03545     ot->name = "Copy Tracks";
03546     ot->description = "Copy selected tracks to clipboard";
03547     ot->idname = "CLIP_OT_copy_tracks";
03548 
03549     /* api callbacks */
03550     ot->exec = copy_tracks_exec;
03551     ot->poll = ED_space_clip_poll;
03552 
03553     /* flags */
03554     ot->flag= OPTYPE_REGISTER;
03555 }
03556 
03557 /********************** paste tracks from clipboard operator *********************/
03558 
03559 static int paste_tracks_poll(bContext *C)
03560 {
03561     if (ED_space_clip_poll(C)) {
03562         return BKE_tracking_clipboard_has_tracks();
03563     }
03564 
03565     return 0;
03566 }
03567 
03568 static int paste_tracks_exec(bContext *C, wmOperator *UNUSED(op))
03569 {
03570     SpaceClip *sc = CTX_wm_space_clip(C);
03571     MovieClip *clip = ED_space_clip(sc);
03572     MovieTracking *tracking = &clip->tracking;
03573     MovieTrackingObject *object = BKE_tracking_active_object(tracking);
03574 
03575     BKE_tracking_clipboard_paste_tracks(tracking, object);
03576 
03577     WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
03578 
03579     return OPERATOR_FINISHED;
03580 }
03581 
03582 void CLIP_OT_paste_tracks(wmOperatorType *ot)
03583 {
03584     /* identifiers */
03585     ot->name = "Paste Tracks";
03586     ot->description = "Paste tracks from clipboard";
03587     ot->idname = "CLIP_OT_paste_tracks";
03588 
03589     /* api callbacks */
03590     ot->exec = paste_tracks_exec;
03591     ot->poll = paste_tracks_poll;
03592 
03593     /* flags */
03594     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03595 }