/* draw grease pencil */
void clip_draw_grease_pencil(bContext *C, int onlyv2d)
{
	SpaceClip *sc = CTX_wm_space_clip(C);
	MovieClip *clip = ED_space_clip_get_clip(sc);

	if (!clip)
		return;

	if (onlyv2d) {
		/* if manual calibration is used then grease pencil data is already
		 * drawn in draw_distortion */
		if ((sc->flag & SC_MANUAL_CALIBRATION) == 0) {
			glPushMatrix();
			glMultMatrixf(sc->unistabmat);

			if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
				MovieTrackingTrack *track = BKE_tracking_track_get_active(&sc->clip->tracking);

				if (track) {
					int framenr = ED_space_clip_get_clip_frame_number(sc);
					MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);

					glTranslatef(marker->pos[0], marker->pos[1], 0.0f);
				}
			}

			draw_gpencil_2dimage(C);

			glPopMatrix();
		}
	}
	else {
		draw_gpencil_view2d(C, 0);
	}
}
static int graph_disable_markers_exec(bContext *C, wmOperator *op)
{
	SpaceClip *sc = CTX_wm_space_clip(C);
	MovieClip *clip = ED_space_clip_get_clip(sc);
	MovieTracking *tracking = &clip->tracking;
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
	MovieTrackingMarker *marker;
	int action = RNA_enum_get(op->ptr, "action");
	int a;

	if (!act_track || (act_track->flag & TRACK_LOCKED))
		return OPERATOR_CANCELLED;

	for (a = 0; a < act_track->markersnr; a++) {
		marker = &act_track->markers[a];

		if (marker->flag & MARKER_GRAPH_SEL) {
			if (action == 0)
				marker->flag |= MARKER_DISABLED;
			else if (action == 1)
				marker->flag &= ~MARKER_DISABLED;
			else
				marker->flag ^= MARKER_DISABLED;
		}
	}

	DAG_id_tag_update(&clip->id, 0);

	WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);

	return OPERATOR_FINISHED;
}
static int border_select_graph_exec(bContext *C, wmOperator *op)
{
	SpaceClip *sc = CTX_wm_space_clip(C);
	ARegion *ar = CTX_wm_region(C);

	MovieClip *clip = ED_space_clip_get_clip(sc);
	MovieTracking *tracking = &clip->tracking;
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
	BorderSelectuserData userdata;
	rctf rect;

	if (act_track == NULL) {
		return OPERATOR_CANCELLED;
	}

	/* get rectangle from operator */
	WM_operator_properties_border_to_rctf(op, &rect);
	UI_view2d_region_to_view_rctf(&ar->v2d, &rect, &userdata.rect);

	userdata.changed = false;
	userdata.mode = RNA_int_get(op->ptr, "gesture_mode");
	userdata.extend = RNA_boolean_get(op->ptr, "extend");

	clip_graph_tracking_values_iterate_track(sc, act_track, &userdata, border_select_cb, NULL, NULL);

	if (userdata.changed) {
		WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);

		return OPERATOR_FINISHED;
	}

	return OPERATOR_CANCELLED;
}
static void draw_tracks_error_curves(SpaceClip *sc)
{
	MovieClip *clip = ED_space_clip_get_clip(sc);
	MovieTracking *tracking = &clip->tracking;
	TrackErrorCurveUserData data;

	data.clip = clip;
	data.tracking = tracking;
	data.tracking_object = BKE_tracking_object_get_active(tracking);
	data.active_track = BKE_tracking_track_get_active(tracking);
	data.matrix_initialized = false;
	BKE_movieclip_get_size(clip, &sc->user, &data.width, &data.height);
	data.aspy = 1.0f / tracking->camera.pixel_aspect;

	if (!data.width || !data.height) {
		return;
	}

	clip_graph_tracking_values_iterate(sc,
	                                   (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
	                                   (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
	                                   &data,
	                                   tracking_error_segment_point_cb,
	                                   tracking_error_segment_start_cb,
	                                   tracking_error_segment_end_cb);
}
static bool mouse_select_knot(bContext *C, float co[2], bool extend)
{
	SpaceClip *sc = CTX_wm_space_clip(C);
	MovieClip *clip = ED_space_clip_get_clip(sc);
	ARegion *ar = CTX_wm_region(C);
	View2D *v2d = &ar->v2d;
	MovieTracking *tracking = &clip->tracking;
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
	static const int delta = 6;

	if (act_track) {
		MouseSelectUserData userdata;

		mouse_select_init_data(&userdata, co);
		clip_graph_tracking_values_iterate_track(sc, act_track, &userdata,
		                                         find_nearest_tracking_knot_cb, NULL, NULL);

		if (userdata.marker) {
			int x1, y1, x2, y2;

			if (UI_view2d_view_to_region_clip(v2d, co[0], co[1], &x1, &y1) &&
			    UI_view2d_view_to_region_clip(v2d, userdata.min_co[0], userdata.min_co[1], &x2, &y2) &&
			    (abs(x2 - x1) <= delta && abs(y2 - y1) <= delta))
			{
				if (!extend) {
					SelectUserData selectdata = {SEL_DESELECT};

					clip_graph_tracking_iterate(sc,
					                            (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
					                            (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
					                            &selectdata,
					                            toggle_selection_cb);
				}

				if (userdata.coord == 0) {
					if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_X) != 0)
						userdata.marker->flag &= ~MARKER_GRAPH_SEL_X;
					else
						userdata.marker->flag |= MARKER_GRAPH_SEL_X;
				}
				else {
					if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_Y) != 0)
						userdata.marker->flag &= ~MARKER_GRAPH_SEL_Y;
					else
						userdata.marker->flag |= MARKER_GRAPH_SEL_Y;
				}

				return true;
			}
		}
	}

	return false;
}
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;
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);

	if (!act_track)
		return OPERATOR_CANCELLED;

	clip_delete_track(C, clip, act_track);

	return OPERATOR_FINISHED;
}
static int graph_select_all_markers_exec(bContext *C, wmOperator *op)
{
	SpaceClip *sc = CTX_wm_space_clip(C);
	MovieClip *clip = ED_space_clip_get_clip(sc);
	MovieTracking *tracking = &clip->tracking;
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
	MovieTrackingMarker *marker;
	int action = RNA_enum_get(op->ptr, "action");
	int a;

	if (!act_track)
		return OPERATOR_CANCELLED;

	if (action == SEL_TOGGLE) {
		action = SEL_SELECT;

		for (a = 0; a < act_track->markersnr; a++) {
			marker = &act_track->markers[a];

			if (marker->flag & MARKER_GRAPH_SEL) {
				action = SEL_DESELECT;
				break;
			}
		}
	}

	for (a = 0; a < act_track->markersnr; a++) {
		marker = &act_track->markers[a];

		switch (action) {
			case SEL_SELECT:
				marker->flag |= MARKER_GRAPH_SEL;
				break;
			case SEL_DESELECT:
				marker->flag &= ~MARKER_GRAPH_SEL;
				break;
			case SEL_INVERT:
				marker->flag ^= MARKER_GRAPH_SEL;
				break;
		}
	}

	WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);

	return OPERATOR_FINISHED;
}
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);
	ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
	bool has_bundle = false, update_stab = false;
	char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];

	if (track == act_track)
		tracking->act_track = NULL;

	if (track == stab->rot_track) {
		stab->rot_track = NULL;

		update_stab = true;
	}

	/* handle reconstruction display in 3d viewport */
	if (track->flag & TRACK_HAS_BUNDLE)
		has_bundle = true;

	/* Make sure no plane will use freed track */
	BKE_tracking_plane_tracks_remove_point_track(tracking, track);

	/* Delete f-curves associated with the track (such as weight, i.e.) */
	BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped));
	BLI_snprintf(prefix, sizeof(prefix), "tracks[\"%s\"]", track_name_escaped);
	BKE_animdata_fix_paths_remove(&clip->id, prefix);

	BKE_tracking_track_free(track);
	BLI_freelinkN(tracksbase, track);

	WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);

	if (update_stab) {
		tracking->stabilization.ok = false;
		WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
	}

	DAG_id_tag_update(&clip->id, 0);

	if (has_bundle)
		WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
