示例#1
0
static void rna_Mask_update_parent(Main *bmain, Scene *scene, PointerRNA *ptr)
{
	MaskParent *parent = ptr->data;

	if (parent->id) {
		if (GS(parent->id->name) == ID_MC) {
			MovieClip *clip = (MovieClip *) parent->id;
			MovieTracking *tracking = &clip->tracking;
			MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, parent->parent);

			if (object) {
				MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, object, parent->sub_parent);

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

					BKE_movieclip_user_set_frame(&user, scene->r.cfra);

					add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset);

					BKE_mask_coord_from_movieclip(clip, &user, parmask_pos, marker_pos_ofs);

					copy_v2_v2(parent->parent_orig, parmask_pos);
				}
			}
		}
	}

	rna_Mask_update_data(bmain, scene, ptr);
}
示例#2
0
static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather_points)[2], float (*diff_points)[2],
                                                            const unsigned int tot_diff_point, const float ofs,
                                                            const bool do_test)
{
	unsigned int k_prev = tot_diff_point - 2;
	unsigned int k_curr = tot_diff_point - 1;
	unsigned int k_next = 0;

	unsigned int k;

	float d_prev[2];
	float d_next[2];
	float d[2];

	const float *co_prev;
	const float *co_curr;
	const float *co_next;

	const float ofs_squared = ofs * ofs;

	co_prev = diff_points[k_prev];
	co_curr = diff_points[k_curr];
	co_next = diff_points[k_next];

	/* precalc */
	sub_v2_v2v2(d_prev, co_prev, co_curr);
	normalize_v2(d_prev);

	for (k = 0; k < tot_diff_point; k++) {

		/* co_prev = diff_points[k_prev]; */ /* precalc */
		co_curr = diff_points[k_curr];
		co_next = diff_points[k_next];

		/* sub_v2_v2v2(d_prev, co_prev, co_curr); */ /* precalc */
		sub_v2_v2v2(d_next, co_curr, co_next);

		/* normalize_v2(d_prev); */ /* precalc */
		normalize_v2(d_next);

		if ((do_test == FALSE) ||
		    (len_squared_v2v2(diff_feather_points[k], diff_points[k]) < ofs_squared))
		{

			add_v2_v2v2(d, d_prev, d_next);

			normalize_v2(d);

			diff_feather_points[k][0] = diff_points[k][0] + ( d[1] * ofs);
			diff_feather_points[k][1] = diff_points[k][1] + (-d[0] * ofs);
		}

		/* use next iter */
		copy_v2_v2(d_prev, d_next);

		/* k_prev = k_curr; */ /* precalc */
		k_curr = k_next;
		k_next++;
	}
}
示例#3
0
static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
	PointSlideData *psd = op->customdata;

	if (event->type == psd->event && event->val == KM_RELEASE) {
		MEM_freeN(psd);
		ED_paintcurve_undo_push_begin(op->type->name);
		ED_paintcurve_undo_push_end();
		return OPERATOR_FINISHED;
	}

	switch (event->type) {
		case MOUSEMOVE:
		{
			ARegion *ar = CTX_wm_region(C);
			wmWindow *window = CTX_wm_window(C);
			float diff[2] = {
				event->mval[0] - psd->initial_loc[0],
				event->mval[1] - psd->initial_loc[1]};
			if (psd->select == 1) {
				int i;
				for (i = 0; i < 3; i++)
					add_v2_v2v2(psd->pcp->bez.vec[i], diff, psd->point_initial_loc[i]);
			}
			else {
				add_v2_v2(diff, psd->point_initial_loc[psd->select]);
				copy_v2_v2(psd->pcp->bez.vec[psd->select], diff);

				if (psd->align) {
					char opposite = (psd->select == 0) ? 2 : 0;
					sub_v2_v2v2(diff, psd->pcp->bez.vec[1], psd->pcp->bez.vec[psd->select]);
					add_v2_v2v2(psd->pcp->bez.vec[opposite], psd->pcp->bez.vec[1], diff);
				}
			}
			WM_paint_cursor_tag_redraw(window, ar);
			break;
		}
		default:
			break;
	}

	return OPERATOR_RUNNING_MODAL;
}
/**
 * equivalent to ``shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)``
 */
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2])
{
	float angle_cos;
	float ab[2];
	BLI_ASSERT_UNIT_V2(a);
	BLI_ASSERT_UNIT_V2(b);
	add_v2_v2v2(ab, a, b);
	angle_cos = (normalize_v2(ab) != 0.0f) ? fabsf(dot_v2v2(a, ab)) : 0.0f;
	return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
}
示例#5
0
static void stencil_control_calculate(StencilControlData *scd, const int mval[2])
{
#define PIXEL_MARGIN 5

	float mdiff[2];
	float mvalf[2] = {mval[0], mval[1]};
	switch (scd->mode) {
		case STENCIL_TRANSLATE:
			sub_v2_v2v2(mdiff, mvalf, scd->init_mouse);
			add_v2_v2v2(scd->pos_target, scd->init_spos,
			            mdiff);
			CLAMP(scd->pos_target[0],
			      -scd->dim_target[0] + PIXEL_MARGIN,
			      scd->area_size[0] + scd->dim_target[0] - PIXEL_MARGIN);

			CLAMP(scd->pos_target[1],
			      -scd->dim_target[1] + PIXEL_MARGIN,
			      scd->area_size[1] + scd->dim_target[1] - PIXEL_MARGIN);

			break;
		case STENCIL_SCALE:
		{
			float len, factor;
			sub_v2_v2v2(mdiff, mvalf, scd->pos_target);
			len = len_v2(mdiff);
			factor = len / scd->lenorig;
			copy_v2_v2(mdiff, scd->init_sdim);
			if (scd->constrain_mode != STENCIL_CONSTRAINT_Y)
				mdiff[0] = factor * scd->init_sdim[0];
			if (scd->constrain_mode != STENCIL_CONSTRAINT_X)
				mdiff[1] = factor * scd->init_sdim[1];
			CLAMP(mdiff[0], 5.0f, 10000.0f);
			CLAMP(mdiff[1], 5.0f, 10000.0f);
			copy_v2_v2(scd->dim_target, mdiff);
			break;
		}
		case STENCIL_ROTATE:
		{
			float angle;
			sub_v2_v2v2(mdiff, mvalf, scd->pos_target);
			angle = atan2(mdiff[1], mdiff[0]);
			angle = scd->init_rot + angle - scd->init_angle;
			if (angle < 0.0f)
				angle += (float)(2 * M_PI);
			if (angle > (float)(2 * M_PI))
				angle -= (float)(2 * M_PI);
			*scd->rot_target = angle;
			break;
		}
	}
#undef PIXEL_MARGIN
}
static void search_pixel_to_marker_unified(int frame_width, int frame_height,
                                           const MovieTrackingMarker *marker,
                                           const float search_pixel[2], float marker_unified[2])
{
	float frame_unified[2];
	float search_origin_frame_pixel[2];

	tracking_get_search_origin_frame_pixel(frame_width, frame_height, marker, search_origin_frame_pixel);
	add_v2_v2v2(frame_unified, search_pixel, search_origin_frame_pixel);
	pixel_to_unified(frame_width, frame_height, frame_unified, frame_unified);

	/* marker pos is in frame unified */
	sub_v2_v2v2(marker_unified, frame_unified, marker->pos);
}
示例#7
0
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 = 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);
}
示例#8
0
static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
	SlidePointData *data = (SlidePointData *)op->customdata;
	BezTriple *bezt = &data->point->bezt;
	float co[2], dco[2];

	switch (event->type) {
		case LEFTALTKEY:
		case RIGHTALTKEY:
		case LEFTSHIFTKEY:
		case RIGHTSHIFTKEY:
			if (ELEM(event->type, LEFTALTKEY, RIGHTALTKEY)) {
				if (data->action == SLIDE_ACTION_FEATHER)
					data->overall_feather = (event->val == KM_PRESS);
				else
					data->curvature_only = (event->val == KM_PRESS);
			}

			if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
				data->accurate = (event->val == KM_PRESS);

			/* fall-through */  /* update CV position */
		case MOUSEMOVE:
		{
			ScrArea *sa = CTX_wm_area(C);
			ARegion *ar = CTX_wm_region(C);

			ED_mask_mouse_pos(sa, ar, event->mval, co);
			sub_v2_v2v2(dco, co, data->co);

			if (data->action == SLIDE_ACTION_HANDLE) {
				float delta[2], offco[2];

				sub_v2_v2v2(delta, data->handle, data->co);

				sub_v2_v2v2(offco, co, data->co);
				if (data->accurate)
					mul_v2_fl(offco, 0.2f);
				add_v2_v2(offco, data->co);
				add_v2_v2(offco, delta);

				BKE_mask_point_set_handle(data->point, offco, data->curvature_only, data->handle, data->vec);
			}
			else if (data->action == SLIDE_ACTION_POINT) {
				float delta[2];

				copy_v2_v2(delta, dco);
				if (data->accurate)
					mul_v2_fl(delta, 0.2f);

				add_v2_v2v2(bezt->vec[0], data->vec[0], delta);
				add_v2_v2v2(bezt->vec[1], data->vec[1], delta);
				add_v2_v2v2(bezt->vec[2], data->vec[2], delta);
			}
			else if (data->action == SLIDE_ACTION_FEATHER) {
				float vec[2], no[2], p[2], c[2], w, offco[2];
				float *weight = NULL;
				float weight_scalar = 1.0f;
				int overall_feather = data->overall_feather || data->initial_feather;

				add_v2_v2v2(offco, data->feather, dco);

				if (data->uw) {
					/* project on both sides and find the closest one,
					 * prevents flickering when projecting onto both sides can happen */
					const float u_pos = BKE_mask_spline_project_co(data->spline, data->point,
					                                               data->uw->u, offco, MASK_PROJ_NEG);
					const float u_neg = BKE_mask_spline_project_co(data->spline, data->point,
					                                               data->uw->u, offco, MASK_PROJ_POS);
					float dist_pos = FLT_MAX;
					float dist_neg = FLT_MAX;
					float co_pos[2];
					float co_neg[2];
					float u;

					if (u_pos > 0.0f && u_pos < 1.0f) {
						BKE_mask_point_segment_co(data->spline, data->point, u_pos, co_pos);
						dist_pos = len_squared_v2v2(offco, co_pos);
					}

					if (u_neg > 0.0f && u_neg < 1.0f) {
						BKE_mask_point_segment_co(data->spline, data->point, u_neg, co_neg);
						dist_neg = len_squared_v2v2(offco, co_neg);
					}

					u = dist_pos < dist_neg ? u_pos : u_neg;

					if (u > 0.0f && u < 1.0f) {
						data->uw->u = u;

						data->uw = BKE_mask_point_sort_uw(data->point, data->uw);
						weight = &data->uw->w;
						weight_scalar = BKE_mask_point_weight_scalar(data->spline, data->point, u);
						if (weight_scalar != 0.0f) {
							weight_scalar = 1.0f / weight_scalar;
						}

						BKE_mask_point_normal(data->spline, data->point, data->uw->u, no);
						BKE_mask_point_segment_co(data->spline, data->point, data->uw->u, p);
					}
				}
				else {
					weight = &bezt->weight;
					/* weight_scalar = 1.0f; keep as is */
					copy_v2_v2(no, data->no);
					copy_v2_v2(p, bezt->vec[1]);
				}

				if (weight) {
					sub_v2_v2v2(c, offco, p);
					project_v2_v2v2(vec, c, no);

					w = len_v2(vec);

					if (overall_feather) {
						float delta;

						if (dot_v2v2(no, vec) <= 0.0f)
							w = -w;

						delta = w - data->weight * data->weight_scalar;

						if (data->orig_spline == NULL) {
							/* restore weight for currently sliding point, so orig_spline would be created
							 * with original weights used
							 */
							*weight = data->weight;

							data->orig_spline = BKE_mask_spline_copy(data->spline);
						}

						slide_point_delta_all_feather(data, delta);
					}
					else {
						if (dot_v2v2(no, vec) <= 0.0f)
							w = 0.0f;

						if (data->orig_spline) {
							/* restore possible overall feather changes */
							slide_point_restore_spline(data);

							BKE_mask_spline_free(data->orig_spline);
							data->orig_spline = NULL;
						}

						if (weight_scalar != 0.0f) {
							*weight = w * weight_scalar;
						}
					}
				}
			}

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

			break;
		}

		case LEFTMOUSE:
			if (event->val == KM_RELEASE) {
				Scene *scene = CTX_data_scene(C);

				/* dont key sliding feather uw's */
				if ((data->action == SLIDE_ACTION_FEATHER && data->uw) == FALSE) {
					if (IS_AUTOKEY_ON(scene)) {
						ED_mask_layer_shape_auto_key(data->masklay, CFRA);
					}
				}

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

				free_slide_point_data(op->customdata); /* keep this last! */
				return OPERATOR_FINISHED;
			}

			break;

		case ESCKEY:
			cancel_slide_point(op->customdata);

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

			free_slide_point_data(op->customdata); /* keep this last! */
			return OPERATOR_CANCELLED;
	}

	return OPERATOR_RUNNING_MODAL;
}
示例#9
0
static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
                                    const float marker_pos[2], int outline, int sel, int act, int width, int height)
{
	float dx, dy, patdx, patdy, searchdx, searchdy;
	int tiny = sc->flag & SC_SHOW_TINY_MARKER;
	float col[3], scol[3], px[2], side;

	if ((tiny && outline) || (marker->flag & MARKER_DISABLED))
		return;

	if (!TRACK_VIEW_SELECTED(sc, track) || track->flag & TRACK_LOCKED)
		return;

	track_colors(track, act, col, scol);

	if (outline) {
		glLineWidth(3.0f);
		UI_ThemeColor(TH_MARKER_OUTLINE);
	}

	glPushMatrix();
	glTranslatef(marker_pos[0], marker_pos[1], 0);

	dx = 6.0f / width / sc->zoom;
	dy = 6.0f / height / sc->zoom;

	side = get_shortest_pattern_side(marker);
	patdx = min_ff(dx * 2.0f / 3.0f, side / 6.0f) * UI_DPI_FAC;
	patdy = min_ff(dy * 2.0f / 3.0f, side * width / height / 6.0f) * UI_DPI_FAC;

	searchdx = min_ff(dx, (marker->search_max[0] - marker->search_min[0]) / 6.0f) * UI_DPI_FAC;
	searchdy = min_ff(dy, (marker->search_max[1] - marker->search_min[1]) / 6.0f) * UI_DPI_FAC;

	px[0] = 1.0f / sc->zoom / width / sc->scale;
	px[1] = 1.0f / sc->zoom / height / sc->scale;

	if ((sc->flag & SC_SHOW_MARKER_SEARCH) && ((track->search_flag & SELECT) == sel || outline)) {
		if (!outline) {
			if (track->search_flag & SELECT)
				glColor3fv(scol);
			else
				glColor3fv(col);
		}

		/* search offset square */
		draw_marker_slide_square(marker->search_min[0], marker->search_max[1], searchdx, searchdy, outline, px);

		/* search re-sizing triangle */
		draw_marker_slide_triangle(marker->search_max[0], marker->search_min[1], searchdx, searchdy, outline, px);
	}

	if ((sc->flag & SC_SHOW_MARKER_PATTERN) && ((track->pat_flag & SELECT) == sel || outline)) {
		int i;
		float pat_min[2], pat_max[2];
/*		float dx = 12.0f / width, dy = 12.0f / height;*/ /* XXX UNUSED */
		float tilt_ctrl[2];

		if (!outline) {
			if (track->pat_flag & SELECT)
				glColor3fv(scol);
			else
				glColor3fv(col);
		}

		/* pattern's corners sliding squares */
		for (i = 0; i < 4; i++) {
			draw_marker_slide_square(marker->pattern_corners[i][0], marker->pattern_corners[i][1],
			                         patdx / 1.5f, patdy / 1.5f, outline, px);
		}

		/* ** sliders to control overall pattern  ** */
		add_v2_v2v2(tilt_ctrl, marker->pattern_corners[1], marker->pattern_corners[2]);

		BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);

		glEnable(GL_LINE_STIPPLE);
		glLineStipple(3, 0xaaaa);

#if 0
		/* TODO: disable for now, needs better approach visualizing this */

		glBegin(GL_LINE_LOOP);
		glVertex2f(pat_min[0] - dx, pat_min[1] - dy);
		glVertex2f(pat_max[0] + dx, pat_min[1] - dy);
		glVertex2f(pat_max[0] + dx, pat_max[1] + dy);
		glVertex2f(pat_min[0] - dx, pat_max[1] + dy);
		glEnd();

		/* marker's offset slider */
		draw_marker_slide_square(pat_min[0] - dx, pat_max[1] + dy, patdx, patdy, outline, px);

		/* pattern re-sizing triangle */
		draw_marker_slide_triangle(pat_max[0] + dx, pat_min[1] - dy, patdx, patdy, outline, px);
#endif

		glBegin(GL_LINES);
		glVertex2f(0.0f, 0.0f);
		glVertex2fv(tilt_ctrl);
		glEnd();

		glDisable(GL_LINE_STIPPLE);


		/* slider to control pattern tilt */
		draw_marker_slide_square(tilt_ctrl[0], tilt_ctrl[1], patdx, patdy, outline, px);
	}

	glPopMatrix();

	if (outline)
		glLineWidth(1.0f);
}
示例#10
0
static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
                              const float marker_pos[2], int width, int height, int act, int sel)
{
	int tiny = sc->flag & SC_SHOW_TINY_MARKER;
	bool show_search = false;
	float col[3], scol[3], px[2];

	track_colors(track, act, col, scol);

	px[0] = 1.0f / width / sc->zoom;
	px[1] = 1.0f / height / sc->zoom;

	/* marker position and offset position */
	if ((track->flag & SELECT) == sel && (marker->flag & MARKER_DISABLED) == 0) {
		float pos[2], p[2];

		if (track->flag & TRACK_LOCKED) {
			if (act)
				UI_ThemeColor(TH_ACT_MARKER);
			else if (track->flag & SELECT)
				UI_ThemeColorShade(TH_LOCK_MARKER, 64);
			else
				UI_ThemeColor(TH_LOCK_MARKER);
		}
		else {
			if (track->flag & SELECT)
				glColor3fv(scol);
			else
				glColor3fv(col);
		}

		add_v2_v2v2(pos, marker->pos, track->offset);
		ED_clip_point_undistorted_pos(sc, pos, pos);

		sub_v2_v2v2(p, pos, marker_pos);

		if (isect_point_quad_v2(p, marker->pattern_corners[0], marker->pattern_corners[1],
		                        marker->pattern_corners[2], marker->pattern_corners[3]))
		{
			if (!tiny)
				glPointSize(2.0f);

			glBegin(GL_POINTS);
			glVertex2f(pos[0], pos[1]);
			glEnd();

			if (!tiny)
				glPointSize(1.0f);
		}
		else {
			glBegin(GL_LINES);
			glVertex2f(pos[0] + px[0] * 3, pos[1]);
			glVertex2f(pos[0] + px[0] * 7, pos[1]);

			glVertex2f(pos[0] - px[0] * 3, pos[1]);
			glVertex2f(pos[0] - px[0] * 7, pos[1]);

			glVertex2f(pos[0], pos[1] - px[1] * 3);
			glVertex2f(pos[0], pos[1] - px[1] * 7);

			glVertex2f(pos[0], pos[1] + px[1] * 3);
			glVertex2f(pos[0], pos[1] + px[1] * 7);
			glEnd();

			glColor3f(0.0f, 0.0f, 0.0f);
			glLineStipple(3, 0xaaaa);
			glEnable(GL_LINE_STIPPLE);
			glEnable(GL_COLOR_LOGIC_OP);
			glLogicOp(GL_NOR);

			glBegin(GL_LINES);
			glVertex2fv(pos);
			glVertex2fv(marker_pos);
			glEnd();

			glDisable(GL_COLOR_LOGIC_OP);
			glDisable(GL_LINE_STIPPLE);
		}
	}

	/* pattern */
	glPushMatrix();
	glTranslatef(marker_pos[0], marker_pos[1], 0);

	if (tiny) {
		glLineStipple(3, 0xaaaa);
		glEnable(GL_LINE_STIPPLE);
	}

	if ((track->pat_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_PATTERN)) {
		if (track->flag & TRACK_LOCKED) {
			if (act)
				UI_ThemeColor(TH_ACT_MARKER);
			else if (track->pat_flag & SELECT)
				UI_ThemeColorShade(TH_LOCK_MARKER, 64);
			else UI_ThemeColor(TH_LOCK_MARKER);
		}
		else if (marker->flag & MARKER_DISABLED) {
			if (act)
				UI_ThemeColor(TH_ACT_MARKER);
			else if (track->pat_flag & SELECT)
				UI_ThemeColorShade(TH_DIS_MARKER, 128);
			else UI_ThemeColor(TH_DIS_MARKER);
		}
		else {
			if (track->pat_flag & SELECT)
				glColor3fv(scol);
			else glColor3fv(col);
		}

		glBegin(GL_LINE_LOOP);
		glVertex2fv(marker->pattern_corners[0]);
		glVertex2fv(marker->pattern_corners[1]);
		glVertex2fv(marker->pattern_corners[2]);
		glVertex2fv(marker->pattern_corners[3]);
		glEnd();
	}

	/* search */
	show_search = (TRACK_VIEW_SELECTED(sc, track) &&
	               ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0;
	if ((track->search_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_SEARCH) && show_search) {
		if (track->flag & TRACK_LOCKED) {
			if (act)
				UI_ThemeColor(TH_ACT_MARKER);
			else if (track->search_flag & SELECT)
				UI_ThemeColorShade(TH_LOCK_MARKER, 64);
			else UI_ThemeColor(TH_LOCK_MARKER);
		}
		else if (marker->flag & MARKER_DISABLED) {
			if (act)
				UI_ThemeColor(TH_ACT_MARKER);
			else if (track->search_flag & SELECT)
				UI_ThemeColorShade(TH_DIS_MARKER, 128);
			else UI_ThemeColor(TH_DIS_MARKER);
		}
		else {
			if (track->search_flag & SELECT)
				glColor3fv(scol);
			else
				glColor3fv(col);
		}

		glBegin(GL_LINE_LOOP);
		glVertex2f(marker->search_min[0], marker->search_min[1]);
		glVertex2f(marker->search_max[0], marker->search_min[1]);
		glVertex2f(marker->search_max[0], marker->search_max[1]);
		glVertex2f(marker->search_min[0], marker->search_max[1]);
		glEnd();
	}

	if (tiny)
		glDisable(GL_LINE_STIPPLE);

	glPopMatrix();
}
示例#11
0
static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
                                const float marker_pos[2], int width, int height)
{
	int tiny = sc->flag & SC_SHOW_TINY_MARKER;
	bool show_search = false;
	float px[2];

	UI_ThemeColor(TH_MARKER_OUTLINE);

	px[0] = 1.0f / width / sc->zoom;
	px[1] = 1.0f / height / sc->zoom;

	if ((marker->flag & MARKER_DISABLED) == 0) {
		float pos[2];
		float p[2];

		add_v2_v2v2(pos, marker->pos, track->offset);

		ED_clip_point_undistorted_pos(sc, pos, pos);

		sub_v2_v2v2(p, pos, marker_pos);

		if (isect_point_quad_v2(p, marker->pattern_corners[0], marker->pattern_corners[1],
		                        marker->pattern_corners[2], marker->pattern_corners[3]))
		{
			if (tiny) glPointSize(3.0f);
			else glPointSize(4.0f);
			glBegin(GL_POINTS);
			glVertex2f(pos[0], pos[1]);
			glEnd();
			glPointSize(1.0f);
		}
		else {
			if (!tiny) glLineWidth(3.0f);
			glBegin(GL_LINES);
			glVertex2f(pos[0] + px[0] * 2, pos[1]);
			glVertex2f(pos[0] + px[0] * 8, pos[1]);

			glVertex2f(pos[0] - px[0] * 2, pos[1]);
			glVertex2f(pos[0] - px[0] * 8, pos[1]);

			glVertex2f(pos[0], pos[1] - px[1] * 2);
			glVertex2f(pos[0], pos[1] - px[1] * 8);

			glVertex2f(pos[0], pos[1] + px[1] * 2);
			glVertex2f(pos[0], pos[1] + px[1] * 8);
			glEnd();
			if (!tiny) glLineWidth(1.0f);
		}
	}

	/* pattern and search outline */
	glPushMatrix();
	glTranslatef(marker_pos[0], marker_pos[1], 0);

	if (!tiny)
		glLineWidth(3.0f);

	if (sc->flag & SC_SHOW_MARKER_PATTERN) {
		glBegin(GL_LINE_LOOP);
		glVertex2fv(marker->pattern_corners[0]);
		glVertex2fv(marker->pattern_corners[1]);
		glVertex2fv(marker->pattern_corners[2]);
		glVertex2fv(marker->pattern_corners[3]);
		glEnd();
	}

	show_search = (TRACK_VIEW_SELECTED(sc, track) &&
	               ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0;
	if (sc->flag & SC_SHOW_MARKER_SEARCH && show_search) {
		glBegin(GL_LINE_LOOP);
		glVertex2f(marker->search_min[0], marker->search_min[1]);
		glVertex2f(marker->search_max[0], marker->search_min[1]);
		glVertex2f(marker->search_max[0], marker->search_max[1]);
		glVertex2f(marker->search_min[0], marker->search_max[1]);
		glEnd();
	}
	glPopMatrix();

	if (!tiny)
		glLineWidth(1.0f);
}
示例#12
0
static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
{
	int count = sc->path_length;
	int i, a, b, curindex = -1;
	float path[102][2];
	int tiny = sc->flag & SC_SHOW_TINY_MARKER, framenr, start_frame;
	MovieTrackingMarker *marker;

	if (count == 0)
		return;

	start_frame = framenr = ED_space_clip_get_clip_frame_number(sc);

	marker = BKE_tracking_marker_get(track, framenr);
	if (marker->framenr != framenr || marker->flag & MARKER_DISABLED)
		return;

	a = count;
	i = framenr - 1;
	while (i >= framenr - count) {
		marker = BKE_tracking_marker_get(track, i);

		if (!marker || marker->flag & MARKER_DISABLED)
			break;

		if (marker->framenr == i) {
			add_v2_v2v2(path[--a], marker->pos, track->offset);
			ED_clip_point_undistorted_pos(sc, path[a], path[a]);

			if (marker->framenr == start_frame)
				curindex = a;
		}
		else {
			break;
		}

		i--;
	}

	b = count;
	i = framenr;
	while (i <= framenr + count) {
		marker = BKE_tracking_marker_get(track, i);

		if (!marker || marker->flag & MARKER_DISABLED)
			break;

		if (marker->framenr == i) {
			if (marker->framenr == start_frame)
				curindex = b;

			add_v2_v2v2(path[b++], marker->pos, track->offset);
			ED_clip_point_undistorted_pos(sc, path[b - 1], path[b - 1]);
		}
		else
			break;

		i++;
	}

	if (!tiny) {
		UI_ThemeColor(TH_MARKER_OUTLINE);

		if (TRACK_VIEW_SELECTED(sc, track)) {
			glPointSize(5.0f);
			glBegin(GL_POINTS);
			for (i = a; i < b; i++) {
				if (i != curindex)
					glVertex2f(path[i][0], path[i][1]);
			}
			glEnd();
		}

		glLineWidth(3.0f);
		glBegin(GL_LINE_STRIP);
		for (i = a; i < b; i++)
			glVertex2f(path[i][0], path[i][1]);
		glEnd();
		glLineWidth(1.0f);
	}

	UI_ThemeColor(TH_PATH_BEFORE);

	if (TRACK_VIEW_SELECTED(sc, track)) {
		glPointSize(3.0f);
		glBegin(GL_POINTS);
		for (i = a; i < b; i++) {
			if (i == count + 1)
				UI_ThemeColor(TH_PATH_AFTER);

			if (i != curindex)
				glVertex2f(path[i][0], path[i][1]);
		}
		glEnd();
	}

	UI_ThemeColor(TH_PATH_BEFORE);

	glBegin(GL_LINE_STRIP);
	for (i = a; i < b; i++) {
		if (i == count + 1)
			UI_ThemeColor(TH_PATH_AFTER);

		glVertex2f(path[i][0], path[i][1]);
	}
	glEnd();
	glPointSize(1.0f);
}
KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTriangulation()
{
	MovieClipUser user = {0};
	TriangulationData *triangulation;
	MovieTracking *tracking = &this->m_movieClip->tracking;
	MovieTrackingTrack *track;
	VoronoiSite *sites, *site;
	ImBuf *ibuf;
	ListBase *tracksbase;
	ListBase edges = {NULL, NULL};
	int sites_total;
	int i;
	int width = this->getWidth();
	int height = this->getHeight();
	int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber);

	if (this->m_trackingObject[0]) {
		MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, this->m_trackingObject);

		if (!object)
			return NULL;

		tracksbase = BKE_tracking_object_get_tracks(tracking, object);
	}
	else
		tracksbase = BKE_tracking_get_active_tracks(tracking);

	/* count sites */
	for (track = (MovieTrackingTrack *) tracksbase->first, sites_total = 0; track; track = track->next) {
		MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame);
		float pos[2];

		if (marker->flag & MARKER_DISABLED)
			continue;

		add_v2_v2v2(pos, marker->pos, track->offset);

		if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) ||
		    !IN_RANGE_INCL(pos[1], 0.0f, 1.0f))
		{
			continue;
		}

		sites_total++;
	}

	if (!sites_total)
		return NULL;

	BKE_movieclip_user_set_frame(&user, clip_frame);
	ibuf = BKE_movieclip_get_ibuf(this->m_movieClip, &user);

	if (!ibuf)
		return NULL;

	triangulation = (TriangulationData *) MEM_callocN(sizeof(TriangulationData), "keying screen triangulation data");

	sites = (VoronoiSite *) MEM_callocN(sizeof(VoronoiSite) * sites_total, "keyingscreen voronoi sites");
	track = (MovieTrackingTrack *) tracksbase->first;
	for (track = (MovieTrackingTrack *) tracksbase->first, site = sites; track; track = track->next) {
		MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame);
		ImBuf *pattern_ibuf;
		int j;
		float pos[2];

		if (marker->flag & MARKER_DISABLED)
			continue;

		add_v2_v2v2(pos, marker->pos, track->offset);

		if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) ||
		    !IN_RANGE_INCL(pos[1], 0.0f, 1.0f))
		{
			continue;
		}

		pattern_ibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, marker, TRUE, FALSE);

		zero_v3(site->color);

		if (pattern_ibuf) {
			for (j = 0; j < pattern_ibuf->x * pattern_ibuf->y; j++) {
				if (pattern_ibuf->rect_float) {
					add_v3_v3(site->color, &pattern_ibuf->rect_float[4 * j]);
				}
				else {
					unsigned char *rrgb = (unsigned char *)pattern_ibuf->rect;

					site->color[0] += srgb_to_linearrgb((float)rrgb[4 * j + 0] / 255.0f);
					site->color[1] += srgb_to_linearrgb((float)rrgb[4 * j + 1] / 255.0f);
					site->color[2] += srgb_to_linearrgb((float)rrgb[4 * j + 2] / 255.0f);
				}
			}

			mul_v3_fl(site->color, 1.0f / (pattern_ibuf->x * pattern_ibuf->y));
			IMB_freeImBuf(pattern_ibuf);
		}

		site->co[0] = pos[0] * width;
		site->co[1] = pos[1] * height;

		site++;
	}

	IMB_freeImBuf(ibuf);

	BLI_voronoi_compute(sites, sites_total, width, height, &edges);

	BLI_voronoi_triangulate(sites, sites_total, &edges, width, height,
	                        &triangulation->triangulated_points, &triangulation->triangulated_points_total,
	                        &triangulation->triangles, &triangulation->triangles_total);

	MEM_freeN(sites);
	BLI_freelistN(&edges);

	if (triangulation->triangles_total) {
		rctf *rect;
		rect = triangulation->triangles_AABB =
			(rctf *) MEM_callocN(sizeof(rctf) * triangulation->triangles_total, "voronoi triangulation AABB");

		for (i = 0; i < triangulation->triangles_total; i++, rect++) {
			int *triangle = triangulation->triangles[i];
			VoronoiTriangulationPoint *a = &triangulation->triangulated_points[triangle[0]],
			                          *b = &triangulation->triangulated_points[triangle[1]],
			                          *c = &triangulation->triangulated_points[triangle[2]];

			float min[2], max[2];

			INIT_MINMAX2(min, max);

			minmax_v2v2_v2(min, max, a->co);
			minmax_v2v2_v2(min, max, b->co);
			minmax_v2v2_v2(min, max, c->co);

			rect->xmin = min[0];
			rect->ymin = min[1];

			rect->xmax = max[0];
			rect->ymax = max[1];
		}
	}

	return triangulation;
}
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;
}
示例#15
0
static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
                              const char draw_flag, const char draw_type,
                              const bool is_active,
                              const int width, const int height)
{
	const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
	                                  BKE_mask_spline_resolution(spline, width, height));

	unsigned char rgb_tmp[4];

	const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
	const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
	const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;

	unsigned int tot_diff_point;
	float (*diff_points)[2];

	unsigned int tot_feather_point;
	float (*feather_points)[2];

	diff_points = BKE_mask_spline_differentiate_with_resolution(spline, &tot_diff_point, resol);

	if (!diff_points)
		return;

	if (is_smooth) {
		glEnable(GL_LINE_SMOOTH);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	}

	feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(spline, &tot_feather_point, resol, (is_fill != false));

	/* draw feather */
	mask_spline_feather_color_get(masklay, spline, is_spline_sel, rgb_tmp);
	mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
	                     true, is_smooth, is_active,
	                     rgb_tmp, draw_type);

	if (!is_fill) {

		const float *fp   = &diff_points[0][0];
		float *fp_feather = &feather_points[0][0];
		float tvec[2];
		int i;

		BLI_assert(tot_diff_point == tot_feather_point);

		for (i = 0; i < tot_diff_point; i++, fp += 2, fp_feather += 2) {
			sub_v2_v2v2(tvec, fp, fp_feather);
			add_v2_v2v2(fp_feather, fp, tvec);
		}

		/* same as above */
		mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
		                     true, is_smooth, is_active,
		                     rgb_tmp, draw_type);
	}

	MEM_freeN(feather_points);

	/* draw main curve */
	mask_spline_color_get(masklay, spline, is_spline_sel, rgb_tmp);
	mask_draw_curve_type(C, spline, diff_points, tot_diff_point,
	                     false, is_smooth, is_active,
	                     rgb_tmp, draw_type);
	MEM_freeN(diff_points);

	if (draw_flag & MASK_DRAWFLAG_SMOOTH) {
		glDisable(GL_LINE_SMOOTH);
		glDisable(GL_BLEND);
	}

	(void)draw_type;
}
示例#16
0
void uiTemplateMarker(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *userptr,
                      PointerRNA *trackptr, int compact)
{
	PropertyRNA *prop;
	uiBlock *block;
	uiBut *bt;
	PointerRNA clipptr;
	MovieClip *clip;
	MovieClipUser *user;
	MovieTrackingTrack *track;
	MovieTrackingMarker *marker;
	MarkerUpdateCb *cb;
	const char *tip;
	float pat_min[2], pat_max[2];

	if (!ptr->data)
		return;

	prop = RNA_struct_find_property(ptr, propname);
	if (!prop) {
		printf("%s: property not found: %s.%s\n",
		       __func__, RNA_struct_identifier(ptr->type), propname);
		return;
	}

	if (RNA_property_type(prop) != PROP_POINTER) {
		printf("%s: expected pointer property for %s.%s\n",
		       __func__, RNA_struct_identifier(ptr->type), propname);
		return;
	}

	clipptr = RNA_property_pointer_get(ptr, prop);
	clip = (MovieClip *)clipptr.data;
	user = userptr->data;
	track = trackptr->data;

	marker = BKE_tracking_marker_get(track, user->framenr);

	cb = MEM_callocN(sizeof(MarkerUpdateCb), "uiTemplateMarker update_cb");
	cb->compact = compact;
	cb->clip = clip;
	cb->user = user;
	cb->track = track;
	cb->marker = marker;
	cb->marker_flag = marker->flag;
	cb->framenr = user->framenr;

	if (compact) {
		block = uiLayoutGetBlock(layout);

		if (cb->marker_flag & MARKER_DISABLED)
			tip = "Marker is disabled at current frame";
		else
			tip = "Marker is enabled at current frame";

		bt = uiDefIconButBitI(block, TOGN, MARKER_DISABLED, 0, ICON_RESTRICT_VIEW_OFF, 0, 0, 20, 20,
		                      &cb->marker_flag, 0, 0, 1, 0, tip);
		uiButSetNFunc(bt, marker_update_cb, cb, NULL);
	}
	else {
		int width, height, step, digits;
		float pat_dim[2], search_dim[2], search_pos[2];
		uiLayout *col;

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

		if (track->flag & TRACK_LOCKED) {
			uiLayoutSetActive(layout, FALSE);
			block = uiLayoutAbsoluteBlock(layout);
			uiDefBut(block, LABEL, 0, "Track is locked", 0, 0, 300, 19, NULL, 0, 0, 0, 0, "");

			return;
		}

		step = 100;
		digits = 2;

		BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);

		sub_v2_v2v2(pat_dim, pat_max, pat_min);
		sub_v2_v2v2(search_dim, marker->search_max, marker->search_min);

		add_v2_v2v2(search_pos, marker->search_max, marker->search_min);
		mul_v2_fl(search_pos, 0.5);

		to_pixel_space(cb->marker_pos, marker->pos, width, height);
		to_pixel_space(cb->marker_pat, pat_dim, width, height);
		to_pixel_space(cb->marker_search, search_dim, width, height);
		to_pixel_space(cb->marker_search_pos, search_pos, width, height);
		to_pixel_space(cb->track_offset, track->offset, width, height);

		cb->marker_flag = marker->flag;

		block = uiLayoutAbsoluteBlock(layout);
		uiBlockSetHandleFunc(block, marker_block_handler, cb);
		uiBlockSetNFunc(block, marker_update_cb, cb, NULL);

		if (cb->marker_flag & MARKER_DISABLED)
			tip = "Marker is disabled at current frame";
		else
			tip = "Marker is enabled at current frame";

		uiDefButBitI(block, OPTIONN, MARKER_DISABLED, B_MARKER_FLAG,  "Enabled", 10, 190, 145, 19, &cb->marker_flag,
		             0, 0, 0, 0, tip);

		col = uiLayoutColumn(layout, TRUE);
		uiLayoutSetActive(col, (cb->marker_flag & MARKER_DISABLED) == 0);

		block = uiLayoutAbsoluteBlock(col);
		uiBlockBeginAlign(block);

		uiDefBut(block, LABEL, 0, "Position:", 0, 190, 300, 19, NULL, 0, 0, 0, 0, "");
		uiDefButF(block, NUM, B_MARKER_POS, "X:", 10, 171, 145, 19, &cb->marker_pos[0],
		          -10 * width, 10.0 * width, step, digits, "X-position of marker at frame in screen coordinates");
		uiDefButF(block, NUM, B_MARKER_POS, "Y:", 165, 171, 145, 19, &cb->marker_pos[1],
		          -10 * height, 10.0 * height, step, digits, "Y-position of marker at frame in screen coordinates");

		uiDefBut(block, LABEL, 0, "Offset:", 0, 152, 300, 19, NULL, 0, 0, 0, 0, "");
		uiDefButF(block, NUM, B_MARKER_OFFSET, "X:", 10, 133, 145, 19, &cb->track_offset[0],
		          -10 * width, 10.0 * width, step, digits, "X-offset to parenting point");
		uiDefButF(block, NUM, B_MARKER_OFFSET, "Y:", 165, 133, 145, 19, &cb->track_offset[1],
		          -10 * height, 10.0 * height, step, digits, "Y-offset to parenting point");

		uiDefBut(block, LABEL, 0, "Pattern Area:", 0, 114, 300, 19, NULL, 0, 0, 0, 0, "");
		uiDefButF(block, NUM, B_MARKER_PAT_DIM, "Width:", 10, 95, 300, 19, &cb->marker_pat[0], 3.0f,
		          10.0 * width, step, digits, "Width of marker's pattern in screen coordinates");
		uiDefButF(block, NUM, B_MARKER_PAT_DIM, "Height:", 10, 76, 300, 19, &cb->marker_pat[1], 3.0f,
		          10.0 * height, step, digits, "Height of marker's pattern in screen coordinates");

		uiDefBut(block, LABEL, 0, "Search Area:", 0, 57, 300, 19, NULL, 0, 0, 0, 0, "");
		uiDefButF(block, NUM, B_MARKER_SEARCH_POS, "X:", 10, 38, 145, 19, &cb->marker_search_pos[0],
		          -width, width, step, digits, "X-position of search at frame relative to marker's position");
		uiDefButF(block, NUM, B_MARKER_SEARCH_POS, "Y:", 165, 38, 145, 19, &cb->marker_search_pos[1],
		          -height, height, step, digits, "X-position of search at frame relative to marker's position");
		uiDefButF(block, NUM, B_MARKER_SEARCH_DIM, "Width:", 10, 19, 300, 19, &cb->marker_search[0], 3.0f,
		          10.0 * width, step, digits, "Width of marker's search in screen soordinates");
		uiDefButF(block, NUM, B_MARKER_SEARCH_DIM, "Height:", 10, 0, 300, 19, &cb->marker_search[1], 3.0f,
		          10.0 * height, step, digits, "Height of marker's search in screen soordinates");

		uiBlockEndAlign(block);
	}
}
示例#17
0
static void marker_block_handler(bContext *C, void *arg_cb, int event)
{
	MarkerUpdateCb *cb = (MarkerUpdateCb *) arg_cb;
	MovieTrackingMarker *marker;
	int width, height, ok = FALSE;

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

	marker = BKE_tracking_marker_ensure(cb->track, cb->framenr);

	if (event == B_MARKER_POS) {
		marker->pos[0] = cb->marker_pos[0] / width;
		marker->pos[1] = cb->marker_pos[1] / height;

		/* to update position of "parented" objects */
		DAG_id_tag_update(&cb->clip->id, 0);
		WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);

		ok = TRUE;
	}
	else if (event == B_MARKER_PAT_DIM) {
		float dim[2], pat_dim[2], pat_min[2], pat_max[2];
		float scale_x, scale_y;
		int a;

		BKE_tracking_marker_pattern_minmax(cb->marker, pat_min, pat_max);

		sub_v2_v2v2(pat_dim, pat_max, pat_min);

		dim[0] = cb->marker_pat[0] / width;
		dim[1] = cb->marker_pat[1] / height;

		scale_x = dim[0] / pat_dim[0];
		scale_y = dim[1] / pat_dim[1];

		for (a = 0; a < 4; a++) {
			cb->marker->pattern_corners[a][0] *= scale_x;
			cb->marker->pattern_corners[a][1] *= scale_y;
		}

		BKE_tracking_marker_clamp(cb->marker, CLAMP_PAT_DIM);

		ok = TRUE;
	}
	else if (event == B_MARKER_SEARCH_POS) {
		float delta[2], side[2];

		sub_v2_v2v2(side, cb->marker->search_max, cb->marker->search_min);
		mul_v2_fl(side, 0.5f);

		delta[0] = cb->marker_search_pos[0] / width;
		delta[1] = cb->marker_search_pos[1] / height;

		sub_v2_v2v2(cb->marker->search_min, delta, side);
		add_v2_v2v2(cb->marker->search_max, delta, side);

		BKE_tracking_marker_clamp(cb->marker, CLAMP_SEARCH_POS);

		ok = TRUE;
	}
	else if (event == B_MARKER_SEARCH_DIM) {
		float dim[2], search_dim[2];

		sub_v2_v2v2(search_dim, cb->marker->search_max, cb->marker->search_min);

		dim[0] = cb->marker_search[0] / width;
		dim[1] = cb->marker_search[1] / height;

		sub_v2_v2(dim, search_dim);
		mul_v2_fl(dim, 0.5f);

		cb->marker->search_min[0] -= dim[0];
		cb->marker->search_min[1] -= dim[1];

		cb->marker->search_max[0] += dim[0];
		cb->marker->search_max[1] += dim[1];

		BKE_tracking_marker_clamp(cb->marker, CLAMP_SEARCH_DIM);

		ok = TRUE;
	}
	else if (event == B_MARKER_FLAG) {
		marker->flag = cb->marker_flag;

		ok = TRUE;
	}
	else if (event == B_MARKER_OFFSET) {
		float offset[2], delta[2];
		int i;

		offset[0] = cb->track_offset[0] / width;
		offset[1] = cb->track_offset[1] / height;

		sub_v2_v2v2(delta, offset, cb->track->offset);
		copy_v2_v2(cb->track->offset, offset);

		for (i = 0; i < cb->track->markersnr; i++)
			sub_v2_v2(cb->track->markers[i].pos, delta);

		/* to update position of "parented" objects */
		DAG_id_tag_update(&cb->clip->id, 0);
		WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);

		ok = TRUE;
	}

	if (ok)
		WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, cb->clip);
}
示例#18
0
/* determines the velocity the boid wants to have */
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
{
	BoidRule *rule;
	BoidSettings *boids = bbd->part->boids;
	BoidValues val;
	BoidState *state = get_boid_state(boids, pa);
	BoidParticle *bpa = pa->boid;
	ParticleSystem *psys = bbd->sim->psys;
	int rand;
	//BoidCondition *cond;

	if (bpa->data.health <= 0.0f) {
		pa->alive = PARS_DYING;
		pa->dietime = bbd->cfra;
		return;
	}

	//planned for near future
	//cond = state->conditions.first;
	//for (; cond; cond=cond->next) {
	//	if (boid_condition_is_true(cond)) {
	//		pa->boid->state_id = cond->state_id;
	//		state = get_boid_state(boids, pa);
	//		break; /* only first true condition is used */
	//	}
	//}

	zero_v3(bbd->wanted_co);
	bbd->wanted_speed = 0.0f;

	/* create random seed for every particle & frame */
	rand = (int)(psys_frand(psys, psys->seed + p) * 1000);
	rand = (int)(psys_frand(psys, (int)bbd->cfra + rand) * 1000);

	set_boid_values(&val, bbd->part->boids, pa);

	/* go through rules */
	switch (state->ruleset_type) {
		case eBoidRulesetType_Fuzzy:
		{
			for (rule = state->rules.first; rule; rule = rule->next) {
				if (apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness))
					break; /* only first nonzero rule that comes through fuzzy rule is applied */
			}
			break;
		}
		case eBoidRulesetType_Random:
		{
			/* use random rule for each particle (always same for same particle though) */
			rule = BLI_findlink(&state->rules, rand % BLI_listbase_count(&state->rules));

			apply_boid_rule(bbd, rule, &val, pa, -1.0);
			break;
		}
		case eBoidRulesetType_Average:
		{
			float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f;
			int n = 0;
			for (rule = state->rules.first; rule; rule=rule->next) {
				if (apply_boid_rule(bbd, rule, &val, pa, -1.0f)) {
					add_v3_v3(wanted_co, bbd->wanted_co);
					wanted_speed += bbd->wanted_speed;
					n++;
					zero_v3(bbd->wanted_co);
					bbd->wanted_speed = 0.0f;
				}
			}

			if (n > 1) {
				mul_v3_fl(wanted_co, 1.0f/(float)n);
				wanted_speed /= (float)n;
			}

			copy_v3_v3(bbd->wanted_co, wanted_co);
			bbd->wanted_speed = wanted_speed;
			break;
		}

	}

	/* decide on jumping & liftoff */
	if (bpa->data.mode == eBoidMode_OnLand) {
		/* fuzziness makes boids capable of misjudgement */
		float mul = 1.0f + state->rule_fuzziness;
		
		if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
			float cvel[3], dir[3];

			copy_v3_v3(dir, pa->prev_state.ave);
			normalize_v2(dir);

			copy_v3_v3(cvel, bbd->wanted_co);
			normalize_v2(cvel);

			if (dot_v2v2(cvel, dir) > 0.95f / mul)
				bpa->data.mode = eBoidMode_Liftoff;
		}
		else if (val.jump_speed > 0.0f) {
			float jump_v[3];
			int jump = 0;

			/* jump to get to a location */
			if (bbd->wanted_co[2] > 0.0f) {
				float cvel[3], dir[3];
				float z_v, ground_v, cur_v;
				float len;

				copy_v3_v3(dir, pa->prev_state.ave);
				normalize_v2(dir);

				copy_v3_v3(cvel, bbd->wanted_co);
				normalize_v2(cvel);

				len = len_v2(pa->prev_state.vel);

				/* first of all, are we going in a suitable direction? */
				/* or at a suitably slow speed */
				if (dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
					/* try to reach goal at highest point of the parabolic path */
					cur_v = len_v2(pa->prev_state.vel);
					z_v = sasqrt(-2.0f * bbd->sim->scene->physics_settings.gravity[2] * bbd->wanted_co[2]);
					ground_v = len_v2(bbd->wanted_co)*sasqrt(-0.5f * bbd->sim->scene->physics_settings.gravity[2] / bbd->wanted_co[2]);

					len = sasqrt((ground_v-cur_v)*(ground_v-cur_v) + z_v*z_v);

					if (len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) {
						jump = 1;

						len = MIN2(len, val.jump_speed);

						copy_v3_v3(jump_v, dir);
						jump_v[2] = z_v;
						mul_v3_fl(jump_v, ground_v);

						normalize_v3(jump_v);
						mul_v3_fl(jump_v, len);
						add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel);
					}
				}
			}

			/* jump to go faster */
			if (jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) {
				
			}

			if (jump) {
				copy_v3_v3(pa->prev_state.vel, jump_v);
				bpa->data.mode = eBoidMode_Falling;
			}
		}
	}
}
示例#19
0
static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, bNode *gnode)
{
	bNodeTree *ngroup = (bNodeTree *)gnode->id;
	bNodeLink *link, *linkn;
	bNode *node, *nextn;
	bNodeSocket *sock;
	ListBase anim_basepaths = {NULL, NULL};
	float min[2], max[2], center[2];
	int totselect;
	int expose_all = FALSE;
	bNode *input_node, *output_node;
	
	/* XXX rough guess, not nice but we don't have access to UI constants here ... */
	static const float offsetx = 200;
	static const float offsety = 0.0f;
	
	/* deselect all nodes in the target tree */
	for (node = ngroup->nodes.first; node; node = node->next)
		nodeSetSelected(node, FALSE);
	
	totselect = node_get_selected_minmax(ntree, gnode, min, max);
	add_v2_v2v2(center, min, max);
	mul_v2_fl(center, 0.5f);
	
	/* auto-add interface for "solo" nodes */
	if (totselect == 1)
		expose_all = TRUE;
	
	/* move nodes over */
	for (node = ntree->nodes.first; node; node = nextn) {
		nextn = node->next;
		if (node_group_make_use_node(node, gnode)) {
			/* keep track of this node's RNA "base" path (the part of the pat identifying the node) 
			 * if the old nodetree has animation data which potentially covers this node
			 */
			if (ntree->adt) {
				PointerRNA ptr;
				char *path;
				
				RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
				path = RNA_path_from_ID_to_struct(&ptr);
				
				if (path)
					BLI_addtail(&anim_basepaths, BLI_genericNodeN(path));
			}
			
			/* ensure valid parent pointers, detach if parent stays outside the group */
			if (node->parent && !(node->parent->flag & NODE_SELECT))
				nodeDetachNode(node);
			
			/* change node-collection membership */
			BLI_remlink(&ntree->nodes, node);
			BLI_addtail(&ngroup->nodes, node);
			
			/* ensure unique node name in the ngroup */
			nodeUniqueName(ngroup, node);
		}
	}
	
	/* move animation data over */
	if (ntree->adt) {
		LinkData *ld, *ldn = NULL;
		
		BKE_animdata_separate_by_basepath(&ntree->id, &ngroup->id, &anim_basepaths);
		
		/* paths + their wrappers need to be freed */
		for (ld = anim_basepaths.first; ld; ld = ldn) {
			ldn = ld->next;
			
			MEM_freeN(ld->data);
			BLI_freelinkN(&anim_basepaths, ld);
		}
	}
	
	/* node groups don't use internal cached data */
	ntreeFreeCache(ngroup);
	
	/* create input node */
	input_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_INPUT);
	input_node->locx = min[0] - center[0] - offsetx;
	input_node->locy = -offsety;
	
	/* create output node */
	output_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_OUTPUT);
	output_node->locx = max[0] - center[0] + offsetx;
	output_node->locy = -offsety;
	
	/* relink external sockets */
	for (link = ntree->links.first; link; link = linkn) {
		int fromselect = node_group_make_use_node(link->fromnode, gnode);
		int toselect = node_group_make_use_node(link->tonode, gnode);
		
		linkn = link->next;
		
		if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) {
			/* remove all links to/from the gnode.
			 * this can remove link information, but there's no general way to preserve it.
			 */
			nodeRemLink(ntree, link);
		}
		else if (fromselect && toselect) {
			BLI_remlink(&ntree->links, link);
			BLI_addtail(&ngroup->links, link);
		}
		else if (toselect) {
			bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->tonode, link->tosock);
			bNodeSocket *input_sock;
			
			/* update the group node and interface node sockets,
			 * so the new interface socket can be linked.
			 */
			node_group_verify(ntree, gnode, (ID *)ngroup);
			node_group_input_verify(ngroup, input_node, (ID *)ngroup);
			
			/* create new internal link */
			input_sock = node_group_input_find_socket(input_node, iosock->identifier);
			nodeAddLink(ngroup, input_node, input_sock, link->tonode, link->tosock);
			
			/* redirect external link */
			link->tonode = gnode;
			link->tosock = node_group_find_input_socket(gnode, iosock->identifier);
		}
		else if (fromselect) {
			bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->fromnode, link->fromsock);
			bNodeSocket *output_sock;
			
			/* update the group node and interface node sockets,
			 * so the new interface socket can be linked.
			 */
			node_group_verify(ntree, gnode, (ID *)ngroup);
			node_group_output_verify(ngroup, output_node, (ID *)ngroup);

			/* create new internal link */
			output_sock = node_group_output_find_socket(output_node, iosock->identifier);
			nodeAddLink(ngroup, link->fromnode, link->fromsock, output_node, output_sock);
			
			/* redirect external link */
			link->fromnode = gnode;
			link->fromsock = node_group_find_output_socket(gnode, iosock->identifier);
		}
	}

	/* move nodes in the group to the center */
	for (node = ngroup->nodes.first; node; node = node->next) {
		if (node_group_make_use_node(node, gnode) && !node->parent) {
			node->locx -= center[0];
			node->locy -= center[1];
		}
	}
	
	/* expose all unlinked sockets too */
	if (expose_all) {
		for (node = ngroup->nodes.first; node; node = node->next) {
			if (node_group_make_use_node(node, gnode)) {
				for (sock = node->inputs.first; sock; sock = sock->next) {
					bNodeSocket *iosock, *input_sock;
					int skip = FALSE;
					for (link = ngroup->links.first; link; link = link->next) {
						if (link->tosock == sock) {
							skip = TRUE;
							break;
						}
					}
					if (skip)
						continue;
					
					iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
					
					node_group_input_verify(ngroup, input_node, (ID *)ngroup);
					
					/* create new internal link */
					input_sock = node_group_input_find_socket(input_node, iosock->identifier);
					nodeAddLink(ngroup, input_node, input_sock, node, sock);
				}
				
				for (sock = node->outputs.first; sock; sock = sock->next) {
					bNodeSocket *iosock, *output_sock;
					int skip = FALSE;
					for (link = ngroup->links.first; link; link = link->next)
						if (link->fromsock == sock)
							skip = TRUE;
					if (skip)
						continue;
					
					iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
					
					node_group_output_verify(ngroup, output_node, (ID *)ngroup);
					
					/* create new internal link */
					output_sock = node_group_output_find_socket(output_node, iosock->identifier);
					nodeAddLink(ngroup, node, sock, output_node, output_sock);
				}
			}
		}
	}

	/* update of the group tree */
	ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS;
	/* update of the tree containing the group instance node */
	ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
}
示例#20
0
void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mask,
                                   const int width, const int height,
                                   const bool do_aspect_correct, const bool do_mask_aa,
                                   const bool do_feather)
{
	const rctf default_bounds = {0.0f, 1.0f, 0.0f, 1.0f};
	const float pixel_size = 1.0f / (float)min_ii(width, height);
	const float asp_xy[2] = {(do_aspect_correct && width > height) ? (float)height / (float)width  : 1.0f,
	                         (do_aspect_correct && width < height) ? (float)width  / (float)height : 1.0f};

	const float zvec[3] = {0.0f, 0.0f, 1.0f};
	MaskLayer *masklay;
	unsigned int masklay_index;
	MemArena *sf_arena;

	mr_handle->layers_tot = (unsigned int)BLI_countlist(&mask->masklayers);
	mr_handle->layers = MEM_mallocN(sizeof(MaskRasterLayer) * mr_handle->layers_tot, "MaskRasterLayer");
	BLI_rctf_init_minmax(&mr_handle->bounds);

	sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__);

	for (masklay = mask->masklayers.first, masklay_index = 0; masklay; masklay = masklay->next, masklay_index++) {

		/* we need to store vertex ranges for open splines for filling */
		unsigned int tot_splines;
		MaskRasterSplineInfo *open_spline_ranges;
		unsigned int   open_spline_index = 0;

		MaskSpline *spline;

		/* scanfill */
		ScanFillContext sf_ctx;
		ScanFillVert *sf_vert = NULL;
		ScanFillVert *sf_vert_next = NULL;
		ScanFillFace *sf_tri;

		unsigned int sf_vert_tot = 0;
		unsigned int tot_feather_quads = 0;

#ifdef USE_SCANFILL_EDGE_WORKAROUND
		unsigned int tot_boundary_used = 0;
		unsigned int tot_boundary_found = 0;
#endif

		if (masklay->restrictflag & MASK_RESTRICT_RENDER) {
			/* skip the layer */
			mr_handle->layers_tot--;
			masklay_index--;
			continue;
		}

		tot_splines = (unsigned int)BLI_countlist(&masklay->splines);
		open_spline_ranges = MEM_callocN(sizeof(*open_spline_ranges) * tot_splines, __func__);

		BLI_scanfill_begin_arena(&sf_ctx, sf_arena);

		for (spline = masklay->splines.first; spline; spline = spline->next) {
			const bool is_cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0;
			const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;

			float (*diff_points)[2];
			unsigned int tot_diff_point;

			float (*diff_feather_points)[2];
			float (*diff_feather_points_flip)[2];
			unsigned int tot_diff_feather_points;

			const unsigned int resol_a = BKE_mask_spline_resolution(spline, width, height) / 4;
			const unsigned int resol_b = BKE_mask_spline_feather_resolution(spline, width, height) / 4;
			const unsigned int resol = CLAMPIS(MAX2(resol_a, resol_b), 4, 512);

			diff_points = BKE_mask_spline_differentiate_with_resolution(
			                  spline, &tot_diff_point, resol);

			if (do_feather) {
				diff_feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(
				                          spline, &tot_diff_feather_points, resol, FALSE);
				BLI_assert(diff_feather_points);
			}
			else {
				tot_diff_feather_points = 0;
				diff_feather_points = NULL;
			}

			if (tot_diff_point > 3) {
				ScanFillVert *sf_vert_prev;
				unsigned int j;

				float co[3];
				co[2] = 0.0f;

				sf_ctx.poly_nr++;

				if (do_aspect_correct) {
					if (width != height) {
						float *fp;
						float *ffp;
						unsigned int i;
						float asp;

						if (width < height) {
							fp = &diff_points[0][0];
							ffp = tot_diff_feather_points ? &diff_feather_points[0][0] : NULL;
							asp = (float)width / (float)height;
						}
						else {
							fp = &diff_points[0][1];
							ffp = tot_diff_feather_points ? &diff_feather_points[0][1] : NULL;
							asp = (float)height / (float)width;
						}

						for (i = 0; i < tot_diff_point; i++, fp += 2) {
							(*fp) = (((*fp) - 0.5f) / asp) + 0.5f;
						}

						if (tot_diff_feather_points) {
							for (i = 0; i < tot_diff_feather_points; i++, ffp += 2) {
								(*ffp) = (((*ffp) - 0.5f) / asp) + 0.5f;
							}
						}
					}
				}

				/* fake aa, using small feather */
				if (do_mask_aa == TRUE) {
					if (do_feather == FALSE) {
						tot_diff_feather_points = tot_diff_point;
						diff_feather_points = MEM_mallocN(sizeof(*diff_feather_points) *
						                                  (size_t)tot_diff_feather_points,
						                                  __func__);
						/* add single pixel feather */
						maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points,
						                                               tot_diff_point, pixel_size, FALSE);
					}
					else {
						/* ensure single pixel feather, on any zero feather areas */
						maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points,
						                                               tot_diff_point, pixel_size, TRUE);
					}
				}

				if (is_fill) {
					/* applt intersections depending on fill settings */
					if (spline->flag & MASK_SPLINE_NOINTERSECT) {
						BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points, tot_diff_feather_points);
					}

					copy_v2_v2(co, diff_points[0]);
					sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co);
					sf_vert_prev->tmp.u = sf_vert_tot;
					sf_vert_prev->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
					sf_vert_tot++;

					/* TODO, an alternate functions so we can avoid double vector copy! */
					for (j = 1; j < tot_diff_point; j++) {
						copy_v2_v2(co, diff_points[j]);
						sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
						sf_vert->tmp.u = sf_vert_tot;
						sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
						sf_vert_tot++;
					}

					sf_vert = sf_vert_prev;
					sf_vert_prev = sf_ctx.fillvertbase.last;

					for (j = 0; j < tot_diff_point; j++) {
						ScanFillEdge *sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_prev, sf_vert);

