Merging r47624 through r47661 from trunk into soc-2011-tomato
[blender.git] / source / blender / editors / space_clip / tracking_ops.c
index f3a96ef7a79039b8a5e1544d0b5e47b5d7549226..f6e9622f0a53b071d18925ed7c5407f0f474b761 100644 (file)
@@ -79,6 +79,8 @@
 
 #include "clip_intern.h"       // own include
 
+static float dist_to_crns(float co[2], float pos[2], float crns[4][2]);
+
 /********************** add marker operator *********************/
 
 static void add_marker(SpaceClip *sc, float x, float y)
@@ -260,15 +262,16 @@ typedef struct {
 
        int mval[2];
        int width, height;
-       float *min, *max, *pos, *offset;
-       float smin[2], smax[2], spos[2], soff[2];
+       float *min, *max, *pos, *offset, (*corners)[2];
+       float smin[2], smax[2], spos[2], soff[2], scorners[4][2];
        float (*smarkers)[2];
 
-       int lock, accurate;
+       int lock, accurate, scale;
 } SlideMarkerData;
 
 static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTrack *track,
-                       MovieTrackingMarker *marker, wmEvent *event, int area, int action, int width, int height)
+                                                 MovieTrackingMarker *marker, wmEvent *event,
+                                                                                                int area, int corner, int action, int width, int height)
 {
        SlideMarkerData *data = MEM_callocN(sizeof(SlideMarkerData), "slide marker data");
        int framenr = ED_space_clip_clip_framenr(sc);
@@ -288,10 +291,9 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTra
        }
        else if (area == TRACK_AREA_PAT) {
                if (action == SLIDE_ACTION_SIZE) {
-                       data->min = track->pat_min;
-                       data->max = track->pat_max;
+                       data->corners = marker->pattern_corners;
                }
-               else {
+               else if (action == SLIDE_ACTION_OFFSET) {
                        int a;
 
                        data->pos = marker->pos;
@@ -303,15 +305,28 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTra
                        for (a = 0; a < track->markersnr; a++)
                                copy_v2_v2(data->smarkers[a], track->markers[a].pos);
                }
+               else if (action == SLIDE_ACTION_POS) {
+                       data->corners = marker->pattern_corners;
+                       data->pos = marker->pattern_corners[corner];
+
+                       copy_v2_v2(data->spos, data->pos);
+               }
        }
        else if (area == TRACK_AREA_SEARCH) {
-               data->min = track->search_min;
-               data->max = track->search_max;
+               data->min = marker->search_min;
+               data->max = marker->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);
+       if ((area == TRACK_AREA_SEARCH) ||
+               (area == TRACK_AREA_PAT && action != SLIDE_ACTION_OFFSET))
+       {
+               if (data->corners) {
+                       memcpy(data->scorners, data->corners, sizeof(data->scorners));
+               }
+               else {
+                       copy_v2_v2(data->smin, data->min);
+                       copy_v2_v2(data->smax, data->max);
+               }
        }
 
        data->mval[0] = event->mval[0];
@@ -326,9 +341,7 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTra
        return data;
 }
 
-/* corner = 0: right-bottom corner,
- * corner = 1: left-top corner */
-static int mouse_on_corner(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
+static int mouse_on_corner(SpaceClip *sc, MovieTrackingMarker *marker,
                            int area, float co[2], int corner, int width, int height)
 {
        int inside = 0;
@@ -337,12 +350,11 @@ static int mouse_on_corner(SpaceClip *sc, MovieTrackingTrack *track, MovieTracki
        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);
+               copy_v2_v2(min, marker->search_min);
+               copy_v2_v2(max, marker->search_max);
        }
        else {
-               copy_v2_v2(min, track->pat_min);
-               copy_v2_v2(max, track->pat_max);
+               BKE_tracking_marker_pattern_minmax(marker, min, max);
        }
 
        dx = size / width / sc->zoom;
@@ -370,22 +382,95 @@ static int mouse_on_corner(SpaceClip *sc, MovieTrackingTrack *track, MovieTracki
        return inside;
 }
 
+static int get_mouse_pattern_corner(SpaceClip *sc, MovieTrackingMarker *marker, float co[2], int width, int height)
+{
+       int i, next;
+       float len = FLT_MAX, dx, dy;
+
+       for (i = 0; i < 4; i++) {
+               float cur_len;
+
+               next = (i + 1) % 4;
+
+               cur_len = len_v2v2(marker->pattern_corners[i], marker->pattern_corners[next]);
+
+               len = MIN2(cur_len, len);
+       }
+
+       dx = 6.0f / width / sc->zoom;
+       dy = 6.0f / height / sc->zoom;
+
+       dx = MIN2(dx * 2.0f / 3.0f, len / 6.0f);
+       dy = MIN2(dy * 2.0f / 3.0f, len * width / height / 6.0f);
+
+       for (i = 0; i < 4; i++) {
+               float crn[2];
+               int inside;
+
+               add_v2_v2v2(crn, marker->pattern_corners[i], marker->pos);
+
+               inside = IN_RANGE_INCL(co[0], crn[0] - dx, crn[0] + dx) &&
+                        IN_RANGE_INCL(co[1], crn[1] - dy, crn[1] + dy);
+
+               if (inside)
+                       return i;
+       }
+
+       return -1;
+}
+
 static int mouse_on_offset(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
-                       float co[2], int width, int height)
+                           float co[2], int width, int height)
 {
        float pos[2], dx, dy;
+       float pat_min[2], pat_max[2];
+
+       BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
 
        add_v2_v2v2(pos, marker->pos, track->offset);
 
        dx = 12.0f / width / sc->zoom;
        dy = 12.0f / height / sc->zoom;
 
-       dx = MIN2(dx, (track->pat_max[0] - track->pat_min[0]) / 2.0f);
-       dy = MIN2(dy, (track->pat_max[1] - track->pat_min[1]) / 2.0f);
+       dx = MIN2(dx, (pat_max[0] - pat_min[0]) / 2.0f);
+       dy = MIN2(dy, (pat_max[1] - pat_min[1]) / 2.0f);
 
        return co[0] >= pos[0] - dx && co[0] <= pos[0] + dx && co[1] >= pos[1] - dy && co[1] <= pos[1] + dy;
 }
 
