Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_mask.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/BKE_tracking.h36
-rw-r--r--source/blender/blenkernel/intern/mask.c115
-rw-r--r--source/blender/blenkernel/intern/node.c1
-rw-r--r--source/blender/blenkernel/intern/tracking.c480
-rw-r--r--source/blender/blenloader/intern/readfile.c25
-rw-r--r--source/blender/blenloader/intern/writefile.c17
-rw-r--r--source/blender/compositor/CMakeLists.txt9
-rw-r--r--source/blender/compositor/intern/COM_Converter.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp81
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h38
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp95
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h62
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp69
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h49
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp207
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h53
-rw-r--r--source/blender/editors/mask/mask_relationships.c55
-rw-r--r--source/blender/editors/mask/mask_shapekey.c1
-rw-r--r--source/blender/editors/space_clip/clip_draw.c232
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c6
-rw-r--r--source/blender/editors/space_clip/clip_intern.h7
-rw-r--r--source/blender/editors/space_clip/clip_utils.c56
-rw-r--r--source/blender/editors/space_clip/space_clip.c7
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c403
-rw-r--r--source/blender/editors/space_clip/tracking_select.c257
-rw-r--r--source/blender/editors/space_node/drawnode.c36
-rw-r--r--source/blender/editors/transform/transform.c7
-rw-r--r--source/blender/editors/transform/transform.h2
-rw-r--r--source/blender/editors/transform/transform_conversions.c159
-rw-r--r--source/blender/editors/transform/transform_generics.c11
-rw-r--r--source/blender/makesdna/DNA_mask_types.h13
-rw-r--r--source/blender/makesdna/DNA_node_types.h4
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h55
-rw-r--r--source/blender/makesrna/intern/rna_mask.c43
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c23
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c297
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_composite.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c64
42 files changed, 2937 insertions, 149 deletions
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 92332116ba6..14ceba42aff 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -53,9 +53,11 @@ void BKE_mask_layer_active_set(struct Mask *mask, struct MaskLayer *masklay);
void BKE_mask_layer_remove(struct Mask *mask, struct MaskLayer *masklay);
void BKE_mask_layer_free_shapes(struct MaskLayer *masklay);
+void BKE_mask_layer_free_deform(struct MaskLayer *mask_layer);
void BKE_mask_layer_free(struct MaskLayer *masklay);
void BKE_mask_layer_free_list(struct ListBase *masklayers);
void BKE_mask_spline_free(struct MaskSpline *spline);
+void BKE_mask_spline_free_list(struct ListBase *splines);
struct MaskSpline *BKE_mask_spline_copy(struct MaskSpline *spline);
void BKE_mask_point_free(struct MaskSplinePoint *point);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 4e9e18d43e3..27192437c89 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -898,6 +898,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
#define CMP_NODE_PIXELATE 318
#define CMP_NODE_MAP_RANGE 319
+#define CMP_NODE_PLANETRACKDEFORM 320
/* channel toggles */
#define CMP_CHAN_RGB 1
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 84bca0bd3ba..0d148e55753 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -38,6 +38,8 @@ struct ListBase;
struct MovieReconstructContext;
struct MovieTrackingTrack;
struct MovieTrackingMarker;
+struct MovieTrackingPlaneTrack;
+struct MovieTrackingPlaneMarker;
struct MovieTracking;
struct MovieTrackingContext;
struct MovieTrackingObject;
@@ -55,6 +57,7 @@ void BKE_tracking_free(struct MovieTracking *tracking);
void BKE_tracking_settings_init(struct MovieTracking *tracking);
struct ListBase *BKE_tracking_get_active_tracks(struct MovieTracking *tracking);
+struct ListBase *BKE_tracking_get_active_plane_tracks(struct MovieTracking *tracking);
struct MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(struct MovieTracking *tracking);
/* matrices for constraints and drawing */
@@ -97,6 +100,7 @@ float *BKE_tracking_track_get_mask(int frame_width, int frame_height, struct Mov
/* selection */
void BKE_tracking_track_select(struct ListBase *tracksbase, struct MovieTrackingTrack *track, int area, int extend);
void BKE_tracking_track_deselect(struct MovieTrackingTrack *track, int area);
+void BKE_tracking_tracks_deselect_all(struct ListBase *tracksbase);
/* **** Marker **** */
struct MovieTrackingMarker *BKE_tracking_marker_insert(struct MovieTrackingTrack *track,
@@ -113,6 +117,32 @@ void BKE_tracking_marker_pattern_minmax(const struct MovieTrackingMarker *marker
void BKE_tracking_marker_get_subframe_position(struct MovieTrackingTrack *track, float framenr, float pos[2]);
+/* **** Plane Track **** */
+struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(struct MovieTracking *tracking, struct ListBase *plane_tracks_base,
+ struct ListBase *tracks, int framenr);
+void BKE_tracking_plane_track_unique_name(struct ListBase *plane_tracks_base, struct MovieTrackingPlaneTrack *plane_track);
+void BKE_tracking_plane_track_free(struct MovieTrackingPlaneTrack *plane_track);
+
+bool BKE_tracking_plane_track_has_marker_at_frame(struct MovieTrackingPlaneTrack *plane_track, int framenr);
+bool BKE_tracking_plane_track_has_enabled_marker_at_frame(struct MovieTrackingPlaneTrack *plane_track, int framenr);
+
+struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_named(struct MovieTracking *tracking,
+ struct MovieTrackingObject *object,
+ const char *name);
+
+struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct MovieTracking *tracking);
+
+void BKE_tracking_plane_tracks_deselect_all(struct ListBase *plane_tracks_base);
+
+/* **** Plane Marker **** */
+struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(struct MovieTrackingPlaneTrack *plane_track,
+ struct MovieTrackingPlaneMarker *plane_marker);
+void BKE_tracking_plane_marker_delete(struct MovieTrackingPlaneTrack *plane_track, int framenr);
+
+struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(struct MovieTrackingPlaneTrack *plane_track, int framenr);
+struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(struct MovieTrackingPlaneTrack *plane_track, int framenr);
+struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(struct MovieTrackingPlaneTrack *plane_track, int framenr);
+
/* **** Object **** */
struct MovieTrackingObject *BKE_tracking_object_add(struct MovieTracking *tracking, const char *name);
int BKE_tracking_object_delete(struct MovieTracking *tracking, struct MovieTrackingObject *object);
@@ -125,6 +155,7 @@ struct MovieTrackingObject *BKE_tracking_object_get_active(struct MovieTracking
struct MovieTrackingObject *BKE_tracking_object_get_camera(struct MovieTracking *tracking);
struct ListBase *BKE_tracking_object_get_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object);
+struct ListBase *BKE_tracking_object_get_plane_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object);
struct MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(struct MovieTracking *tracking,
struct MovieTrackingObject *object);
@@ -182,6 +213,11 @@ void BKE_tracking_context_sync_user(const struct MovieTrackingContext *context,
int BKE_tracking_context_step(struct MovieTrackingContext *context);
void BKE_tracking_refine_marker(struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, int backwards);
+/* **** Plane tracking **** */
+
+void BKE_tracking_track_plane_from_existing_motion(struct MovieTrackingPlaneTrack *plane_track, int start_frame);
+void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners[4][2], /*const*/ float corners[4][2], float H[3][3]);
+
/* **** Camera solving **** */
int BKE_tracking_reconstruction_check(struct MovieTracking *tracking, struct MovieTrackingObject *object,
char *error_msg, int error_size);
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index e3f30bad5cf..a7bfb15c99d 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -817,6 +817,19 @@ void BKE_mask_spline_free(MaskSpline *spline)
MEM_freeN(spline);
}
+void BKE_mask_spline_free_list(ListBase *splines)
+{
+ MaskSpline *spline = splines->first;
+ while (spline) {
+ MaskSpline *next_spline = spline->next;
+
+ BLI_remlink(splines, spline);
+ BKE_mask_spline_free(spline);
+
+ spline = next_spline;
+ }
+}
+
static MaskSplinePoint *mask_spline_points_copy(MaskSplinePoint *points, int tot_point)
{
MaskSplinePoint *npoints;
@@ -891,20 +904,30 @@ void BKE_mask_layer_free_shapes(MaskLayer *masklay)
}
}
-void BKE_mask_layer_free(MaskLayer *masklay)
+void BKE_mask_layer_free_deform(MaskLayer *mask_layer)
{
- MaskSpline *spline;
-
- /* free splines */
- spline = masklay->splines.first;
- while (spline) {
- MaskSpline *next_spline = spline->next;
+ MaskSpline *mask_spline;
- BLI_remlink(&masklay->splines, spline);
- BKE_mask_spline_free(spline);
-
- spline = next_spline;
+ for (mask_spline = mask_layer->splines.first;
+ mask_spline;
+ mask_spline = mask_spline->next)
+ {
+ if (mask_spline->points_deform) {
+ int i;
+ MaskSplinePoint *points_deform = mask_spline->points_deform;
+ for (i = 0; i < mask_spline->tot_point; i++) {
+ BKE_mask_point_free(&points_deform[i]);
+ }
+ MEM_freeN(points_deform);
+ mask_spline->points_deform = NULL;
+ }
}
+}
+
+void BKE_mask_layer_free(MaskLayer *masklay)
+{
+ /* free splines */
+ BKE_mask_spline_free_list(&masklay->splines);
/* free animation data */
BKE_mask_layer_free_shapes(masklay);
@@ -1072,7 +1095,7 @@ void BKE_mask_coord_to_image(Image *image, ImageUser *iuser, float r_co[2], cons
BKE_mask_coord_to_frame(r_co, co, frame_size);
}
-static int BKE_mask_evaluate_parent(MaskParent *parent, float ctime, float r_co[2])
+static int mask_evaluate_parent(MaskParent *parent, float ctime, float orig_co[2], float r_co[2])
{
if (!parent)
return FALSE;
@@ -1084,18 +1107,38 @@ static int BKE_mask_evaluate_parent(MaskParent *parent, float ctime, float r_co[
MovieTrackingObject *ob = BKE_tracking_object_get_named(tracking, parent->parent);
if (ob) {
- MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, ob, parent->sub_parent);
+ MovieClipUser user = {0};
float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
+ BKE_movieclip_user_set_frame(&user, ctime);
- MovieClipUser user = {0};
- user.framenr = ctime;
+ if (parent->type == MASK_PARENT_POINT_TRACK) {
+ MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, ob, parent->sub_parent);
- if (track) {
- float marker_pos_ofs[2];
- BKE_tracking_marker_get_subframe_position(track, clip_framenr, marker_pos_ofs);
- BKE_mask_coord_from_movieclip(clip, &user, r_co, marker_pos_ofs);
+ if (track) {
+ float marker_pos_ofs[2];
+ BKE_tracking_marker_get_subframe_position(track, clip_framenr, marker_pos_ofs);
+ BKE_mask_coord_from_movieclip(clip, &user, r_co, marker_pos_ofs);
- return TRUE;
+ return TRUE;
+ }
+ }
+ else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ {
+ MovieTrackingPlaneTrack *plane_track = BKE_tracking_plane_track_get_named(tracking, ob, parent->sub_parent);
+
+ if (plane_track) {
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr);
+ float H[3][3], vec[3], warped[3];
+
+ BKE_tracking_homography_between_two_quads(parent->parent_corners_orig, plane_marker->corners, H);
+
+ BKE_mask_coord_to_movieclip(clip, &user, vec, orig_co);
+ vec[2] = 1.0f;
+ mul_v3_m3v3(warped, H, vec);
+ warped[0] /= warped[2];
+ warped[1] /= warped[2];
+
+ BKE_mask_coord_from_movieclip(clip, &user, r_co, warped);
+ }
}
}
}
@@ -1104,17 +1147,26 @@ static int BKE_mask_evaluate_parent(MaskParent *parent, float ctime, float r_co[
return FALSE;
}
-/* could make external but for now its only used internally */
-static int mask_evaluate_parent_delta(MaskParent *parent, float ctime, float r_delta[2])
+static void mask_evaluate_apply_point_parent(MaskSplinePoint *point, float ctime)
{
- float parent_co[2];
+ MaskParent *parent = &point->parent;
+
+ if (parent->type == MASK_PARENT_POINT_TRACK) {
+ float parent_co[2];
- if (BKE_mask_evaluate_parent(parent, ctime, parent_co)) {
- sub_v2_v2v2(r_delta, parent_co, parent->parent_orig);
- return TRUE;
+ if (mask_evaluate_parent(parent, ctime, NULL, parent_co)) {
+ float delta[2];
+ sub_v2_v2v2(delta, parent_co, parent->parent_orig);
+
+ add_v2_v2(point->bezt.vec[0], delta);
+ add_v2_v2(point->bezt.vec[1], delta);
+ add_v2_v2(point->bezt.vec[2], delta);
+ }
}
- else {
- return FALSE;
+ else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ {
+ mask_evaluate_parent(parent, ctime, point->bezt.vec[0], point->bezt.vec[0]);
+ mask_evaluate_parent(parent, ctime, point->bezt.vec[1], point->bezt.vec[1]);
+ mask_evaluate_parent(parent, ctime, point->bezt.vec[2], point->bezt.vec[2]);
}
}
@@ -1438,18 +1490,13 @@ void BKE_mask_layer_evaluate(MaskLayer *masklay, const float ctime, const int do
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
MaskSplinePoint *point_deform = &spline->points_deform[i];
- float delta[2];
BKE_mask_point_free(point_deform);
*point_deform = *point;
point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL;
- if (mask_evaluate_parent_delta(&point->parent, ctime, delta)) {
- add_v2_v2(point_deform->bezt.vec[0], delta);
- add_v2_v2(point_deform->bezt.vec[1], delta);
- add_v2_v2(point_deform->bezt.vec[2], delta);
- }
+ mask_evaluate_apply_point_parent(point_deform, ctime);
if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) {
need_handle_recalc = TRUE;
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 5001aa01653..1349c4dc8d4 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -3391,6 +3391,7 @@ static void registerCompositNodes(void)
register_node_type_cmp_mask();
register_node_type_cmp_trackpos();
+ register_node_type_cmp_planetrackdeform();
}
static void registerShaderNodes(void)
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 4c363292898..54ba9ea56d7 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -103,6 +103,18 @@ static void tracking_tracks_free(ListBase *tracks)
BLI_freelistN(tracks);
}
+/* Free the whole list of plane tracks, list's head and tail are set to NULL. */
+static void tracking_plane_tracks_free(ListBase *plane_tracks)
+{
+ MovieTrackingPlaneTrack *plane_track;
+
+ for (plane_track = plane_tracks->first; plane_track; plane_track = plane_track->next) {
+ BKE_tracking_plane_track_free(plane_track);
+ }
+
+ BLI_freelistN(plane_tracks);
+}
+
/* Free reconstruction structures, only frees contents of a structure,
* (if structure is allocated in heap, it shall be handled outside).
*
@@ -122,6 +134,7 @@ static void tracking_reconstruction_free(MovieTrackingReconstruction *reconstruc
static void tracking_object_free(MovieTrackingObject *object)
{
tracking_tracks_free(&object->tracks);
+ tracking_plane_tracks_free(&object->plane_tracks);
tracking_reconstruction_free(&object->reconstruction);
}
@@ -173,6 +186,7 @@ static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet)
void BKE_tracking_free(MovieTracking *tracking)
{
tracking_tracks_free(&tracking->tracks);
+ tracking_plane_tracks_free(&tracking->plane_tracks);
tracking_reconstruction_free(&tracking->reconstruction);
tracking_objects_free(&tracking->objects);
@@ -221,6 +235,18 @@ ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
return &tracking->tracks;
}
+/* Get list base of active object's plane tracks. */
+ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking)
+{
+ MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
+
+ if (object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+ return &object->plane_tracks;
+ }
+
+ return &tracking->plane_tracks;
+}
+
/* Get reconstruction data of active object. */
MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTracking *tracking)
{
@@ -1025,6 +1051,17 @@ void BKE_tracking_track_deselect(MovieTrackingTrack *track, int area)
BKE_tracking_track_flag_clear(track, area, SELECT);
}
+void BKE_tracking_tracks_deselect_all(ListBase *tracksbase)
+{
+ MovieTrackingTrack *track;
+
+ for (track = tracksbase->first; track; track = track->next) {
+ if ((track->flag & TRACK_HIDDEN) == 0) {
+ BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT);
+ }
+ }
+}
+
/*********************** Marker *************************/
MovieTrackingMarker *BKE_tracking_marker_insert(MovieTrackingTrack *track, MovieTrackingMarker *marker)
@@ -1264,6 +1301,296 @@ void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track, float
add_v2_v2(pos, track->offset);
}
+/*********************** Plane Track *************************/
+
+/* Creates new plane track out of selected point tracks */
+MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking, ListBase *plane_tracks_base,
+ ListBase *tracks, int framenr)
+{
+ MovieTrackingPlaneTrack *plane_track;
+ MovieTrackingPlaneMarker plane_marker;
+ MovieTrackingTrack *track;
+ float tracks_min[2], tracks_max[2];
+ int track_index, num_selected_tracks = 0;
+
+ (void) tracking; /* Ignored. */
+
+ /* Use bounding box of selected markers as an initial size of plane. */
+ INIT_MINMAX2(tracks_min, tracks_max);
+ for (track = tracks->first; track; track = track->next) {
+ if (TRACK_SELECTED(track)) {
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+ float pattern_min[2], pattern_max[2];
+ BKE_tracking_marker_pattern_minmax(marker, pattern_min, pattern_max);
+ add_v2_v2(pattern_min, marker->pos);
+ add_v2_v2(pattern_max, marker->pos);
+ minmax_v2v2_v2(tracks_min, tracks_max, pattern_min);
+ minmax_v2v2_v2(tracks_min, tracks_max, pattern_max);
+ num_selected_tracks++;
+ }
+ }
+
+ if (num_selected_tracks < 4) {
+ return NULL;
+ }
+
+ /* Allocate new plane track. */
+ plane_track = MEM_callocN(sizeof(MovieTrackingPlaneTrack), "new plane track");
+
+ /* Use some default name. */
+ strcpy(plane_track->name, "Plane Track");
+
+ /* Use selected tracks from given list as a plane. */
+ plane_track->point_tracks = MEM_mallocN(sizeof(MovieTrackingTrack *) * num_selected_tracks, "new plane tracks array");
+ for (track = tracks->first, track_index = 0; track; track = track->next) {
+ if (TRACK_SELECTED(track)) {
+ plane_track->point_tracks[track_index] = track;
+ track_index++;
+ }
+ }
+ plane_track->point_tracksnr = num_selected_tracks;
+
+ /* Setup new plane marker and add it to the track. */
+ plane_marker.framenr = framenr;
+ plane_marker.flag = 0;
+
+ copy_v2_v2(plane_marker.corners[0], tracks_min);
+ copy_v2_v2(plane_marker.corners[2], tracks_max);
+
+ plane_marker.corners[1][0] = tracks_max[0];
+ plane_marker.corners[1][1] = tracks_min[1];
+ plane_marker.corners[3][0] = tracks_min[0];
+ plane_marker.corners[3][1] = tracks_max[1];
+
+ BKE_tracking_plane_marker_insert(plane_track, &plane_marker);
+
+ /* Put new plane track to the list, ensure it's name is unique. */
+ BLI_addtail(plane_tracks_base, plane_track);
+ BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track);
+
+ return plane_track;
+}
+
+void BKE_tracking_plane_track_unique_name(ListBase *plane_tracks_base, MovieTrackingPlaneTrack *plane_track)
+{
+ BLI_uniquename(plane_tracks_base, plane_track, CTX_DATA_(BLF_I18NCONTEXT_ID_MOVIECLIP, "Plane Track"), '.',
+ offsetof(MovieTrackingPlaneTrack, name), sizeof(plane_track->name));
+}
+
+/* Free specified plane track, only frees contents of a structure
+ * (if track is allocated in heap, it shall be handled outside).
+ *
+ * All the pointers inside track becomes invalid after this call.
+ */
+void BKE_tracking_plane_track_free(MovieTrackingPlaneTrack *plane_track)
+{
+ if (plane_track->markers) {
+ MEM_freeN(plane_track->markers);
+ }
+
+ MEM_freeN(plane_track->point_tracks);
+}
+
+MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_named(MovieTracking *tracking,
+ MovieTrackingObject *object,
+ const char *name)
+{
+ ListBase *plane_tracks_base = BKE_tracking_object_get_plane_tracks(tracking, object);
+ MovieTrackingPlaneTrack *plane_track;
+
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if (!strcmp(plane_track->name, name)) {
+ return plane_track;
+ }
+ }
+
+ return NULL;
+}
+
+MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct MovieTracking *tracking)
+{
+ ListBase *plane_tracks_base;
+
+ if (tracking->act_plane_track == NULL) {
+ return NULL;
+ }
+
+ plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+
+ /* Check that active track is in current plane tracks list */
+ if (BLI_findindex(plane_tracks_base, tracking->act_plane_track) >= 0) {
+ return tracking->act_plane_track;
+ }
+
+ return NULL;
+}
+
+void BKE_tracking_plane_tracks_deselect_all(ListBase *plane_tracks_base)
+{
+ MovieTrackingPlaneTrack *plane_track;
+
+ for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
+ plane_track->flag &= ~SELECT;
+ }
+}
+
+/*********************** Plane Marker *************************/
+
+MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingPlaneMarker *plane_marker)
+{
+ MovieTrackingPlaneMarker *old_plane_marker = NULL;
+
+ if (plane_track->markersnr)
+ old_plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, plane_marker->framenr);
+
+ if (old_plane_marker) {
+ /* Simply replace settings in existing marker. */
+ *old_plane_marker = *plane_marker;
+
+ return old_plane_marker;
+ }
+ else {
+ int a = plane_track->markersnr;
+
+ /* Find position in array where to add new marker. */
+ /* TODO(sergey): we coud use bisect to speed things up. */
+ while (a--) {
+ if (plane_track->markers[a].framenr < plane_marker->framenr) {
+ break;
+ }
+ }
+
+ plane_track->markersnr++;
+ plane_track->markers = MEM_reallocN(plane_track->markers,
+ sizeof(MovieTrackingPlaneMarker) * plane_track->markersnr);
+
+ /* Shift array to "free" space for new marker. */
+ memmove(plane_track->markers + a + 2, plane_track->markers + a + 1,
+ (plane_track->markersnr - a - 2) * sizeof(MovieTrackingPlaneMarker));
+
+ /* Put new marker to an array. */
+ plane_track->markers[a + 1] = *plane_marker;
+ plane_track->last_marker = a + 1;
+
+ return &plane_track->markers[a + 1];
+ }
+}
+
+void BKE_tracking_plane_marker_delete(MovieTrackingPlaneTrack *plane_track, int framenr)
+{
+ int a = 0;
+
+ while (a < plane_track->markersnr) {
+ if (plane_track->markers[a].framenr == framenr) {
+ if (plane_track->markersnr > 1) {
+ memmove(plane_track->markers + a, plane_track->markers + a + 1,
+ (plane_track->markersnr - a - 1) * sizeof(MovieTrackingPlaneMarker));
+ plane_track->markersnr--;
+ plane_track->markers = MEM_reallocN(plane_track->markers,
+ sizeof(MovieTrackingMarker) * plane_track->markersnr);
+ }
+ else {
+ MEM_freeN(plane_track->markers);
+ plane_track->markers = NULL;
+ plane_track->markersnr = 0;
+ }
+
+ break;
+ }
+
+ a++;
+ }
+}
+
+/* TODO(sergey): The next couple of functions are really quite the same as point marker version,
+ * would be nice to de-duplicate them somehow..
+ */
+
+/* Get a plane marker at given frame,
+ * If there's no such marker, closest one from the left side will be returned.
+ */
+MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack *plane_track, int framenr)
+{
+ int a = plane_track->markersnr - 1;
+
+ if (!plane_track->markersnr)
+ return NULL;
+
+ /* Approximate pre-first framenr marker with first marker. */
+ if (framenr < plane_track->markers[0].framenr) {
+ return &plane_track->markers[0];
+ }
+
+ if (plane_track->last_marker < plane_track->markersnr) {
+ a = plane_track->last_marker;
+ }
+
+ if (plane_track->markers[a].framenr <= framenr) {
+ while (a < plane_track->markersnr && plane_track->markers[a].framenr <= framenr) {
+ if (plane_track->markers[a].framenr == framenr) {
+ plane_track->last_marker = a;
+
+ return &plane_track->markers[a];
+ }
+ a++;
+ }
+
+ /* If there's no marker for exact position, use nearest marker from left side. */
+ return &plane_track->markers[a - 1];
+ }
+ else {
+ while (a >= 0 && plane_track->markers[a].framenr >= framenr) {
+ if (plane_track->markers[a].framenr == framenr) {
+ plane_track->last_marker = a;
+
+ return &plane_track->markers[a];
+ }
+
+ a--;
+ }
+
+ /* If there's no marker for exact position, use nearest marker from left side. */
+ return &plane_track->markers[a];
+ }
+
+ return NULL;
+}
+
+/* Get a plane marker at exact given frame, if there's no marker at the frame,
+ * NULL will be returned.
+ */
+MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlaneTrack *plane_track, int framenr)
+{
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
+
+ if (plane_marker->framenr != framenr) {
+ return NULL;
+ }
+
+ return plane_marker;
+}
+
+/* Ensure there's a marker for the given frame. */
+MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTrack *plane_track, int framenr)
+{
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
+
+ if (plane_marker->framenr != framenr) {
+ MovieTrackingPlaneMarker plane_marker_new;
+
+ plane_marker_new = *plane_marker;
+ plane_marker_new.framenr = framenr;
+
+ plane_marker = BKE_tracking_plane_marker_insert(plane_track, &plane_marker_new);
+ }
+
+ return plane_marker;
+}
+
/*********************** Object *************************/
MovieTrackingObject *BKE_tracking_object_add(MovieTracking *tracking, const char *name)
@@ -1379,6 +1706,15 @@ ListBase *BKE_tracking_object_get_tracks(MovieTracking *tracking, MovieTrackingO
return &object->tracks;
}
+ListBase *BKE_tracking_object_get_plane_tracks(MovieTracking *tracking, MovieTrackingObject *object)
+{
+ if (object->flag & TRACKING_OBJECT_CAMERA) {
+ return &tracking->plane_tracks;
+ }
+
+ return &object->plane_tracks;
+}
+
MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(MovieTracking *tracking,
MovieTrackingObject *object)
{
@@ -2528,7 +2864,7 @@ static bool track_context_update_reference(MovieTrackingContext *context, TrackC
}
/* Fill in libmv tracker options structure with settings need to be used to perform track. */
-static void tracking_configure_tracker(MovieTrackingTrack *track, float *mask,
+static void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask,
libmv_TrackRegionOptions *options)
{
options->motion_model = track->motion_model;
@@ -2863,6 +3199,147 @@ void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, Movi
IMB_freeImBuf(destination_ibuf);
}
+/*********************** Plane tracking *************************/
+
+typedef double Vec2[2];
+
+static int point_markers_correspondences_on_both_image(MovieTrackingPlaneTrack *plane_track, int frame1, int frame2,
+ Vec2 **x1_r, Vec2 **x2_r)
+{
+ int i, correspondence_index;
+ Vec2 *x1, *x2;
+
+ *x1_r = x1 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x1");
+ *x2_r = x2 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x2");
+
+ for (i = 0, correspondence_index = 0; i < plane_track->point_tracksnr; i++) {
+ MovieTrackingTrack *point_track = plane_track->point_tracks[i];
+ MovieTrackingMarker *point_marker1, *point_marker2;
+
+ point_marker1 = BKE_tracking_marker_get_exact(point_track, frame1);
+ point_marker2 = BKE_tracking_marker_get_exact(point_track, frame2);
+
+ if (point_marker1 != NULL && point_marker2 != NULL) {
+ /* Here conversion from float to double happens. */
+ x1[correspondence_index][0] = point_marker1->pos[0];
+ x1[correspondence_index][1] = point_marker1->pos[1];
+
+ x2[correspondence_index][0] = point_marker2->pos[0];
+ x2[correspondence_index][1] = point_marker2->pos[1];
+
+ correspondence_index++;
+ }
+ }
+
+ return correspondence_index;
+}
+
+/* TODO(sergey): Make it generic function available for everyone. */
+BLI_INLINE void mat3f_from_mat3d(float mat_float[3][3], double mat_double[3][3])
+{
+ /* Keep it stupid simple for better data flow in CPU. */
+ mat_float[0][0] = mat_double[0][0];
+ mat_float[0][1] = mat_double[0][1];
+ mat_float[0][2] = mat_double[0][2];
+
+ mat_float[1][0] = mat_double[1][0];
+ mat_float[1][1] = mat_double[1][1];
+ mat_float[1][2] = mat_double[1][2];
+
+ mat_float[2][0] = mat_double[2][0];
+ mat_float[2][1] = mat_double[2][1];
+ mat_float[2][2] = mat_double[2][2];
+}
+
+/* NOTE: frame number should be in clip space, not scene space */
+static void track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track, int start_frame, int direction)
+{
+ MovieTrackingPlaneMarker *start_plane_marker = BKE_tracking_plane_marker_get(plane_track, start_frame);
+ MovieTrackingPlaneMarker new_plane_marker;
+ int current_frame, frame_delta = direction > 0 ? 1 : -1;
+
+ new_plane_marker = *start_plane_marker;
+ new_plane_marker.flag |= PLANE_MARKER_TRACKED;
+
+ for (current_frame = start_frame; ; current_frame += frame_delta) {
+ MovieTrackingPlaneMarker *next_plane_marker =
+ BKE_tracking_plane_marker_get_exact(plane_track, current_frame + frame_delta);
+ Vec2 *x1, *x2;
+ int i, num_correspondences;
+ double H_double[3][3];
+ float H[3][3];
+
+ /* As soon as we meet keyframed plane, we stop updating the sequence. */
+ if (next_plane_marker && (next_plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
+ break;
+ }
+
+ num_correspondences =
+ point_markers_correspondences_on_both_image(plane_track, current_frame, current_frame + frame_delta,
+ &x1, &x2);
+
+ if (num_correspondences < 4) {
+ MEM_freeN(x1);
+ MEM_freeN(x2);
+
+ break;
+ }
+
+ libmv_homography2DFromCorrespondencesLinear(x1, x2, num_correspondences, H_double, 1e-8);
+
+ mat3f_from_mat3d(H, H_double);
+
+ for (i = 0; i < 4; i++) {
+ float vec[3] = {0.0f, 0.0f, 1.0f}, vec2[3];
+ copy_v2_v2(vec, new_plane_marker.corners[i]);
+
+ /* Apply homography */
+ mul_v3_m3v3(vec2, H, vec);
+
+ /* Normalize. */
+ vec2[0] /= vec2[2];
+ vec2[1] /= vec2[2];
+
+ copy_v2_v2(new_plane_marker.corners[i], vec2);
+ }
+
+ new_plane_marker.framenr = current_frame + frame_delta;
+
+ BKE_tracking_plane_marker_insert(plane_track, &new_plane_marker);
+
+ MEM_freeN(x1);
+ MEM_freeN(x2);
+ }
+}
+
+/* NOTE: frame number should be in clip space, not scene space */
+void BKE_tracking_track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track, int start_frame)
+{
+ track_plane_from_existing_motion(plane_track, start_frame, 1);
+ track_plane_from_existing_motion(plane_track, start_frame, -1);
+}
+
+BLI_INLINE void float_corners_to_double(/*const*/ float corners[4][2], double double_corners[4][2])
+{
+ copy_v2db_v2fl(double_corners[0], corners[0]);
+ copy_v2db_v2fl(double_corners[1], corners[1]);
+ copy_v2db_v2fl(double_corners[2], corners[2]);
+ copy_v2db_v2fl(double_corners[3], corners[3]);
+}
+
+void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners[4][2], /*const*/ float corners[4][2], float H[3][3])
+{
+ Vec2 x1[4], x2[4];
+ double H_double[3][3];
+
+ float_corners_to_double(reference_corners, x1);
+ float_corners_to_double(corners, x2);
+
+ libmv_homography2DFromCorrespondencesLinear(x1, x2, 4, H_double, 1e-8);
+
+ mat3f_from_mat3d(H, H_double);
+}
+
/*********************** Camera solving *************************/
typedef struct MovieReconstructContext {
@@ -3264,7 +3741,6 @@ static void reconstruct_update_solve_cb(void *customdata, double progress, const
BLI_snprintf(progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
}
-
/* FIll in camera intrinsics structure from reconstruction context. */
static void camraIntrincicsOptionsFromContext(libmv_CameraIntrinsicsOptions *camera_intrinsics_options,
MovieReconstructContext *context)
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 22ab7e49973..37cebc3063d 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -6687,6 +6687,28 @@ static void direct_link_movieTracks(FileData *fd, ListBase *tracksbase)
}
}
+static void direct_link_moviePlaneTracks(FileData *fd, ListBase *plane_tracks_base)
+{
+ MovieTrackingPlaneTrack *plane_track;
+
+ link_list(fd, plane_tracks_base);
+
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ int i;
+
+ plane_track->point_tracks = newdataadr(fd, plane_track->point_tracks);
+
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ plane_track->point_tracks[i] = newdataadr(fd, plane_track->point_tracks[i]);
+ }
+
+ plane_track->markers = newdataadr(fd, plane_track->markers);
+ }
+}
+
static void direct_link_movieclip(FileData *fd, MovieClip *clip)
{
MovieTracking *tracking = &clip->tracking;
@@ -6701,9 +6723,11 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip)
else clip->tracking.camera.intrinsics = NULL;
direct_link_movieTracks(fd, &tracking->tracks);
+ direct_link_moviePlaneTracks(fd, &tracking->plane_tracks);
direct_link_movieReconstruction(fd, &tracking->reconstruction);
clip->tracking.act_track = newdataadr(fd, clip->tracking.act_track);
+ clip->tracking.act_plane_track = newdataadr(fd, clip->tracking.act_plane_track);
clip->anim = NULL;
clip->tracking_context = NULL;
@@ -6720,6 +6744,7 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip)
for (object = tracking->objects.first; object; object = object->next) {
direct_link_movieTracks(fd, &object->tracks);
+ direct_link_moviePlaneTracks(fd, &object->plane_tracks);
direct_link_movieReconstruction(fd, &object->reconstruction);
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 4f0ccd3c626..f3d58c42bc8 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -2920,6 +2920,21 @@ static void write_movieTracks(WriteData *wd, ListBase *tracks)
}
}
+static void write_moviePlaneTracks(WriteData *wd, ListBase *plane_tracks_base)
+{
+ MovieTrackingPlaneTrack *plane_track;
+
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ writestruct(wd, DATA, "MovieTrackingPlaneTrack", 1, plane_track);
+
+ writedata(wd, DATA, sizeof(MovieTrackingTrack *) * plane_track->point_tracksnr, plane_track->point_tracks);
+ writestruct(wd, DATA, "MovieTrackingPlaneMarker", plane_track->markersnr, plane_track->markers);
+ }
+}
+
static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction *reconstruction)
{
if (reconstruction->camnr)
@@ -2944,6 +2959,7 @@ static void write_movieclips(WriteData *wd, ListBase *idbase)
write_animdata(wd, clip->adt);
write_movieTracks(wd, &tracking->tracks);
+ write_moviePlaneTracks(wd, &tracking->plane_tracks);
write_movieReconstruction(wd, &tracking->reconstruction);
object= tracking->objects.first;
@@ -2951,6 +2967,7 @@ static void write_movieclips(WriteData *wd, ListBase *idbase)
writestruct(wd, DATA, "MovieTrackingObject", 1, object);
write_movieTracks(wd, &object->tracks);
+ write_moviePlaneTracks(wd, &object->plane_tracks);
write_movieReconstruction(wd, &object->reconstruction);
object= object->next;
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index c1b99274bed..a119a89c842 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -184,6 +184,9 @@ set(SRC
nodes/COM_GlareNode.cpp
nodes/COM_GlareNode.h
+ nodes/COM_PlaneTrackDeformNode.cpp
+ nodes/COM_PlaneTrackDeformNode.h
+
nodes/COM_CropNode.cpp
nodes/COM_CropNode.h
operations/COM_CropOperation.cpp
@@ -595,6 +598,12 @@ set(SRC
operations/COM_ProjectorLensDistortionOperation.h
operations/COM_ScreenLensDistortionOperation.cpp
operations/COM_ScreenLensDistortionOperation.h
+ operations/COM_PlaneTrackCommonOperation.cpp
+ operations/COM_PlaneTrackCommonOperation.h
+ operations/COM_PlaneTrackMaskOperation.cpp
+ operations/COM_PlaneTrackMaskOperation.h
+ operations/COM_PlaneTrackWarpImageOperation.cpp
+ operations/COM_PlaneTrackWarpImageOperation.h
#Filter operations
operations/COM_ConvolutionFilterOperation.h
diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp
index 80ae952b87f..db0cdd1692e 100644
--- a/source/blender/compositor/intern/COM_Converter.cpp
+++ b/source/blender/compositor/intern/COM_Converter.cpp
@@ -121,6 +121,7 @@
#include "COM_ViewerNode.h"
#include "COM_ZCombineNode.h"
#include "COM_PixelateNode.h"
+#include "COM_PlaneTrackDeformNode.h"
Node *Converter::convert(bNode *b_node, bool fast)
{
@@ -402,6 +403,9 @@ Node *Converter::convert(bNode *b_node, bool fast)
case CMP_NODE_PIXELATE:
node = new PixelateNode(b_node);
break;
+ case CMP_NODE_PLANETRACKDEFORM:
+ node = new PlaneTrackDeformNode(b_node);
+ break;
default:
node = new MuteNode(b_node);
break;
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
new file mode 100644
index 00000000000..d6434c26c7d
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Jeroen Bakker
+ * Monique Dewanchand
+ * Sergey Sharybin
+ */
+
+#include "COM_PlaneTrackDeformNode.h"
+#include "COM_ExecutionSystem.h"
+
+#include "COM_PlaneTrackMaskOperation.h"
+#include "COM_PlaneTrackWarpImageOperation.h"
+
+extern "C" {
+ #include "BKE_node.h"
+ #include "BKE_movieclip.h"
+ #include "BKE_tracking.h"
+}
+
+PlaneTrackDeformNode::PlaneTrackDeformNode(bNode *editorNode) : Node(editorNode)
+{
+ /* pass */
+}
+
+void PlaneTrackDeformNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
+{
+ InputSocket *input_image = this->getInputSocket(0);
+
+ OutputSocket *output_warped_image = this->getOutputSocket(0);
+ OutputSocket *output_plane = this->getOutputSocket(1);
+
+ bNode *editorNode = this->getbNode();
+ MovieClip *clip = (MovieClip *) editorNode->id;
+
+ NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *) editorNode->storage;
+
+ int frame_number = context->getFramenumber();
+
+ if (output_warped_image->isConnected()) {
+ PlaneTrackWarpImageOperation *warp_image_operation = new PlaneTrackWarpImageOperation();
+
+ warp_image_operation->setMovieClip(clip);
+ warp_image_operation->setTrackingObject(data->tracking_object);
+ warp_image_operation->setPlaneTrackName(data->plane_track_name);
+ warp_image_operation->setFramenumber(frame_number);
+
+ input_image->relinkConnections(warp_image_operation->getInputSocket(0), 0, graph);
+ output_warped_image->relinkConnections(warp_image_operation->getOutputSocket());
+
+ graph->addOperation(warp_image_operation);
+ }
+
+ if (output_plane->isConnected()) {
+ PlaneTrackMaskOperation *plane_mask_operation = new PlaneTrackMaskOperation();
+
+ plane_mask_operation->setMovieClip(clip);
+ plane_mask_operation->setTrackingObject(data->tracking_object);
+ plane_mask_operation->setPlaneTrackName(data->plane_track_name);
+ plane_mask_operation->setFramenumber(frame_number);
+
+ output_plane->relinkConnections(plane_mask_operation->getOutputSocket());
+
+ graph->addOperation(plane_mask_operation);
+ }
+}
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
new file mode 100644
index 00000000000..cf173cd19f9
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Sergey Sharybin
+ */
+
+#include "COM_Node.h"
+#include "DNA_node_types.h"
+
+extern "C" {
+ #include "DNA_movieclip_types.h"
+ #include "DNA_node_types.h"
+}
+
+/**
+ * @brief PlaneTrackDeformNode
+ * @ingroup Node
+ */
+class PlaneTrackDeformNode : public Node {
+public:
+ PlaneTrackDeformNode(bNode *editorNode);
+ void convertToOperations(ExecutionSystem *graph, CompositorContext *context);
+};
diff --git a/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp
new file mode 100644
index 00000000000..51e803f696b
--- /dev/null
+++ b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Sergey Sharybin
+ */
+
+#include "COM_PlaneTrackMaskOperation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+
+extern "C" {
+ #include "BKE_movieclip.h"
+ #include "BKE_node.h"
+ #include "BKE_tracking.h"
+}
+
+PlaneTrackCommonOperation::PlaneTrackCommonOperation() : NodeOperation()
+{
+ this->m_movieClip = NULL;
+ this->m_framenumber = 0;
+ this->m_trackingObjectName[0] = '\0';
+ this->m_planeTrackName[0] = '\0';
+}
+
+void PlaneTrackCommonOperation::initExecution()
+{
+ MovieTracking *tracking;
+ MovieTrackingObject *object;
+
+ memset(this->m_corners, 0, sizeof(this->m_corners));
+ memset(this->m_frameSpaceCorners, 0, sizeof(this->m_frameSpaceCorners));
+
+ if (!this->m_movieClip)
+ return;
+
+ tracking = &this->m_movieClip->tracking;
+
+ object = BKE_tracking_object_get_named(tracking, this->m_trackingObjectName);
+ if (object) {
+ MovieTrackingPlaneTrack *plane_track;
+
+ plane_track = BKE_tracking_plane_track_get_named(tracking, object, this->m_planeTrackName);
+
+ if (plane_track) {
+ MovieTrackingPlaneMarker *plane_marker;
+ int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber);
+
+ plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr);
+ memcpy(this->m_corners, plane_marker->corners, sizeof(this->m_corners));
+ }
+ }
+
+ for (int i = 0; i < 4; i++) {
+ this->m_frameSpaceCorners[i][0] = this->m_corners[i][0] * this->getWidth();
+ this->m_frameSpaceCorners[i][1] = this->m_corners[i][1] * this->getHeight();
+ }
+}
+
+void PlaneTrackCommonOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
+{
+ NodeOperation::determineResolution(resolution, preferredResolution);
+
+ resolution[0] = 0;
+ resolution[1] = 0;
+
+ if (this->m_movieClip) {
+ int width, height;
+ MovieClipUser user = {0};
+
+ BKE_movieclip_user_set_frame(&user, this->m_framenumber);
+ BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height);
+
+ resolution[0] = width;
+ resolution[1] = height;
+ }
+}
diff --git a/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h
new file mode 100644
index 00000000000..705bdf4bd81
--- /dev/null
+++ b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h
@@ -0,0 +1,62 @@
+
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Sergey Sharybin
+ */
+
+#ifndef _COM_PlaneTrackCommonOperation_h
+#define _COM_PlaneTrackCommonOperation_h
+
+#include <string.h>
+
+#include "COM_NodeOperation.h"
+
+#include "DNA_movieclip_types.h"
+#include "DNA_tracking_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+class PlaneTrackCommonOperation : public NodeOperation {
+protected:
+ MovieClip *m_movieClip;
+ int m_framenumber;
+ char m_trackingObjectName[64];
+ char m_planeTrackName[64];
+
+ float m_corners[4][2]; /* Corners coordinates in normalized space. */
+ float m_frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */
+
+ /**
+ * Determine the output resolution. The resolution is retrieved from the Renderer
+ */
+ void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
+
+public:
+ PlaneTrackCommonOperation();
+
+ void setMovieClip(MovieClip *clip) {this->m_movieClip = clip;}
+ void setTrackingObject(char *object) { BLI_strncpy(this->m_trackingObjectName, object, sizeof(this->m_trackingObjectName)); }
+ void setPlaneTrackName(char *plane_track) { BLI_strncpy(this->m_planeTrackName, plane_track, sizeof(this->m_planeTrackName)); }
+ void setFramenumber(int framenumber) {this->m_framenumber = framenumber;}
+
+ void initExecution();
+};
+
+#endif
diff --git a/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp
new file mode 100644
index 00000000000..fe794cb769f
--- /dev/null
+++ b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Sergey Sharybin
+ */
+
+#include "COM_PlaneTrackMaskOperation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+
+extern "C" {
+ #include "BLI_jitter.h"
+
+ #include "BKE_movieclip.h"
+ #include "BKE_node.h"
+ #include "BKE_tracking.h"
+}
+
+PlaneTrackMaskOperation::PlaneTrackMaskOperation() : PlaneTrackCommonOperation()
+{
+ this->addOutputSocket(COM_DT_VALUE);
+}
+
+void PlaneTrackMaskOperation::initExecution()
+{
+ PlaneTrackCommonOperation::initExecution();
+
+ const int osa = 8;
+ this->m_osa = osa;
+ BLI_jitter_init(this->m_jitter[0], osa);
+}
+
+void PlaneTrackMaskOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
+{
+ float point[2];
+
+ int inside_counter = 0;
+ for (int sample = 0; sample < this->m_osa; sample++) {
+ point[0] = x + this->m_jitter[sample][0];
+ point[1] = y + this->m_jitter[sample][1];
+
+ if (isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[1], this->m_frameSpaceCorners[2]) ||
+ isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[2], this->m_frameSpaceCorners[3]))
+ {
+ inside_counter++;
+ }
+ }
+
+ output[0] = (float) inside_counter / this->m_osa;
+}
diff --git a/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h
new file mode 100644
index 00000000000..db32f9830e0
--- /dev/null
+++ b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h
@@ -0,0 +1,49 @@
+
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Sergey Sharybin
+ */
+
+#ifndef _COM_PlaneTrackMaskOperation_h
+#define _COM_PlaneTrackMaskOperation_h
+
+#include <string.h>
+
+#include "COM_PlaneTrackCommonOperation.h"
+
+#include "DNA_movieclip_types.h"
+#include "DNA_tracking_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+class PlaneTrackMaskOperation : public PlaneTrackCommonOperation {
+protected:
+ int m_osa;
+ float m_jitter[32][2];
+
+public:
+ PlaneTrackMaskOperation();
+
+ void initExecution();
+
+ void executePixel(float output[4], float x, float y, PixelSampler sampler);
+};
+
+#endif
diff --git a/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp
new file mode 100644
index 00000000000..9bbf45682f2
--- /dev/null
+++ b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Sergey Sharybin
+ */
+
+#include "COM_PlaneTrackWarpImageOperation.h"
+#include "COM_ReadBufferOperation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+
+extern "C" {
+ #include "BLI_jitter.h"
+
+ #include "BKE_movieclip.h"
+ #include "BKE_node.h"
+ #include "BKE_tracking.h"
+}
+
+BLI_INLINE bool isPointInsideQuad(const float x, const float y, const float corners[4][2])
+{
+ float point[2];
+
+ point[0] = x;
+ point[1] = y;
+
+ return isect_point_tri_v2(point, corners[0], corners[1], corners[2]) ||
+ isect_point_tri_v2(point, corners[0], corners[2], corners[3]);
+}
+
+BLI_INLINE bool resolveUV(const float x, const float y, const float corners[4][2], float uv[2])
+{
+ float point[2];
+ bool inside;
+
+ inside = isPointInsideQuad(x, y, corners);
+
+ point[0] = x;
+ point[1] = y;
+
+ /* Use reverse bilinear to get UV coordinates within original frame */
+ resolve_quad_uv(uv, point, corners[0], corners[1], corners[2], corners[3]);
+
+ return inside;
+}
+
+BLI_INLINE void resolveUVAndDxDy(const float x, const float y, const float corners[4][2],
+ float *u_r, float *v_r, float *dx_r, float *dy_r)
+{
+ float inputUV[2];
+ float uv_a[2], uv_b[2];
+
+ float dx, dy;
+ float uv_l, uv_r;
+ float uv_u, uv_d;
+
+ bool ok1, ok2;
+
+ resolveUV(x, y, corners, inputUV);
+
+ /* adaptive sampling, red (U) channel */
+ ok1 = resolveUV(x - 1, y, corners, uv_a);
+ ok2 = resolveUV(x + 1, y, corners, uv_b);
+ uv_l = ok1 ? fabsf(inputUV[0] - uv_a[0]) : 0.0f;
+ uv_r = ok2 ? fabsf(inputUV[0] - uv_b[0]) : 0.0f;
+
+ dx = 0.5f * (uv_l + uv_r);
+
+ /* adaptive sampling, green (V) channel */
+ ok1 = resolveUV(x, y - 1, corners, uv_a);
+ ok2 = resolveUV(x, y + 1, corners, uv_b);
+ uv_u = ok1 ? fabsf(inputUV[1] - uv_a[1]) : 0.f;
+ uv_d = ok2 ? fabsf(inputUV[1] - uv_b[1]) : 0.f;
+
+ dy = 0.5f * (uv_u + uv_d);
+
+ /* more adaptive sampling, red and green (UV) channels */
+ ok1 = resolveUV(x - 1, y - 1, corners, uv_a);
+ ok2 = resolveUV(x - 1, y + 1, corners, uv_b);
+ uv_l = ok1 ? fabsf(inputUV[0] - uv_a[0]) : 0.f;
+ uv_r = ok2 ? fabsf(inputUV[0] - uv_b[0]) : 0.f;
+ uv_u = ok1 ? fabsf(inputUV[1] - uv_a[1]) : 0.f;
+ uv_d = ok2 ? fabsf(inputUV[1] - uv_b[1]) : 0.f;
+
+ dx += 0.25f * (uv_l + uv_r);
+ dy += 0.25f * (uv_u + uv_d);
+
+ ok1 = resolveUV(x + 1, y - 1, corners, uv_a);
+ ok2 = resolveUV(x + 1, y + 1, corners, uv_b);
+ uv_l = ok1 ? fabsf(inputUV[0] - uv_a[0]) : 0.f;
+ uv_r = ok2 ? fabsf(inputUV[0] - uv_b[0]) : 0.f;
+ uv_u = ok1 ? fabsf(inputUV[1] - uv_a[1]) : 0.f;
+ uv_d = ok2 ? fabsf(inputUV[1] - uv_b[1]) : 0.f;
+
+ dx += 0.25f * (uv_l + uv_r);
+ dy += 0.25f * (uv_u + uv_d);
+
+ /* should use mipmap */
+ *dx_r = min(dx, 0.2f);
+ *dy_r = min(dy, 0.2f);
+
+ *u_r = inputUV[0];
+ *v_r = inputUV[1];
+}
+
+PlaneTrackWarpImageOperation::PlaneTrackWarpImageOperation() : PlaneTrackCommonOperation()
+{
+ this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE);
+ this->addOutputSocket(COM_DT_COLOR);
+ this->m_pixelReader = NULL;
+ this->setComplex(true);
+}
+
+void PlaneTrackWarpImageOperation::initExecution()
+{
+ PlaneTrackCommonOperation::initExecution();
+
+ this->m_pixelReader = this->getInputSocketReader(0);
+
+ const int osa = 8;
+ this->m_osa = osa;
+ BLI_jitter_init(this->m_jitter[0], osa);
+}
+
+void PlaneTrackWarpImageOperation::deinitExecution()
+{
+ this->m_pixelReader = NULL;
+}
+
+void PlaneTrackWarpImageOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
+{
+ float color_accum[4];
+
+ zero_v4(color_accum);
+ for (int sample = 0; sample < this->m_osa; sample++) {
+ float current_x = x + this->m_jitter[sample][0],
+ current_y = y + this->m_jitter[sample][1];
+ if (isPointInsideQuad(current_x, current_y, this->m_frameSpaceCorners)) {
+ float current_color[4];
+ float u, v, dx, dy;
+
+ resolveUVAndDxDy(current_x, current_y, this->m_frameSpaceCorners, &u, &v, &dx, &dy);
+
+ u *= this->m_pixelReader->getWidth();
+ v *= this->m_pixelReader->getHeight();
+
+ this->m_pixelReader->read(current_color, u, v, dx, dy, COM_PS_BICUBIC);
+ premul_to_straight_v4(current_color);
+ add_v4_v4(color_accum, current_color);
+ }
+ }
+
+ mul_v4_v4fl(output, color_accum, 1.0f / this->m_osa);
+ straight_to_premul_v4(output);
+}
+
+bool PlaneTrackWarpImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+{
+ float frame_space_corners[4][2];
+
+ for (int i = 0; i < 4; i++) {
+ frame_space_corners[i][0] = this->m_corners[i][0] * this->getWidth();
+ frame_space_corners[i][1] = this->m_corners[i][1] * this->getHeight();
+ }
+
+ float UVs[4][2];
+
+ /* TODO(sergey): figure out proper way to do this. */
+ resolveUV(input->xmin - 2, input->ymin - 2, frame_space_corners, UVs[0]);
+ resolveUV(input->xmax + 2, input->ymin - 2, frame_space_corners, UVs[1]);
+ resolveUV(input->xmax + 2, input->ymax + 2, frame_space_corners, UVs[2]);
+ resolveUV(input->xmin - 2, input->ymax + 2, frame_space_corners, UVs[3]);
+
+ float min[2], max[2];
+ INIT_MINMAX2(min, max);
+ for (int i = 0; i < 4; i++) {
+ minmax_v2v2_v2(min, max, UVs[i]);
+ }
+
+ rcti newInput;
+
+ newInput.xmin = min[0] * readOperation->getWidth() - 1;
+ newInput.ymin = min[1] * readOperation->getHeight() - 1;
+ newInput.xmax = max[0] * readOperation->getWidth() + 1;
+ newInput.ymax = max[1] * readOperation->getHeight() + 1;
+
+ return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+}
diff --git a/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h
new file mode 100644
index 00000000000..a92ff3f9ddf
--- /dev/null
+++ b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright 2013, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor:
+ * Sergey Sharybin
+ */
+
+#ifndef _COM_PlaneTrackWarpImageOperation_h
+#define _COM_PlaneTrackWarpImageOperation_h
+
+#include <string.h>
+
+#include "COM_PlaneTrackCommonOperation.h"
+
+#include "DNA_movieclip_types.h"
+#include "DNA_tracking_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+class PlaneTrackWarpImageOperation : public PlaneTrackCommonOperation {
+protected:
+ SocketReader *m_pixelReader;
+ int m_osa;
+ float m_jitter[32][2];
+
+public:
+ PlaneTrackWarpImageOperation();
+
+ void initExecution();
+ void deinitExecution();
+
+ void executePixel(float output[4], float x, float y, PixelSampler sampler);
+
+ bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
+};
+
+#endif
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 2a1bdee32f7..6ced2423074 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -102,32 +102,53 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
MaskLayer *masklay;
/* parent info */
- SpaceClip *sc;
- MovieClip *clip;
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking;
MovieTrackingTrack *track;
- MovieTrackingMarker *marker;
+ MovieTrackingPlaneTrack *plane_track;
MovieTrackingObject *tracking_object;
/* done */
- int framenr;
+ int framenr, parent_type;
+ float parmask_pos[2], orig_corners[4][2];
+ char *sub_parent_name;
- float marker_pos_ofs[2];
- float parmask_pos[2];
-
- if ((NULL == (sc = CTX_wm_space_clip(C))) ||
- (NULL == (clip = sc->clip)) ||
- (NULL == (track = clip->tracking.act_track)) ||
- (NULL == (tracking_object = BKE_tracking_object_get_active(&clip->tracking))))
- {
+ if (ELEM(NULL, sc, clip)) {
return OPERATOR_CANCELLED;
}
framenr = ED_space_clip_get_clip_frame_number(sc);
- marker = BKE_tracking_marker_get(track, framenr);
- add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset);
+ tracking = &clip->tracking;
+ tracking_object = BKE_tracking_object_get_active(&clip->tracking);
+
+ if (tracking_object == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if ((track = BKE_tracking_track_get_active(tracking)) != NULL) {
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+ float marker_pos_ofs[2];
+
+ add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset);
- BKE_mask_coord_from_movieclip(clip, &sc->user, parmask_pos, marker_pos_ofs);
+ BKE_mask_coord_from_movieclip(clip, &sc->user, parmask_pos, marker_pos_ofs);
+
+ sub_parent_name = track->name;
+ parent_type = MASK_PARENT_POINT_TRACK;
+ }
+ else if ((plane_track = BKE_tracking_plane_track_get_active(tracking)) != NULL) {
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
+
+ zero_v2(parmask_pos);
+ sub_parent_name = plane_track->name;
+ parent_type = MASK_PARENT_PLANE_TRACK;
+ memcpy(orig_corners, plane_marker->corners, sizeof(orig_corners));
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
@@ -144,10 +165,12 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
if (MASKPOINT_ISSEL_ANY(point)) {
point->parent.id_type = ID_MC;
point->parent.id = &clip->id;
+ point->parent.type = parent_type;
BLI_strncpy(point->parent.parent, tracking_object->name, sizeof(point->parent.parent));
- BLI_strncpy(point->parent.sub_parent, track->name, sizeof(point->parent.sub_parent));
+ BLI_strncpy(point->parent.sub_parent, sub_parent_name, sizeof(point->parent.sub_parent));
copy_v2_v2(point->parent.parent_orig, parmask_pos);
+ memcpy(point->parent.parent_corners_orig, orig_corners, sizeof(point->parent.parent_corners_orig));
}
}
}
diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c
index 93bdca93096..d5fbdca5b0a 100644
--- a/source/blender/editors/mask/mask_shapekey.c
+++ b/source/blender/editors/mask/mask_shapekey.c
@@ -38,6 +38,7 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_mask.h"
+#include "BKE_report.h"
#include "DNA_object_types.h"
#include "DNA_mask_types.h"
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index d1fd5093974..eb58bdc7696 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -111,6 +111,57 @@ static void draw_keyframe(int frame, int cfra, int sfra, float framelen, int wid
}
}
+static int generic_track_get_markersnr(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track)
+{
+ if (track) {
+ return track->markersnr;
+ }
+ else if (plane_track) {
+ return plane_track->markersnr;
+ }
+
+ return 0;
+}
+
+static int generic_track_get_marker_framenr(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track,
+ int marker_index)
+{
+ if (track) {
+ return track->markers[marker_index].framenr;
+ }
+ else if (plane_track) {
+ return plane_track->markers[marker_index].framenr;
+ }
+
+ return 0;
+}
+
+static bool generic_track_is_marker_enabled(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track,
+ int marker_index)
+{
+ if (track) {
+ return (track->markers[marker_index].flag & MARKER_DISABLED) == 0;
+ }
+ else if (plane_track) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool generic_track_is_marker_keyframed(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track,
+ int marker_index)
+{
+ if (track) {
+ return (track->markers[marker_index].flag & MARKER_TRACKED) == 0;
+ }
+ else if (plane_track) {
+ return (plane_track->markers[marker_index].flag & PLANE_MARKER_TRACKED) == 0;
+ }
+
+ return false;
+}
+
static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Scene *scene)
{
float x;
@@ -119,6 +170,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *act_object = BKE_tracking_object_get_active(tracking);
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking);
+ MovieTrackingPlaneTrack *act_plane_track = BKE_tracking_plane_track_get_active(&clip->tracking);
MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
glEnable(GL_BLEND);
@@ -143,34 +195,29 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
}
/* track */
- if (act_track) {
- MovieTrackingTrack *track = act_track;
-
+ if (act_track || act_plane_track) {
for (i = sfra - clip->start_frame + 1, a = 0; i <= efra - clip->start_frame + 1; i++) {
int framenr;
- MovieTrackingMarker *marker;
+ int markersnr = generic_track_get_markersnr(act_track, act_plane_track);
- while (a < track->markersnr) {
- if (track->markers[a].framenr >= i)
+ while (a < markersnr) {
+ int marker_framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a);
+
+ if (marker_framenr >= i)
break;
- if (a < track->markersnr - 1 && track->markers[a + 1].framenr > i)
+ if (a < markersnr - 1 && generic_track_get_marker_framenr(act_track, act_plane_track, a + 1) > i)
break;
a++;
}
- if (a < track->markersnr)
- marker = &track->markers[a];
- else
- marker = &track->markers[track->markersnr - 1];
-
- if ((marker->flag & MARKER_DISABLED) == 0) {
- framenr = marker->framenr;
+ if (generic_track_is_marker_enabled(act_track, act_plane_track, a)) {
+ framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a);
if (framenr != i)
glColor4ub(128, 128, 0, 96);
- else if ((marker->flag & MARKER_TRACKED) == 0)
+ else if (generic_track_is_marker_keyframed(act_track, act_plane_track, a))
glColor4ub(255, 255, 0, 196);
else
glColor4ub(255, 255, 0, 96);
@@ -961,13 +1008,159 @@ static void view2d_to_region_float(View2D *v2d, float x, float y, float *regionx
*regiony = v2d->mask.ymin + y * BLI_rcti_size_y(&v2d->mask);
}
+static void plane_track_colors(bool is_active, float color[3], float selected_color[3])
+{
+ UI_GetThemeColor3fv(TH_MARKER, color);
+
+ if (is_active)
+ UI_GetThemeColor3fv(TH_ACT_MARKER, selected_color);
+ else
+ UI_GetThemeColor3fv(TH_SEL_MARKER, selected_color);
+}
+
+static void getArrowEndPoint(const int width, const int height, const float zoom,
+ const float start_corner[2], const float end_corner[2],
+ float end_point[2])
+{
+ float direction[2];
+ float max_length;
+
+ sub_v2_v2v2(direction, end_corner, start_corner);
+
+ direction[0] *= width;
+ direction[1] *= height;
+ max_length = len_v2(direction);
+ normalize_v2(direction);
+ mul_v2_fl(direction, min_ff(32.0f / zoom, max_length));
+ direction[0] /= width;
+ direction[1] /= height;
+
+ add_v2_v2v2(end_point, start_corner, direction);
+}
+
+static void draw_plane_marker_ex(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingPlaneMarker *plane_marker, bool is_active_track,
+ bool draw_outline, int width, int height)
+{
+ bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0;
+ bool is_selected_track = plane_track->flag & SELECT;
+ float px[2];
+
+ if (draw_outline) {
+ UI_ThemeColor(TH_MARKER_OUTLINE);
+ }
+ else {
+ float color[3], selected_color[3];
+ plane_track_colors(is_active_track, color, selected_color);
+ if (is_selected_track) {
+ glColor3fv(selected_color);
+ }
+ else {
+ glColor3fv(color);
+ }
+ }
+
+ px[0] = 1.0f / width / sc->zoom;
+ px[1] = 1.0f / height / sc->zoom;
+
+ if (draw_outline) {
+ if (!tiny) {
+ glLineWidth(3.0f);
+ }
+ }
+ else if (tiny) {
+ glLineStipple(3, 0xaaaa);
+ glEnable(GL_LINE_STIPPLE);
+ glEnable(GL_COLOR_LOGIC_OP);
+ glLogicOp(GL_NOR);
+ }
+
+ /* Draw rectangle itself. */
+ glBegin(GL_LINE_LOOP);
+ glVertex2fv(plane_marker->corners[0]);
+ glVertex2fv(plane_marker->corners[1]);
+ glVertex2fv(plane_marker->corners[2]);
+ glVertex2fv(plane_marker->corners[3]);
+ glEnd();
+
+ /* Draw axis. */
+ if (!draw_outline) {
+ float end_point[2];
+ glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT);
+
+ getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[1], end_point);
+ glColor3f(1.0, 0.0, 0.0f);
+ glBegin(GL_LINES);
+ glVertex2fv(plane_marker->corners[0]);
+ glVertex2fv(end_point);
+ glEnd();
+
+ getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[3], end_point);
+ glColor3f(0.0, 1.0, 0.0f);
+ glBegin(GL_LINES);
+ glVertex2fv(plane_marker->corners[0]);
+ glVertex2fv(end_point);
+ glEnd();
+
+ glPopAttrib();
+ }
+
+ /* Draw sliders. */
+ if (is_selected_track) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ draw_marker_slide_square(plane_marker->corners[i][0], plane_marker->corners[i][1],
+ 3.0f * px[0], 3.0f * px[1], draw_outline, px);
+ }
+ }
+
+ if (draw_outline) {
+ if (!tiny) {
+ glLineWidth(1.0f);
+ }
+ }
+ else if (tiny) {
+ glDisable(GL_COLOR_LOGIC_OP);
+ glDisable(GL_LINE_STIPPLE);
+ glLineStipple(3, 0xaaaa);
+ glEnable(GL_LINE_STIPPLE);
+ }
+}
+
+static void draw_plane_marker_outline(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingPlaneMarker *plane_marker, int width, int height)
+{
+ draw_plane_marker_ex(sc, plane_track, plane_marker, false, true, width, height);
+}
+
+static void draw_plane_marker(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track,
+ MovieTrackingPlaneMarker *plane_marker, bool is_active_track,
+ int width, int height)
+{
+ draw_plane_marker_ex(sc, plane_track, plane_marker, is_active_track, false, width, height);
+}
+
+static void draw_plane_track(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track,
+ int framenr, bool is_active_track, int width, int height)
+{
+ MovieTrackingPlaneMarker *plane_marker;
+
+ plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
+
+ draw_plane_marker_outline(sc, plane_track, plane_marker, width, height);
+ draw_plane_marker(sc, plane_track, plane_marker, is_active_track, width, height);
+}
+
+/* Draw all kind of tracks. */
static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip,
int width, int height, float zoomx, float zoomy)
{
float x, y;
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
MovieTrackingTrack *track, *act_track;
+ MovieTrackingPlaneTrack *plane_track, *active_plane_track;
MovieTrackingMarker *marker;
int framenr = ED_space_clip_get_clip_frame_number(sc);
int undistort = sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
@@ -1160,6 +1353,15 @@ static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip,
glDisable(GL_POINT_SMOOTH);
}
+ /* Draw plane tracks */
+ active_plane_track = BKE_tracking_plane_track_get_active(tracking);
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ draw_plane_track(sc, plane_track, framenr, plane_track == active_plane_track, width, height);
+ }
+
glPopMatrix();
if (sc->flag & SC_SHOW_NAMES) {
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index edc6ac1ecf7..cdb0fdadebd 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -466,11 +466,10 @@ static int delete_curve_exec(bContext *C, wmOperator *UNUSED(op))
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
if (act_track)
- clip_delete_track(C, clip, tracksbase, act_track);
+ clip_delete_track(C, clip, act_track);
return OPERATOR_FINISHED;
}
@@ -498,7 +497,6 @@ static int delete_knot_exec(bContext *C, wmOperator *UNUSED(op))
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
if (act_track) {
@@ -508,7 +506,7 @@ static int delete_knot_exec(bContext *C, wmOperator *UNUSED(op))
MovieTrackingMarker *marker = &act_track->markers[a];
if (marker->flag & MARKER_GRAPH_SEL)
- clip_delete_marker(C, clip, tracksbase, act_track, marker);
+ clip_delete_marker(C, clip, act_track, marker);
else
a++;
}
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 51cb83eecad..8d112b7413c 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -132,8 +132,8 @@ void clip_graph_tracking_values_iterate(struct SpaceClip *sc, int selected_only,
void clip_graph_tracking_iterate(struct SpaceClip *sc, int selected_only, int include_hidden, void *userdata,
void (*func)(void *userdata, struct MovieTrackingMarker *marker));
-void clip_delete_track(struct bContext *C, struct MovieClip *clip, struct ListBase *tracksbase, struct MovieTrackingTrack *track);
-void clip_delete_marker(struct bContext *C, struct MovieClip *clip, struct ListBase *tracksbase, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker);
+void clip_delete_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track);
+void clip_delete_marker(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker);
void clip_view_center_to_point(SpaceClip *sc, float x, float y);
@@ -193,6 +193,9 @@ void CLIP_OT_tracking_object_remove(struct wmOperatorType *ot);
void CLIP_OT_copy_tracks(struct wmOperatorType *ot);
void CLIP_OT_paste_tracks(struct wmOperatorType *ot);
+void CLIP_OT_create_plane_track(struct wmOperatorType *ot);
+void CLIP_OT_slide_plane_marker(struct wmOperatorType *ot);
+
/* tracking_select.c */
void CLIP_OT_select(struct wmOperatorType *ot);
void CLIP_OT_select_all(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index d7a9b1c0cb6..72a3cb98a6a 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -175,11 +175,14 @@ void clip_graph_tracking_iterate(SpaceClip *sc, int selected_only, int include_h
}
}
-void clip_delete_track(bContext *C, MovieClip *clip, ListBase *tracksbase, MovieTrackingTrack *track)
+void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
{
MovieTracking *tracking = &clip->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
+ MovieTrackingPlaneTrack *plane_track, *next_plane_track;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
int has_bundle = FALSE, update_stab = FALSE;
@@ -196,6 +199,51 @@ void clip_delete_track(bContext *C, MovieClip *clip, ListBase *tracksbase, Movie
if (track->flag & TRACK_HAS_BUNDLE)
has_bundle = TRUE;
+ /* Make sure no plane will use freed track */
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = next_plane_track)
+ {
+ bool found = false;
+ int i;
+
+ next_plane_track = plane_track->next;
+
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] == track) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ continue;
+ }
+
+ if (plane_track->point_tracksnr > 4) {
+ int track_index;
+ MovieTrackingTrack **new_point_tracks;
+
+ new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * plane_track->point_tracksnr,
+ "new point tracks array");
+
+ for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] != track) {
+ new_point_tracks[track_index++] = plane_track->point_tracks[i];
+ }
+ }
+
+ MEM_freeN(plane_track->point_tracks);
+ plane_track->point_tracks = new_point_tracks;
+ plane_track->point_tracksnr--;
+ }
+ else {
+ /* Delete planes with less than 3 point tracks in it. */
+ BKE_tracking_plane_track_free(plane_track);
+ BLI_freelinkN(plane_tracks_base, plane_track);
+ }
+ }
+
BKE_tracking_track_free(track);
BLI_freelinkN(tracksbase, track);
@@ -212,11 +260,11 @@ void clip_delete_track(bContext *C, MovieClip *clip, ListBase *tracksbase, Movie
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
-void clip_delete_marker(bContext *C, MovieClip *clip, ListBase *tracksbase,
- MovieTrackingTrack *track, MovieTrackingMarker *marker)
+void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track,
+ MovieTrackingMarker *marker)
{
if (track->markersnr == 1) {
- clip_delete_track(C, clip, tracksbase, track);
+ clip_delete_track(C, clip, track);
}
else {
BKE_tracking_marker_delete(track, marker->framenr);
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 562a8584560..8213853c937 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -517,6 +517,10 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_copy_tracks);
WM_operatortype_append(CLIP_OT_paste_tracks);
+ /* Plane tracker */
+ WM_operatortype_append(CLIP_OT_create_plane_track);
+ WM_operatortype_append(CLIP_OT_slide_plane_marker);
+
/* ** clip_graph_ops.c ** */
/* graph editing */
@@ -685,6 +689,9 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "CLIP_OT_hide_tracks_clear", HKEY, KM_PRESS, KM_ALT, 0);
+ /* plane tracks */
+ WM_keymap_add_item(keymap, "CLIP_OT_slide_plane_marker", LEFTMOUSE, KM_PRESS, 0, 0);
+
/* clean-up */
WM_keymap_add_item(keymap, "CLIP_OT_join_tracks", JKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index f3d070452a5..e14fc8ad399 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -34,6 +34,7 @@
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_object_types.h" /* SELECT */
#include "DNA_scene_types.h"
@@ -55,6 +56,8 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_library.h"
+#include "BKE_mask.h"
+#include "BKE_node.h"
#include "BKE_sound.h"
#include "WM_api.h"
@@ -88,6 +91,7 @@ static bool add_marker(const bContext *C, float x, float y)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
MovieTrackingTrack *track;
int width, height;
int framenr = ED_space_clip_get_clip_frame_number(sc);
@@ -101,8 +105,10 @@ static bool add_marker(const bContext *C, float x, float y)
track = BKE_tracking_track_add(tracking, tracksbase, x, y, framenr, width, height);
BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, 0);
+ BKE_tracking_plane_tracks_deselect_all(plane_tracks_base);
clip->tracking.act_track = track;
+ clip->tracking.act_plane_track = NULL;
return true;
}
@@ -234,13 +240,31 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
MovieTrackingTrack *track = tracksbase->first, *next;
+ MovieTrackingPlaneTrack *plane_track, *next_plane_track;
+ bool modified = false;
+
+ /* Delete selected plane tracks. */
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = next_plane_track)
+ {
+ next_plane_track = plane_track->next;
+
+ if (plane_track->flag & SELECT) {
+ BKE_tracking_plane_track_free(plane_track);
+ BLI_freelinkN(plane_tracks_base, plane_track);
+ modified = true;
+ }
+ }
+ /* Remove selected point tracks (they'll also be removed from planes which uses them). */
while (track) {
next = track->next;
if (TRACK_VIEW_SELECTED(sc, track))
- clip_delete_track(C, clip, tracksbase, track);
+ clip_delete_track(C, clip, track);
track = next;
}
@@ -248,6 +272,10 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
/* nothing selected now, unlock view so it can be scrolled nice again */
sc->flag &= ~SC_LOCK_SELECTION;
+ if (modified) {
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+ }
+
return OPERATOR_FINISHED;
}
@@ -274,7 +302,9 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
MovieTrackingTrack *track = tracksbase->first, *next;
+ MovieTrackingPlaneTrack *plane_track, *plane_track_next;
int framenr = ED_space_clip_get_clip_frame_number(sc);
int has_selection = 0;
@@ -287,13 +317,34 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
if (marker) {
has_selection |= track->markersnr > 1;
- clip_delete_marker(C, clip, tracksbase, track, marker);
+ clip_delete_marker(C, clip, track, marker);
}
}
track = next;
}
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track_next)
+ {
+ plane_track_next = plane_track->next;
+
+ if (plane_track->flag & SELECT) {
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, framenr);
+
+ if (plane_marker) {
+ if (plane_track->markersnr == 1) {
+ BKE_tracking_plane_track_free(plane_track);
+ BLI_freelinkN(plane_tracks_base, plane_track);
+ }
+ else {
+ BKE_tracking_plane_marker_delete(plane_track, framenr);
+ }
+ }
+ }
+ }
+
if (!has_selection) {
/* nothing selected now, unlock view so it can be scrolled nice again */
sc->flag &= ~SC_LOCK_SELECTION;
@@ -727,6 +778,7 @@ static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event
MovieTracking *tracking = &clip->tracking;
tracking->act_track = slidedata->track;
+ tracking->act_plane_track = NULL;
op->customdata = slidedata;
@@ -3670,3 +3722,350 @@ void CLIP_OT_paste_tracks(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/********************** Create plane track operator *********************/
+
+static int create_plane_track_tracks_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingPlaneTrack *plane_track;
+ ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ plane_track = BKE_tracking_plane_track_add(tracking, plane_tracks_base, tracks_base, framenr);
+
+ if (plane_track == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Need at least 4 selected point tracks to create a plane");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ BKE_tracking_tracks_deselect_all(tracks_base);
+
+ plane_track->flag |= SELECT;
+ clip->tracking.act_track = NULL;
+ clip->tracking.act_plane_track = plane_track;
+
+ /* Copute homoraphies and apply them on marker's corner, so we've got
+ * quite nice motion from the very beginning.
+ */
+ BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
+ }
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_create_plane_track(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Create Plane Track";
+ ot->description = "Create new plane track out of selected point tracks";
+ ot->idname = "CLIP_OT_create_plane_track";
+
+ /* api callbacks */
+ ot->exec = create_plane_track_tracks_exec;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************** Slide plane marker corner operator *********************/
+
+typedef struct SlidePlaneMarkerData {
+ MovieTrackingPlaneTrack *plane_track;
+ MovieTrackingPlaneMarker *plane_marker;
+ int width, height;
+ int corner_index;
+ float *corner;
+ int previous_mval[2];
+ float previous_corner[2];
+ float old_corner[2];
+ bool accurate;
+} SlidePlaneMarkerData;
+
+static bool mouse_on_plane_slide_zone(SpaceClip *sc, float co[2], float slide_zone[2], int width, int height)
+{
+ const float size = 12.0f;
+ float dx, dy;
+
+ dx = size / width / sc->zoom;
+ dy = size / height / sc->zoom;
+
+ return IN_RANGE_INCL(co[0], slide_zone[0] - dx, slide_zone[0] + dx) &&
+ IN_RANGE_INCL(co[1], slide_zone[1] - dy, slide_zone[1] + dy);
+}
+
+static MovieTrackingPlaneTrack *tracking_plane_marker_check_slide(bContext *C, const wmEvent *event, int *corner_r)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ ARegion *ar = CTX_wm_region(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTrackingPlaneTrack *plane_track;
+ int width, height;
+ float co[2];
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ ED_space_clip_get_size(sc, &width, &height);
+
+ if (width == 0 || height == 0) {
+ return NULL;
+ }
+
+ ED_clip_mouse_pos(sc, ar, event->mval, co);
+
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if (plane_track->flag & SELECT) {
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
+ bool ok = false;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (mouse_on_plane_slide_zone(sc, co, plane_marker->corners[i], width, height)) {
+ if (corner_r) {
+ *corner_r = i;
+ }
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok) {
+ return plane_track;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void *slide_plane_marker_customdata(bContext *C, const wmEvent *event)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ ARegion *ar = CTX_wm_region(C);
+ MovieTrackingPlaneTrack *plane_track;
+ int width, height;
+ float co[2];
+ SlidePlaneMarkerData *customdata = NULL;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+ int corner;
+
+ ED_space_clip_get_size(sc, &width, &height);
+
+ if (width == 0 || height == 0) {
+ return NULL;
+ }
+
+ ED_clip_mouse_pos(sc, ar, event->mval, co);
+
+ plane_track = tracking_plane_marker_check_slide(C, event, &corner);
+ if (plane_track) {
+ MovieTrackingPlaneMarker *plane_marker;
+
+ customdata = MEM_callocN(sizeof(SlidePlaneMarkerData), "slide plane marker data");
+
+ plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
+
+ customdata->plane_track = plane_track;
+ customdata->plane_marker = plane_marker;
+ customdata->width = width;
+ customdata->height = height;
+
+ customdata->previous_mval[0] = event->mval[0];
+ customdata->previous_mval[1] = event->mval[1];
+
+ customdata->corner_index = corner;
+ customdata->corner = plane_marker->corners[corner];
+
+ copy_v2_v2(customdata->previous_corner, customdata->corner);
+ copy_v2_v2(customdata->old_corner, customdata->corner);
+ }
+
+ return customdata;
+}
+
+static int slide_plane_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ SlidePlaneMarkerData *slidedata = slide_plane_marker_customdata(C, event);
+
+ if (slidedata) {
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+
+ tracking->act_plane_track = slidedata->plane_track;
+ tracking->act_track = NULL;
+
+ op->customdata = slidedata;
+
+ hide_cursor(C);
+ WM_event_add_modal_handler(C, op);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void cancel_mouse_slide_plane_marker(SlidePlaneMarkerData *data)
+{
+ copy_v2_v2(data->corner, data->old_corner);
+}
+
+static void free_slide_plane_marker_data(SlidePlaneMarkerData *data)
+{
+ MEM_freeN(data);
+}
+
+static void slide_plane_marker_update_homographies(SpaceClip *sc, SlidePlaneMarkerData *data)
+{
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ BKE_tracking_track_plane_from_existing_motion(data->plane_track, framenr);
+}
+
+static int slide_plane_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ SlidePlaneMarkerData *data = (SlidePlaneMarkerData *) op->customdata;
+ float dx, dy, mdelta[2];
+ int next_corner_index, prev_corner_index, diag_corner_index;
+ float *next_corner, *prev_corner, *diag_corner;
+ float next_edge[2], prev_edge[2], next_diag_edge[2], prev_diag_edge[2];
+
+ switch (event->type) {
+ case LEFTCTRLKEY:
+ case RIGHTCTRLKEY:
+ case LEFTSHIFTKEY:
+ case RIGHTSHIFTKEY:
+ if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
+ data->accurate = event->val == KM_PRESS;
+
+ /* fall-through */
+ case MOUSEMOVE:
+ mdelta[0] = event->mval[0] - data->previous_mval[0];
+ mdelta[1] = event->mval[1] - data->previous_mval[1];
+
+ dx = mdelta[0] / data->width / sc->zoom;
+ dy = mdelta[1] / data->height / sc->zoom;
+
+ if (data->accurate) {
+ dx /= 5.0f;
+ dy /= 5.0f;
+ }
+
+ data->corner[0] = data->previous_corner[0] + dx;
+ data->corner[1] = data->previous_corner[1] + dy;
+
+
+ /*
+ prev_edge
+ (Corner 3, current) <----------------------- (Corner 2, previous)
+ | ^
+ | |
+ | |
+ | |
+ next_edge | | next_diag_edge
+ | |
+ | |
+ | |
+ v |
+ (Corner 0, next) -----------------------> (Corner 1, diagonal)
+ prev_diag_edge
+ */
+
+ next_corner_index = (data->corner_index + 1) % 4;
+ prev_corner_index = (data->corner_index + 3) % 4;
+ diag_corner_index = (data->corner_index + 2) % 4;
+
+ next_corner = data->plane_marker->corners[next_corner_index];
+ prev_corner = data->plane_marker->corners[prev_corner_index];
+ diag_corner = data->plane_marker->corners[diag_corner_index];
+
+ sub_v2_v2v2(next_edge, next_corner, data->corner);
+ sub_v2_v2v2(prev_edge, data->corner, prev_corner);
+ sub_v2_v2v2(next_diag_edge, prev_corner, diag_corner);
+ sub_v2_v2v2(prev_diag_edge, diag_corner, next_corner);
+
+ if (cross_v2v2(prev_edge, next_edge) < 0.0f) {
+ closest_to_line_v2(data->corner, data->corner, prev_corner, next_corner);
+ }
+
+ if (cross_v2v2(next_diag_edge, prev_edge) < 0.0f) {
+ closest_to_line_v2(data->corner, data->corner, prev_corner, diag_corner);
+ }
+
+ if (cross_v2v2(next_edge, prev_diag_edge) < 0.0f) {
+ closest_to_line_v2(data->corner, data->corner, next_corner, diag_corner);
+ }
+
+ data->previous_mval[0] = event->mval[0];
+ data->previous_mval[1] = event->mval[1];
+ copy_v2_v2(data->previous_corner, data->corner);
+
+ DAG_id_tag_update(&sc->clip->id, 0);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
+
+ break;
+
+ case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ /* Marker is now keyframed. */
+ data->plane_marker->flag &= ~PLANE_MARKER_TRACKED;
+
+ slide_plane_marker_update_homographies(sc, data);
+
+ free_slide_plane_marker_data(op->customdata);
+
+ show_cursor(C);
+
+ DAG_id_tag_update(&sc->clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+
+ return OPERATOR_FINISHED;
+ }
+
+ break;
+
+ case ESCKEY:
+ cancel_mouse_slide_plane_marker(op->customdata);
+
+ free_slide_plane_marker_data(op->customdata);
+
+ show_cursor(C);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void CLIP_OT_slide_plane_marker(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Slide Plane Marker";
+ ot->description = "Slide plane marker areas";
+ ot->idname = "CLIP_OT_slide_plane_marker";
+
+ /* api callbacks */
+ ot->poll = ED_space_clip_tracking_poll;
+ ot->invoke = slide_plane_marker_invoke;
+ ot->modal = slide_plane_marker_modal;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
+}
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index b03209173d8..6e4d10173fb 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -169,6 +169,7 @@ static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
return sqrtf(min_ffff(d1, d2, d3, d4));
}
+/* Distance to quad defined by it's corners, corners are relative to pos */
static float dist_to_crns(float co[2], float pos[2], float crns[4][2])
{
float d1, d2, d3, d4;
@@ -184,7 +185,22 @@ static float dist_to_crns(float co[2], float pos[2], float crns[4][2])
return sqrtf(min_ffff(d1, d2, d3, d4));
}
-static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2])
+/* Same as above, but all the coordinates are absolute */
+static float dist_to_crns_abs(float co[2], float corners[4][2])
+{
+ float d1, d2, d3, d4;
+ float *v1 = corners[0], *v2 = corners[1];
+ float *v3 = corners[2], *v4 = corners[3];
+
+ d1 = dist_squared_to_line_segment_v2(co, v1, v2);
+ d2 = dist_squared_to_line_segment_v2(co, v2, v3);
+ d3 = dist_squared_to_line_segment_v2(co, v3, v4);
+ d4 = dist_squared_to_line_segment_v2(co, v4, v1);
+
+ return sqrtf(min_ffff(d1, d2, d3, d4));
+}
+
+static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2], float *distance_r)
{
MovieTrackingTrack *track = NULL, *cur;
float mindist = 0.0f;
@@ -221,19 +237,88 @@ static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbas
cur = cur->next;
}
+ *distance_r = mindist;
+
return track;
}
+static MovieTrackingPlaneTrack *find_nearest_plane_track(SpaceClip *sc, ListBase *plane_tracks_base,
+ float co[2], float *distance_r)
+{
+ MovieTrackingPlaneTrack *plane_track = NULL, *current_plane_track;
+ float min_distance = 0.0f;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ for (current_plane_track = plane_tracks_base->first;
+ current_plane_track;
+ current_plane_track = current_plane_track->next)
+ {
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(current_plane_track, framenr);
+
+ if ((current_plane_track->flag & TRACK_HIDDEN) == 0) {
+ float distance = dist_to_crns_abs(co, plane_marker->corners);
+ if (plane_track == NULL || distance < min_distance) {
+ plane_track = current_plane_track;
+ min_distance = distance;
+ }
+ }
+ }
+
+ *distance_r = min_distance;
+
+ return plane_track;
+}
+
+static void delect_all_tracks(ListBase *tracks_base)
+{
+ MovieTrackingTrack *track;
+ for (track = tracks_base->first;
+ track;
+ track = track->next)
+ {
+ BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT);
+ }
+}
+
+static void delect_all_plane_tracks(ListBase *plane_tracks_base)
+{
+ MovieTrackingPlaneTrack *plane_track;
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ plane_track->flag &= ~SELECT;
+ }
+}
+
static int mouse_select(bContext *C, float co[2], int extend)
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
- MovieTrackingTrack *track = NULL; /* selected marker */
+ MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
+ float distance_to_track, distance_to_plane_track;
+
+ track = find_nearest_track(sc, tracksbase, co, &distance_to_track);
+ plane_track = find_nearest_plane_track(sc, plane_tracks_base, co, &distance_to_plane_track);
+
+ /* Between track and plane we choose closest to the mouse for selection here. */
+ if (track && plane_track) {
+ if (distance_to_track < distance_to_plane_track) {
+ plane_track = NULL;
+ }
+ else {
+ track = NULL;
+ }
+ }
- track = find_nearest_track(sc, tracksbase, co);
+ if (!extend) {
+ delect_all_plane_tracks(plane_tracks_base);
+ }
if (track) {
int area = track_mouse_area(C, co, track);
@@ -242,10 +327,13 @@ static int mouse_select(bContext *C, float co[2], int extend)
area = TRACK_AREA_ALL;
if (extend && TRACK_AREA_SELECTED(track, area)) {
- if (track == act_track)
+ if (track == act_track) {
BKE_tracking_track_deselect(track, area);
- else
+ }
+ else {
clip->tracking.act_track = track;
+ clip->tracking.act_plane_track = NULL;
+ }
}
else {
if (area == TRACK_AREA_POINT)
@@ -253,7 +341,25 @@ static int mouse_select(bContext *C, float co[2], int extend)
BKE_tracking_track_select(tracksbase, track, area, extend);
clip->tracking.act_track = track;
+ clip->tracking.act_plane_track = NULL;
+ }
+ }
+ else if (plane_track) {
+ if (!extend) {
+ delect_all_tracks(tracksbase);
+ }
+
+ if (plane_track->flag & SELECT) {
+ if (extend) {
+ plane_track->flag &= ~SELECT;
+ }
+ }
+ else {
+ plane_track->flag |= SELECT;
}
+
+ clip->tracking.act_track = NULL;
+ clip->tracking.act_plane_track = plane_track;
}
if (!extend) {
@@ -350,7 +456,9 @@ static int border_select_exec(bContext *C, wmOperator *op)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
rcti rect;
rctf rectf;
int change = FALSE, mode, extend;
@@ -389,6 +497,33 @@ static int border_select_exec(bContext *C, wmOperator *op)
track = track->next;
}
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) {
+ MovieTrackingPlaneMarker *plane_marker =
+ BKE_tracking_plane_marker_get(plane_track, framenr);
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (BLI_rctf_isect_pt_v(&rectf, plane_marker->corners[i])) {
+ if (mode == GESTURE_MODAL_SELECT) {
+ plane_track->flag |= SELECT;
+ }
+ else {
+ plane_track->flag &= ~SELECT;
+ }
+ }
+ else if (!extend) {
+ plane_track->flag &= ~SELECT;
+ }
+ }
+
+ change = TRUE;
+ }
+ }
+
if (change) {
BKE_tracking_dopesheet_tag_update(tracking);
@@ -430,7 +565,9 @@ static int do_lasso_select_marker(bContext *C, const int mcords[][2], const shor
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
rcti rect;
int change = FALSE;
int framenr = ED_space_clip_get_clip_frame_number(sc);
@@ -466,6 +603,37 @@ static int do_lasso_select_marker(bContext *C, const int mcords[][2], const shor
track = track->next;
}
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) {
+ MovieTrackingPlaneMarker *plane_marker =
+ BKE_tracking_plane_marker_get(plane_track, framenr);
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ float screen_co[2];
+
+ /* marker in screen coords */
+ ED_clip_point_stable_pos__reverse(sc, ar, plane_marker->corners[i], screen_co);
+
+ if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
+ BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED))
+ {
+ if (select) {
+ plane_track->flag |= SELECT;
+ }
+ else {
+ plane_track->flag &= ~SELECT;
+ }
+ }
+ }
+
+ change = TRUE;
+ }
+ }
+
if (change) {
BKE_tracking_dopesheet_tag_update(tracking);
@@ -518,17 +686,22 @@ void CLIP_OT_select_lasso(wmOperatorType *ot)
/********************** circle select operator *********************/
-static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
+static int point_inside_ellipse(float point[2], 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];
+ x = (point[0] - offset[0]) * ellipse[0];
+ y = (point[1] - offset[1]) * ellipse[1];
return x * x + y * y < 1.0f;
}
+static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
+{
+ return point_inside_ellipse(marker->pos, offset, ellipse);
+}
+
static int circle_select_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -537,7 +710,9 @@ static int circle_select_exec(bContext *C, wmOperator *op)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
int x, y, radius, width, height, mode, change = FALSE;
float zoomx, zoomy, offset[2], ellipse[2];
int framenr = ED_space_clip_get_clip_frame_number(sc);
@@ -577,6 +752,30 @@ static int circle_select_exec(bContext *C, wmOperator *op)
track = track->next;
}
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) {
+ MovieTrackingPlaneMarker *plane_marker =
+ BKE_tracking_plane_marker_get(plane_track, framenr);
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (point_inside_ellipse(plane_marker->corners[i], offset, ellipse)) {
+ if (mode == GESTURE_MODAL_SELECT) {
+ plane_track->flag |= SELECT;
+ }
+ else {
+ plane_track->flag &= ~SELECT;
+ }
+ }
+ }
+
+ change = TRUE;
+ }
+ }
+
if (change) {
BKE_tracking_dopesheet_tag_update(tracking);
@@ -619,16 +818,18 @@ static int select_all_exec(bContext *C, wmOperator *op)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingTrack *track = NULL; /* selected track */
+ MovieTrackingPlaneTrack *plane_track = NULL; /* selected plane track */
MovieTrackingMarker *marker;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
int action = RNA_enum_get(op->ptr, "action");
int framenr = ED_space_clip_get_clip_frame_number(sc);
int has_selection = FALSE;
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- track = tracksbase->first;
- while (track) {
+
+ for (track = tracksbase->first; track; track = track->next) {
if (TRACK_VIEW_SELECTED(sc, track)) {
marker = BKE_tracking_marker_get(track, framenr);
@@ -637,13 +838,20 @@ static int select_all_exec(bContext *C, wmOperator *op)
break;
}
}
+ }
- track = track->next;
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if (plane_track->flag & SELECT) {
+ action = SEL_DESELECT;
+ break;
+ }
}
}
- track = tracksbase->first;
- while (track) {
+ for (track = tracksbase->first; track; track = track->next) {
if ((track->flag & TRACK_HIDDEN) == 0) {
marker = BKE_tracking_marker_get(track, framenr);
@@ -670,8 +878,29 @@ static int select_all_exec(bContext *C, wmOperator *op)
if (TRACK_VIEW_SELECTED(sc, track))
has_selection = TRUE;
+ }
- track = track->next;
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) {
+ switch (action) {
+ case SEL_SELECT:
+ plane_track->flag |= SELECT;
+ break;
+ case SEL_DESELECT:
+ plane_track->flag &= ~SELECT;
+ break;
+ case SEL_INVERT:
+ plane_track->flag ^= SELECT;
+ break;
+ }
+ }
+
+ if (plane_track->flag & SELECT) {
+ has_selection = TRUE;
+ }
}
if (!has_selection)
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index cf3c0454e6b..5cc22b25f72 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -2225,6 +2225,39 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
}
}
+static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = ptr->data;
+
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
+
+ if (node->id) {
+ MovieClip *clip = (MovieClip *) node->id;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
+ uiLayout *col;
+ PointerRNA tracking_ptr;
+ NodeTrackPosData *data = node->storage;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
+
+ col = uiLayoutColumn(layout, FALSE);
+ uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
+
+ object = BKE_tracking_object_get_named(tracking, data->tracking_object);
+ if (object) {
+ PointerRNA object_ptr;
+
+ RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr);
+
+ uiItemPointerR(col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA);
+ }
+ else {
+ uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA);
+ }
+ }
+}
+
/* only once called */
static void node_composit_set_butfunc(bNodeType *ntype)
{
@@ -2444,6 +2477,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_TRACKPOS:
ntype->uifunc = node_composit_buts_trackpos;
break;
+ case CMP_NODE_PLANETRACKDEFORM:
+ ntype->uifunc = node_composit_buts_planetrackdeform;
+ break;
}
}
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index d5a9d0f9f93..6d801b86685 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -3005,7 +3005,12 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
copy_v3_v3(center, td->center);
}
else if (t->options & CTX_MOVIECLIP) {
- copy_v3_v3(center, td->center);
+ if (td->flag & TD_INDIVIDUAL_SCALE) {
+ copy_v3_v3(center, td->center);
+ }
+ else {
+ copy_v3_v3(center, t->center);
+ }
}
else {
copy_v3_v3(center, t->center);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 4a1c4203a43..4954f861934 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -455,7 +455,7 @@ typedef struct TransInfo {
#define TD_USEQUAT (1 << 3)
#define TD_NOTCONNECTED (1 << 4)
#define TD_SINGLESIZE (1 << 5) /* used for scaling of MetaElem->rad */
-/*#define TD_TIMEONLY (1 << 8) */ /*UNUSED*/
+#define TD_INDIVIDUAL_SCALE (1 << 8) /* Scale relative to individual element center */
#define TD_NOCENTER (1 << 9)
#define TD_NO_EXT (1 << 10) /* ext abused for particle key timing */
#define TD_SKIP (1 << 11) /* don't transform this data */
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 95ec20a0c2b..01605003d7b 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -5959,7 +5959,8 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
enum transDataTracking_Mode {
transDataTracking_ModeTracks = 0,
- transDataTracking_ModeCurves = 1
+ transDataTracking_ModeCurves = 1,
+ transDataTracking_ModePlaneTracks = 2,
};
typedef struct TransDataTracking {
@@ -5978,6 +5979,9 @@ typedef struct TransDataTracking {
/* marker transformation from curves editor */
float *prev_pos, scale;
short coord;
+
+ MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
} TransDataTracking;
static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt,
@@ -6008,6 +6012,7 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
tdt->markersnr = track->markersnr;
tdt->markers = track->markers;
+ tdt->track = track;
if (rel) {
if (!anchor) {
@@ -6026,6 +6031,7 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
copy_v3_v3(td->iloc, td->loc);
//copy_v3_v3(td->center, td->loc);
+ td->flag |= TD_INDIVIDUAL_SCALE;
td->center[0] = marker->pos[0] * aspx;
td->center[1] = marker->pos[1] * aspy;
@@ -6076,6 +6082,52 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d
}
}
+static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt,
+ MovieTrackingPlaneTrack *plane_track, float corner[2],
+ float aspx, float aspy)
+{
+ tdt->mode = transDataTracking_ModePlaneTracks;
+ tdt->plane_track = plane_track;
+
+ td2d->loc[0] = corner[0] * aspx; /* hold original location */
+ td2d->loc[1] = corner[1] * aspy;
+
+ td2d->loc2d = corner; /* current location */
+ td2d->loc[2] = 0.0f;
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->center, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+}
+
+static void planeTrackToTransData(const int framenr, TransData *td, TransData2D *td2d,
+ TransDataTracking *tdt, MovieTrackingPlaneTrack *plane_track,
+ float aspx, float aspy)
+{
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
+ int i;
+
+ tdt->flag = plane_marker->flag;
+ plane_marker->flag &= ~PLANE_MARKER_TRACKED;
+
+ for (i = 0; i < 4; i++) {
+ planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspx, aspy);
+ }
+}
+
static void transDataTrackingFree(TransInfo *t)
{
TransDataTracking *tdt = t->customData;
@@ -6096,7 +6148,9 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
TransDataTracking *tdt;
int framenr = ED_space_clip_get_clip_frame_number(sc);
float aspx, aspy;
@@ -6122,6 +6176,15 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
track = track->next;
}
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if (plane_track->flag & SELECT) {
+ t->total += 4;
+ }
+ }
+
if (t->total == 0)
return;
@@ -6165,11 +6228,23 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
track = track->next;
}
+
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if (plane_track->flag & SELECT) {
+ planeTrackToTransData(framenr, td, td2d, tdt, plane_track, aspx, aspy);
+ td += 4;
+ td2d += 4;
+ tdt += 4;
+ }
+ }
}
static void markerToTransCurveDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt,
- MovieTrackingMarker *marker, MovieTrackingMarker *prev_marker,
- short coord, float size)
+ MovieTrackingTrack *track, MovieTrackingMarker *marker,
+ MovieTrackingMarker *prev_marker, short coord, float size)
{
float frames_delta = (marker->framenr - prev_marker->framenr);
@@ -6180,6 +6255,7 @@ static void markerToTransCurveDataInit(TransData *td, TransData2D *td2d, TransDa
tdt->coord = coord;
tdt->scale = 1.0f / size * frames_delta;
tdt->prev_pos = prev_marker->pos;
+ tdt->track = track;
/* calculate values depending on marker's speed */
td2d->loc[0] = marker->framenr;
@@ -6265,14 +6341,14 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
continue;
if (marker->flag & MARKER_GRAPH_SEL_X) {
- markerToTransCurveDataInit(td, td2d, tdt, marker, &track->markers[i - 1], 0, width);
+ markerToTransCurveDataInit(td, td2d, tdt, track, marker, &track->markers[i - 1], 0, width);
td += 1;
td2d += 1;
tdt += 1;
}
if (marker->flag & MARKER_GRAPH_SEL_Y) {
- markerToTransCurveDataInit(td, td2d, tdt, marker, &track->markers[i - 1], 1, height);
+ markerToTransCurveDataInit(td, td2d, tdt, track, marker, &track->markers[i - 1], 1, height);
td += 1;
td2d += 1;
@@ -6313,57 +6389,54 @@ static void createTransTrackingData(bContext *C, TransInfo *t)
static void cancelTransTracking(TransInfo *t)
{
- TransDataTracking *tdt = t->customData;
SpaceClip *sc = t->sa->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- MovieTrackingTrack *track;
- MovieTrackingMarker *marker;
- int a, framenr = ED_space_clip_get_clip_frame_number(sc);
+ int i, framenr = ED_space_clip_get_clip_frame_number(sc);
- if (tdt->mode == transDataTracking_ModeTracks) {
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- marker = BKE_tracking_marker_get(track, framenr);
- marker->flag = tdt->flag;
+ i = 0;
+ while (i < t->total) {
+ TransDataTracking *tdt = (TransDataTracking *) t->customData + i;
- tdt++;
+ if (tdt->mode == transDataTracking_ModeTracks) {
+ MovieTrackingTrack *track = tdt->track;
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- if (track->flag & SELECT)
- tdt++;
+ marker->flag = tdt->flag;
- if (track->pat_flag & SELECT)
- tdt += 2;
+ if (track->flag & SELECT)
+ i++;
- if (track->search_flag & SELECT)
- tdt += 2;
- }
+ if (track->pat_flag & SELECT)
+ i += 4;
- track = track->next;
+ if (track->search_flag & SELECT)
+ i += 2;
}
- }
- else if (tdt->mode == transDataTracking_ModeCurves) {
- MovieTrackingMarker *prev_marker;
+ else if (tdt->mode == transDataTracking_ModeCurves) {
+ MovieTrackingTrack *track = tdt->track;
+ MovieTrackingMarker *marker, *prev_marker;
+ int a;
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- for (a = 1; a < track->markersnr; a++) {
- marker = &track->markers[a];
- prev_marker = &track->markers[a - 1];
+ for (a = 1; a < track->markersnr; a++) {
+ marker = &track->markers[a];
+ prev_marker = &track->markers[a - 1];
- if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED))
- continue;
+ if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED))
+ continue;
- if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) {
- marker->flag = tdt->flag;
- }
+ if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) {
+ marker->flag = tdt->flag;
}
}
+ }
+ else if (tdt->mode == transDataTracking_ModePlaneTracks) {
+ MovieTrackingPlaneTrack *plane_track = tdt->plane_track;
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
- track = track->next;
+ plane_marker->flag = tdt->flag;
+ i += 3;
}
+
+ i++;
}
}
@@ -6432,6 +6505,10 @@ void flushTransTracking(TransInfo *t)
else if (tdt->mode == transDataTracking_ModeCurves) {
td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale;
}
+ else if (tdt->mode == transDataTracking_ModePlaneTracks) {
+ td2d->loc2d[0] = td2d->loc[0] / aspx;
+ td2d->loc2d[1] = td2d->loc[1] / aspy;
+ }
}
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index cb0a0530036..4c7ac4193b3 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -659,7 +659,9 @@ static void recalcData_spaceclip(TransInfo *t)
if (ED_space_clip_check_show_trackedit(sc)) {
MovieClip *clip = ED_space_clip_get_clip(sc);
ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
int framenr = ED_space_clip_get_clip_frame_number(sc);
flushTransTracking(t);
@@ -690,6 +692,15 @@ static void recalcData_spaceclip(TransInfo *t)
track = track->next;
}
+ for (plane_track = plane_tracks_base->first;
+ plane_track;
+ plane_track = plane_track->next)
+ {
+ if (plane_track->flag & SELECT) {
+ BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
+ }
+ }
+
DAG_id_tag_update(&clip->id, 0);
}
else if (t->options & CTX_MASK) {
diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h
index 1b6b802f2de..1b1c912d179 100644
--- a/source/blender/makesdna/DNA_mask_types.h
+++ b/source/blender/makesdna/DNA_mask_types.h
@@ -58,15 +58,18 @@ typedef struct Mask {
typedef struct MaskParent {
// int flag; /* parenting flags */ /* not used */
- int pad;
int id_type; /* type of parenting */
+ int type; /* type of parenting */
ID *id; /* ID block of entity to which mask/spline is parented to
* in case of parenting to movie tracking data set to MovieClip datablock */
char parent[64]; /* entity of parent to which parenting happened
* in case of parenting to movie tracking data contains name of layer */
char sub_parent[64]; /* sub-entity of parent to which parenting happened
* in case of parenting to movie tracking data contains name of track */
- float parent_orig[2]; /* track location at the moment of parenting */
+ float parent_orig[2]; /* track location at the moment of parenting,
+ stored in mask space*/
+
+ float parent_corners_orig[4][2]; /* Original corners of plane track at the moment of parenting */
} MaskParent;
typedef struct MaskSplinePointUW {
@@ -141,6 +144,12 @@ typedef struct MaskLayer {
/* MaskParent->flag */
/* #define MASK_PARENT_ACTIVE (1 << 0) */ /* UNUSED */
+/* MaskParent->type */
+enum {
+ MASK_PARENT_POINT_TRACK = 0, /* parenting happens to point track */
+ MASK_PARENT_PLANE_TRACK = 1, /* parenting happens to plane track */
+};
+
/* MaskSpline->flag */
/* reserve (1 << 0) for SELECT */
enum {
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 9ff4392242e..109cdf5f1a1 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -827,6 +827,10 @@ typedef struct NodeTranslateData {
char pad[6];
} NodeTranslateData;
+typedef struct NodePlaneTrackDeformData {
+ char tracking_object[64];
+ char plane_track_name[64];
+} NodePlaneTrackDeformData;
typedef struct NodeShaderScript {
int mode;
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index 04cd69bc5ae..f81ac4dab06 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -144,6 +144,44 @@ typedef struct MovieTrackingTrack {
struct bGPdata *gpd; /* grease-pencil data */
} MovieTrackingTrack;
+typedef struct MovieTrackingPlaneMarker {
+ /* Corners of the plane in the following order:
+ *
+ * Y
+ * ^
+ * | (3) --- (2)
+ * | | |
+ * | | |
+ * | | |
+ * | (0) --- (1)
+ * +-------------> X
+ *
+ * The coordinates are stored in frame normalized coordinates.
+ */
+ float corners[4][2];
+
+ int framenr; /* Number of frame plane marker is associated with */
+ int flag; /* Marker's flag (alive, ...) */
+} MovieTrackingPlaneMarker;
+
+typedef struct MovieTrackingPlaneTrack {
+ struct MovieTrackingPlaneTrack *next, *prev;
+
+ char name[64]; /* MAX_NAME */
+
+ MovieTrackingTrack **point_tracks; /* Array of point tracks used to define this plane.
+ Each element is a pointer to MovieTrackingTrack. */
+ int point_tracksnr, pad; /* Number of tracks in point_tracks array. */
+
+ MovieTrackingPlaneMarker *markers; /* Markers in the plane track */
+ int markersnr; /* Count of markers in track (size of markers array) */
+
+ int flag; /* flags (selection, ...) */
+
+ /* Runtime data */
+ int last_marker, pad2; /* Most recently used marker */
+} MovieTrackingPlaneTrack;
+
typedef struct MovieTrackingSettings {
int flag;
@@ -225,6 +263,7 @@ typedef struct MovieTrackingObject {
float scale; /* scale of object solution in amera space */
ListBase tracks; /* list of tracks use to tracking this object */
+ ListBase plane_tracks; /* list of plane tracks used by this object */
MovieTrackingReconstruction reconstruction; /* reconstruction data for this object */
/* reconstruction options */
@@ -280,9 +319,11 @@ typedef struct MovieTracking {
MovieTrackingSettings settings; /* different tracking-related settings */
MovieTrackingCamera camera; /* camera intrinsics */
ListBase tracks; /* list of tracks used for camera object */
+ ListBase plane_tracks; /* list of plane tracks used by camera object */
MovieTrackingReconstruction reconstruction; /* reconstruction data for camera object */
MovieTrackingStabilization stabilization; /* stabilization data */
- MovieTrackingTrack *act_track; /* active track */
+ MovieTrackingTrack *act_track; /* active track */
+ MovieTrackingPlaneTrack *act_plane_track; /* active plane track */
ListBase objects;
int objectnr, tot_object; /* index of active object and total number of objects */
@@ -432,4 +473,16 @@ enum {
TRACKING_COVERAGE_OK = 2
};
+/* MovieTrackingPlaneMarker->flag */
+enum {
+ PLANE_MARKER_DISABLED = (1 << 0),
+ PLANE_MARKER_TRACKED = (1 << 1),
+};
+
+/* MovieTrackingPlaneTrack->flag */
+enum {
+ PLANE_TRACK_HIDDEN = (1 << 1),
+ PLANE_TRACK_LOCKED = (1 << 2),
+};
+
#endif /* __DNA_TRACKING_TYPES_H__ */
diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c
index 65e6b15d676..6a5fc393269 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -84,21 +84,33 @@ static void rna_Mask_update_parent(Main *bmain, Scene *scene, PointerRNA *ptr)
MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, parent->parent);
if (object) {
- MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, object, parent->sub_parent);
+ int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra);
- if (track) {
- int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra);
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_framenr);
- float marker_pos_ofs[2], parmask_pos[2];
- MovieClipUser user = {0};
+ if (parent->type == MASK_PARENT_POINT_TRACK) {
+ MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, object, parent->sub_parent);
- BKE_movieclip_user_set_frame(&user, scene->r.cfra);
+ if (track) {
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_framenr);
+ float marker_pos_ofs[2], parmask_pos[2];
+ MovieClipUser user = {0};
- add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset);
+ BKE_movieclip_user_set_frame(&user, scene->r.cfra);
- BKE_mask_coord_from_movieclip(clip, &user, parmask_pos, marker_pos_ofs);
+ add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset);
- copy_v2_v2(parent->parent_orig, parmask_pos);
+ BKE_mask_coord_from_movieclip(clip, &user, parmask_pos, marker_pos_ofs);
+
+ copy_v2_v2(parent->parent_orig, parmask_pos);
+ }
+ }
+ else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ {
+ MovieTrackingPlaneTrack *plane_track = BKE_tracking_plane_track_get_named(tracking, object, parent->sub_parent);
+ if (plane_track) {
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr);
+
+ memcpy(parent->parent_corners_orig, plane_marker->corners, sizeof(parent->parent_corners_orig));
+ zero_v2(parent->parent_orig);
+ }
}
}
}
@@ -513,6 +525,11 @@ static void rna_MaskSpline_point_remove(ID *id, MaskSpline *spline, ReportList *
{ID_MC, "MOVIECLIP", ICON_SEQUENCE, "Movie Clip", ""},
{0, NULL, 0, NULL, NULL}};
+ static EnumPropertyItem parent_type_items[] = {
+ {MASK_PARENT_POINT_TRACK, "POINT_TRACK", 0, "Point Track", ""},
+ {MASK_PARENT_PLANE_TRACK, "PLANE_TRACK", 0, "Plane Track", ""},
+ {0, NULL, 0, NULL, NULL}};
+
srna = RNA_def_struct(brna, "MaskParent", NULL);
RNA_def_struct_ui_text(srna, "Mask Parent", "Parenting settings for masking element");
@@ -535,6 +552,12 @@ static void rna_MaskSpline_point_remove(ID *id, MaskSpline *spline, ReportList *
RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used");
RNA_def_property_update(prop, 0, "rna_Mask_update_parent");
+ /* type */
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, parent_type_items);
+ RNA_def_property_ui_text(prop, "Parent Type", "Parent Type");
+ RNA_def_property_update(prop, 0, "rna_Mask_update_parent");
+
/* parent */
prop = RNA_def_property(srna, "parent", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Parent", "Name of parent object in specified data block to which parenting happens");
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 535c279c02f..3b594ab0961 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -5919,6 +5919,29 @@ static void def_cmp_translate(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_planetrackdeform(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "id");
+ RNA_def_property_struct_type(prop, "MovieClip");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Movie Clip", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "NodePlaneTrackDeformData", "storage");
+
+ prop = RNA_def_property(srna, "tracking_object", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "tracking_object");
+ RNA_def_property_ui_text(prop, "Tracking Object", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "plane_track_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "plane_track_name");
+ RNA_def_property_ui_text(prop, "Plane Track", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
/* -- Texture Nodes --------------------------------------------------------- */
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 4c47bbf93a6..c92af884b1b 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -95,6 +95,13 @@ static void rna_trackingTracks_begin(CollectionPropertyIterator *iter, PointerRN
rna_iterator_listbase_begin(iter, &clip->tracking.tracks, NULL);
}
+static void rna_trackingPlaneTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+
+ rna_iterator_listbase_begin(iter, &clip->tracking.plane_tracks, NULL);
+}
+
static void rna_trackingObjects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
@@ -146,6 +153,27 @@ static void rna_tracking_active_track_set(PointerRNA *ptr, PointerRNA value)
clip->tracking.act_track = NULL;
}
+static PointerRNA rna_tracking_active_plane_track_get(PointerRNA *ptr)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+ MovieTrackingPlaneTrack *act_plane_track = BKE_tracking_plane_track_get_active(&clip->tracking);
+
+ return rna_pointer_inherit_refine(ptr, &RNA_MovieTrackingPlaneTrack, act_plane_track);
+}
+
+static void rna_tracking_active_plane_track_set(PointerRNA *ptr, PointerRNA value)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+ MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *) value.data;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
+ int index = BLI_findindex(plane_tracks_base, plane_track);
+
+ if (index >= 0)
+ clip->tracking.act_plane_track = plane_track;
+ else
+ clip->tracking.act_plane_track = NULL;
+}
+
static void rna_trackingTrack_name_set(PointerRNA *ptr, const char *value)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
@@ -197,6 +225,71 @@ static void rna_trackingTrack_select_set(PointerRNA *ptr, int value)
}
}
+static void rna_trackingPlaneMarker_frame_set(PointerRNA *ptr, int value)
+{
+ MovieClip *clip = (MovieClip *) ptr->id.data;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingPlaneTrack *plane_track;
+ MovieTrackingPlaneMarker *plane_marker = (MovieTrackingPlaneMarker *) ptr->data;
+
+ /* TODO(sergey): Need to support editing markers from object's tracks */
+
+ plane_track = tracking->plane_tracks.first;
+ while (plane_track) {
+ if (plane_marker >= plane_track->markers &&
+ plane_marker < plane_track->markers + plane_track->markersnr)
+ {
+ break;
+ }
+
+ plane_track = plane_track->next;
+ }
+
+ if (plane_track) {
+ MovieTrackingPlaneMarker new_plane_marker = *plane_marker;
+ new_plane_marker.framenr = value;
+
+ BKE_tracking_plane_marker_delete(plane_track, plane_marker->framenr);
+ BKE_tracking_plane_marker_insert(plane_track, &new_plane_marker);
+ }
+}
+
+static char *rna_trackingPlaneTrack_path(PointerRNA *ptr)
+{
+ MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data;
+ char name_esc[sizeof(plane_track->name) * 2];
+ BLI_strescape(name_esc, plane_track->name, sizeof(name_esc));
+ return BLI_sprintfN("tracking.plane_tracks[\"%s\"]", name_esc);
+}
+
+static void rna_trackingPlaneTrack_name_set(PointerRNA *ptr, const char *value)
+{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data;
+ ListBase *plane_tracks_base = &tracking->plane_tracks;
+
+ BLI_strncpy(plane_track->name, value, sizeof(plane_track->name));
+
+ /* TODO: it's a bit difficult to find list track came from knowing just
+ * movie clip ID and MovieTracking structure, so keep this naive
+ * search for a while */
+ if (BLI_findindex(plane_tracks_base, plane_track) < 0) {
+ MovieTrackingObject *object = tracking->objects.first;
+
+ while (object) {
+ if (BLI_findindex(&object->plane_tracks, plane_track)) {
+ plane_tracks_base = &object->plane_tracks;
+ break;
+ }
+
+ object = object->next;
+ }
+ }
+
+ BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track);
+}
+
static char *rna_trackingCamera_path(PointerRNA *UNUSED(ptr))
{
return BLI_sprintfN("tracking.camera");
@@ -294,6 +387,20 @@ static void rna_trackingObject_tracks_begin(CollectionPropertyIterator *iter, Po
}
}
+static void rna_trackingObject_plane_tracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ MovieTrackingObject *object = (MovieTrackingObject *)ptr->data;
+
+ if (object->flag & TRACKING_OBJECT_CAMERA) {
+ MovieClip *clip = (MovieClip *)ptr->id.data;
+
+ rna_iterator_listbase_begin(iter, &clip->tracking.plane_tracks, NULL);
+ }
+ else {
+ rna_iterator_listbase_begin(iter, &object->plane_tracks, NULL);
+ }
+}
+
static PointerRNA rna_trackingObject_reconstruction_get(PointerRNA *ptr)
{
MovieTrackingObject *object = (MovieTrackingObject *)ptr->data;
@@ -1188,6 +1295,115 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
}
+static void rna_def_trackingPlaneMarker(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MovieTrackingPlaneMarker", NULL);
+ RNA_def_struct_ui_text(srna, "Movie Tracking Plane Marker Data", "Match-moving plane marker data for tracking");
+
+ /* frame */
+ prop = RNA_def_property(srna, "frame", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "framenr");
+ RNA_def_property_ui_text(prop, "Frame", "Frame number marker is keyframed on");
+ RNA_def_property_int_funcs(prop, NULL, "rna_trackingPlaneMarker_frame_set", NULL);
+ RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, 0);
+
+ /* Corners */
+ prop = RNA_def_property(srna, "corners", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_float_sdna(prop, NULL, "corners");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x2);
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_ui_text(prop, "Corners",
+ "Array of coordinates which represents UI rectange corners in "
+ "frame normalized coordinates");
+ RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
+
+ /* enable */
+ prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PLANE_MARKER_DISABLED);
+ RNA_def_property_ui_text(prop, "Mode", "Is marker muted for current frame");
+ RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
+}
+
+static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ //FunctionRNA *func;
+ //PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "MovieTrackingPlaneMarkers");
+ srna = RNA_def_struct(brna, "MovieTrackingPlaneMarkers", NULL);
+ RNA_def_struct_sdna(srna, "MovieTrackingPlaneTrack");
+ RNA_def_struct_ui_text(srna, "Movie Tracking Plane Markers", "Collection of markers for movie tracking plane track");
+
+ /*
+ func = RNA_def_function(srna, "find_frame", "rna_trackingMarkers_find_frame");
+ RNA_def_function_ui_description(func, "Get marker for specified frame");
+ parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
+ "Frame number to find marker for", MINFRAME, MAXFRAME);
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "exact", TRUE, "Exact",
+ "Get marker at exact frame number rather than get estimated marker");
+ parm = RNA_def_pointer(func, "marker", "MovieTrackingMarker", "", "Marker for specified frame");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "insert_frame", "rna_trackingMarkers_insert_frame");
+ RNA_def_function_ui_description(func, "Add a number of tracks to this movie clip");
+ parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
+ "Frame number to insert marker to", MINFRAME, MAXFRAME);
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_float_vector(func, "co", 2, 0, -1.0, 1.0, "Coordinate",
+ "Place new marker at the given frame using specified in normalized space coordinates",
+ -1.0, 1.0);
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "marker", "MovieTrackingMarker", "", "Newly created marker");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "delete_frame", "rna_trackingMarkers_delete_frame");
+ RNA_def_function_ui_description(func, "Delete marker at specified frame");
+ parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame",
+ "Frame number to delete marker from", MINFRAME, MAXFRAME);
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ */
+}
+
+static void rna_def_trackingPlaneTrack(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ rna_def_trackingPlaneMarker(brna);
+
+ srna = RNA_def_struct(brna, "MovieTrackingPlaneTrack", NULL);
+ RNA_def_struct_path_func(srna, "rna_trackingPlaneTrack_path");
+ RNA_def_struct_ui_text(srna, "Movie tracking plane track data", "Match-moving plane track data for tracking");
+ RNA_def_struct_ui_icon(srna, ICON_ANIM_DATA);
+
+ /* name */
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Name", "Unique name of track");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_trackingPlaneTrack_name_set");
+ RNA_def_property_string_maxlength(prop, MAX_ID_NAME - 2);
+ RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
+ RNA_def_struct_name_property(srna, prop);
+
+ /* markers */
+ prop = RNA_def_property(srna, "markers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MovieTrackingPlaneMarker");
+ RNA_def_property_collection_sdna(prop, NULL, "markers", "markersnr");
+ RNA_def_property_ui_text(prop, "Markers", "Collection of markers in track");
+ rna_def_trackingPlaneMarkers(brna, prop);
+
+ /* select */
+ prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SELECT);
+ RNA_def_property_ui_text(prop, "Select", "Plane track is selected");
+ RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
+}
+
static void rna_def_trackingStabilization(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1373,6 +1589,37 @@ static void rna_def_trackingTracks(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Active Track", "Active track in this tracking data object");
}
+static void rna_def_trackingPlaneTracks(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ //FunctionRNA *func;
+ PropertyRNA *prop;
+ //PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "MovieTrackingPlaneTracks", NULL);
+ RNA_def_struct_sdna(srna, "MovieTracking");
+ RNA_def_struct_ui_text(srna, "Movie Plane Tracks", "Collection of movie tracking plane tracks");
+
+ /* TODO(sergey): Need to support tracks API. */
+
+#if 0
+ func = RNA_def_function(srna, "new", "rna_trackingTracks_new");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ RNA_def_function_ui_description(func, "Create new motion track in this movie clip");
+ RNA_def_string(func, "name", "", 0, "", "Name of new track");
+ RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to add track on", MINFRAME, MAXFRAME);
+ parm = RNA_def_pointer(func, "track", "MovieTrackingTrack", "", "Newly created track");
+ RNA_def_function_return(func, parm);
+#endif
+
+ /* active plane track */
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MovieTrackingPlaneTrack");
+ RNA_def_property_pointer_funcs(prop, "rna_tracking_active_plane_track_get", "rna_tracking_active_plane_track_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
+ RNA_def_property_ui_text(prop, "Active Plane Track", "Active plane track in this tracking data object");
+}
+
static void rna_def_trackingObjectTracks(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1400,6 +1647,35 @@ static void rna_def_trackingObjectTracks(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Active Track", "Active track in this tracking data object");
}
+static void rna_def_trackingObjectPlaneTracks(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ //FunctionRNA *func;
+ PropertyRNA *prop;
+ //PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "MovieTrackingObjectPlaneTracks", NULL);
+ RNA_def_struct_sdna(srna, "MovieTrackingObject");
+ RNA_def_struct_ui_text(srna, "Plane Tracks", "Collection of tracking plane tracks");
+
+#if 0
+ func = RNA_def_function(srna, "new", "rna_trackingObject_tracks_new");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ RNA_def_function_ui_description(func, "create new motion track in this movie clip");
+ RNA_def_string(func, "name", "", 0, "", "Name of new track");
+ RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to add tracks on", MINFRAME, MAXFRAME);
+ parm = RNA_def_pointer(func, "track", "MovieTrackingTrack", "", "Newly created track");
+ RNA_def_function_return(func, parm);
+#endif
+
+ /* active track */
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MovieTrackingTrack");
+ RNA_def_property_pointer_funcs(prop, "rna_tracking_active_plane_track_get", "rna_tracking_active_plane_track_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
+ RNA_def_property_ui_text(prop, "Active Track", "Active track in this tracking data object");
+}
+
static void rna_def_trackingObject(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1432,6 +1708,15 @@ static void rna_def_trackingObject(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Tracks", "Collection of tracks in this tracking data object");
RNA_def_property_srna(prop, "MovieTrackingObjectTracks");
+ /* plane tracks */
+ prop = RNA_def_property(srna, "plane_tracks", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop, "rna_trackingObject_plane_tracks_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "MovieTrackingPlaneTrack");
+ RNA_def_property_ui_text(prop, "Plane Tracks", "Collection of plane tracks in this tracking data object");
+ RNA_def_property_srna(prop, "MovieTrackingObjectPlaneTracks");
+
/* reconstruction */
prop = RNA_def_property(srna, "reconstruction", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "MovieTrackingReconstruction");
@@ -1549,8 +1834,11 @@ static void rna_def_tracking(BlenderRNA *brna)
rna_def_trackingSettings(brna);
rna_def_trackingCamera(brna);
rna_def_trackingTrack(brna);
+ rna_def_trackingPlaneTrack(brna);
rna_def_trackingTracks(brna);
+ rna_def_trackingPlaneTracks(brna);
rna_def_trackingObjectTracks(brna);
+ rna_def_trackingObjectPlaneTracks(brna);
rna_def_trackingStabilization(brna);
rna_def_trackingReconstruction(brna);
rna_def_trackingObject(brna);
@@ -1577,6 +1865,15 @@ static void rna_def_tracking(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Tracks", "Collection of tracks in this tracking data object");
RNA_def_property_srna(prop, "MovieTrackingTracks");
+ /* tracks */
+ prop = RNA_def_property(srna, "plane_tracks", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop, "rna_trackingPlaneTracks_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "MovieTrackingPlaneTrack");
+ RNA_def_property_ui_text(prop, "Plane Tracks", "Collection of plane tracks in this tracking data object");
+ RNA_def_property_srna(prop, "MovieTrackingPlaneTracks");
+
/* stabilization */
prop = RNA_def_property(srna, "stabilization", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "MovieTrackingStabilization");
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 64261246e3d..4ac75c15efe 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -92,6 +92,7 @@ set(SRC
composite/nodes/node_composite_normal.c
composite/nodes/node_composite_normalize.c
composite/nodes/node_composite_outputFile.c
+ composite/nodes/node_composite_planetrackdeform.c
composite/nodes/node_composite_premulkey.c
composite/nodes/node_composite_rgb.c
composite/nodes/node_composite_rotate.c
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 626e7955b08..4320e0436ce 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -137,6 +137,7 @@ void register_node_type_cmp_bokehblur(void);
void register_node_type_cmp_switch(void);
void register_node_type_cmp_pixelate(void);
void register_node_type_cmp_trackpos(void);
+void register_node_type_cmp_planetrackdeform(void);
void node_cmp_rlayers_force_hidden_passes(struct bNode *node);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 0b526fcde0e..eeec40c911f 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -1,3 +1,4 @@
+
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -200,6 +201,7 @@ DefNode( CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYIN
DefNode( CompositorNode, CMP_NODE_KEYING, def_cmp_keying, "KEYING", Keying, "Keying", "" )
DefNode( CompositorNode, CMP_NODE_TRACKPOS, def_cmp_trackpos, "TRACKPOS", TrackPos, "Track Position", "" )
DefNode( CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELATE", Pixelate, "Pixelate", "" )
+DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" )
DefNode( TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode( TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c
new file mode 100644
index 00000000000..7a15d6364dc
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c
@@ -0,0 +1,64 @@
+/*
+ * ***** 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) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_planetrackdeform.c
+ * \ingroup cmpnodes
+ */
+
+
+#include "node_composite_util.h"
+
+static bNodeSocketTemplate cmp_node_planetrackdeform_in[] = {
+ { SOCK_RGBA, 1, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate cmp_node_planetrackdeform_out[] = {
+ { SOCK_RGBA, 0, N_("Image")},
+ { SOCK_FLOAT, 0, N_("Plane")},
+ { -1, 0, "" }
+};
+
+static void init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodePlaneTrackDeformData *data = MEM_callocN(sizeof(NodePlaneTrackDeformData), "node plane track deform data");
+
+ node->storage = data;
+}
+
+void register_node_type_cmp_planetrackdeform(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT, 0);
+ node_type_socket_templates(&ntype, cmp_node_planetrackdeform_in, cmp_node_planetrackdeform_out);
+ node_type_init(&ntype, init);
+ node_type_storage(&ntype, "NodePlaneTrackDeformData", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}