#ifdef USE_SCANFILL_EDGE_WORKAROUND
						if (diff_feather_points) {
							sf_edge->tmp.c = SF_EDGE_IS_BOUNDARY;
							tot_boundary_used++;
						}
#else
						(void)sf_edge;
#endif
						sf_vert_prev = sf_vert;
						sf_vert = sf_vert->next;
					}

					if (diff_feather_points) {
						float co_feather[3];
						co_feather[2] = 1.0f;

						BLI_assert(tot_diff_feather_points == tot_diff_point);

						/* note: only added for convenience, we don't infact use these to scanfill,
						 * only to create feather faces after scanfill */
						for (j = 0; j < tot_diff_feather_points; j++) {
							copy_v2_v2(co_feather, diff_feather_points[j]);
							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);

							/* no need for these attrs */
#if 0
							sf_vert->tmp.u = sf_vert_tot;
							sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
#endif
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
							sf_vert_tot++;
						}

						tot_feather_quads += tot_diff_point;
					}
				}
				else {
					/* unfilled spline */
					if (diff_feather_points) {

						float co_diff[2];

						float co_feather[3];
						co_feather[2] = 1.0f;

						if (spline->flag & MASK_SPLINE_NOINTERSECT) {
							diff_feather_points_flip = MEM_mallocN(sizeof(float) * 2 * tot_diff_feather_points, "diff_feather_points_flip");

							for (j = 0; j < tot_diff_point; j++) {
								sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]);
								add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff);
							}

							BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points,      tot_diff_feather_points);
							BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points_flip, tot_diff_feather_points);
						}
						else {
							diff_feather_points_flip = NULL;
						}


						open_spline_ranges[open_spline_index].vertex_offset = sf_vert_tot;
						open_spline_ranges[open_spline_index].vertex_total = tot_diff_point;

						/* TODO, an alternate functions so we can avoid double vector copy! */
						for (j = 0; j < tot_diff_point; j++) {

							/* center vert */
							copy_v2_v2(co, diff_points[j]);
							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
							sf_vert->tmp.u = sf_vert_tot;
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
							sf_vert_tot++;


							/* feather vert A */
							copy_v2_v2(co_feather, diff_feather_points[j]);
							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
							sf_vert->tmp.u = sf_vert_tot;
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
							sf_vert_tot++;


							/* feather vert B */
							if (diff_feather_points_flip) {
								copy_v2_v2(co_feather, diff_feather_points_flip[j]);
							}
							else {
								sub_v2_v2v2(co_diff, co, co_feather);
								add_v2_v2v2(co_feather, co, co_diff);
							}

							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
							sf_vert->tmp.u = sf_vert_tot;
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
							sf_vert_tot++;

							tot_feather_quads += 2;
						}

						if (!is_cyclic) {
							tot_feather_quads -= 2;
						}

						if (diff_feather_points_flip) {
							MEM_freeN(diff_feather_points_flip);
							diff_feather_points_flip = NULL;
						}

						/* cap ends */

						/* dummy init value */
						open_spline_ranges[open_spline_index].vertex_total_cap_head = 0;
						open_spline_ranges[open_spline_index].vertex_total_cap_tail = 0;

						if (!is_cyclic) {
							float *fp_cent;
							float *fp_turn;

							unsigned int k;

							fp_cent = diff_points[0];
							fp_turn = diff_feather_points[0];

#define CALC_CAP_RESOL                                                                      \
	clampis_uint((unsigned int )(len_v2v2(fp_cent, fp_turn) /                               \
	                             (pixel_size * SPLINE_RESOL_CAP_PER_PIXEL)),                \
	             SPLINE_RESOL_CAP_MIN, SPLINE_RESOL_CAP_MAX)

							{
								const unsigned int vertex_total_cap = CALC_CAP_RESOL;

								for (k = 1; k < vertex_total_cap; k++) {
									const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
									rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy);

									sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
									sf_vert->tmp.u = sf_vert_tot;
									sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
									sf_vert_tot++;
								}
								tot_feather_quads += vertex_total_cap;

								open_spline_ranges[open_spline_index].vertex_total_cap_head = vertex_total_cap;
							}

							fp_cent = diff_points[tot_diff_point - 1];
							fp_turn = diff_feather_points[tot_diff_point - 1];

							{
								const unsigned int vertex_total_cap = CALC_CAP_RESOL;

								for (k = 1; k < vertex_total_cap; k++) {
									const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
									rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy);

									sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
									sf_vert->tmp.u = sf_vert_tot;
									sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
									sf_vert_tot++;
								}
								tot_feather_quads += vertex_total_cap;

								open_spline_ranges[open_spline_index].vertex_total_cap_tail = vertex_total_cap;
							}
						}

						open_spline_ranges[open_spline_index].is_cyclic = is_cyclic;
						open_spline_index++;