+static int slide_check_corners(float (*corners)[2])
+{
+       int i, next, prev;
+       float cross = 0.0f;
+       float p[2] = {0.0f, 0.0f};
+
+       if (!isect_point_quad_v2(p, corners[0], corners[1], corners[2], corners[3]))
+               return FALSE;
+
+       for (i = 0; i < 4; i++) {
+               float v1[2], v2[2], cur_cross;
+
+               next = (i + 1) % 4;
+               prev = (4 + i - 1) % 4;
+
+               sub_v2_v2v2(v1, corners[i], corners[prev]);
+               sub_v2_v2v2(v2, corners[next], corners[i]);
+
+               cur_cross = cross_v2v2(v1, v2);
+
+               if (fabsf(cur_cross) > FLT_EPSILON) {
+                       if (cross == 0.0f) {
+                               cross = cur_cross;
+                       }
+                       else if (cross * cur_cross < 0.0f) {
+                               return FALSE;
+                       }
+               }
+       }
+
+       return TRUE;
+}
+
 static void hide_cursor(bContext *C)
 {
        wmWindow *win = CTX_wm_window(C);
@@ -424,28 +509,45 @@ static void *slide_marker_customdata(bContext *C, wmEvent *event)
                        MovieTrackingMarker *marker = BKE_tracking_get_marker(track, framenr);
 
                        if ((marker->flag & MARKER_DISABLED) == 0) {
-                               if (!customdata)
+                               if (!customdata) {
                                        if (mouse_on_offset(sc, track, marker, co, width, height))
-                                               customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_POINT,
+                                               customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_POINT, 0,
                                                                                      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,
+                                       if (mouse_on_corner(sc, marker, TRACK_AREA_SEARCH, co, 1, width, height)) {
+                                               customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, 0,
                                                                                      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,
+                                       }
+                                       else if (mouse_on_corner(sc, marker, TRACK_AREA_SEARCH, co, 0, width, height)) {
+                                               customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_SEARCH, 0,
                                                                                      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);
+                                       /* XXX: need to be real check if affine tracking is enabled, but for now not
+                                        *      sure how to do this, so assume affine tracker is always enabled */
+                                       if (TRUE) {
+                                               int corner = get_mouse_pattern_corner(sc, marker, co, width, height);
+
+                                               if (corner != -1) {
+                                                       customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, corner,
+                                                                                             SLIDE_ACTION_POS, width, height);
+                                               }
+                                       }
+                                       else {
+                                               if (mouse_on_corner(sc, marker, TRACK_AREA_PAT, co, 1,  width, height)) {
+                                                       customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, 0,
+                                                                                             SLIDE_ACTION_OFFSET, width, height);
+                                               }
+
+                                               if (!customdata && mouse_on_corner(sc, marker, TRACK_AREA_PAT, co, 0, width, height)) {
+                                                       customdata = create_slide_marker_data(sc, track, marker, event, TRACK_AREA_PAT, 0,
+                                                                                             SLIDE_ACTION_SIZE, width, height);
+                                               }
+                                       }
                                }
 
                                if (customdata)
