This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/mask/mask_add.c

849 lines
22 KiB
C
Raw Normal View History

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2012 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation,
* Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/mask/mask_add.c
* \ingroup edmask
*/
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_mask.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_mask_types.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_mask.h" /* own include */
#include "ED_screen.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "mask_intern.h" /* own include */
bool ED_mask_find_nearest_diff_point(const bContext *C,
struct Mask *mask,
const float normal_co[2],
int threshold, bool feather,
float tangent[2],
const bool use_deform,
const bool use_project,
MaskLayer **masklay_r,
MaskSpline **spline_r,
MaskSplinePoint **point_r,
float *u_r,
float *score_r)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
MaskLayer *masklay, *point_masklay;
MaskSpline *point_spline;
MaskSplinePoint *point = NULL;
2012-09-18 03:15:12 +00:00
float dist = FLT_MAX, co[2];
int width, height;
float u;
2012-07-31 17:24:55 +00:00
float scalex, scaley;
ED_mask_get_size(sa, &width, &height);
ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
co[0] = normal_co[0] * scalex;
co[1] = normal_co[1] * scaley;
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
for (spline = masklay->splines.first; spline; spline = spline->next) {
int i;
MaskSplinePoint *cur_point;
for (i = 0, cur_point = use_deform ? spline->points_deform : spline->points;
i < spline->tot_point;
i++, cur_point++)
{
float *diff_points;
unsigned int tot_diff_point;
diff_points = BKE_mask_point_segment_diff(spline, cur_point, width, height,
&tot_diff_point);
if (diff_points) {
2012-10-12 14:35:10 +00:00
int j, tot_point;
unsigned int tot_feather_point;
float *feather_points = NULL, *points;
if (feather) {
feather_points = BKE_mask_point_segment_feather_diff(spline, cur_point,
width, height,
&tot_feather_point);
points = feather_points;
tot_point = tot_feather_point;
}
else {
points = diff_points;
tot_point = tot_diff_point;
}
2012-10-12 14:35:10 +00:00
for (j = 0; j < tot_point - 1; j++) {
float cur_dist, a[2], b[2];
2012-10-12 14:35:10 +00:00
a[0] = points[2 * j] * scalex;
a[1] = points[2 * j + 1] * scaley;
2012-10-12 14:35:10 +00:00
b[0] = points[2 * j + 2] * scalex;
b[1] = points[2 * j + 3] * scaley;
cur_dist = dist_to_line_segment_v2(co, a, b);
2012-09-18 03:15:12 +00:00
if (cur_dist < dist) {
if (tangent)
2012-10-12 14:35:10 +00:00
sub_v2_v2v2(tangent, &diff_points[2 * j + 2], &diff_points[2 * j]);
point_masklay = masklay;
point_spline = spline;
point = use_deform ? &spline->points[(cur_point - spline->points_deform)] : cur_point;
dist = cur_dist;
2012-10-12 14:35:10 +00:00
u = (float)j / tot_point;
}
}
if (feather_points)
MEM_freeN(feather_points);
MEM_freeN(diff_points);
}
}
}
}
if (point && dist < threshold) {
if (masklay_r)
*masklay_r = point_masklay;
if (spline_r)
*spline_r = point_spline;
if (point_r)
*point_r = point;
if (u_r) {
/* TODO(sergey): Projection fails in some weirdo cases.. */
if (use_project) {
u = BKE_mask_spline_project_co(point_spline, point, u, normal_co, MASK_PROJ_ANY);
}
*u_r = u;
}
if (score_r) {
*score_r = dist;
}
return true;
}
if (masklay_r)
*masklay_r = NULL;
if (spline_r)
*spline_r = NULL;
if (point_r)
*point_r = NULL;
return false;
}
/******************** add vertex *********************/
static void setup_vertex_point(Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point,
Implement asymmetric and free handles type for masks Summary: The title actually says it all, it's just possible to have independent free handles for mask splines. Also it's now possible to have aligned handles displayed as independent handles. Required changes in quite a few places, but they're rather straightforward. From user perspective there's one really visible change which is removed Handle Type menu from the panel. With asymmetric handles it's not clear which handle type to display there. So now the only way to change handle type is via V-key menu. Rewrote normal evaluation function to make it deal with new type of handles we support. Now it works in the following way: - Offset the original spline by maximal weight - Calculate vector between corresponding U positions on offset and original spline - Normalize this vector. Seems to be giving more adequate results and doesn't tend to self-intersect as much as old behavior used to, There're still some changes which needed to be done, but which are planned for further patch: - Support colors and handle size via themes. - Make handles color-coded, just the same as done for regular bezier splines in 3D viewport. Additional changes to make roto workflow even better: - Use circles to draw handles - Support AA for handles - Change click-create-drag to change curvature of the spline instead of adjusting point position. Reviewers: campbellbarton CC: sebastian_k, hype, cronk Differential Revision: http://developer.blender.org/D121
2013-10-30 10:38:45 +01:00
const float point_co[2], const float u,
MaskSplinePoint *reference_point, const bool reference_adjacent)
{
MaskSplinePoint *prev_point = NULL;
MaskSplinePoint *next_point = NULL;
BezTriple *bezt;
float co[3];
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) {
Implement asymmetric and free handles type for masks Summary: The title actually says it all, it's just possible to have independent free handles for mask splines. Also it's now possible to have aligned handles displayed as independent handles. Required changes in quite a few places, but they're rather straightforward. From user perspective there's one really visible change which is removed Handle Type menu from the panel. With asymmetric handles it's not clear which handle type to display there. So now the only way to change handle type is via V-key menu. Rewrote normal evaluation function to make it deal with new type of handles we support. Now it works in the following way: - Offset the original spline by maximal weight - Calculate vector between corresponding U positions on offset and original spline - Normalize this vector. Seems to be giving more adequate results and doesn't tend to self-intersect as much as old behavior used to, There're still some changes which needed to be done, but which are planned for further patch: - Support colors and handle size via themes. - Make handles color-coded, just the same as done for regular bezier splines in 3D viewport. Additional changes to make roto workflow even better: - Use circles to draw handles - Support AA for handles - Change click-create-drag to change curvature of the spline instead of adjusting point position. Reviewers: campbellbarton CC: sebastian_k, hype, cronk Differential Revision: http://developer.blender.org/D121
2013-10-30 10:38:45 +01:00
if (reference_point->bezt.h1 == HD_VECT && reference_point->bezt.h2 == HD_VECT) {
/* If the reference point is sharp try using some smooth point as reference
* for handles.
*/
int point_index = reference_point - spline->points;
int delta = new_point == spline->points ? 1 : -1;
int i = 0;
for (i = 0; i < spline->tot_point - 1; ++i) {
MaskSplinePoint *current_point;
point_index += delta;
if (point_index == -1 || point_index >= spline->tot_point) {
if (spline->flag & MASK_SPLINE_CYCLIC) {
if (point_index == -1) {
point_index = spline->tot_point - 1;
}
else if (point_index >= spline->tot_point) {
point_index = 0;
}
}
else {
break;
}
}
current_point = &spline->points[point_index];
if (current_point->bezt.h1 != HD_VECT || current_point->bezt.h2 != HD_VECT) {
bezt->h1 = bezt->h2 = MAX2(current_point->bezt.h2, current_point->bezt.h1);
break;
}
}
}
else {
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);
Implement asymmetric and free handles type for masks Summary: The title actually says it all, it's just possible to have independent free handles for mask splines. Also it's now possible to have aligned handles displayed as independent handles. Required changes in quite a few places, but they're rather straightforward. From user perspective there's one really visible change which is removed Handle Type menu from the panel. With asymmetric handles it's not clear which handle type to display there. So now the only way to change handle type is via V-key menu. Rewrote normal evaluation function to make it deal with new type of handles we support. Now it works in the following way: - Offset the original spline by maximal weight - Calculate vector between corresponding U positions on offset and original spline - Normalize this vector. Seems to be giving more adequate results and doesn't tend to self-intersect as much as old behavior used to, There're still some changes which needed to be done, but which are planned for further patch: - Support colors and handle size via themes. - Make handles color-coded, just the same as done for regular bezier splines in 3D viewport. Additional changes to make roto workflow even better: - Use circles to draw handles - Support AA for handles - Change click-create-drag to change curvature of the spline instead of adjusting point position. Reviewers: campbellbarton CC: sebastian_k, hype, cronk Differential Revision: http://developer.blender.org/D121
2013-10-30 10:38:45 +01:00
BKE_mask_parent_init(&new_point->parent);
if (spline->tot_point != 1) {
2012-06-06 20:05:58 +00:00
BKE_mask_calc_handle_adjacent_interp(spline, new_point, u);
}
/* select new point */
MASKPOINT_SEL_ALL(new_point);
ED_mask_select_flush_all(mask);
}
/* **** add extrude vertex **** */
static void finSelectedSplinePoint(MaskLayer *masklay, MaskSpline **spline, MaskSplinePoint **point, bool check_active)
{
MaskSpline *cur_spline = masklay->splines.first;
*spline = NULL;
*point = NULL;
if (check_active) {
/* TODO, having an active point but no active spline is possible, why? */
if (masklay->act_spline && masklay->act_point && MASKPOINT_ISSEL_ANY(masklay->act_point)) {
*spline = masklay->act_spline;
*point = masklay->act_point;
return;
}
}
while (cur_spline) {
int i;
for (i = 0; i < cur_spline->tot_point; i++) {
MaskSplinePoint *cur_point = &cur_spline->points[i];
if (MASKPOINT_ISSEL_ANY(cur_point)) {
if (*spline != NULL && *spline != cur_spline) {
*spline = NULL;
*point = NULL;
return;
}
else if (*point) {
*point = NULL;
}
else {
*spline = cur_spline;
*point = cur_point;
}
}
}
cur_spline = cur_spline->next;
}
}
/* **** add subdivide vertex **** */
static void mask_spline_add_point_at_index(MaskSpline *spline, int point_index)
{
MaskSplinePoint *new_point_array;
new_point_array = MEM_callocN(sizeof(MaskSplinePoint) * (spline->tot_point + 1), "add mask vert points");
memcpy(new_point_array, spline->points, sizeof(MaskSplinePoint) * (point_index + 1));
memcpy(new_point_array + point_index + 2, spline->points + point_index + 1,
sizeof(MaskSplinePoint) * (spline->tot_point - point_index - 1));
MEM_freeN(spline->points);
spline->points = new_point_array;
spline->tot_point++;
}
static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2])
{
MaskLayer *masklay;
MaskSpline *spline;
MaskSplinePoint *point = NULL;
const float threshold = 9;
float tangent[2];
float u;
if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, false, tangent, true, true,
&masklay, &spline, &point, &u, NULL))
{
MaskSplinePoint *new_point;
int point_index = point - spline->points;
ED_mask_select_toggle_all(mask, SEL_DESELECT);
mask_spline_add_point_at_index(spline, point_index);
new_point = &spline->points[point_index + 1];
setup_vertex_point(mask, spline, new_point, co, u, NULL, true);
/* TODO - we could pass the spline! */
BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index + 1, true, true);
masklay->act_spline = spline;
masklay->act_point = new_point;
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
return true;
}
return false;
}
static bool 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];
2014-02-03 18:55:59 +11:00
bool do_cyclic_correct = false;
bool 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))
{
2012-06-06 20:05:58 +00:00
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;
}
else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) {
do_prev = false;
}
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, 0.5f, ref_point, false);
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);
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
return true;
}
static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
{
MaskSpline *spline;
MaskSplinePoint *point;
MaskSplinePoint *new_point = NULL, *ref_point = NULL;
if (!masklay) {
/* if there's no masklay currently operationg on, create new one */
masklay = BKE_mask_layer_new(mask, "");
mask->masklay_act = mask->masklay_tot - 1;
spline = NULL;
point = NULL;
}
else {
finSelectedSplinePoint(masklay, &spline, &point, true);
}
ED_mask_select_toggle_all(mask, SEL_DESELECT);
if (!spline) {
/* no selected splines in active masklay, create new spline */
spline = BKE_mask_spline_add(masklay);
}
masklay->act_spline = spline;
new_point = spline->points;
masklay->act_point = new_point;
setup_vertex_point(mask, spline, new_point, co, 0.5f, ref_point, false);
{
int 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);
}
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;
2014-02-03 18:55:59 +11:00
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 int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
float co[2];
ED_mask_mouse_pos(sa, ar, event->mval, co);
RNA_float_set_array(op->ptr, "location", co);
return add_vertex_exec(C, op);
}
void MASK_OT_add_vertex(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Vertex";
ot->description = "Add vertex to active spline";
ot->idname = "MASK_OT_add_vertex";
/* api callbacks */
ot->exec = add_vertex_exec;
ot->invoke = add_vertex_invoke;
ot->poll = ED_operator_mask;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
2012-08-07 19:49:38 +00:00
RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
"Location", "Location of vertex in normalized space", -1.0f, 1.0f);
}
/******************** add feather vertex *********************/
static int add_feather_vertex_exec(bContext *C, wmOperator *op)
{
Mask *mask = CTX_data_edit_mask(C);
MaskLayer *masklay;
MaskSpline *spline;
MaskSplinePoint *point = NULL;
const float threshold = 9;
float co[2], u;
RNA_float_get_array(op->ptr, "location", co);
point = ED_mask_point_find_nearest(C, mask, co, threshold, NULL, NULL, NULL, NULL);
if (point)
return OPERATOR_FINISHED;
if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, true, NULL, true, true,
&masklay, &spline, &point, &u, NULL))
{
Scene *scene = CTX_data_scene(C);
float w = BKE_mask_point_weight(spline, point, u);
float weight_scalar = BKE_mask_point_weight_scalar(spline, point, u);
if (weight_scalar != 0.0f) {
w = w / weight_scalar;
}
BKE_mask_point_add_uw(point, u, w);
BKE_mask_update_display(mask, scene->r.cfra);
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
DAG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
}
static int add_feather_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
float co[2];
ED_mask_mouse_pos(sa, ar, event->mval, co);
RNA_float_set_array(op->ptr, "location", co);
return add_feather_vertex_exec(C, op);
}
void MASK_OT_add_feather_vertex(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Feather Vertex";
ot->description = "Add vertex to feather";
ot->idname = "MASK_OT_add_feather_vertex";
/* api callbacks */
ot->exec = add_feather_vertex_exec;
ot->invoke = add_feather_vertex_invoke;
2012-06-04 17:30:54 +00:00
ot->poll = ED_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
2012-08-07 19:49:38 +00:00
RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
"Location", "Location of vertex in normalized space", -1.0f, 1.0f);
}
/******************** common primitive functions *********************/
static int create_primitive_from_points(bContext *C, wmOperator *op, const float (*points)[2],
int num_points, char handle_type)
{
ScrArea *sa = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
Mask *mask;
MaskLayer *mask_layer;
MaskSpline *new_spline;
float scale, location[2], frame_size[2];
int i, width, height;
int size = RNA_float_get(op->ptr, "size");
ED_mask_get_size(sa, &width, &height);
scale = (float)size / max_ii(width, height);
/* Get location in mask space. */
frame_size[0] = width;
frame_size[1] = height;
RNA_float_get_array(op->ptr, "location", location);
location[0] /= width;
location[1] /= height;
BKE_mask_coord_from_frame(location, location, frame_size);
/* Make it so new primitive is centered to mouse location. */
location[0] -= 0.5f * scale;
location[1] -= 0.5f * scale;
mask_layer = ED_mask_layer_ensure(C);
mask = CTX_data_edit_mask(C);
ED_mask_select_toggle_all(mask, SEL_DESELECT);
new_spline = BKE_mask_spline_add(mask_layer);
new_spline->flag = MASK_SPLINE_CYCLIC | SELECT;
new_spline->tot_point = num_points;
new_spline->points = MEM_recallocN(new_spline->points,
sizeof(MaskSplinePoint) * new_spline->tot_point);
mask_layer->act_spline = new_spline;
mask_layer->act_point = NULL;
for (i = 0; i < num_points; i++) {
MaskSplinePoint *new_point = &new_spline->points[i];
copy_v2_v2(new_point->bezt.vec[1], points[i]);
mul_v2_fl(new_point->bezt.vec[1], scale);
add_v2_v2(new_point->bezt.vec[1], location);
new_point->bezt.h1 = handle_type;
new_point->bezt.h2 = handle_type;
BKE_mask_point_select_set(new_point, true);
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
/* TODO: only update this spline */
BKE_mask_update_display(mask, CFRA);
return OPERATOR_FINISHED;
}
static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
ScrArea *sa = CTX_wm_area(C);
float cursor[2];
int width, height;
ED_mask_get_size(sa, &width, &height);
ED_mask_cursor_location_get(sa, cursor);
cursor[0] *= width;
cursor[1] *= height;
RNA_float_set_array(op->ptr, "location", cursor);
return op->type->exec(C, op);
}
static void define_prinitive_add_properties(wmOperatorType *ot)
{
RNA_def_float(ot->srna, "size", 100, -FLT_MAX, FLT_MAX,
"Size", "Size of new circle", -FLT_MAX, FLT_MAX);
RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
"Location", "Location of new circle", -FLT_MAX, FLT_MAX);
}
/******************** primitive add circle *********************/
static int primitive_circle_add_exec(bContext *C, wmOperator *op)
{
const float points[4][2] = {{0.0f, 0.5f},
{0.5f, 1.0f},
{1.0f, 0.5f},
{0.5f, 0.0f}};
int num_points = sizeof(points) / (2 * sizeof(float));
create_primitive_from_points(C, op, points, num_points, HD_AUTO);
return OPERATOR_FINISHED;
}
void MASK_OT_primitive_circle_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Circle";
ot->description = "Add new circle-shaped spline";
ot->idname = "MASK_OT_primitive_circle_add";
/* api callbacks */
ot->exec = primitive_circle_add_exec;
ot->invoke = primitive_add_invoke;
ot->poll = ED_operator_mask;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
define_prinitive_add_properties(ot);
}
/******************** primitive add suqare *********************/
static int primitive_square_add_exec(bContext *C, wmOperator *op)
{
const float points[4][2] = {{0.0f, 0.0f},
{0.0f, 1.0f},
{1.0f, 1.0f},
{1.0f, 0.0f}};
int num_points = sizeof(points) / (2 * sizeof(float));
create_primitive_from_points(C, op, points, num_points, HD_VECT);
return OPERATOR_FINISHED;
}
void MASK_OT_primitive_square_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Square";
ot->description = "Add new square-shaped spline";
ot->idname = "MASK_OT_primitive_square_add";
/* api callbacks */
ot->exec = primitive_square_add_exec;
ot->invoke = primitive_add_invoke;
ot->poll = ED_operator_mask;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
define_prinitive_add_properties(ot);
}