#undef CALC_CAP_RESOL
						/* end capping */

					}
				}
			}

			if (diff_points) {
				MEM_freeN(diff_points);
			}

			if (diff_feather_points) {
				MEM_freeN(diff_feather_points);
			}
		}

		{
			unsigned int (*face_array)[4], *face;  /* access coords */
			float        (*face_coords)[3], *cos; /* xy, z 0-1 (1.0 == filled) */
			unsigned int sf_tri_tot;
			rctf bounds;
			unsigned int face_index;
			int scanfill_flag = 0;

			bool is_isect = false;
			ListBase isect_remvertbase = {NULL, NULL};
			ListBase isect_remedgebase = {NULL, NULL};

			/* now we have all the splines */
			face_coords = MEM_mallocN((sizeof(float) * 3) * sf_vert_tot, "maskrast_face_coords");

			/* init bounds */
			BLI_rctf_init_minmax(&bounds);

			/* coords */
			cos = (float *)face_coords;
			for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert_next) {
				sf_vert_next = sf_vert->next;
				copy_v3_v3(cos, sf_vert->co);

				/* remove so as not to interfere with fill (called after) */
				if (sf_vert->keyindex == SF_KEYINDEX_TEMP_ID) {
					BLI_remlink(&sf_ctx.fillvertbase, sf_vert);
				}

				/* bounds */
				BLI_rctf_do_minmax_v(&bounds, cos);

				cos += 3;
			}


			/* --- inefficient self-intersect case --- */
			/* if self intersections are found, its too trickty to attempt to map vertices
			 * so just realloc and add entirely new vertices - the result of the self-intersect check
			 */
			if ((masklay->flag & MASK_LAYERFLAG_FILL_OVERLAP) &&
			    (is_isect = BLI_scanfill_calc_self_isect(&sf_ctx,
			                                             &isect_remvertbase,
			                                             &isect_remedgebase)))
			{
				unsigned int sf_vert_tot_isect = (unsigned int)BLI_countlist(&sf_ctx.fillvertbase);
				unsigned int i = sf_vert_tot;

				face_coords = MEM_reallocN(face_coords, sizeof(float[3]) * (sf_vert_tot + sf_vert_tot_isect));

				cos = (float *)&face_coords[sf_vert_tot][0];

				for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) {
					copy_v3_v3(cos, sf_vert->co);
					sf_vert->tmp.u = i++;
					cos += 3;
				}

				sf_vert_tot += sf_vert_tot_isect;

				/* we need to calc polys after self intersect */
				scanfill_flag |= BLI_SCANFILL_CALC_POLYS;
			}
			/* --- end inefficient code --- */


			/* main scan-fill */
			if ((masklay->flag & MASK_LAYERFLAG_FILL_DISCRETE) == 0)
				scanfill_flag |= BLI_SCANFILL_CALC_HOLES;

			sf_tri_tot = (unsigned int)BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, zvec);

			if (is_isect) {
				/* add removed data back, we only need edges for feather,
				 * but add verts back so they get freed along with others */
				BLI_movelisttolist(&sf_ctx.fillvertbase, &isect_remvertbase);
				BLI_movelisttolist(&sf_ctx.filledgebase, &isect_remedgebase);
			}

			face_array = MEM_mallocN(sizeof(*face_array) * ((size_t)sf_tri_tot + (size_t)tot_feather_quads), "maskrast_face_index");
			face_index = 0;

			/* faces */
			face = (unsigned int *)face_array;
			for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
				*(face++) = sf_tri->v3->tmp.u;
				*(face++) = sf_tri->v2->tmp.u;
				*(face++) = sf_tri->v1->tmp.u;
				*(face++) = TRI_VERT;
				face_index++;
				FACE_ASSERT(face - 4, sf_vert_tot);
			}

			/* start of feather faces... if we have this set,
			 * 'face_index' is kept from loop above */

			BLI_assert(face_index == sf_tri_tot);

			if (tot_feather_quads) {
				ScanFillEdge *sf_edge;

				for (sf_edge = sf_ctx.filledgebase.first; sf_edge; sf_edge = sf_edge->next) {
					if (sf_edge->tmp.c == SF_EDGE_IS_BOUNDARY) {
						*(face++) = sf_edge->v1->tmp.u;
						*(face++) = sf_edge->v2->tmp.u;
						*(face++) = sf_edge->v2->keyindex;
						*(face++) = sf_edge->v1->keyindex;
						face_index++;
						FACE_ASSERT(face - 4, sf_vert_tot);

#ifdef USE_SCANFILL_EDGE_WORKAROUND
						tot_boundary_found++;
#endif
					}
				}
			}