@@ -493,9 +595,16 @@ static void cancel_mouse_slide(SlideMarkerData *data)
                        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);
+               if ((data->action == SLIDE_ACTION_SIZE) ||
+                   (data->action == SLIDE_ACTION_POS && data->area == TRACK_AREA_PAT))
+               {
+                       if (data->corners) {
+                               memcpy(data->corners, data->scorners, sizeof(data->scorners));
+                       }
+                       else {
+                               copy_v2_v2(data->min, data->smin);
+                               copy_v2_v2(data->max, data->smax);
+                       }
                }
                else {
                        int a;
@@ -531,6 +640,10 @@ static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
                                if (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY))
                                        data->lock = event->val == KM_RELEASE;
 
+                       if (data->action == SLIDE_ACTION_POS)
+                               if (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY))
+                                       data->scale = event->val == KM_PRESS;
+
                        if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
                                data->accurate = event->val == KM_PRESS;
 
@@ -560,8 +673,6 @@ static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
                                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);
@@ -569,18 +680,33 @@ static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
                        }
                        else {
                                if (data->action == SLIDE_ACTION_SIZE) {
-                                       data->min[0] = data->smin[0] - dx;
-                                       data->max[0] = data->smax[0] + dx;
+                                       if (data->corners) {
+                                               data->corners[0][0] = data->scorners[0][0] - dx;
+                                               data->corners[0][1] = data->scorners[0][1] + dy;
 
-                                       data->min[1] = data->smin[1] + dy;
-                                       data->max[1] = data->smax[1] - dy;
+                                               data->corners[1][0] = data->scorners[1][0] + dx;
+                                               data->corners[1][1] = data->scorners[1][1] + dy;
+
+                                               data->corners[2][0] = data->scorners[2][0] + dx;
+                                               data->corners[2][1] = data->scorners[2][1] - dy;
+
+                                               data->corners[3][0] = data->scorners[3][0] - dx;
+                                               data->corners[3][1] = data->scorners[3][1] - dy;
+                                       }
+                                       else {
+                                               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);
+                                               BKE_tracking_clamp_marker(data->marker, CLAMP_SEARCH_DIM);
                                        else
-                                               BKE_tracking_clamp_track(data->track, CLAMP_PAT_DIM);
+                                               BKE_tracking_clamp_marker(data->marker, CLAMP_PAT_DIM);
                                }
-                               else {
+                               else if (data->action == SLIDE_ACTION_OFFSET) {
                                        float d[2] = {dx, dy};
 
                                        if (data->area == TRACK_AREA_SEARCH) {
@@ -597,10 +723,43 @@ static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event)
                                        }
 
                                        if (data->area == TRACK_AREA_SEARCH)
-                                               BKE_tracking_clamp_track(data->track, CLAMP_SEARCH_POS);
+                                               BKE_tracking_clamp_marker(data->marker, CLAMP_SEARCH_POS);
+                               }
+                               else if (data->action == SLIDE_ACTION_POS) {
+                                       if (data->scale) {
+                                               float scale = 1.0f + 10.0f * (dx - dy);
+
+                                               if (scale > 0.0f) {
+                                                       int a;
+
+                                                       for (a = 0; a < 4; a++) {
+                                                               mul_v2_v2fl(data->corners[a], data->scorners[a], scale);
+                                                       }
+                                               }
+                                       }
+                                       else {
+                                               float spos[2];
+
+                                               copy_v2_v2(spos, data->pos);
+
+                                               /* corners might've been scaled before, restore their original position */
+                                               memcpy(data->corners, data->scorners, sizeof(data->scorners));
+
+                                               data->pos[0] = data->spos[0] + dx;
+                                               data->pos[1] = data->spos[1] + dy;
+
+                                               if (!slide_check_corners(data->corners)) {
+                                                       copy_v2_v2(data->pos, spos);
+                                               }
+                                       }
+
+                                       /* currently only patterns are allowed to have such combination of event and data */
+                                       BKE_tracking_clamp_marker(data->marker, CLAMP_PAT_DIM);
                                }
                        }
 
+                       data->marker->flag &= ~MARKER_TRACKED;
+
                        WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
 
                        break;
@@ -673,31 +832,41 @@ static int mouse_on_rect(float co[2], float pos[2], float min[2], float max[2],
               mouse_on_side(co, pos[0] + max[0], pos[1] + min[1], pos[0] + max[0], pos[1] + max[1], epsx, epsy);
 }
 
