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
path: root/source
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2013-08-16 13:46:30 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2013-08-16 13:46:30 +0400
commit24ce60cfe4511534e57a2dea3f24579c74bbdd29 (patch)
tree57df16e6d5f41545e1379f8a51e0e10fe6b2eef1 /source
parentcab2aef71ab44bc7d85cf4e2c1de607d02e0df7d (diff)
Merge plane track feature from tomato branch
This commit includes all the changes made for plane tracker in tomato branch. Movie clip editor changes: - Artist might create a plane track out of multiple point tracks which belongs to the same track (minimum amount of point tracks is 4, maximum is not actually limited). When new plane track is added, it's getting "tracked" across all point tracks, which makes it stick to the same plane point tracks belong to. - After plane track was added, it need to be manually adjusted in a way it covers feature one might to mask/replace. General transform tools (G, R, S) or sliding corners with a mouse could be sued for this. Plane corner which corresponds to left bottom image corner has got X/Y axis on it (red is for X axis, green for Y). - Re-adjusting plane corners makes plane to be "re-tracked" for the frames sequence between current frame and next and previous keyframes. - Kayframes might be removed from the plane, using Shit-X (Marker Delete) operator. However, currently manual re-adjustment or "re-track" trigger is needed. Compositor changes: - Added new node called Plane Track Deform. - User selects which plane track to use (for this he need to select movie clip datablock, object and track names). - Node gets an image input, which need to be warped into the plane. - Node outputs: * Input image warped into the plane. * Plane, rasterized to a mask. Masking changes: - Mask points might be parented to a plane track, which makes this point deforming in a way as if it belongs to the tracked plane. Some video tutorials are available: - Coder video: http://www.youtube.com/watch?v=vISEwqNHqe4 - Artist video: https://vimeo.com/71727578 This is mine and Keir's holiday code project :)
Diffstat (limited to 'source')
-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);
+}