#ifdef USE_SCANFILL_EDGE_WORKAROUND
			if (tot_boundary_found != tot_boundary_used) {
				BLI_assert(tot_boundary_found < tot_boundary_used);
			}
#endif

			/* feather only splines */
			while (open_spline_index > 0) {
				const unsigned int vertex_offset         = open_spline_ranges[--open_spline_index].vertex_offset;
				unsigned int       vertex_total          = open_spline_ranges[  open_spline_index].vertex_total;
				unsigned int       vertex_total_cap_head = open_spline_ranges[  open_spline_index].vertex_total_cap_head;
				unsigned int       vertex_total_cap_tail = open_spline_ranges[  open_spline_index].vertex_total_cap_tail;
				unsigned int k, j;

				j = vertex_offset;

				/* subtract one since we reference next vertex triple */
				for (k = 0; k < vertex_total - 1; k++, j += 3) {

					BLI_assert(j == vertex_offset + (k * 3));

					*(face++) = j + 3; /* next span */ /* z 1 */
					*(face++) = j + 0;                 /* z 1 */
					*(face++) = j + 1;                 /* z 0 */
					*(face++) = j + 4; /* next span */ /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);

					*(face++) = j + 0;                 /* z 1 */
					*(face++) = j + 3; /* next span */ /* z 1 */
					*(face++) = j + 5; /* next span */ /* z 0 */
					*(face++) = j + 2;                 /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);
				}

				if (open_spline_ranges[open_spline_index].is_cyclic) {
					*(face++) = vertex_offset + 0; /* next span */ /* z 1 */
					*(face++) = j             + 0;                 /* z 1 */
					*(face++) = j             + 1;                 /* z 0 */
					*(face++) = vertex_offset + 1; /* next span */ /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);

					*(face++) = j          + 0;                    /* z 1 */
					*(face++) = vertex_offset + 0; /* next span */ /* z 1 */
					*(face++) = vertex_offset + 2; /* next span */ /* z 0 */
					*(face++) = j          + 2;                    /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);
				}
				else {
					unsigned int midvidx = vertex_offset;

					/***************
					 * cap end 'a' */
					j = midvidx + (vertex_total * 3);

					for (k = 0; k < vertex_total_cap_head - 2; k++, j++) {
						*(face++) = midvidx + 0;  /* z 1 */
						*(face++) = midvidx + 0;  /* z 1 */
						*(face++) = j + 0;        /* z 0 */
						*(face++) = j + 1;        /* z 0 */
						face_index++;
						FACE_ASSERT(face - 4, sf_vert_tot);
					}

					j = vertex_offset + (vertex_total * 3);

					/* 2 tris that join the original */
					*(face++) = midvidx + 0;  /* z 1 */
					*(face++) = midvidx + 0;  /* z 1 */
					*(face++) = midvidx + 1;  /* z 0 */
					*(face++) = j + 0;        /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);

					*(face++) = midvidx + 0;                    /* z 1 */
					*(face++) = midvidx + 0;                    /* z 1 */
					*(face++) = j + vertex_total_cap_head - 2;  /* z 0 */
					*(face++) = midvidx + 2;                    /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);


					/***************
					 * cap end 'b' */
					/* ... same as previous but v 2-3 flipped, and different initial offsets */

					j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1);

					midvidx = vertex_offset + (vertex_total * 3) - 3;

					for (k = 0; k < vertex_total_cap_tail - 2; k++, j++) {
						*(face++) = midvidx;  /* z 1 */
						*(face++) = midvidx;  /* z 1 */
						*(face++) = j + 1;    /* z 0 */
						*(face++) = j + 0;    /* z 0 */
						face_index++;
						FACE_ASSERT(face - 4, sf_vert_tot);
					}

					j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1);

					/* 2 tris that join the original */
					*(face++) = midvidx + 0;  /* z 1 */
					*(face++) = midvidx + 0;  /* z 1 */
					*(face++) = j + 0;        /* z 0 */
					*(face++) = midvidx + 1;  /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);

					*(face++) = midvidx + 0;                    /* z 1 */
					*(face++) = midvidx + 0;                    /* z 1 */
					*(face++) = midvidx + 2;                    /* z 0 */
					*(face++) = j + vertex_total_cap_tail - 2;  /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);

				}
			}

			MEM_freeN(open_spline_ranges);

