=========================== - Fixed some silly things ni DNA design. Now all reconstruction data is stored in Tracking->Reconstruction. Please, re-solve your cameras -- reconstruction data wouldn't be read from files saved in blender below this commit. - RNA accessors for reconstruction data. - Store average reconstruction error in new reconstruction structure and show it in clip editor header after reconstruction. - Highlight failed to reconstruct frames with red in cache line. - Added "group" "Failed Tracks" in Select Grouped operator, Meant to be used for selecting tracks bundles from which failed to to be solved. - Hotkey to delete marker: Shift-X. - Jump to next/prev failed frame operator. Hotkeys are Ctrl-Shift-Left/Right Arrow.
2595 lines
66 KiB
C
2595 lines
66 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2011 Blender Foundation.
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* Contributor(s): Blender Foundation,
|
|
* Sergey Sharybin
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_camera_types.h"
|
|
#include "DNA_movieclip_types.h"
|
|
#include "DNA_object_types.h" /* SELECT */
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "BLI_utildefines.h"
|
|
#include "BLI_math.h"
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_rect.h"
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BKE_main.h"
|
|
#include "BKE_context.h"
|
|
#include "BKE_movieclip.h"
|
|
#include "BKE_tracking.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_depsgraph.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_report.h"
|
|
#include "BKE_scene.h"
|
|
#include "BKE_sound.h"
|
|
|
|
#include "WM_api.h"
|
|
#include "WM_types.h"
|
|
|
|
#include "ED_screen.h"
|
|
#include "ED_clip.h"
|
|
#include "ED_keyframing.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
#include "IMB_imbuf.h"
|
|
|
|
#include "UI_interface.h"
|
|
|
|
#include "RNA_access.h"
|
|
#include "RNA_define.h"
|
|
|
|
#include "PIL_time.h"
|
|
|
|
#include "UI_view2d.h"
|
|
|
|
#include "clip_intern.h" // own include
|
|
|
|
/** \file blender/editors/space_clip/tracking_ops.c
|
|
* \ingroup spclip
|
|
*/
|
|
|
|
static int space_clip_tracking_poll(bContext *C)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
|
|
if(sc && sc->clip)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int space_clip_frame_poll(bContext *C)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
|
|
if(sc) {
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
|
|
if(clip)
|
|
return BKE_movieclip_has_frame(clip, &sc->user);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int space_clip_frame_camera_poll(bContext *C)
|
|
{
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
if(space_clip_frame_poll(C)) {
|
|
return scene->camera != NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int space_clip_camera_poll(bContext *C)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
if(sc && sc->clip && scene->camera)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/********************** add marker operator *********************/
|
|
|
|
static void add_marker(SpaceClip *sc, float x, float y)
|
|
{
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
int width, height, sel= 0;
|
|
|
|
ED_space_clip_size(sc, &width, &height);
|
|
|
|
track= BKE_tracking_add_track(&clip->tracking, x, y, sc->user.framenr, width, height);
|
|
|
|
sel= TRACK_AREA_POINT;
|
|
if(sc->flag&SC_SHOW_MARKER_PATTERN) sel|= TRACK_AREA_PAT;
|
|
if(sc->flag&SC_SHOW_MARKER_SEARCH) sel|= TRACK_AREA_SEARCH;
|
|
|
|
BKE_movieclip_select_track(clip, track, sel, 0);
|
|
BKE_movieclip_set_selection(clip, MCLIP_SEL_TRACK, track);
|
|
}
|
|
|
|
static int add_marker_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
float pos[2];
|
|
int width, height;
|
|
|
|
ED_space_clip_size(sc, &width, &height);
|
|
if(!width || !height)
|
|
return OPERATOR_CANCELLED;
|
|
|
|
RNA_float_get_array(op->ptr, "location", pos);
|
|
|
|
add_marker(sc, pos[0], pos[1]);
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int add_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
|
{
|
|
float co[2];
|
|
|
|
ED_clip_mouse_pos(C, event, co);
|
|
|
|
RNA_float_set_array(op->ptr, "location", co);
|
|
|
|
return add_marker_exec(C, op);
|
|
}
|
|
|
|
void CLIP_OT_add_marker(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Add Marker";
|
|
ot->idname= "CLIP_OT_add_marker";
|
|
ot->description= "Place new marker at specified location";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= add_marker_invoke;
|
|
ot->exec= add_marker_exec;
|
|
ot->poll= space_clip_frame_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
|
|
"Location", "Location of marker on frame.", -1.f, 1.f);
|
|
}
|
|
|
|
/********************** delete track operator *********************/
|
|
|
|
static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track= clip->tracking.tracks.first, *next;
|
|
int has_bundle= 0;
|
|
|
|
while(track) {
|
|
next= track->next;
|
|
|
|
if(TRACK_SELECTED(track)) {
|
|
if(track->flag&TRACK_HAS_BUNDLE)
|
|
has_bundle= 1;
|
|
|
|
BKE_tracking_free_track(track);
|
|
BLI_freelinkN(&clip->tracking.tracks, track);
|
|
}
|
|
|
|
track= next;
|
|
}
|
|
|
|
BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
|
|
|
|
if(has_bundle)
|
|
WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_delete_track(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Delete Track";
|
|
ot->idname= "CLIP_OT_delete_track";
|
|
ot->description= "Delete selected tracks";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= WM_operator_confirm;
|
|
ot->exec= delete_track_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** delete marker operator *********************/
|
|
|
|
static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track= clip->tracking.tracks.first, *next;
|
|
int framenr= sc->user.framenr, sel_type;
|
|
void *sel;
|
|
|
|
BKE_movieclip_last_selection(clip, &sel_type, &sel);
|
|
|
|
while(track) {
|
|
next= track->next;
|
|
|
|
if(TRACK_SELECTED(track)) {
|
|
MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, framenr);
|
|
|
|
if(marker) {
|
|
if(track->markersnr==1) {
|
|
if(sel_type==MCLIP_SEL_TRACK && sel==track)
|
|
BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
|
|
|
|
BKE_tracking_free_track(track);
|
|
BLI_freelinkN(&clip->tracking.tracks, track);
|
|
} else {
|
|
BKE_tracking_delete_marker(track, framenr);
|
|
}
|
|
}
|
|
}
|
|
|
|
track= next;
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_delete_marker(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Delete Marker";
|
|
ot->idname= "CLIP_OT_delete_marker";
|
|
ot->description= "Delete marker for current frame from selected tracks";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= WM_operator_confirm;
|
|
ot->exec= delete_marker_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** slide marker operator *********************/
|
|
|
|
#define SLIDE_ACTION_POS 0
|
|
#define SLIDE_ACTION_SIZE 1
|
|
#define SLIDE_ACTION_OFFSET 2
|
|
|
|
typedef struct {
|
|
int area, action;
|
|
MovieTrackingTrack *track;
|
|
MovieTrackingMarker *marker;
|
|
|
|
int mval[2];
|
|
int width, height;
|
|
float *min, *max, *pos, *offset;
|
|
float smin[2], smax[2], spos[2], soff[2];
|
|
|
|
int lock, accurate;
|
|
} SlideMarkerData;
|
|
|
|
static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTrack *track,
|
|
MovieTrackingMarker *marker, wmEvent *event, int area, int action, int width, int height)
|
|
{
|
|
SlideMarkerData *data= MEM_callocN(sizeof(SlideMarkerData), "slide marker data");
|
|
|
|
marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
|
|
|
|
data->area= area;
|
|
data->action= action;
|
|
data->track= track;
|
|
data->marker= marker;
|
|
|
|
if(area==TRACK_AREA_POINT) {
|
|
data->pos= marker->pos;
|
|
data->offset= track->offset;
|
|
copy_v2_v2(data->spos, marker->pos);
|
|
copy_v2_v2(data->soff, track->offset);
|
|
} else if(area==TRACK_AREA_PAT) {
|
|
if(action==SLIDE_ACTION_SIZE) {
|
|
data->min= track->pat_min;
|
|
data->max= track->pat_max;
|
|
} else {
|
|
data->pos= marker->pos;
|
|
data->offset= track->offset;
|
|
copy_v2_v2(data->spos, marker->pos);
|
|
copy_v2_v2(data->soff, track->offset);
|
|
}
|
|
} else if(area==TRACK_AREA_SEARCH) {
|
|
data->min= track->search_min;
|
|
data->max= track->search_max;
|
|
}
|
|
|
|
if(area==TRACK_AREA_SEARCH || (area==TRACK_AREA_PAT && action!=SLIDE_ACTION_OFFSET)) {
|
|
copy_v2_v2(data->smin, data->min);
|
|
copy_v2_v2(data->smax, data->max);
|
|
}
|
|
|
|
data->mval[0]= event->mval[0];
|
|
data->mval[1]= event->mval[1];
|
|
|
|
data->width= width;
|
|
data->height= height;
|
|
|
|
if(action==SLIDE_ACTION_SIZE)
|
|
data->lock= 1;
|
|
|
|
return data;
|
|
}
|
|
|
|
/* corner = 0: right-bottom corner,
|
|
corner = 1: left-top corner */
|
|
static int mouse_on_corner(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
|
|
int area, float co[2], int corner, int width, int height)
|
|
{
|
|
int inside= 0;
|
|
float size= 12.f;
|
|
float min[2], max[2];
|
|
float crn[2], dx, dy, tdx, tdy;
|
|
|
|
if(area==TRACK_AREA_SEARCH) {
|
|
copy_v2_v2(min, track->search_min);
|
|
copy_v2_v2(max, track->search_max);
|
|
} else {
|
|
copy_v2_v2(min, track->pat_min);
|
|
copy_v2_v2(max, track->pat_max);
|
|
}
|
|
|
|
dx= size/width/sc->zoom;
|
|
dy= size/height/sc->zoom;
|
|
|
|
tdx= 5.0f/width/sc->zoom;
|
|
tdy= 5.0f/height/sc->zoom;
|
|
|
|
dx= MIN2(dx, (max[0]-min[0])/6.f) + tdx;
|
|
dy= MIN2(dy, (max[1]-min[1])/6.f) + tdy;
|
|
|
|
if(corner==0) {
|
|
crn[0]= marker->pos[0]+max[0];
|
|
crn[1]= marker->pos[1]+min[1];
|
|
|
|
inside= co[0]>=crn[0]-dx && co[0]<=crn[0]+tdx && co[1]>=crn[1]-tdy && co[1]<=crn[1]+dy;
|
|
} else {
|
|
crn[0]= marker->pos[0]+min[0];
|
|
crn[1]= marker->pos[1]+max[1];
|
|
|
|
inside= co[0]>=crn[0]-dx && co[0]<=crn[0]+dx && co[1]>=crn[1]-dy && co[1]<=crn[1]+dy;
|
|
}
|
|
|
|
return inside;
|
|
}
|
|
|
|
static int mouse_on_offset(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
|
|
float co[2], int width, int height)
|
|
{
|
|
float pos[2], dx, dy;
|
|
|
|
add_v2_v2v2(pos, marker->pos, track->offset);
|
|
|
|
dx= 12.f/width/sc->zoom;
|
|
dy= 12.f/height/sc->zoom;
|
|
|
|
dx=MIN2(dx, (track->pat_max[0]-track->pat_min[0])/2.f);
|
|
dy=MIN2(dy, (track->pat_max[1]-track->pat_min[1])/2.f);
|
|
|
|
return co[0]>=pos[0]-dx && co[0]<=pos[0]+dx && co[1]>=pos[1]-dy && co[1]<=pos[1]+dy;
|
|
}
|
|
|
|
static void hide_cursor(bContext *C)
|
|
{
|
|
wmWindow *win= CTX_wm_window(C);
|
|
|
|
WM_cursor_set(win, CURSOR_NONE);
|
|
}
|
|
|
|
static void show_cursor(bContext *C)
|
|
{
|
|
wmWindow *win= CTX_wm_window(C);
|
|
|
|
WM_cursor_set(win, CURSOR_STD);
|
|
}
|
|
|
|
static void *slide_marker_customdata(bContext *C, wmEvent *event)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
int width, height;
|
|
float co[2];
|
|
void *customdata= NULL;
|
|
|
|
ED_space_clip_size(sc, &width, &height);
|
|
|
|
if(width==0 || height==0)
|
|
return NULL;
|
|
|
|
ED_clip_mouse_pos(C, event, co);
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
|
|
MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
|
|
|
|
if((marker->flag&MARKER_DISABLED)==0) {
|
|
if(!customdata)
|
|
if(mouse_on_offset(sc, track, marker, co, width, height))
|
|
customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_POINT, SLIDE_ACTION_POS, width, height);
|
|
|
|
if(sc->flag&SC_SHOW_MARKER_SEARCH) {
|
|
if(mouse_on_corner(sc, track, marker, TRACK_AREA_SEARCH, co, 1, width, height))
|
|
customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, SLIDE_ACTION_OFFSET, width, height);
|
|
else if(mouse_on_corner(sc, track, marker, TRACK_AREA_SEARCH, co, 0, width, height))
|
|
customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, SLIDE_ACTION_SIZE, width, height);
|
|
}
|
|
|
|
if(!customdata && sc->flag&SC_SHOW_MARKER_PATTERN) {
|
|
if(mouse_on_corner(sc, track, marker, TRACK_AREA_PAT, co, 1, width, height))
|
|
customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, SLIDE_ACTION_OFFSET, width, height);
|
|
|
|
if(!customdata && mouse_on_corner(sc, track, marker, TRACK_AREA_PAT, co, 0, width, height))
|
|
customdata= create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, SLIDE_ACTION_SIZE, width, height);
|
|
}
|
|
|
|
if(customdata)
|
|
break;
|
|
}
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
return customdata;
|
|
}
|
|
|
|
static int slide_marker_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
|
{
|
|
op->customdata= slide_marker_customdata(C, event);
|
|
|
|
if(op->customdata) {
|
|
hide_cursor(C);
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
}
|
|
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
static void cancel_mouse_slide(SlideMarkerData *data)
|
|
{
|
|
/* cancel sliding */
|
|
if(data->area == TRACK_AREA_POINT) {
|
|
if(data->action==SLIDE_ACTION_OFFSET)
|
|
copy_v2_v2(data->offset, data->soff);
|
|
else
|
|
copy_v2_v2(data->pos, data->spos);
|
|
} else {
|
|
if(data->action==SLIDE_ACTION_SIZE) {
|
|
copy_v2_v2(data->min, data->smin);
|
|
copy_v2_v2(data->max, data->smax);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
SlideMarkerData *data= (SlideMarkerData *)op->customdata;
|
|
float dx, dy, mdelta[2];
|
|
|
|
switch(event->type) {
|
|
case LEFTCTRLKEY:
|
|
case RIGHTCTRLKEY:
|
|
case LEFTSHIFTKEY:
|
|
case RIGHTSHIFTKEY:
|
|
if(data->action==SLIDE_ACTION_SIZE)
|
|
if(ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY))
|
|
data->lock= event->val==KM_RELEASE;
|
|
|
|
if(ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
|
|
data->accurate= event->val==KM_PRESS;
|
|
|
|
/* no break! update area size */
|
|
|
|
case MOUSEMOVE:
|
|
mdelta[0]= event->mval[0]-data->mval[0];
|
|
mdelta[1]= event->mval[1]-data->mval[1];
|
|
|
|
dx= mdelta[0]/data->width/sc->zoom;
|
|
|
|
if(data->lock) dy= -dx/data->height*data->width;
|
|
else dy= mdelta[1]/data->height/sc->zoom;
|
|
|
|
if(data->accurate) {
|
|
dx/= 5;
|
|
dy/= 5;
|
|
}
|
|
|
|
if(data->area==TRACK_AREA_POINT) {
|
|
if(data->action==SLIDE_ACTION_OFFSET) {
|
|
data->offset[0]= data->soff[0]+dx;
|
|
data->offset[1]= data->soff[1]+dy;
|
|
} else {
|
|
data->pos[0]= data->spos[0]+dx;
|
|
data->pos[1]= data->spos[1]+dy;
|
|
|
|
data->marker->flag&= ~MARKER_TRACKED;
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
|
|
DAG_id_tag_update(&sc->clip->id, 0);
|
|
} else {
|
|
if(data->action==SLIDE_ACTION_SIZE) {
|
|
data->min[0]= data->smin[0]-dx;
|
|
data->max[0]= data->smax[0]+dx;
|
|
|
|
data->min[1]= data->smin[1]+dy;
|
|
data->max[1]= data->smax[1]-dy;
|
|
|
|
if(data->area==TRACK_AREA_SEARCH) BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_DIM);
|
|
else BKE_tracking_clamp_track(data->track, CLAMP_PAT_DIM);
|
|
} else {
|
|
float d[2]={dx, dy};
|
|
|
|
if(data->area==TRACK_AREA_SEARCH) {
|
|
add_v2_v2v2(data->min, data->smin, d);
|
|
add_v2_v2v2(data->max, data->smax, d);
|
|
} else {
|
|
add_v2_v2v2(data->pos, data->spos, d);
|
|
add_v2_v2v2(data->pos, data->spos, d);
|
|
|
|
sub_v2_v2v2(data->offset, data->soff, d);
|
|
}
|
|
|
|
if(data->area==TRACK_AREA_SEARCH)
|
|
BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_POS);
|
|
}
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
|
|
|
|
break;
|
|
|
|
case LEFTMOUSE:
|
|
if(event->val==KM_RELEASE) {
|
|
MEM_freeN(op->customdata);
|
|
|
|
show_cursor(C);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
break;
|
|
|
|
case ESCKEY:
|
|
cancel_mouse_slide(op->customdata);
|
|
|
|
MEM_freeN(op->customdata);
|
|
|
|
show_cursor(C);
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
|
|
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
}
|
|
|
|
void CLIP_OT_slide_marker(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Slide Marker";
|
|
ot->description= "Slide marker areas";
|
|
ot->idname= "CLIP_OT_slide_marker";
|
|
|
|
/* api callbacks */
|
|
//ot->exec= slide_marker_exec;
|
|
ot->poll= space_clip_frame_poll;
|
|
ot->invoke= slide_marker_invoke;
|
|
ot->modal= slide_marker_modal;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_GRAB_POINTER|OPTYPE_BLOCKING;
|
|
|
|
/* properties */
|
|
RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
|
|
"Offset", "Offset in floating point units, 1.0 is the width and height of the image.", -FLT_MAX, FLT_MAX);
|
|
}
|
|
|
|
/********************** mouse select operator *********************/
|
|
|
|
static int mouse_on_side(float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
|
|
{
|
|
if(x1>x2) SWAP(float, x1, x2);
|
|
if(y1>y2) SWAP(float, y1, y2);
|
|
|
|
return (co[0]>=x1-epsx && co[0]<=x2+epsx) && (co[1]>=y1-epsy && co[1]<=y2+epsy);
|
|
}
|
|
|
|
static int mouse_on_rect(float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
|
|
{
|
|
return mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+max[0], pos[1]+min[1], epsx, epsy) ||
|
|
mouse_on_side(co, pos[0]+min[0], pos[1]+min[1], pos[0]+min[0], pos[1]+max[1], epsx, epsy) ||
|
|
mouse_on_side(co, pos[0]+min[0], pos[1]+max[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy) ||
|
|
mouse_on_side(co, pos[0]+max[0], pos[1]+min[1], pos[0]+max[0], pos[1]+max[1], epsx, epsy);
|
|
}
|
|
|
|
static int track_mouse_area(SpaceClip *sc, float co[2], MovieTrackingTrack *track)
|
|
{
|
|
MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
|
|
float epsx, epsy;
|
|
int width, height;
|
|
|
|
ED_space_clip_size(sc, &width, &height);
|
|
|
|
epsx= MIN4(track->pat_min[0]-track->search_min[0], track->search_max[0]-track->pat_max[0],
|
|
fabsf(track->pat_min[0]), fabsf(track->pat_max[0])) / 2;
|
|
epsy= MIN4(track->pat_min[1]-track->search_min[1], track->search_max[1]-track->pat_max[1],
|
|
fabsf(track->pat_min[1]), fabsf(track->pat_max[1])) / 2;
|
|
|
|
epsx= MAX2(epsy, 2.f / width);
|
|
epsy= MAX2(epsy, 2.f / height);
|
|
|
|
if(sc->flag&SC_SHOW_MARKER_SEARCH)
|
|
if(mouse_on_rect(co, marker->pos, track->search_min, track->search_max, epsx, epsy))
|
|
return TRACK_AREA_SEARCH;
|
|
|
|
if((marker->flag&MARKER_DISABLED)==0) {
|
|
if(sc->flag&SC_SHOW_MARKER_PATTERN)
|
|
if(mouse_on_rect(co, marker->pos, track->pat_min, track->pat_max, epsx, epsy))
|
|
return TRACK_AREA_PAT;
|
|
|
|
epsx= 12.f/width;
|
|
epsy= 12.f/height;
|
|
|
|
if(fabsf(co[0]-marker->pos[0]-track->offset[0])< epsx && fabsf(co[1]-marker->pos[1]-track->offset[1])<=epsy)
|
|
return TRACK_AREA_POINT;
|
|
}
|
|
|
|
return TRACK_AREA_NONE;
|
|
}
|
|
|
|
static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
|
|
{
|
|
float d1, d2, d3, d4;
|
|
float p[2]= {co[0]-pos[0], co[1]-pos[1]};
|
|
float v1[2]= {min[0], min[1]}, v2[2]= {max[0], min[1]},
|
|
v3[2]= {max[0], max[1]}, v4[2]= {min[0], max[1]};
|
|
|
|
d1= dist_to_line_segment_v2(p, v1, v2);
|
|
d2= dist_to_line_segment_v2(p, v2, v3);
|
|
d3= dist_to_line_segment_v2(p, v3, v4);
|
|
d4= dist_to_line_segment_v2(p, v4, v1);
|
|
|
|
return MIN4(d1, d2, d3, d4);
|
|
}
|
|
|
|
static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, MovieClip *clip, float co[2])
|
|
{
|
|
MovieTrackingTrack *track= NULL, *cur;
|
|
float mindist= 0.0f;
|
|
|
|
cur= clip->tracking.tracks.first;
|
|
while(cur) {
|
|
MovieTrackingMarker *marker= BKE_tracking_get_marker(cur, sc->user.framenr);
|
|
|
|
if(((cur->flag&TRACK_HIDDEN)==0) && MARKER_VISIBLE(sc, marker)) {
|
|
float dist, d1, d2=FLT_MAX, d3=FLT_MAX;
|
|
|
|
d1= sqrtf((co[0]-marker->pos[0]-cur->offset[0])*(co[0]-marker->pos[0]-cur->offset[0])+
|
|
(co[1]-marker->pos[1]-cur->offset[1])*(co[1]-marker->pos[1]-cur->offset[1])); /* distance to marker point */
|
|
|
|
/* distance to pattern boundbox */
|
|
if(sc->flag&SC_SHOW_MARKER_PATTERN)
|
|
d2= dist_to_rect(co, marker->pos, cur->pat_min, cur->pat_max);
|
|
|
|
/* distance to search boundbox */
|
|
if(sc->flag&SC_SHOW_MARKER_SEARCH)
|
|
d3= dist_to_rect(co, marker->pos, cur->search_min, cur->search_max);
|
|
|
|
/* choose minimal distance. useful for cases of overlapped markers. */
|
|
dist= MIN3(d1, d2, d3);
|
|
|
|
if(track==NULL || dist<mindist) {
|
|
track= cur;
|
|
mindist= dist;
|
|
}
|
|
}
|
|
|
|
cur= cur->next;
|
|
}
|
|
|
|
return track;
|
|
}
|
|
|
|
static int mouse_select(bContext *C, float co[2], int extend)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track= NULL; /* selected marker */
|
|
int hidden= 0;
|
|
|
|
track= find_nearest_track(sc, clip, co);
|
|
|
|
if((sc->flag&SC_SHOW_MARKER_PATTERN)==0) hidden|= TRACK_AREA_PAT;
|
|
if((sc->flag&SC_SHOW_MARKER_SEARCH)==0) hidden|= TRACK_AREA_SEARCH;
|
|
|
|
if(track) {
|
|
int area= track_mouse_area(sc, co, track);
|
|
|
|
if(!extend || !TRACK_SELECTED(track))
|
|
area= TRACK_AREA_ALL & ~hidden;
|
|
|
|
if(extend && TRACK_AREA_SELECTED(track, area)) {
|
|
BKE_movieclip_deselect_track(clip, track, area);
|
|
} else {
|
|
if(area==TRACK_AREA_POINT)
|
|
area= TRACK_AREA_ALL & ~hidden;
|
|
|
|
BKE_movieclip_select_track(clip, track, area, extend);
|
|
BKE_movieclip_set_selection(clip, MCLIP_SEL_TRACK, track);
|
|
}
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int select_exec(bContext *C, wmOperator *op)
|
|
{
|
|
float co[2];
|
|
int extend;
|
|
|
|
RNA_float_get_array(op->ptr, "location", co);
|
|
extend= RNA_boolean_get(op->ptr, "extend");
|
|
|
|
return mouse_select(C, co, extend);
|
|
}
|
|
|
|
static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
|
{
|
|
void *customdata;
|
|
float co[2];
|
|
int extend= RNA_boolean_get(op->ptr, "extend");
|
|
|
|
if(!extend) {
|
|
customdata= slide_marker_customdata(C, event);
|
|
if(customdata) {
|
|
MEM_freeN(customdata);
|
|
return OPERATOR_PASS_THROUGH;
|
|
}
|
|
}
|
|
|
|
ED_clip_mouse_pos(C, event, co);
|
|
RNA_float_set_array(op->ptr, "location", co);
|
|
|
|
return select_exec(C, op);
|
|
}
|
|
|
|
void CLIP_OT_select(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Select";
|
|
ot->description= "Select tracking markers";
|
|
ot->idname= "CLIP_OT_select";
|
|
|
|
/* api callbacks */
|
|
ot->exec= select_exec;
|
|
ot->invoke= select_invoke;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
RNA_def_boolean(ot->srna, "extend", 0,
|
|
"Extend", "Extend selection rather than clearing the existing selection.");
|
|
RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
|
|
"Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
|
|
}
|
|
|
|
/********************** border select operator *********************/
|
|
|
|
static int border_select_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
rcti rect;
|
|
rctf rectf;
|
|
int change= 0, mode;
|
|
|
|
/* get rectangle from operator */
|
|
rect.xmin= RNA_int_get(op->ptr, "xmin");
|
|
rect.ymin= RNA_int_get(op->ptr, "ymin");
|
|
rect.xmax= RNA_int_get(op->ptr, "xmax");
|
|
rect.ymax= RNA_int_get(op->ptr, "ymax");
|
|
|
|
ED_clip_point_stable_pos(C, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
|
|
ED_clip_point_stable_pos(C, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
|
|
|
|
mode= RNA_int_get(op->ptr, "gesture_mode");
|
|
|
|
/* do actual selection */
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if((track->flag&TRACK_HIDDEN)==0) {
|
|
MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
|
|
|
|
if(MARKER_VISIBLE(sc, marker) && BLI_in_rctf(&rectf, marker->pos[0], marker->pos[1])) {
|
|
BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
|
|
|
|
change= 1;
|
|
}
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
|
|
|
|
if(change) {
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
void CLIP_OT_select_border(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Border Select";
|
|
ot->description= "Select markers using border selection";
|
|
ot->idname= "CLIP_OT_select_border";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= WM_border_select_invoke;
|
|
ot->exec= border_select_exec;
|
|
ot->modal= WM_border_select_modal;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
WM_operator_properties_gesture_border(ot, FALSE);
|
|
}
|
|
|
|
/********************** circle select operator *********************/
|
|
|
|
static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
|
|
{
|
|
/* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
|
|
float x, y;
|
|
|
|
x= (marker->pos[0] - offset[0])*ellipse[0];
|
|
y= (marker->pos[1] - offset[1])*ellipse[1];
|
|
|
|
return x*x + y*y < 1.0f;
|
|
}
|
|
|
|
static int circle_select_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
ARegion *ar= CTX_wm_region(C);
|
|
MovieTrackingTrack *track;
|
|
int x, y, radius, width, height, mode, change= 0;
|
|
float zoomx, zoomy, offset[2], ellipse[2];
|
|
|
|
/* get operator properties */
|
|
x= RNA_int_get(op->ptr, "x");
|
|
y= RNA_int_get(op->ptr, "y");
|
|
radius= RNA_int_get(op->ptr, "radius");
|
|
|
|
mode= RNA_int_get(op->ptr, "gesture_mode");
|
|
|
|
/* compute ellipse and position in unified coordinates */
|
|
ED_space_clip_size(sc, &width, &height);
|
|
ED_space_clip_zoom(sc, ar, &zoomx, &zoomy);
|
|
|
|
ellipse[0]= width*zoomx/radius;
|
|
ellipse[1]= height*zoomy/radius;
|
|
|
|
ED_clip_point_stable_pos(C, x, y, &offset[0], &offset[1]);
|
|
|
|
/* do selection */
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if((track->flag&TRACK_HIDDEN)==0) {
|
|
MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
|
|
|
|
if(MARKER_VISIBLE(sc, marker) && marker_inside_ellipse(marker, offset, ellipse)) {
|
|
BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, mode!=GESTURE_MODAL_SELECT);
|
|
|
|
change= 1;
|
|
}
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
|
|
|
|
if(change) {
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
void CLIP_OT_select_circle(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Circle Select";
|
|
ot->description= "Select markers using circle selection";
|
|
ot->idname= "CLIP_OT_select_circle";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= WM_gesture_circle_invoke;
|
|
ot->modal= WM_gesture_circle_modal;
|
|
ot->exec= circle_select_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
|
|
RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
|
|
RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
|
|
RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
|
|
}
|
|
|
|
/********************** select all operator *********************/
|
|
|
|
static int select_all_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track= NULL; /* selected track */
|
|
int action= RNA_enum_get(op->ptr, "action");
|
|
int sel_type, framenr= sc->user.framenr;
|
|
void *sel;
|
|
|
|
if(action == SEL_TOGGLE){
|
|
action= SEL_SELECT;
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
int selected= 0;
|
|
|
|
selected|= track->flag&SELECT;
|
|
if(sc->flag&SC_SHOW_MARKER_PATTERN) selected|= track->pat_flag&SELECT;
|
|
if(sc->flag&SC_SHOW_MARKER_SEARCH) selected|= track->search_flag&SELECT;
|
|
|
|
if(selected) {
|
|
action= SEL_DESELECT;
|
|
break;
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
}
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if((track->flag&TRACK_HIDDEN)==0) {
|
|
MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
|
|
|
|
if(marker && MARKER_VISIBLE(sc, marker)) {
|
|
switch (action) {
|
|
case SEL_SELECT:
|
|
track->flag|= SELECT;
|
|
if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag|= SELECT;
|
|
if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag|= SELECT;
|
|
break;
|
|
case SEL_DESELECT:
|
|
track->flag&= ~SELECT;
|
|
track->pat_flag&= ~SELECT;
|
|
track->search_flag&= ~SELECT;
|
|
break;
|
|
case SEL_INVERT:
|
|
track->flag^= SELECT;
|
|
if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag^= SELECT;
|
|
if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag^= SELECT;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
BKE_movieclip_last_selection(clip, &sel_type, &sel);
|
|
if(sel_type==MCLIP_SEL_TRACK)
|
|
if(!TRACK_SELECTED(((MovieTrackingTrack*)sel)))
|
|
BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
|
|
|
|
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_select_all(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Select or Deselect All";
|
|
ot->description= "Change selection of all tracking markers";
|
|
ot->idname= "CLIP_OT_select_all";
|
|
|
|
/* api callbacks */
|
|
ot->exec= select_all_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
WM_operator_properties_select_all(ot);
|
|
}
|
|
|
|
/********************** select grouped operator *********************/
|
|
|
|
static int select_groped_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track, *sel;
|
|
MovieTrackingMarker *marker;
|
|
int group= RNA_enum_get(op->ptr, "group");
|
|
int sel_type;
|
|
|
|
BKE_movieclip_last_selection(clip, &sel_type, (void**)&sel);
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
int ok= 0;
|
|
|
|
marker= BKE_tracking_get_marker(track, sc->user.framenr);
|
|
|
|
if(group==0) { /* Keyframed */
|
|
ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED)==0;
|
|
}
|
|
else if(group==1) { /* Estimated */
|
|
ok= marker->framenr!=sc->user.framenr;
|
|
}
|
|
else if(group==2) { /* tracked */
|
|
ok= marker->framenr==sc->user.framenr && (marker->flag&MARKER_TRACKED);
|
|
}
|
|
else if(group==3) { /* locked */
|
|
ok= track->flag&TRACK_LOCKED;
|
|
}
|
|
else if(group==4) { /* disabled */
|
|
ok= marker->flag&MARKER_DISABLED;
|
|
}
|
|
else if(group==5) { /* color */
|
|
if(sel_type==MCLIP_SEL_TRACK) {
|
|
ok= (track->flag&TRACK_CUSTOMCOLOR) == (sel->flag&TRACK_CUSTOMCOLOR);
|
|
|
|
if(ok && track->flag&TRACK_CUSTOMCOLOR)
|
|
ok= equals_v3v3(track->color, sel->color);
|
|
}
|
|
}
|
|
else if(group==6) { /* failed */
|
|
ok= (track->flag&TRACK_HAS_BUNDLE) == 0;
|
|
}
|
|
|
|
if(ok) {
|
|
track->flag|= SELECT;
|
|
if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag|= SELECT;;
|
|
if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag|= SELECT;;
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_select_grouped(wmOperatorType *ot)
|
|
{
|
|
static EnumPropertyItem select_group_items[] = {
|
|
{0, "KEYFRAMED", 0, "Keyframed tracks", "Select all keyframed tracks"},
|
|
{1, "ESTIMATED", 0, "Estimated tracks", "Select all estimated tracks"},
|
|
{2, "TRACKED", 0, "Tracked tracks", "Select all tracked tracks"},
|
|
{3, "LOCKED", 0, "Locked tracks", "Select all locked tracks"},
|
|
{4, "DISABLED", 0, "Disabled tracks", "Select all disabled tracks"},
|
|
{5, "COLOR", 0, "Tracks with same color", "Select all tracks with same color as actiev track"},
|
|
{6, "FAILED", 0, "Failed Tracks", "Select all tracks which failed to be reconstructed"},
|
|
{0, NULL, 0, NULL, NULL}
|
|
};
|
|
|
|
/* identifiers */
|
|
ot->name= "Join Tracks";
|
|
ot->description= "Joint Selected Tracks";
|
|
ot->idname= "CLIP_OT_select_grouped";
|
|
|
|
/* api callbacks */
|
|
ot->exec= select_groped_exec;
|
|
ot->poll= space_clip_frame_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* proeprties */
|
|
RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
|
|
}
|
|
|
|
/********************** track operator *********************/
|
|
|
|
typedef struct TrackMarkersJob {
|
|
struct MovieTrackingContext *context; /* tracking context */
|
|
int sfra, efra, lastfra; /* Start, end and recently tracked frames */
|
|
int backwards; /* Backwards tracking flag */
|
|
MovieClip *clip; /* Clip which is tracking */
|
|
float delay; /* Delay in milliseconds to allow tracking at fixed FPS */
|
|
|
|
struct Main *main;
|
|
struct Scene *scene;
|
|
struct bScreen *screen;
|
|
} TrackMarkersJob;
|
|
|
|
static int track_markers_testbreak(void)
|
|
{
|
|
return G.afbreek;
|
|
}
|
|
|
|
static void track_init_markers(SpaceClip *sc, MovieClip *clip)
|
|
{
|
|
MovieTrackingTrack *track;
|
|
int framenr= sc->user.framenr;
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if((track->flag&TRACK_HIDDEN)==0 && (track->flag&TRACK_LOCKED)==0)
|
|
BKE_tracking_ensure_marker(track, framenr);
|
|
|
|
track= track->next;
|
|
}
|
|
}
|
|
|
|
static void track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
Scene *scene= CTX_data_scene(C);
|
|
MovieTrackingSettings *settings= &clip->tracking.settings;
|
|
|
|
tmj->sfra= sc->user.framenr;
|
|
tmj->clip= clip;
|
|
tmj->backwards= backwards;
|
|
|
|
if(backwards) tmj->efra= SFRA;
|
|
else tmj->efra= EFRA;
|
|
|
|
/* limit frames to be tracked by user setting */
|
|
if(settings->flag&TRACKING_FRAMES_LIMIT) {
|
|
if(backwards) tmj->efra= MAX2(tmj->efra, tmj->sfra-settings->frames_limit);
|
|
else tmj->efra= MIN2(tmj->efra, tmj->sfra+settings->frames_limit);
|
|
}
|
|
|
|
if(settings->speed!=TRACKING_SPEED_FASTEST) {
|
|
tmj->delay= 1.0f/scene->r.frs_sec*1000.0f;
|
|
|
|
if(settings->speed==TRACKING_SPEED_HALF) tmj->delay*= 2;
|
|
else if(settings->speed==TRACKING_SPEED_QUARTER) tmj->delay*= 4;
|
|
}
|
|
|
|
track_init_markers(sc, clip);
|
|
|
|
tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards);
|
|
|
|
clip->tracking_context= tmj->context;
|
|
|
|
tmj->lastfra= tmj->sfra;
|
|
|
|
/* XXX: silly to store this, but this data is needed to update scene and movieclip
|
|
frame numbers when tracking is finished. This introduces better feedback for artists.
|
|
Maybe there's another way to solve this problem, but can't think better way atm.
|
|
Anyway, this way isn't more unstable as animation rendering animation
|
|
which uses the same approach (except storing screen). */
|
|
tmj->scene= scene;
|
|
tmj->main= CTX_data_main(C);
|
|
tmj->screen= CTX_wm_screen(C);
|
|
}
|
|
|
|
static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
|
|
{
|
|
TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
|
|
int framenr= tmj->sfra;
|
|
//double t= PIL_check_seconds_timer();
|
|
|
|
while(framenr != tmj->efra) {
|
|
if(tmj->delay>0) {
|
|
/* tracking should happen with fixed fps. Calculate time
|
|
using current timer value before tracking frame and after.
|
|
|
|
Small (and maybe unneeded optimization): do not calculate exec_time
|
|
for "Fastest" tracking */
|
|
|
|
double start_time= PIL_check_seconds_timer(), exec_time;
|
|
|
|
if(!BKE_tracking_next(tmj->context))
|
|
break;
|
|
|
|
exec_time= PIL_check_seconds_timer()-start_time;
|
|
if(tmj->delay>exec_time)
|
|
PIL_sleep_ms(tmj->delay-exec_time);
|
|
} else if(!BKE_tracking_next(tmj->context))
|
|
break;
|
|
|
|
*do_update= 1;
|
|
*progress=(float)(framenr-tmj->sfra) / (tmj->efra-tmj->sfra);
|
|
|
|
if(tmj->backwards) framenr--;
|
|
else framenr++;
|
|
|
|
tmj->lastfra= framenr;
|
|
|
|
if(*stop || track_markers_testbreak())
|
|
break;
|
|
}
|
|
|
|
//printf("Tracking time: %lf\n", PIL_check_seconds_timer()-t);
|
|
}
|
|
|
|
static void track_markers_updatejob(void *tmv)
|
|
{
|
|
TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
|
|
|
|
BKE_tracking_sync(tmj->context);
|
|
}
|
|
|
|
static void track_markers_freejob(void *tmv)
|
|
{
|
|
TrackMarkersJob *tmj= (TrackMarkersJob *)tmv;
|
|
|
|
tmj->clip->tracking_context= NULL;
|
|
tmj->scene->r.cfra= tmj->lastfra;
|
|
ED_update_for_newframe(tmj->main, tmj->scene, tmj->screen, 0);
|
|
|
|
BKE_tracking_sync(tmj->context);
|
|
BKE_tracking_context_free(tmj->context);
|
|
|
|
MEM_freeN(tmj);
|
|
|
|
WM_main_add_notifier(NC_SCENE|ND_FRAME, tmj->scene);
|
|
}
|
|
|
|
static int track_markers_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
Scene *scene= CTX_data_scene(C);
|
|
struct MovieTrackingContext *context;
|
|
int framenr= sc->user.framenr;
|
|
int sfra= framenr, efra;
|
|
int backwards= RNA_boolean_get(op->ptr, "backwards");
|
|
int sequence= RNA_boolean_get(op->ptr, "sequence");
|
|
MovieTrackingSettings *settings= &clip->tracking.settings;
|
|
|
|
if(backwards) efra= SFRA;
|
|
else efra= EFRA;
|
|
|
|
/* limit frames to be tracked by user setting */
|
|
if(settings->flag&TRACKING_FRAMES_LIMIT) {
|
|
if(backwards) efra= MAX2(efra, sfra-settings->frames_limit);
|
|
else efra= MIN2(efra, sfra+settings->frames_limit);
|
|
}
|
|
|
|
track_init_markers(sc, clip);
|
|
|
|
context= BKE_tracking_context_new(clip, &sc->user, backwards);
|
|
|
|
while(framenr != efra) {
|
|
if(!BKE_tracking_next(context))
|
|
break;
|
|
|
|
if(backwards) framenr--;
|
|
else framenr++;
|
|
|
|
if(!sequence)
|
|
break;
|
|
}
|
|
|
|
BKE_tracking_sync(context);
|
|
BKE_tracking_context_free(context);
|
|
|
|
/* update scene current frame to the lastes tracked frame */
|
|
scene->r.cfra= framenr;
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
|
|
WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
|
|
{
|
|
TrackMarkersJob *tmj;
|
|
ScrArea *sa= CTX_wm_area(C);
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
wmJob *steve;
|
|
int backwards= RNA_boolean_get(op->ptr, "backwards");
|
|
int sequence= RNA_boolean_get(op->ptr, "sequence");
|
|
|
|
if(clip->tracking_context)
|
|
return OPERATOR_CANCELLED;
|
|
|
|
if(!sequence)
|
|
return track_markers_exec(C, op);
|
|
|
|
tmj= MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
|
|
track_markers_initjob(C, tmj, backwards);
|
|
|
|
/* setup job */
|
|
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Track Markers", WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS);
|
|
WM_jobs_customdata(steve, tmj, track_markers_freejob);
|
|
|
|
/* if there's delay set in tracking job, tracking should happen
|
|
with fixed FPS. To deal with editor refresh we have to syncronize
|
|
tracks from job and tracks in clip. Do this in timer callback
|
|
to prevent threading conflicts. */
|
|
if(tmj->delay>0) WM_jobs_timer(steve, tmj->delay/1000.0f, NC_MOVIECLIP|NA_EVALUATED, 0);
|
|
else WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|NA_EVALUATED, 0);
|
|
|
|
WM_jobs_callbacks(steve, track_markers_startjob, NULL, track_markers_updatejob, NULL);
|
|
|
|
G.afbreek= 0;
|
|
|
|
WM_jobs_start(CTX_wm_manager(C), steve);
|
|
WM_cursor_wait(0);
|
|
|
|
/* add modal handler for ESC */
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
}
|
|
|
|
static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
|
|
{
|
|
/* no running blender, remove handler and pass through */
|
|
if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
|
|
return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
|
|
|
|
/* running tracking */
|
|
switch (event->type) {
|
|
case ESCKEY:
|
|
return OPERATOR_RUNNING_MODAL;
|
|
break;
|
|
}
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
}
|
|
|
|
void CLIP_OT_track_markers(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Track Markers";
|
|
ot->description= "Track selected markers";
|
|
ot->idname= "CLIP_OT_track_markers";
|
|
|
|
/* api callbacks */
|
|
ot->exec= track_markers_exec;
|
|
ot->invoke= track_markers_invoke;
|
|
ot->poll= space_clip_frame_poll;
|
|
ot->modal= track_markers_modal;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tarcking");
|
|
RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
|
|
}
|
|
|
|
/********************** solve camera operator *********************/
|
|
|
|
static int check_solve_track_count(MovieTracking *tracking)
|
|
{
|
|
int tot= 0;
|
|
int frame1= tracking->settings.keyframe1, frame2= tracking->settings.keyframe2;
|
|
MovieTrackingTrack *track;
|
|
|
|
track= tracking->tracks.first;
|
|
while(track) {
|
|
if(BKE_tracking_has_marker(track, frame1))
|
|
if(BKE_tracking_has_marker(track, frame2))
|
|
tot++;
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
return tot>=10;
|
|
}
|
|
|
|
static int solve_camera_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
Scene *scene= CTX_data_scene(C);
|
|
MovieTracking *tracking= &clip->tracking;
|
|
int width, height;
|
|
float error;
|
|
|
|
if(!check_solve_track_count(tracking)) {
|
|
BKE_report(op->reports, RPT_ERROR, "At least 10 tracks on both of keyframes are needed for reconstruction");
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
/* could fail if footage uses images with different sizes */
|
|
BKE_movieclip_acquire_size(clip, NULL, &width, &height);
|
|
|
|
error= BKE_tracking_solve_reconstruction(tracking, width, height);
|
|
|
|
if(error<0)
|
|
BKE_report(op->reports, RPT_WARNING, "Some data failed to reconstruct, see console for details");
|
|
else
|
|
BKE_reportf(op->reports, RPT_INFO, "Average reprojection error %.3f", error);
|
|
|
|
scene->clip= clip;
|
|
|
|
if(!scene->camera)
|
|
scene->camera= scene_find_camera(scene);
|
|
|
|
if(scene->camera) {
|
|
float focal= tracking->camera.focal;
|
|
|
|
/* set blender camera focal length so result would look fine there */
|
|
if(focal) {
|
|
Camera *camera= (Camera*)scene->camera->data;
|
|
|
|
if(clip->lastsize[0]) {
|
|
camera->sensor_x= tracking->camera.sensor_width;
|
|
camera->sensor_y= tracking->camera.sensor_height;
|
|
|
|
camera->lens= focal*camera->sensor_x/(float)clip->lastsize[0];
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT, camera);
|
|
}
|
|
}
|
|
|
|
DAG_id_tag_update(&clip->id, 0);
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
|
|
WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_solve_camera(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Solve Camera";
|
|
ot->description= "Solve camera motion from tracks";
|
|
ot->idname= "CLIP_OT_solve_camera";
|
|
|
|
/* api callbacks */
|
|
ot->exec= solve_camera_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** clear reconstruction operator *********************/
|
|
|
|
static int clear_reconstruction_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTracking *tracking= &clip->tracking;
|
|
MovieTrackingTrack *track= tracking->tracks.first;
|
|
|
|
while(track) {
|
|
track->flag&= ~TRACK_HAS_BUNDLE;
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
if(tracking->reconstruction.cameras)
|
|
MEM_freeN(tracking->reconstruction.cameras);
|
|
|
|
tracking->reconstruction.cameras= NULL;
|
|
tracking->reconstruction.camnr= 0;
|
|
|
|
tracking->reconstruction.flag&= ~TRACKING_RECONSTRUCTED;
|
|
|
|
DAG_id_tag_update(&clip->id, 0);
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
|
|
WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_clear_reconstruction(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Clear Reconstruction";
|
|
ot->description= "Clear all reconstruciton data";
|
|
ot->idname= "CLIP_OT_clear_reconstruction";
|
|
|
|
/* api callbacks */
|
|
ot->exec= clear_reconstruction_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** clear track operator *********************/
|
|
|
|
static int clear_track_path_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
int action= RNA_enum_get(op->ptr, "action");
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if(TRACK_SELECTED(track))
|
|
BKE_tracking_clear_path(track, sc->user.framenr, action);
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_clear_track_path(wmOperatorType *ot)
|
|
{
|
|
static EnumPropertyItem clear_path_actions[] = {
|
|
{TRACK_CLEAR_UPTO, "UPTO", 0, "Clear up-to", "Clear path up to current frame"},
|
|
{TRACK_CLEAR_REMAINED, "REMAINED", 0, "Clear remained", "Clear path at remained frames (after current)"},
|
|
{TRACK_CLEAR_ALL, "ALL", 0, "Clear all", "Clear the whole path"},
|
|
{0, NULL, 0, NULL, NULL}
|
|
};
|
|
|
|
/* identifiers */
|
|
ot->name= "Clear Track Path";
|
|
ot->description= "Clear path of selected tracks";
|
|
ot->idname= "CLIP_OT_clear_track_path";
|
|
|
|
/* api callbacks */
|
|
ot->exec= clear_track_path_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* proeprties */
|
|
RNA_def_enum(ot->srna, "action", clear_path_actions, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
|
|
}
|
|
|
|
/********************** disable markers operator *********************/
|
|
|
|
static int disable_markers_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTracking *tracking= &clip->tracking;
|
|
MovieTrackingTrack *track= tracking->tracks.first;
|
|
int action= RNA_enum_get(op->ptr, "action");
|
|
|
|
while(track) {
|
|
if(TRACK_SELECTED(track) && (track->flag&TRACK_LOCKED)==0) {
|
|
MovieTrackingMarker *marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
|
|
|
|
if(action==0) marker->flag|= MARKER_DISABLED;
|
|
else if(action==1) marker->flag&= ~MARKER_DISABLED;
|
|
else marker->flag^= MARKER_DISABLED;
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
DAG_id_tag_update(&clip->id, 0);
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_disable_markers(wmOperatorType *ot)
|
|
{
|
|
static EnumPropertyItem actions_items[] = {
|
|
{0, "DISABLE", 0, "Disable", "Disable selected markers"},
|
|
{1, "ENABLE", 0, "Enable", "Enable selected markers"},
|
|
{2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
|
|
{0, NULL, 0, NULL, NULL}
|
|
};
|
|
|
|
/* identifiers */
|
|
ot->name= "Disable Markers";
|
|
ot->description= "Disable/enable selected markers";
|
|
ot->idname= "CLIP_OT_disable_markers";
|
|
|
|
/* api callbacks */
|
|
ot->exec= disable_markers_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
|
|
}
|
|
|
|
/********************** set origin operator *********************/
|
|
|
|
static int count_selected_bundles(bContext *C)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
int tot= 0;
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if(TRACK_SELECTED(track))
|
|
tot++;
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
return tot;
|
|
}
|
|
|
|
static int set_origin_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
Scene *scene= CTX_data_scene(C);
|
|
Object *parent= scene->camera;
|
|
float mat[4][4], vec[3];
|
|
|
|
if(count_selected_bundles(C)!=1) {
|
|
BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define origin position");
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
if(scene->camera->parent)
|
|
parent= scene->camera->parent;
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if(TRACK_SELECTED(track))
|
|
break;
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
BKE_get_tracking_mat(scene, mat);
|
|
mul_v3_m4v3(vec, mat, track->bundle_pos);
|
|
|
|
sub_v3_v3(parent->loc, vec);
|
|
|
|
DAG_id_tag_update(&clip->id, 0);
|
|
DAG_id_tag_update(&parent->id, OB_RECALC_OB);
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
|
|
WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_set_origin(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Set Origin";
|
|
ot->description= "Set active marker as origin";
|
|
ot->idname= "CLIP_OT_set_origin";
|
|
|
|
/* api callbacks */
|
|
ot->exec= set_origin_exec;
|
|
ot->poll= space_clip_frame_camera_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** set floor operator *********************/
|
|
|
|
static void set_axis(Scene *scene, Object *ob, MovieTrackingTrack *track, char axis)
|
|
{
|
|
float mat[4][4], vec[3], obmat[4][4];
|
|
|
|
BKE_get_tracking_mat(scene, mat);
|
|
mul_v3_m4v3(vec, mat, track->bundle_pos);
|
|
|
|
if(len_v2(vec)<1e-3)
|
|
return;
|
|
|
|
unit_m4(mat);
|
|
|
|
if(axis=='X') {
|
|
if(fabsf(vec[1])<1e-3) {
|
|
mat[0][0]= -1.f; mat[0][1]= 0.f; mat[0][2]= 0.f;
|
|
mat[1][0]= 0.f; mat[1][1]= -1.f; mat[1][2]= 0.f;
|
|
mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
|
|
} else {
|
|
copy_v3_v3(mat[0], vec);
|
|
mat[0][2]= 0.f;
|
|
mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
|
|
cross_v3_v3v3(mat[1], mat[2], mat[0]);
|
|
}
|
|
} else {
|
|
if(fabsf(vec[0])<1e-3) {
|
|
mat[0][0]= -1.f; mat[0][1]= 0.f; mat[0][2]= 0.f;
|
|
mat[1][0]= 0.f; mat[1][1]= -1.f; mat[1][2]= 0.f;
|
|
mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
|
|
} else {
|
|
copy_v3_v3(mat[1], vec);
|
|
mat[1][2]= 0.f;
|
|
mat[2][0]= 0.f; mat[2][1]= 0.f; mat[2][2]= 1.0f;
|
|
cross_v3_v3v3(mat[0], mat[1], mat[2]);
|
|
}
|
|
}
|
|
|
|
normalize_v3(mat[0]);
|
|
normalize_v3(mat[1]);
|
|
normalize_v3(mat[2]);
|
|
|
|
invert_m4(mat);
|
|
|
|
object_to_mat4(ob, obmat);
|
|
mul_m4_m4m4(mat, obmat, mat);
|
|
object_apply_mat4(ob, mat, 0, 0);
|
|
}
|
|
|
|
static int set_floor_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
Scene *scene= CTX_data_scene(C);
|
|
MovieTrackingTrack *track, *sel, *axis_track= NULL;
|
|
Object *camera= scene->camera;
|
|
Object *parent= camera;
|
|
int tot= 0, sel_type;
|
|
float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3]= {0.f, 0.f, 0.f};
|
|
float rot[4][4]={{0.f, 0.f, -1.f, 0.f},
|
|
{0.f, 1.f, 0.f, 0.f},
|
|
{1.f, 0.f, 0.f, 0.f},
|
|
{0.f, 0.f, 0.f, 1.f}}; /* 90 degrees Y-axis rotation matrix */
|
|
|
|
if(count_selected_bundles(C)!=3) {
|
|
BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
if(scene->camera->parent)
|
|
parent= scene->camera->parent;
|
|
|
|
BKE_get_tracking_mat(scene, mat);
|
|
|
|
BKE_movieclip_last_selection(clip, &sel_type, (void**)&sel);
|
|
|
|
/* get 3 bundles to use as reference */
|
|
track= clip->tracking.tracks.first;
|
|
while(track && tot<3) {
|
|
if(track->flag&TRACK_HAS_BUNDLE && TRACK_SELECTED(track)) {
|
|
mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
|
|
|
|
if(tot==0 || (sel_type==MCLIP_SEL_TRACK && track==sel))
|
|
copy_v3_v3(orig, vec[tot]);
|
|
else
|
|
axis_track= track;
|
|
|
|
tot++;
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
sub_v3_v3(vec[1], vec[0]);
|
|
sub_v3_v3(vec[2], vec[0]);
|
|
|
|
/* construct ortho-normal basis */
|
|
unit_m4(mat);
|
|
|
|
cross_v3_v3v3(mat[0], vec[1], vec[2]);
|
|
copy_v3_v3(mat[1], vec[1]);
|
|
cross_v3_v3v3(mat[2], mat[0], mat[1]);
|
|
|
|
normalize_v3(mat[0]);
|
|
normalize_v3(mat[1]);
|
|
normalize_v3(mat[2]);
|
|
|
|
/* move to origin point */
|
|
mat[3][0]= orig[0];
|
|
mat[3][1]= orig[1];
|
|
mat[3][2]= orig[2];
|
|
|
|
invert_m4(mat);
|
|
|
|
object_to_mat4(parent, obmat);
|
|
mul_m4_m4m4(mat, obmat, mat);
|
|
mul_m4_m4m4(newmat, mat, rot);
|
|
object_apply_mat4(parent, newmat, 0, 0);
|
|
|
|
/* make camera have positive z-coordinate */
|
|
mul_v3_m4v3(vec[0], mat, camera->loc);
|
|
if(camera->loc[2]<0) {
|
|
invert_m4(rot);
|
|
mul_m4_m4m4(newmat, mat, rot);
|
|
object_apply_mat4(camera, newmat, 0, 0);
|
|
}
|
|
|
|
where_is_object(scene, parent);
|
|
set_axis(scene, parent, axis_track, 'X');
|
|
|
|
DAG_id_tag_update(&clip->id, 0);
|
|
DAG_id_tag_update(&parent->id, OB_RECALC_OB);
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
|
|
WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_set_floor(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Set Floor";
|
|
ot->description= "Set floor using 3 selected bundles";
|
|
ot->idname= "CLIP_OT_set_floor";
|
|
|
|
/* api callbacks */
|
|
ot->exec= set_floor_exec;
|
|
ot->poll= space_clip_camera_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** set origin operator *********************/
|
|
|
|
static int set_axis_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
Scene *scene= CTX_data_scene(C);
|
|
Object *parent= scene->camera;
|
|
int axis= RNA_enum_get(op->ptr, "axis");
|
|
|
|
if(count_selected_bundles(C)!=1) {
|
|
BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define X-axis");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
if(scene->camera->parent)
|
|
parent= scene->camera->parent;
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if(TRACK_SELECTED(track))
|
|
break;
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
set_axis(scene, parent, track, axis==0?'X':'Y');
|
|
|
|
DAG_id_tag_update(&clip->id, 0);
|
|
DAG_id_tag_update(&parent->id, OB_RECALC_OB);
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
|
|
WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_set_axis(wmOperatorType *ot)
|
|
{
|
|
static EnumPropertyItem axis_actions[] = {
|
|
{0, "X", 0, "X", "Align bundle align X axis"},
|
|
{1, "Y", 0, "Y", "Align bundle align Y axis"},
|
|
{0, NULL, 0, NULL, NULL}
|
|
};
|
|
|
|
/* identifiers */
|
|
ot->name= "Set Axis";
|
|
ot->description= "Set direction of scene axis";
|
|
ot->idname= "CLIP_OT_set_axis";
|
|
|
|
/* api callbacks */
|
|
ot->exec= set_axis_exec;
|
|
ot->poll= space_clip_frame_camera_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
|
|
}
|
|
|
|
/********************** set scale operator *********************/
|
|
|
|
static int set_scale_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
Scene *scene= CTX_data_scene(C);
|
|
Object *parent= scene->camera;
|
|
int tot= 0;
|
|
float vec[2][3], mat[4][4], scale;
|
|
|
|
if(count_selected_bundles(C)!=2) {
|
|
BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to scale scene");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
if(scene->camera->parent)
|
|
parent= scene->camera->parent;
|
|
|
|
BKE_get_tracking_mat(scene, mat);
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if(TRACK_SELECTED(track)) {
|
|
mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
|
|
tot++;
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
sub_v3_v3(vec[0], vec[1]);
|
|
|
|
if(len_v3(vec[0])>1e-5) {
|
|
scale= clip->tracking.settings.dist / len_v3(vec[0]);
|
|
|
|
mul_v3_fl(parent->size, scale);
|
|
mul_v3_fl(parent->loc, scale);
|
|
|
|
DAG_id_tag_update(&clip->id, 0);
|
|
DAG_id_tag_update(&parent->id, OB_RECALC_OB);
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
|
|
WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, NULL);
|
|
}
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_set_scale(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Set Scale";
|
|
ot->description= "Set scale of scene";
|
|
ot->idname= "CLIP_OT_set_scale";
|
|
|
|
/* api callbacks */
|
|
ot->exec= set_scale_exec;
|
|
ot->poll= space_clip_frame_camera_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** set principal center operator *********************/
|
|
|
|
static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
int width, height;
|
|
|
|
BKE_movieclip_acquire_size(clip, &sc->user, &width, &height);
|
|
|
|
if(width==0 || height==0)
|
|
return OPERATOR_CANCELLED;
|
|
|
|
clip->tracking.camera.principal[0]= ((float)width)/2.0f;
|
|
clip->tracking.camera.principal[1]= ((float)height)/2.0f;
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_set_center_principal(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Set Principal to Center";
|
|
ot->description= "Set principal point to center of footage";
|
|
ot->idname= "CLIP_OT_set_center_principal";
|
|
|
|
/* api callbacks */
|
|
ot->exec= set_center_principal_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** hide tracks operator *********************/
|
|
|
|
static int hide_tracks_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
int sel_type, unselected;
|
|
void *sel;
|
|
|
|
unselected= RNA_boolean_get(op->ptr, "unselected");
|
|
|
|
BKE_movieclip_last_selection(clip, &sel_type, &sel);
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if(unselected==0 && TRACK_SELECTED(track)) {
|
|
track->flag|= TRACK_HIDDEN;
|
|
} else if(unselected==1 && !TRACK_SELECTED(track)) {
|
|
track->flag|= TRACK_HIDDEN;
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
if(sel_type==MCLIP_SEL_TRACK) {
|
|
track= (MovieTrackingTrack *)sel;
|
|
|
|
if(track->flag&TRACK_HIDDEN)
|
|
BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_hide_tracks(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Hide Tracks";
|
|
ot->description= "Hide selected tracks";
|
|
ot->idname= "CLIP_OT_hide_tracks";
|
|
|
|
/* api callbacks */
|
|
ot->exec= hide_tracks_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected tracks");
|
|
}
|
|
|
|
/********************** hide tracks clear operator *********************/
|
|
|
|
static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
track->flag&= ~TRACK_HIDDEN;
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Hide Tracks Clear";
|
|
ot->description= "Clear hide selected tracks";
|
|
ot->idname= "CLIP_OT_hide_tracks_clear";
|
|
|
|
/* api callbacks */
|
|
ot->exec= hide_tracks_clear_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** detect features operator *********************/
|
|
|
|
static int detect_features_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
ImBuf *ibuf= BKE_movieclip_acquire_ibuf(clip, &sc->user);
|
|
MovieTrackingTrack *track= clip->tracking.tracks.first;
|
|
|
|
/* deselect existing tracks */
|
|
while(track) {
|
|
track->flag&= ~SELECT;
|
|
track->pat_flag&= ~SELECT;
|
|
track->search_flag&= ~SELECT;
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
BKE_tracking_detect(&clip->tracking, ibuf, sc->user.framenr);
|
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
BKE_movieclip_set_selection(clip, MCLIP_SEL_NONE, NULL);
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_detect_features(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Detect Features";
|
|
ot->description= "Automatically detect features to track";
|
|
ot->idname= "CLIP_OT_detect_features";
|
|
|
|
/* api callbacks */
|
|
ot->exec= detect_features_exec;
|
|
ot->poll= space_clip_frame_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** frame jump operator *********************/
|
|
|
|
static int frame_jump_exec(bContext *C, wmOperator *op)
|
|
{
|
|
Scene *scene= CTX_data_scene(C);
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track;
|
|
int pos= RNA_enum_get(op->ptr, "position");
|
|
int sel_type, delta;
|
|
|
|
if(pos<=1) { /* jump to path */
|
|
BKE_movieclip_last_selection(clip, &sel_type, (void**)&track);
|
|
|
|
if(sel_type!=MCLIP_SEL_TRACK)
|
|
return OPERATOR_CANCELLED;
|
|
|
|
delta= pos == 1 ? 1 : -1;
|
|
|
|
while(sc->user.framenr+delta >= SFRA && sc->user.framenr+delta <= EFRA) {
|
|
MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, sc->user.framenr+delta);
|
|
|
|
if(!marker || marker->flag&MARKER_DISABLED)
|
|
break;
|
|
|
|
sc->user.framenr+= delta;
|
|
}
|
|
}
|
|
else { /* to to failed frame */
|
|
if(clip->tracking.reconstruction.flag&TRACKING_RECONSTRUCTED) {
|
|
int a= sc->user.framenr;
|
|
MovieTracking *tracking= &clip->tracking;
|
|
|
|
delta= pos == 3 ? 1 : -1;
|
|
|
|
a+= delta;
|
|
|
|
while(a+delta >= SFRA && a+delta <= EFRA) {
|
|
MovieReconstructedCamera *cam= BKE_tracking_get_reconstructed_camera(tracking, a);
|
|
|
|
if(!cam) {
|
|
sc->user.framenr= a;
|
|
|
|
break;
|
|
}
|
|
|
|
a+= delta;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(CFRA!=sc->user.framenr) {
|
|
CFRA= sc->user.framenr;
|
|
sound_seek_scene(C);
|
|
|
|
WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_frame_jump(wmOperatorType *ot)
|
|
{
|
|
static EnumPropertyItem position_items[] = {
|
|
{0, "PATHSTART", 0, "Path Start", "Jump to start of current path"},
|
|
{1, "PATHEND", 0, "Path End", "Jump to end of current path"},
|
|
{2, "FAILEDPREV", 0, "Previons Failed", "Jump to previous failed frame"},
|
|
{2, "FAILNEXT", 0, "Next Failed", "Jump to next failed frame"},
|
|
{0, NULL, 0, NULL, NULL}
|
|
};
|
|
|
|
/* identifiers */
|
|
ot->name= "Jump to Frame";
|
|
ot->description= "Jump to special frame";
|
|
ot->idname= "CLIP_OT_frame_jump";
|
|
|
|
/* api callbacks */
|
|
ot->exec= frame_jump_exec;
|
|
ot->poll= space_clip_frame_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
RNA_def_enum(ot->srna, "position", position_items, 0, "Position", "Position to jumo to");
|
|
}
|
|
|
|
/********************** join tracks operator *********************/
|
|
|
|
static int join_tracks_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *act_track, *track, *next;
|
|
int sel_type;
|
|
|
|
BKE_movieclip_last_selection(clip, &sel_type, (void**)&act_track);
|
|
|
|
if(sel_type!=MCLIP_SEL_TRACK) {
|
|
BKE_report(op->reports, RPT_ERROR, "No active track to join to");
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if(TRACK_SELECTED(track) && track!=act_track) {
|
|
if(!BKE_tracking_test_join_tracks(act_track, track)) {
|
|
BKE_report(op->reports, RPT_ERROR, "Some selected tracks have got keyframed markers to the same frame");
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
next= track->next;
|
|
|
|
if(TRACK_SELECTED(track) && track!=act_track) {
|
|
BKE_tracking_join_tracks(act_track, track);
|
|
|
|
BKE_tracking_free_track(track);
|
|
BLI_freelinkN(&clip->tracking.tracks, track);
|
|
}
|
|
|
|
track= next;
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_join_tracks(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Join Tracks";
|
|
ot->description= "Joint Selected Tracks";
|
|
ot->idname= "CLIP_OT_join_tracks";
|
|
|
|
/* api callbacks */
|
|
ot->exec= join_tracks_exec;
|
|
ot->poll= space_clip_frame_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** lock tracks operator *********************/
|
|
|
|
static int lock_tracks_exec(bContext *C, wmOperator *op)
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTracking *tracking= &clip->tracking;
|
|
MovieTrackingTrack *track= tracking->tracks.first;
|
|
int action= RNA_enum_get(op->ptr, "action");
|
|
|
|
while(track) {
|
|
if(TRACK_SELECTED(track)) {
|
|
if(action==0) track->flag|= TRACK_LOCKED;
|
|
else if(action==1) track->flag&= ~TRACK_LOCKED;
|
|
else track->flag^= TRACK_LOCKED;
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_lock_tracks(wmOperatorType *ot)
|
|
{
|
|
static EnumPropertyItem actions_items[] = {
|
|
{0, "LOCK", 0, "Lock", "Lock selected tracks"},
|
|
{1, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
|
|
{2, "TOGGLE", 0, "Toggle", "Toggle locked flag for selected tracks"},
|
|
{0, NULL, 0, NULL, NULL}
|
|
};
|
|
|
|
/* identifiers */
|
|
ot->name= "Lock Tracks";
|
|
ot->description= "Lock/unlock selected tracks";
|
|
ot->idname= "CLIP_OT_lock_tracks";
|
|
|
|
/* api callbacks */
|
|
ot->exec= lock_tracks_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
|
|
}
|
|
|
|
/********************** track copy color operator *********************/
|
|
|
|
static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTrackingTrack *track, *sel;
|
|
int sel_type;
|
|
|
|
BKE_movieclip_last_selection(clip, &sel_type, (void**)&sel);
|
|
|
|
if(sel_type!=MCLIP_SEL_TRACK)
|
|
return OPERATOR_CANCELLED;
|
|
|
|
track= clip->tracking.tracks.first;
|
|
while(track) {
|
|
if(TRACK_SELECTED(track) && track!=sel) {
|
|
track->flag&= ~TRACK_CUSTOMCOLOR;
|
|
|
|
if(sel->flag&TRACK_CUSTOMCOLOR) {
|
|
copy_v3_v3(track->color, sel->color);
|
|
track->flag|= TRACK_CUSTOMCOLOR;
|
|
}
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_track_copy_color(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Copy Color";
|
|
ot->description= "Copy color to all selected tracks";
|
|
ot->idname= "CLIP_OT_track_copy_color";
|
|
|
|
/* api callbacks */
|
|
ot->exec= track_copy_color_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** add 2d stabilization tracks operator *********************/
|
|
|
|
static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTracking *tracking= &clip->tracking;
|
|
MovieTrackingTrack *track;
|
|
MovieTrackingStabilization *stab= &tracking->stabilization;
|
|
|
|
track= tracking->tracks.first;
|
|
while(track) {
|
|
if(TRACK_SELECTED(track)) {
|
|
track->flag|= TRACK_USE_2D_STAB;
|
|
stab->tot_track++;
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
stab->ok= 0;
|
|
|
|
DAG_id_tag_update(&clip->id, 0);
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Add Stabilization Tracks";
|
|
ot->description= "Add selected tracks to 2D stabilization tool";
|
|
ot->idname= "CLIP_OT_stabilize_2d_add";
|
|
|
|
/* api callbacks */
|
|
ot->exec= stabilize_2d_add_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** remove 2d stabilization tracks operator *********************/
|
|
|
|
static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTracking *tracking= &clip->tracking;
|
|
MovieTrackingStabilization *stab= &tracking->stabilization;
|
|
MovieTrackingTrack *track;
|
|
int a= 0;
|
|
|
|
track= tracking->tracks.first;
|
|
while(track) {
|
|
if(track->flag&TRACK_USE_2D_STAB) {
|
|
if(a==stab->act_track) {
|
|
track->flag&= ~TRACK_USE_2D_STAB;
|
|
|
|
stab->act_track--;
|
|
stab->tot_track--;
|
|
|
|
if(stab->act_track<0)
|
|
stab->act_track= 0;
|
|
|
|
break;
|
|
}
|
|
|
|
a++;
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
stab->ok= 0;
|
|
|
|
DAG_id_tag_update(&clip->id, 0);
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Remove Stabilization Track";
|
|
ot->description= "Remove selected track from stabilization";
|
|
ot->idname= "CLIP_OT_stabilize_2d_remove";
|
|
|
|
/* api callbacks */
|
|
ot->exec= stabilize_2d_remove_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
/********************** select 2d stabilization tracks operator *********************/
|
|
|
|
static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
SpaceClip *sc= CTX_wm_space_clip(C);
|
|
MovieClip *clip= ED_space_clip(sc);
|
|
MovieTracking *tracking= &clip->tracking;
|
|
MovieTrackingTrack *track;
|
|
int a= 0, area;
|
|
|
|
area= TRACK_AREA_POINT;
|
|
if(sc->flag&SC_SHOW_MARKER_PATTERN) area|= TRACK_AREA_PAT;
|
|
if(sc->flag&SC_SHOW_MARKER_SEARCH) area|= TRACK_AREA_SEARCH;
|
|
|
|
track= tracking->tracks.first;
|
|
while(track) {
|
|
if(track->flag&TRACK_USE_2D_STAB) {
|
|
BKE_tracking_track_flag(track, area, SELECT, 0);
|
|
|
|
a++;
|
|
}
|
|
|
|
track= track->next;
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP|ND_SELECT, clip);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "Select Stabilization Tracks";
|
|
ot->description= "Select track whic hare used for stabilization";
|
|
ot->idname= "CLIP_OT_stabilize_2d_select";
|
|
|
|
/* api callbacks */
|
|
ot->exec= stabilize_2d_select_exec;
|
|
ot->poll= space_clip_tracking_poll;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|