Blender V2.61 - r43446
|
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 }