diff options
48 files changed, 3013 insertions, 151 deletions
diff --git a/extern/libmv/libmv-capi.cc b/extern/libmv/libmv-capi.cc index 063c63f9266..e1fd509d581 100644 --- a/extern/libmv/libmv-capi.cc +++ b/extern/libmv/libmv-capi.cc @@ -58,6 +58,8 @@ #include "libmv/simple_pipeline/reconstruction_scale.h" #include "libmv/simple_pipeline/keyframe_selection.h" +#include "libmv/multiview/homography.h" + #ifdef _MSC_VER # define snprintf _snprintf #endif @@ -1080,4 +1082,28 @@ void libmv_cameraIntrinsicsInvert(const libmv_CameraIntrinsicsOptions *libmv_cam } } +void libmv_homography2DFromCorrespondencesLinear(double (*x1)[2], double (*x2)[2], int num_points, + double H[3][3], double expected_precision) +{ + libmv::Mat x1_mat, x2_mat; + libmv::Mat3 H_mat; + + x1_mat.resize(2, num_points); + x2_mat.resize(2, num_points); + + for (int i = 0; i < num_points; i++) { + x1_mat.col(i) = libmv::Vec2(x1[i][0], x1[i][1]); + x2_mat.col(i) = libmv::Vec2(x2[i][0], x2[i][1]); + } + + LG << "x1: " << x1_mat; + LG << "x2: " << x2_mat; + + libmv::Homography2DFromCorrespondencesLinear(x1_mat, x2_mat, &H_mat, expected_precision); + + LG << "H: " << H_mat; + + memcpy(H, H_mat.data(), 9 * sizeof(double)); +} + #endif diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h index 7c91881fe71..37aab2465ed 100644 --- a/extern/libmv/libmv-capi.h +++ b/extern/libmv/libmv-capi.h @@ -159,6 +159,9 @@ void libmv_cameraIntrinsicsApply(const libmv_CameraIntrinsicsOptions *libmv_came void libmv_cameraIntrinsicsInvert(const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, double x, double y, double *x1, double *y1); +void libmv_homography2DFromCorrespondencesLinear(double (*x1)[2], double (*x2)[2], int num_points, + double H[3][3], double expected_precision); + #ifdef __cplusplus } #endif diff --git a/extern/libmv/libmv-capi_stub.cc b/extern/libmv/libmv-capi_stub.cc index 36977eb58ba..07125b80f04 100644 --- a/extern/libmv/libmv-capi_stub.cc +++ b/extern/libmv/libmv-capi_stub.cc @@ -277,4 +277,13 @@ void libmv_cameraIntrinsicsInvert(const libmv_CameraIntrinsicsOptions *libmv_cam *y1 = (y - principal_y) / focal_length; } +void libmv_homography2DFromCorrespondencesLinear(double (* /* x1 */)[2], double (* /* x2 */)[2], int /* num_points */, + double H[3][3], double /* expected_precision */) +{ + memset(H, 0, sizeof(H)); + N[0][0] = 1.0f; + N[1][1] = 1.0f; + N[02[2] = 1.0f; +} + #endif // ifndef WITH_LIBMV diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py index d38f5f934b4..9f72d7a6d88 100644 --- a/release/scripts/startup/bl_ui/properties_mask_common.py +++ b/release/scripts/startup/bl_ui/properties_mask_common.py @@ -190,16 +190,21 @@ class MASK_PT_point(): clip = parent.id tracking = clip.tracking + row = col.row() + row.prop(parent, "type", expand=True) + col.prop_search(parent, "parent", tracking, "objects", icon='OBJECT_DATA', text="Object:") + tracks_list = "tracks" if parent.type == 'POINT_TRACK' else 'plane_tracks' + if parent.parent in tracking.objects: object = tracking.objects[parent.parent] col.prop_search(parent, "sub_parent", object, - "tracks", icon='ANIM_DATA', text="Track:") + tracks_list, icon='ANIM_DATA', text="Track:") else: col.prop_search(parent, "sub_parent", tracking, - "tracks", icon='ANIM_DATA', text="Track:") + tracks_list, icon='ANIM_DATA', text="Track:") class MASK_PT_display(): diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index 5048a93d565..04584855ed3 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -311,6 +311,16 @@ class CLIP_PT_tools_tracking(CLIP_PT_tracking_panel, Panel): layout.operator("clip.join_tracks", text="Join") +class CLIP_PT_tools_plane_tracking(CLIP_PT_tracking_panel, Panel): + bl_space_type = 'CLIP_EDITOR' + bl_region_type = 'TOOLS' + bl_label = "Plane Track" + + def draw(self, context): + layout = self.layout + layout.operator("clip.create_plane_track") + + class CLIP_PT_tools_solve(CLIP_PT_tracking_panel, Panel): bl_space_type = 'CLIP_EDITOR' bl_region_type = 'TOOLS' @@ -579,6 +589,26 @@ class CLIP_PT_track(CLIP_PT_tracking_panel, Panel): layout.label(text=label_text) +class CLIP_PT_plane_track(CLIP_PT_tracking_panel, Panel): + bl_space_type = 'CLIP_EDITOR' + bl_region_type = 'UI' + bl_label = "Plane Track" + + def draw(self, context): + layout = self.layout + + sc = context.space_data + clip = context.space_data.clip + active_track = clip.tracking.plane_tracks.active + + if not active_track: + layout.active = False + layout.label(text="No active plane track") + return + + layout.prop(active_track, "name") + + class CLIP_PT_track_settings(CLIP_PT_tracking_panel, Panel): bl_space_type = 'CLIP_EDITOR' bl_region_type = 'UI' diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 91090dc2c75..6a5dccaed88 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -342,6 +342,7 @@ compositor_node_categories = [ NodeItem("CompositorNodeMapUV"), NodeItem("CompositorNodeTransform"), NodeItem("CompositorNodeStabilize"), + NodeItem("CompositorNodePlaneTrackDeform"), ]), CompositorNodeCategory("CMP_GROUP", "Group", items=node_group_items), CompositorNodeCategory("CMP_LAYOUT", "Layout", items=[ 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); +} |