static bool mouse_select_curve(bContext *C, float co[2], bool extend)
{
	SpaceClip *sc = CTX_wm_space_clip(C);
	MovieClip *clip = ED_space_clip_get_clip(sc);
	MovieTracking *tracking = &clip->tracking;
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
	MouseSelectUserData userdata;

	mouse_select_init_data(&userdata, co);
	clip_graph_tracking_values_iterate(sc,
	                                   (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
	                                   (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
	                                   &userdata, find_nearest_tracking_segment_cb,
	                                   NULL, find_nearest_tracking_segment_end_cb);

	if (userdata.track) {
		if (extend) {
			if (act_track == userdata.track) {
				/* currently only single curve can be selected (selected curve represents active track) */
				act_track = NULL;
			}
		}
		else if (act_track != userdata.track) {
			SelectUserData selectdata = {SEL_DESELECT};
			MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);

			tracking->act_track = userdata.track;
			if ((sc->flag & SC_SHOW_GRAPH_SEL_ONLY) == 0) {
				ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
				BKE_tracking_track_select(tracksbase, userdata.track, TRACK_AREA_ALL, false);
			}

			/* deselect all knots on newly selected curve */
			clip_graph_tracking_iterate(sc,
			                            (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
			                            (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
			                            &selectdata, toggle_selection_cb);
		}

		return true;
	}

	return false;
}
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);
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
	MovieTrackingTrack *track = NULL;   /* selected marker */

	track = find_nearest_track(sc, tracksbase, co);

	if (track) {
		int area = track_mouse_area(C, co, track);

		if (!extend || !TRACK_VIEW_SELECTED(sc, track))
			area = TRACK_AREA_ALL;

		if (extend && TRACK_AREA_SELECTED(track, area)) {
			if (track == act_track)
				BKE_tracking_track_deselect(track, area);
			else
				clip->tracking.act_track = track;
		}
		else {
			if (area == TRACK_AREA_POINT)
				area = TRACK_AREA_ALL;

			BKE_tracking_track_select(tracksbase, track, area, extend);
			clip->tracking.act_track = track;
		}
	}

	if (!extend) {
		sc->xlockof = 0.0f;
		sc->ylockof = 0.0f;
	}

	BKE_tracking_dopesheet_tag_update(tracking);

	WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);

	return OPERATOR_FINISHED;
}
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;
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);

	if (act_track) {
		int a = 0;

		while (a < act_track->markersnr) {
			MovieTrackingMarker *marker = &act_track->markers[a];

			if (marker->flag & MARKER_GRAPH_SEL)
				clip_delete_marker(C, clip, act_track, marker);
			else
				a++;
		}
	}

	return OPERATOR_FINISHED;
}
static void draw_tracks_motion_curves(View2D *v2d, SpaceClip *sc)
{
	MovieClip *clip = ED_space_clip_get_clip(sc);
	MovieTracking *tracking = &clip->tracking;
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
	int width, height;
	TrackMotionCurveUserData userdata;

	BKE_movieclip_get_size(clip, &sc->user, &width, &height);

	if (!width || !height)
		return;

	/* non-selected knot handles */
	userdata.hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE);
	userdata.sel = false;
	userdata.act_track = act_track;
	UI_view2d_scale_get(v2d, &userdata.xscale, &userdata.yscale);
	clip_graph_tracking_values_iterate(sc,
	                                   (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
	                                   (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
	                                   &userdata, tracking_segment_knot_cb, NULL, NULL);

	/* draw graph lines */
	glEnable(GL_BLEND);
	clip_graph_tracking_values_iterate(sc,
	                                   (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
	                                   (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
	                                   act_track, tracking_segment_point_cb, tracking_segment_start_cb,
	                                   tracking_segment_end_cb);
	glDisable(GL_BLEND);

	/* selected knot handles on top of curves */
	userdata.sel = true;
	clip_graph_tracking_values_iterate(sc,
	                                   (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
	                                   (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
	                                   &userdata, tracking_segment_knot_cb, NULL, NULL);
}
static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Scene *scene)
{
	float x;
	int *points, totseg, i, a;
	float sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1);
	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);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	/* cache background */
	ED_region_cache_draw_background(ar);

	/* cached segments -- could be usefu lto debug caching strategies */
	BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points);
	ED_region_cache_draw_cached_segments(ar, totseg, points, sfra, efra);

	/* 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;
			int markersnr = generic_track_get_markersnr(act_track, act_plane_track);

			while (a < markersnr) {
				int marker_framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a);

				if (marker_framenr >= i)
					break;

				if (a < markersnr - 1 && generic_track_get_marker_framenr(act_track, act_plane_track, a + 1) > i)
					break;

				a++;
			}

			a = min_ii(a, markersnr - 1);

			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 (generic_track_is_marker_keyframed(act_track, act_plane_track, a))
					glColor4ub(255, 255, 0, 196);
				else
					glColor4ub(255, 255, 0, 96);

				glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 4 * UI_DPI_FAC);
			}
		}
	}

	/* failed frames */
	if (reconstruction->flag & TRACKING_RECONSTRUCTED) {
		int n = reconstruction->camnr;
		MovieReconstructedCamera *cameras = reconstruction->cameras;

		glColor4ub(255, 0, 0, 96);

		for (i = sfra, a = 0; i <= efra; i++) {
			bool ok = false;

			while (a < n) {
				if (cameras[a].framenr == i) {
					ok = true;
					break;
				}
				else if (cameras[a].framenr > i) {
					break;
				}

				a++;
			}

			if (!ok)
				glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 8 * UI_DPI_FAC);
		}
	}

	glDisable(GL_BLEND);

	/* current frame */
	x = (sc->user.framenr - sfra) / (efra - sfra + 1) * ar->winx;

	UI_ThemeColor(TH_CFRAME);
	glRecti(x, 0, x + ceilf(framelen), 8 * UI_DPI_FAC);

	ED_region_cache_draw_curfra_label(sc->user.framenr, x, 8.0f * UI_DPI_FAC);

	/* solver keyframes */
	glColor4ub(175, 255, 0, 255);
	draw_keyframe(act_object->keyframe1 + clip->start_frame - 1, CFRA, sfra, framelen, 2);
	draw_keyframe(act_object->keyframe2 + clip->start_frame - 1, CFRA, sfra, framelen, 2);

	/* movie clip animation */
	if ((sc->mode == SC_MODE_MASKEDIT) && sc->mask_info.mask) {
		ED_mask_draw_frames(sc->mask_info.mask, ar, CFRA, sfra, efra);
	}
}
static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
                            int width, int height, float zoomx, float zoomy)
{
	float x, y;
	const int n = 10;
	int i, j, a;
	float pos[2], tpos[2], grid[11][11][2];
	MovieTracking *tracking = &clip->tracking;
	bGPdata *gpd = NULL;
	float aspy = 1.0f / tracking->camera.pixel_aspect;
	float dx = (float)width / n, dy = (float)height / n * aspy;
	float offsx = 0.0f, offsy = 0.0f;

	if (!tracking->camera.focal)
		return;

	if ((sc->flag & SC_SHOW_GRID) == 0 && (sc->flag & SC_MANUAL_CALIBRATION) == 0)
		return;

	UI_view2d_view_to_region_fl(&ar->v2d, 0.0f, 0.0f, &x, &y);

	glPushMatrix();
	glTranslatef(x, y, 0);
	glScalef(zoomx, zoomy, 0);
	glMultMatrixf(sc->stabmat);
	glScalef(width, height, 0);

	/* grid */
	if (sc->flag & SC_SHOW_GRID) {
		float val[4][2], idx[4][2];
		float min[2], max[2];

		for (a = 0; a < 4; a++) {
			if (a < 2)
				val[a][a % 2] = FLT_MAX;
			else
				val[a][a % 2] = -FLT_MAX;
		}

		zero_v2(pos);
		for (i = 0; i <= n; i++) {
			for (j = 0; j <= n; j++) {
				if (i == 0 || j == 0 || i == n || j == n) {
					BKE_tracking_distort_v2(tracking, pos, tpos);

					for (a = 0; a < 4; a++) {
						int ok;

						if (a < 2)
							ok = tpos[a % 2] < val[a][a % 2];
						else
							ok = tpos[a % 2] > val[a][a % 2];

						if (ok) {
							copy_v2_v2(val[a], tpos);
							idx[a][0] = j;
							idx[a][1] = i;
						}
					}
				}

				pos[0] += dx;
			}

			pos[0] = 0.0f;
			pos[1] += dy;
		}

		INIT_MINMAX2(min, max);

		for (a = 0; a < 4; a++) {
			pos[0] = idx[a][0] * dx;
			pos[1] = idx[a][1] * dy;

			BKE_tracking_undistort_v2(tracking, pos, tpos);

			minmax_v2v2_v2(min, max, tpos);
		}

		copy_v2_v2(pos, min);
		dx = (max[0] - min[0]) / n;
		dy = (max[1] - min[1]) / n;

		for (i = 0; i <= n; i++) {
			for (j = 0; j <= n; j++) {
				BKE_tracking_distort_v2(tracking, pos, grid[i][j]);

				grid[i][j][0] /= width;
				grid[i][j][1] /= height * aspy;

				pos[0] += dx;
			}

			pos[0] = min[0];
			pos[1] += dy;
		}

		glColor3f(1.0f, 0.0f, 0.0f);

		for (i = 0; i <= n; i++) {
			glBegin(GL_LINE_STRIP);
			for (j = 0; j <= n; j++) {
				glVertex2fv(grid[i][j]);
			}
			glEnd();
		}

		for (j = 0; j <= n; j++) {
			glBegin(GL_LINE_STRIP);
			for (i = 0; i <= n; i++) {
				glVertex2fv(grid[i][j]);
			}
			glEnd();
		}
	}

	if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
		MovieTrackingTrack *track = BKE_tracking_track_get_active(&sc->clip->tracking);

		if (track) {
			int framenr = ED_space_clip_get_clip_frame_number(sc);
			MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);

			offsx = marker->pos[0];
			offsy = marker->pos[1];

			gpd = track->gpd;
		}

	}
	else {
		gpd = clip->gpd;
	}

	if (sc->flag & SC_MANUAL_CALIBRATION && gpd) {
		bGPDlayer *layer = gpd->layers.first;

		while (layer) {
			bGPDframe *frame = layer->frames.first;

			if (layer->flag & GP_LAYER_HIDE) {
				layer = layer->next;
				continue;
			}

			glColor4fv(layer->color);
			glLineWidth(layer->thickness);
			glPointSize((float)(layer->thickness + 2));

			while (frame) {
				bGPDstroke *stroke = frame->strokes.first;

				while (stroke) {
					if (stroke->flag & GP_STROKE_2DSPACE) {
						if (stroke->totpoints > 1) {
							glBegin(GL_LINE_STRIP);
							for (i = 0; i < stroke->totpoints - 1; i++) {
								float npos[2], dpos[2], len;
								int steps;

								pos[0] = (stroke->points[i].x + offsx) * width;
								pos[1] = (stroke->points[i].y + offsy) * height * aspy;

								npos[0] = (stroke->points[i + 1].x + offsx) * width;
								npos[1] = (stroke->points[i + 1].y + offsy) * height * aspy;

								len = len_v2v2(pos, npos);
								steps = ceil(len / 5.0f);

								/* we want to distort only long straight lines */
								if (stroke->totpoints == 2) {
									BKE_tracking_undistort_v2(tracking, pos, pos);
									BKE_tracking_undistort_v2(tracking, npos, npos);
								}

								sub_v2_v2v2(dpos, npos, pos);
								mul_v2_fl(dpos, 1.0f / steps);

								for (j = 0; j <= steps; j++) {
									BKE_tracking_distort_v2(tracking, pos, tpos);
									glVertex2f(tpos[0] / width, tpos[1] / (height * aspy));

									add_v2_v2(pos, dpos);
								}
							}
							glEnd();
						}
						else if (stroke->totpoints == 1) {
							glBegin(GL_POINTS);
							glVertex2f(stroke->points[0].x + offsx, stroke->points[0].y + offsy);
							glEnd();
						}
					}

					stroke = stroke->next;
				}

				frame = frame->next;
			}

			layer = layer->next;
		}

		glLineWidth(1.0f);
		glPointSize(1.0f);
	}

	glPopMatrix();
}
/* Draw all kind of tracks. */
static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, 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;
	float *marker_pos = NULL, *fp, *active_pos = NULL, cur_pos[2];

	/* ** find window pixel coordinates of origin ** */

	/* UI_view2d_view_to_region_no_clip return integer values, this could
	 * lead to 1px flickering when view is locked to selection during playbeck.
	 * to avoid this flickering, calculate base point in the same way as it happens
	 * in UI_view2d_view_to_region_no_clip, but do it in floats here */

	UI_view2d_view_to_region_fl(&ar->v2d, 0.0f, 0.0f, &x, &y);

	glPushMatrix();
	glTranslatef(x, y, 0);

	glPushMatrix();
	glScalef(zoomx, zoomy, 0);
	glMultMatrixf(sc->stabmat);
	glScalef(width, height, 0);

	act_track = BKE_tracking_track_get_active(tracking);

	/* 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)
	{
		if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) {
			draw_plane_track(sc, scene, plane_track, framenr, plane_track == active_plane_track, width, height);
		}
	}

	if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
		int count = 0;

		/* count */
		track = tracksbase->first;
		while (track) {
			if ((track->flag & TRACK_HIDDEN) == 0) {
				marker = BKE_tracking_marker_get(track, framenr);

				if (MARKER_VISIBLE(sc, track, marker))
					count++;
			}

			track = track->next;
		}

		/* undistort */
		if (count) {
			marker_pos = MEM_callocN(2 * sizeof(float) * count, "draw_tracking_tracks marker_pos");

			track = tracksbase->first;
			fp = marker_pos;
			while (track) {
				if ((track->flag & TRACK_HIDDEN) == 0) {
					marker = BKE_tracking_marker_get(track, framenr);

					if (MARKER_VISIBLE(sc, track, marker)) {
						ED_clip_point_undistorted_pos(sc, marker->pos, fp);

						if (track == act_track)
							active_pos = fp;

						fp += 2;
					}
				}

				track = track->next;
			}
		}
	}

	if (sc->flag & SC_SHOW_TRACK_PATH) {
		track = tracksbase->first;
		while (track) {
			if ((track->flag & TRACK_HIDDEN) == 0)
				draw_track_path(sc, clip, track);

			track = track->next;
		}
	}

	/* markers outline and non-selected areas */
	track = tracksbase->first;
	fp = marker_pos;
	while (track) {
		if ((track->flag & TRACK_HIDDEN) == 0) {
			marker = BKE_tracking_marker_get(track, framenr);

			if (MARKER_VISIBLE(sc, track, marker)) {
				copy_v2_v2(cur_pos, fp ? fp : marker->pos);

				draw_marker_outline(sc, track, marker, cur_pos, width, height);
				draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 0);
				draw_marker_slide_zones(sc, track, marker, cur_pos, 1, 0, 0, width, height);
				draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 0, 0, width, height);

				if (fp)
					fp += 2;
			}
		}

		track = track->next;
	}

	/* selected areas only, so selection wouldn't be overlapped by
	 * non-selected areas */
	track = tracksbase->first;
	fp = marker_pos;
	while (track) {
		if ((track->flag & TRACK_HIDDEN) == 0) {
			int act = track == act_track;
			marker = BKE_tracking_marker_get(track, framenr);

			if (MARKER_VISIBLE(sc, track, marker)) {
				if (!act) {
					copy_v2_v2(cur_pos, fp ? fp : marker->pos);

					draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 1);
					draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 1, 0, width, height);
				}

				if (fp)
					fp += 2;
			}
		}

		track = track->next;
	}

	/* active marker would be displayed on top of everything else */
	if (act_track) {
		if ((act_track->flag & TRACK_HIDDEN) == 0) {
			marker = BKE_tracking_marker_get(act_track, framenr);

			if (MARKER_VISIBLE(sc, act_track, marker)) {
				copy_v2_v2(cur_pos, active_pos ? active_pos : marker->pos);

				draw_marker_areas(sc, act_track, marker, cur_pos, width, height, 1, 1);
				draw_marker_slide_zones(sc, act_track, marker, cur_pos, 0, 1, 1, width, height);
			}
		}
	}

	if (sc->flag & SC_SHOW_BUNDLES) {
		MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
		float pos[4], vec[4], mat[4][4], aspy;

		glEnable(GL_POINT_SMOOTH);
		glPointSize(3.0f);

		aspy = 1.0f / clip->tracking.camera.pixel_aspect;
		BKE_tracking_get_projection_matrix(tracking, object, framenr, width, height, mat);

		track = tracksbase->first;
		while (track) {
			if ((track->flag & TRACK_HIDDEN) == 0 && track->flag & TRACK_HAS_BUNDLE) {
				marker = BKE_tracking_marker_get(track, framenr);

				if (MARKER_VISIBLE(sc, track, marker)) {
					float npos[2];
					copy_v3_v3(vec, track->bundle_pos);
					vec[3] = 1;

					mul_v4_m4v4(pos, mat, vec);

					pos[0] = (pos[0] / (pos[3] * 2.0f) + 0.5f) * width;
					pos[1] = (pos[1] / (pos[3] * 2.0f) + 0.5f) * height * aspy;

					BKE_tracking_distort_v2(tracking, pos, npos);

					if (npos[0] >= 0.0f && npos[1] >= 0.0f && npos[0] <= width && npos[1] <= height * aspy) {
						vec[0] = (marker->pos[0] + track->offset[0]) * width;
						vec[1] = (marker->pos[1] + track->offset[1]) * height * aspy;

						sub_v2_v2(vec, npos);

						if (len_squared_v2(vec) < (3.0f * 3.0f))
							glColor3f(0.0f, 1.0f, 0.0f);
						else
							glColor3f(1.0f, 0.0f, 0.0f);

						glBegin(GL_POINTS);
						if (undistort)
							glVertex3f(pos[0] / width, pos[1] / (height * aspy), 0);
						else
							glVertex3f(npos[0] / width, npos[1] / (height * aspy), 0);
						glEnd();
					}
				}
			}

			track = track->next;
		}

		glPointSize(1.0f);
		glDisable(GL_POINT_SMOOTH);
	}

	glPopMatrix();

	if (sc->flag & SC_SHOW_NAMES) {
		/* scaling should be cleared before drawing texts, otherwise font would also be scaled */
		track = tracksbase->first;
		fp = marker_pos;
		while (track) {
			if ((track->flag & TRACK_HIDDEN) == 0) {
				marker = BKE_tracking_marker_get(track, framenr);

				if (MARKER_VISIBLE(sc, track, marker)) {
					int act = track == act_track;

					copy_v2_v2(cur_pos, fp ? fp : marker->pos);

					draw_marker_texts(sc, track, marker, cur_pos, act, width, height, zoomx, zoomy);

					if (fp)
						fp += 2;
				}
			}

			track = track->next;
		}
	}

	glPopMatrix();

	if (marker_pos)
		MEM_freeN(marker_pos);
}
static int select_groped_exec(bContext *C, wmOperator *op)
{
	SpaceClip *sc = CTX_wm_space_clip(C);
	MovieClip *clip = ED_space_clip_get_clip(sc);
	MovieTrackingTrack *track;
	MovieTrackingMarker *marker;
	MovieTracking *tracking = &clip->tracking;
	ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
	int group = RNA_enum_get(op->ptr, "group");
	int framenr = ED_space_clip_get_clip_frame_number(sc);

	track = tracksbase->first;
	while (track) {
		bool ok = false;

		marker = BKE_tracking_marker_get(track, framenr);

		if (group == 0) { /* Keyframed */
			ok = marker->framenr == framenr && (marker->flag & MARKER_TRACKED) == 0;
		}
		else if (group == 1) { /* Estimated */
			ok = marker->framenr != framenr;
		}
		else if (group == 2) { /* tracked */
			ok = marker->framenr == framenr && (marker->flag & MARKER_TRACKED);
		}
		else if (group == 3) { /* locked */
			ok = track->flag & TRACK_LOCKED;
		}
		else if (group == 4) { /* disabled */
			ok = marker->flag & MARKER_DISABLED;
		}
		else if (group == 5) { /* color */
			MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);

			if (act_track) {
				ok = (track->flag & TRACK_CUSTOMCOLOR) == (act_track->flag & TRACK_CUSTOMCOLOR);

				if (ok && track->flag & TRACK_CUSTOMCOLOR)
					ok = equals_v3v3(track->color, act_track->color);
			}
		}
		else if (group == 6) { /* failed */
			ok = (track->flag & TRACK_HAS_BUNDLE) == 0;
		}

		if (ok) {
			track->flag |= SELECT;
			if (sc->flag & SC_SHOW_MARKER_PATTERN)
				track->pat_flag |= SELECT;
			if (sc->flag & SC_SHOW_MARKER_SEARCH)
				track->search_flag |= SELECT;
		}

		track = track->next;
	}

	BKE_tracking_dopesheet_tag_update(tracking);

	WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);

	return OPERATOR_FINISHED;
}
Exemple #17
0
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);
	bool has_bundle = false, update_stab = false;
	char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];

	if (track == act_track)
		tracking->act_track = NULL;

	if (track == stab->rot_track) {
		stab->rot_track = NULL;

		update_stab = true;
	}

	/* handle reconstruction display in 3d viewport */
	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 - 1),
			                               "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);
		}
	}

	/* Delete f-curves associated with the track (such as weight, i.e.) */
	BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped));
	BLI_snprintf(prefix, sizeof(prefix), "tracks[\"%s\"]", track_name_escaped);
	BKE_animdata_fix_paths_remove(&clip->id, prefix);

	BKE_tracking_track_free(track);
	BLI_freelinkN(tracksbase, track);

	WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);

	if (update_stab) {
		tracking->stabilization.ok = false;
		WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
	}

	DAG_id_tag_update(&clip->id, 0);

	if (has_bundle)
		WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
