static void rna_MaskSpline_points_add(ID *id, MaskSpline *spline, int count) { Mask *mask = (Mask *) id; MaskLayer *layer; int active_point_index = -1; int i, spline_shape_index; if (count <= 0) { return; } for (layer = mask->masklayers.first; layer; layer = layer->next) { if (BLI_findindex(&layer->splines, spline) != -1) { break; } } if (!layer) { /* Shall not happen actually */ BLI_assert(!"No layer found for the spline"); return; } if (layer->act_spline == spline) { active_point_index = layer->act_point - spline->points; } spline->points = MEM_recallocN(spline->points, sizeof(MaskSplinePoint) * (spline->tot_point + count)); spline->tot_point += count; if (active_point_index >= 0) { layer->act_point = spline->points + active_point_index; } spline_shape_index = BKE_mask_layer_shape_spline_to_index(layer, spline); for (i = 0; i < count; i++) { int point_index = spline->tot_point - count + i; MaskSplinePoint *new_point = spline->points + point_index; new_point->bezt.h1 = new_point->bezt.h2 = HD_ALIGN; BKE_mask_calc_handle_point_auto(spline, new_point, TRUE); BKE_mask_parent_init(&new_point->parent); /* Not efficient, but there's no other way for now */ BKE_mask_layer_shape_changed_add(layer, spline_shape_index + point_index, true, true); } WM_main_add_notifier(NC_MASK | ND_DATA, mask); DAG_id_tag_update(&mask->id, 0); }
/* *** recalc normals *** */ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); Mask *mask = CTX_data_edit_mask(C); MaskLayer *masklay; int i; bool changed = false; /* do actual selection */ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; bool changed_layer = false; 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)) { BKE_mask_calc_handle_point_auto(spline, point, FALSE); changed = true; changed_layer = true; } } } if (changed_layer) { if (IS_AUTOKEY_ON(scene)) { ED_mask_layer_shape_auto_key(masklay, CFRA); } } } if (changed) { /* TODO: only update this spline */ BKE_mask_update_display(mask, CFRA); WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask); WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; }
static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2]) { MaskSpline *spline; MaskSplinePoint *point; MaskSplinePoint *new_point = NULL, *ref_point = NULL; /* check on which side we want to add the point */ int point_index; float tangent_point[2]; float tangent_co[2]; int do_cyclic_correct = FALSE; int do_recalc_src = FALSE; /* when extruding from endpoints only */ int do_prev; /* use prev point rather then next?? */ if (!masklay) { return FALSE; } else { finSelectedSplinePoint(masklay, &spline, &point, TRUE); } ED_mask_select_toggle_all(mask, SEL_DESELECT); point_index = (point - spline->points); MASKPOINT_DESEL_ALL(point); if ((spline->flag & MASK_SPLINE_CYCLIC) || (point_index > 0 && point_index != spline->tot_point - 1)) { BKE_mask_calc_tangent_polyline(spline, point, tangent_point); sub_v2_v2v2(tangent_co, co, point->bezt.vec[1]); if (dot_v2v2(tangent_point, tangent_co) < 0.0f) { do_prev = TRUE; } else { do_prev = FALSE; } } else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == 0)) { do_prev = TRUE; do_recalc_src = TRUE; } else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) { do_prev = FALSE; do_recalc_src = TRUE; } else { do_prev = FALSE; /* quiet warning */ /* should never get here */ BLI_assert(0); } /* use the point before the active one */ if (do_prev) { point_index--; if (point_index < 0) { point_index += spline->tot_point; /* wrap index */ if ((spline->flag & MASK_SPLINE_CYCLIC) == 0) { do_cyclic_correct = TRUE; point_index = 0; } } } // print_v2("", tangent_point); // printf("%d\n", point_index); mask_spline_add_point_at_index(spline, point_index); if (do_cyclic_correct) { ref_point = &spline->points[point_index + 1]; new_point = &spline->points[point_index]; *ref_point = *new_point; memset(new_point, 0, sizeof(*new_point)); } else { ref_point = &spline->points[point_index]; new_point = &spline->points[point_index + 1]; } masklay->act_point = new_point; setup_vertex_point(mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, 1.0f); if (masklay->splines_shapes.first) { point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point); BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, TRUE, TRUE); } if (do_recalc_src) { /* TODO, update keyframes in time */ BKE_mask_calc_handle_point_auto(spline, ref_point, FALSE); } WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); return TRUE; }
static int add_vertex_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Mask *mask = CTX_data_edit_mask(C); MaskLayer *masklay; float co[2]; if (mask == NULL) { /* if there's no active mask, create one */ mask = ED_mask_new(C, NULL); } masklay = BKE_mask_layer_active(mask); if (masklay && masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) { masklay = NULL; } RNA_float_get_array(op->ptr, "location", co); /* TODO, having an active point but no active spline is possible, why? */ if (masklay && masklay->act_spline && masklay->act_point && MASKPOINT_ISSEL_ANY(masklay->act_point)) { /* cheap trick - double click for cyclic */ MaskSpline *spline = masklay->act_spline; MaskSplinePoint *point = masklay->act_point; const bool is_sta = (point == spline->points); const bool is_end = (point == &spline->points[spline->tot_point - 1]); /* then check are we overlapping the mouse */ if ((is_sta || is_end) && equals_v2v2(co, point->bezt.vec[1])) { if (spline->flag & MASK_SPLINE_CYCLIC) { /* nothing to do */ return OPERATOR_CANCELLED; } else { /* recalc the connecting point as well to make a nice even curve */ MaskSplinePoint *point_other = is_end ? spline->points : &spline->points[spline->tot_point - 1]; spline->flag |= MASK_SPLINE_CYCLIC; /* TODO, update keyframes in time */ BKE_mask_calc_handle_point_auto(spline, point, false); BKE_mask_calc_handle_point_auto(spline, point_other, false); /* TODO: only update this spline */ BKE_mask_update_display(mask, CFRA); WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); return OPERATOR_FINISHED; } } if (!add_vertex_subdivide(C, mask, co)) { if (!add_vertex_extrude(C, mask, masklay, co)) { return OPERATOR_CANCELLED; } } } else { if (!add_vertex_subdivide(C, mask, co)) { if (!add_vertex_new(C, mask, masklay, co)) { return OPERATOR_CANCELLED; } } } /* TODO: only update this spline */ BKE_mask_update_display(mask, CFRA); return OPERATOR_FINISHED; }
static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point, const float point_co[2], const float tangent[2], const float u, MaskSplinePoint *reference_point, const short reference_adjacent, const float view_zoom) { MaskSplinePoint *prev_point = NULL; MaskSplinePoint *next_point = NULL; BezTriple *bezt; float co[3]; const float len = 10.0; /* default length of handle in pixel space */ copy_v2_v2(co, point_co); co[2] = 0.0f; /* point coordinate */ bezt = &new_point->bezt; bezt->h1 = bezt->h2 = HD_ALIGN; if (reference_point) { bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1); } else if (reference_adjacent) { if (spline->tot_point != 1) { int index = (int)(new_point - spline->points); prev_point = &spline->points[(index - 1) % spline->tot_point]; next_point = &spline->points[(index + 1) % spline->tot_point]; bezt->h1 = bezt->h2 = MAX2(prev_point->bezt.h2, next_point->bezt.h1); /* note, we may want to copy other attributes later, radius? pressure? color? */ } } copy_v3_v3(bezt->vec[0], co); copy_v3_v3(bezt->vec[1], co); copy_v3_v3(bezt->vec[2], co); /* initial offset for handles */ if (spline->tot_point == 1) { /* first point of splien is aligned horizontally */ bezt->vec[0][0] -= len * view_zoom; bezt->vec[2][0] += len * view_zoom; } else if (tangent) { float vec[2]; copy_v2_v2(vec, tangent); mul_v2_fl(vec, len); sub_v2_v2(bezt->vec[0], vec); add_v2_v2(bezt->vec[2], vec); if (reference_adjacent) { BKE_mask_calc_handle_adjacent_interp(spline, new_point, u); } } else { /* calculating auto handles works much nicer */ #if 0 /* next points are aligning in the direction of previous/next point */ MaskSplinePoint *point; float v1[2], v2[2], vec[2]; float dir = 1.0f; if (new_point == spline->points) { point = new_point + 1; dir = -1.0f; } else point = new_point - 1; if (spline->tot_point < 3) { v1[0] = point->bezt.vec[1][0] * width; v1[1] = point->bezt.vec[1][1] * height; v2[0] = new_point->bezt.vec[1][0] * width; v2[1] = new_point->bezt.vec[1][1] * height; } else { if (new_point == spline->points) { v1[0] = spline->points[1].bezt.vec[1][0] * width; v1[1] = spline->points[1].bezt.vec[1][1] * height; v2[0] = spline->points[spline->tot_point - 1].bezt.vec[1][0] * width; v2[1] = spline->points[spline->tot_point - 1].bezt.vec[1][1] * height; } else { v1[0] = spline->points[0].bezt.vec[1][0] * width; v1[1] = spline->points[0].bezt.vec[1][1] * height; v2[0] = spline->points[spline->tot_point - 2].bezt.vec[1][0] * width; v2[1] = spline->points[spline->tot_point - 2].bezt.vec[1][1] * height; } } sub_v2_v2v2(vec, v1, v2); mul_v2_fl(vec, len * dir / len_v2(vec)); vec[0] /= width; vec[1] /= height; add_v2_v2(bezt->vec[0], vec); sub_v2_v2(bezt->vec[2], vec); #else BKE_mask_calc_handle_point_auto(spline, new_point, TRUE); BKE_mask_calc_handle_adjacent_interp(spline, new_point, u); #endif } BKE_mask_parent_init(&new_point->parent); /* select new point */ MASKPOINT_SEL_ALL(new_point); ED_mask_select_flush_all(mask); }