//			fprintf(stderr, "%u %u (%u %u), %u\n", face_index, sf_tri_tot + tot_feather_quads, sf_tri_tot, tot_feather_quads, tot_boundary_used - tot_boundary_found);

#ifdef USE_SCANFILL_EDGE_WORKAROUND
			BLI_assert(face_index + (tot_boundary_used - tot_boundary_found) == sf_tri_tot + tot_feather_quads);
#else
			BLI_assert(face_index == sf_tri_tot + tot_feather_quads);
#endif
			{
				MaskRasterLayer *layer = &mr_handle->layers[masklay_index];

				if (BLI_rctf_isect(&default_bounds, &bounds, &bounds)) {
#ifdef USE_SCANFILL_EDGE_WORKAROUND
					layer->face_tot = (sf_tri_tot + tot_feather_quads) - (tot_boundary_used - tot_boundary_found);
#else
					layer->face_tot = (sf_tri_tot + tot_feather_quads);
#endif
					layer->face_coords = face_coords;
					layer->face_array  = face_array;
					layer->bounds = bounds;

					layer_bucket_init(layer, pixel_size);

					BLI_rctf_union(&mr_handle->bounds, &bounds);
				}
				else {
					MEM_freeN(face_coords);
					MEM_freeN(face_array);

					layer_bucket_init_dummy(layer);
				}

				/* copy as-is */
				layer->alpha = masklay->alpha;
				layer->blend = masklay->blend;
				layer->blend_flag = masklay->blend_flag;
				layer->falloff = masklay->falloff;
			}

			/* printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads); */
		}

		/* add trianges */
		BLI_scanfill_end_arena(&sf_ctx, sf_arena);
	}

	BLI_memarena_free(sf_arena);
}