Exemple #18
0
static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Scene *scene)
{
	float x;
	int *points, totseg, i, a;
	float sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1);
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking);
	MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(&clip->tracking);

	glEnable(GL_BLEND);

	/* cache background */
	glColor4ub(128, 128, 255, 64);
	glRecti(0, 0, ar->winx, 8);

	/* cached segments -- could be usefu lto debug caching strategies */
	BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points);
	if (totseg) {
		glColor4ub(128, 128, 255, 128);

		for (a = 0; a < totseg; a++) {
			float x1, x2;

			x1 = (points[a * 2] - sfra) / (efra - sfra + 1) * ar->winx;
			x2 = (points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * ar->winx;

			glRecti(x1, 0, x2, 8);
		}
	}

	/* track */
	if (act_track) {
		MovieTrackingTrack *track = act_track;

		for (i = sfra - clip->start_frame + 1, a = 0; i <= efra - clip->start_frame + 1; i++) {
			int framenr;
			MovieTrackingMarker *marker;

			while (a < track->markersnr) {
				if (track->markers[a].framenr >= i)
					break;

				if (a < track->markersnr - 1 && track->markers[a + 1].framenr > 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 (framenr != i)
					glColor4ub(128, 128, 0, 96);
				else if ((marker->flag & MARKER_TRACKED) == 0)
					glColor4ub(255, 255, 0, 196);
				else
					glColor4ub(255, 255, 0, 96);

				glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 4);
			}
		}
	}

	/* failed frames */
	if (reconstruction->flag & TRACKING_RECONSTRUCTED) {
		int n = reconstruction->camnr;
		MovieReconstructedCamera *cameras = reconstruction->cameras;

		glColor4ub(255, 0, 0, 96);

		for (i = sfra, a = 0; i <= efra; i++) {
			int ok = FALSE;

			while (a < n) {
				if (cameras[a].framenr == i) {
					ok = TRUE;
					break;
				}
				else if (cameras[a].framenr > i) {
					break;
				}

				a++;
			}

			if (!ok)
				glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 8);
		}
	}

	glDisable(GL_BLEND);

	/* current frame */
	x = (sc->user.framenr - sfra) / (efra - sfra + 1) * ar->winx;

	UI_ThemeColor(TH_CFRAME);
	glRecti(x, 0, x + framelen, 8);

	clip_draw_curfra_label(sc, x, 8.0f);

	/* movie clip animation */
	if ((sc->mode == SC_MODE_MASKEDIT) && sc->mask_info.mask) {
		MaskLayer *masklay = BKE_mask_layer_active(sc->mask_info.mask);
		if (masklay) {
			MaskLayerShape *masklay_shape;

			glColor4ub(255, 175, 0, 255);
			glBegin(GL_LINES);

			for (masklay_shape = masklay->splines_shapes.first;
			     masklay_shape;
			     masklay_shape = masklay_shape->next)
			{
				i = masklay_shape->frame;

				/* glRecti((i - sfra) * framelen, 0, (i - sfra + 1) * framelen, 4); */

				/* use a line so we always see the keyframes */
				glVertex2i((i - sfra) * framelen, 0);
				glVertex2i((i - sfra) * framelen, (i == CFRA) ? 22 : 10);
			}

			glEnd();
		}
	}
}
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;
	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;
		}
	}

	if (!extend) {
		delect_all_plane_tracks(plane_tracks_base);
	}

	if (track) {
		int area = track_mouse_area(C, co, track);

		if (!extend || !TRACK_VIEW_SELECTED(sc, track))
			area = TRACK_AREA_ALL;

		if (extend && TRACK_AREA_SELECTED(track, area)) {
			if (track == act_track) {
				BKE_tracking_track_deselect(track, area);
			}
			else {
				clip->tracking.act_track = track;
				clip->tracking.act_plane_track = NULL;
			}
		}
		else {
			if (area == TRACK_AREA_POINT)
				area = TRACK_AREA_ALL;

			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_VIEW_SELECTED(plane_track)) {
			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) {
		sc->xlockof = 0.0f;
		sc->ylockof = 0.0f;
	}

	BKE_tracking_dopesheet_tag_update(tracking);

	WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);

	return OPERATOR_FINISHED;
}
Exemple #20
0
void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClipScopes *scopes)
{
	if (scopes->ok)
		return;

	if (scopes->track_preview) {
		IMB_freeImBuf(scopes->track_preview);
		scopes->track_preview = NULL;
	}

	if (scopes->track_search) {
		IMB_freeImBuf(scopes->track_search);
		scopes->track_search = NULL;
	}

	scopes->marker = NULL;
	scopes->track = NULL;
	scopes->track_locked = true;

	if (clip) {
		MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking);

		if (act_track) {
			MovieTrackingTrack *track = act_track;
			int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
			MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);

			scopes->marker = marker;
			scopes->track = track;

			if (marker->flag & MARKER_DISABLED) {
				scopes->track_disabled = true;
			}
			else {
				ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user);

				scopes->track_disabled = false;

				if (ibuf && (ibuf->rect || ibuf->rect_float)) {
					MovieTrackingMarker undist_marker = *marker;

					if (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
						int width, height;
						float aspy = 1.0f / clip->tracking.camera.pixel_aspect;

						BKE_movieclip_get_size(clip, user, &width, &height);

						undist_marker.pos[0] *= width;
						undist_marker.pos[1] *= height * aspy;

						BKE_tracking_undistort_v2(&clip->tracking, undist_marker.pos, undist_marker.pos);

						undist_marker.pos[0] /= width;
						undist_marker.pos[1] /= height * aspy;
					}

					scopes->track_search = BKE_tracking_get_search_imbuf(ibuf, track, &undist_marker, true, true);

					scopes->undist_marker = undist_marker;

					scopes->frame_width = ibuf->x;
					scopes->frame_height = ibuf->y;

					scopes->use_track_mask = track->flag & TRACK_PREVIEW_ALPHA;
				}

				IMB_freeImBuf(ibuf);
			}

			if ((track->flag & TRACK_LOCKED) == 0) {
				float pat_min[2], pat_max[2];

				scopes->track_locked = false;

				/* XXX: would work fine with non-transformed patterns, but would likely fail
				 *      with transformed patterns, but that would be easier to debug when
				 *      we'll have real pattern sampling (at least to test) */
				BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);

				scopes->slide_scale[0] = pat_max[0] - pat_min[0];
				scopes->slide_scale[1] = pat_max[1] - pat_min[1];
			}
		}
	}

	scopes->framenr = user->framenr;
	scopes->ok = true;
}
static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
{
	Mask *mask = CTX_data_edit_mask(C);
	MaskLayer *masklay;

	/* parent info */
	SpaceClip *sc = CTX_wm_space_clip(C);
	MovieClip *clip = ED_space_clip_get_clip(sc);
	MovieTracking *tracking;
	MovieTrackingTrack *track;
	MovieTrackingPlaneTrack *plane_track;
	MovieTrackingObject *tracking_object;
	/* done */

	int framenr, parent_type;
	float parmask_pos[2], orig_corners[4][2];
	char *sub_parent_name;

	if (ELEM(NULL, sc, clip)) {
		return OPERATOR_CANCELLED;
	}

	framenr = ED_space_clip_get_clip_frame_number(sc);

	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);

		sub_parent_name = track->name;
		parent_type = MASK_PARENT_POINT_TRACK;
		memset(orig_corners, 0, sizeof(orig_corners));
	}
	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;
		int i;

		if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
			continue;
		}

		for (spline = masklay->splines.first; spline; spline = spline->next) {
			for (i = 0; i < spline->tot_point; i++) {
				MaskSplinePoint *point = &spline->points[i];

				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, 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));
				}
			}
		}
	}

	WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
	DAG_id_tag_update(&mask->id, 0);

	return OPERATOR_FINISHED;
}
static int set_plane_exec(bContext *C, wmOperator *op)
{
  SpaceClip *sc = CTX_wm_space_clip(C);
  MovieClip *clip = ED_space_clip_get_clip(sc);
  Scene *scene = CTX_data_scene(C);
  MovieTracking *tracking = &clip->tracking;
  MovieTrackingObject *tracking_object;
  MovieTrackingTrack *track, *axis_track = NULL, *act_track;
  ListBase *tracksbase;
  Object *object;
  Object *camera = get_camera_with_movieclip(scene, clip);
  Depsgraph *depsgraph = CTX_data_depsgraph(C);
  int tot = 0;
  float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
  int plane = RNA_enum_get(op->ptr, "plane");
  float rot[4][4] = {
      {0.0f, 0.0f, -1.0f, 0.0f},
      {0.0f, 1.0f, 0.0f, 0.0f},
      {1.0f, 0.0f, 0.0f, 0.0f},
      {0.0f, 0.0f, 0.0f, 1.0f},
  }; /* 90 degrees Y-axis rotation matrix */

  if (count_selected_bundles(C) != 3) {
    BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");

    return OPERATOR_CANCELLED;
  }

  tracking_object = BKE_tracking_object_get_active(tracking);
  tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
  act_track = BKE_tracking_track_get_active(tracking);

  object = get_orientation_object(C);
  if (object == NULL) {
    BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
    return OPERATOR_CANCELLED;
  }

  BKE_tracking_get_camera_object_matrix(scene, camera, mat);

  /* Get 3 bundles to use as reference. */
  track = tracksbase->first;
  while (track && tot < 3) {
    if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
      mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
      if (tot == 0 || track == act_track) {
        copy_v3_v3(orig, vec[tot]);
      }
      else {
        axis_track = track;
      }
      tot++;
    }
    track = track->next;
  }

  sub_v3_v3(vec[1], vec[0]);
  sub_v3_v3(vec[2], vec[0]);

  /* Construct ortho-normal basis. */
  unit_m4(mat);
  if (plane == 0) { /* floor */
    cross_v3_v3v3(mat[0], vec[1], vec[2]);
    copy_v3_v3(mat[1], vec[1]);
    cross_v3_v3v3(mat[2], mat[0], mat[1]);
  }
  else if (plane == 1) { /* wall */
    cross_v3_v3v3(mat[2], vec[1], vec[2]);
    copy_v3_v3(mat[1], vec[1]);
    cross_v3_v3v3(mat[0], mat[1], mat[2]);
  }

  normalize_v3(mat[0]);
  normalize_v3(mat[1]);
  normalize_v3(mat[2]);

  /* Move to origin point. */
  mat[3][0] = orig[0];
  mat[3][1] = orig[1];
  mat[3][2] = orig[2];

  if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
    invert_m4(mat);

    BKE_object_to_mat4(object, obmat);
    mul_m4_m4m4(mat, mat, obmat);
    mul_m4_m4m4(newmat, rot, mat);
    BKE_object_apply_mat4(object, newmat, 0, 0);

    /* Make camera have positive z-coordinate. */
    if (object->loc[2] < 0) {
      invert_m4(rot);
      mul_m4_m4m4(newmat, rot, mat);
      BKE_object_apply_mat4(object, newmat, 0, 0);
    }
  }
  else {
    BKE_object_apply_mat4(object, mat, 0, 0);
  }

  BKE_object_where_is_calc(depsgraph, scene, object);
  set_axis(scene, object, clip, tracking_object, axis_track, 'X');

  DEG_id_tag_update(&clip->id, 0);
  DEG_id_tag_update(&object->id, ID_RECALC_TRANSFORM);

  WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
  WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);

  return OPERATOR_FINISHED;
}