+static int mouse_on_crns(float co[2], float pos[2], float crns[4][2], float epsx, float epsy)
+{
+       float dist = dist_to_crns(co, pos, crns);
+
+       return dist < MAX2(epsx, epsy);
+}
+
 static int track_mouse_area(SpaceClip *sc, float co[2], MovieTrackingTrack *track)
 {
        int framenr = ED_space_clip_clip_framenr(sc);
        MovieTrackingMarker *marker = BKE_tracking_get_marker(track, framenr);
+       float pat_min[2], pat_max[2];
        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;
+       BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
+
+       epsx = MIN4(pat_min[0] - marker->search_min[0], marker->search_max[0] - pat_max[0],
+                   fabsf(pat_min[0]), fabsf(pat_max[0])) / 2;
+       epsy = MIN4(pat_min[1] - marker->search_min[1], marker->search_max[1] - pat_max[1],
+                   fabsf(pat_min[1]), fabsf(pat_max[1])) / 2;
 
        epsx = MAX2(epsx, 2.0f / width);
        epsy = MAX2(epsy, 2.0f / height);
 
        if (sc->flag & SC_SHOW_MARKER_SEARCH) {
-               if (mouse_on_rect(co, marker->pos, track->search_min, track->search_max, epsx, epsy))
+               if (mouse_on_rect(co, marker->pos, marker->search_min, marker->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))
+                       if (mouse_on_crns(co, marker->pos, marker->pattern_corners, epsx, epsy))
                                return TRACK_AREA_PAT;
 
                epsx = 12.0f / width;
@@ -728,6 +897,21 @@ static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
        return MIN4(d1, d2, d3, d4);
 }
 
+static float dist_to_crns(float co[2], float pos[2], float crns[4][2])
+{
+       float d1, d2, d3, d4;
+       float p[2] = {co[0] - pos[0], co[1] - pos[1]};
+       float *v1 = crns[0], *v2 = crns[1],
+             *v3 = crns[2], *v4 = crns[3];
+
+       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, ListBase *tracksbase, float co[2])
 {
        MovieTrackingTrack *track = NULL, *cur;
@@ -743,15 +927,15 @@ static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbas
 
                        /* distance to marker point */
                        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]));
+                                          (co[1] - marker->pos[1] - cur->offset[1]) * (co[1] - marker->pos[1] - cur->offset[1]));
 
                        /* distance to pattern boundbox */
                        if (sc->flag & SC_SHOW_MARKER_PATTERN)
-                               d2 = dist_to_rect(co, marker->pos, cur->pat_min, cur->pat_max);
+                               d2 = dist_to_crns(co, marker->pos, marker->pattern_corners);
 
                        /* distance to search boundbox */
                        if (sc->flag & SC_SHOW_MARKER_SEARCH && TRACK_VIEW_SELECTED(sc, cur))
-                               d3 = dist_to_rect(co, marker->pos, cur->search_min, cur->search_max);
+                               d3 = dist_to_rect(co, marker->pos, marker->search_min, marker->search_max);
 
                        /* choose minimal distance. useful for cases of overlapped markers. */
                        dist = MIN3(d1, d2, d3);
@@ -861,7 +1045,8 @@ void CLIP_OT_select(wmOperatorType *ot)
        /* api callbacks */
        ot->exec = select_exec;
        ot->invoke = select_invoke;
-       ot->poll = ED_space_clip_tracking_poll;
+       //ot->poll = ED_space_clip_tracking_poll; // so mask view can Ctrl+RMB markers
+       ot->poll = ED_space_clip_view_clip_poll;
 
        /* flags */
        ot->flag = OPTYPE_UNDO;
@@ -2140,14 +2325,17 @@ static int set_orientation_poll(bContext *C)
        if (sc) {
                Scene *scene = CTX_data_scene(C);
                MovieClip *clip = ED_space_clip(sc);
-               MovieTracking *tracking = &clip->tracking;
-               MovieTrackingObject *tracking_object = BKE_tracking_active_object(tracking);
 
-               if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
-                       return TRUE;
-               }
-               else {
-                       return OBACT != NULL;
+               if (clip) {
+                       MovieTracking *tracking = &clip->tracking;
+                       MovieTrackingObject *tracking_object = BKE_tracking_active_object(tracking);
+
+                       if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+                               return TRUE;
+                       }
+                       else {
+                               return OBACT != NULL;
+                       }
                }
        }
 
@@ -2750,10 +2938,13 @@ static int set_solution_scale_poll(bContext *C)
 
        if (sc) {
                MovieClip *clip = ED_space_clip(sc);
-               MovieTracking *tracking = &clip->tracking;
-               MovieTrackingObject *tracking_object = BKE_tracking_active_object(tracking);
 
-               return (tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0;
+               if (clip) {
+                       MovieTracking *tracking = &clip->tracking;
+                       MovieTrackingObject *tracking_object = BKE_tracking_active_object(tracking);
+
+                       return (tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0;
+               }
        }
 
        return FALSE;