Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFalk David <falkdavid@gmx.de>2020-11-13 23:43:00 +0300
committerFalk David <falkdavid@gmx.de>2020-11-13 23:43:00 +0300
commit0be88c7d15d2ad1af284c6283370173647ae74eb (patch)
tree5fff573c512e284547ebe0c921ecffdae2c377c4 /source/blender/editors/gpencil/gpencil_edit.c
parent9d28353b525ecfbcca1501be72e4276dfb2bbc2a (diff)
GPencil: Merge GSoC curve edit mode
Differential Revision: https://developer.blender.org/D8660 This patch is the result of the GSoC 2020 "Editing Grease Pencil Strokes Using Curves" project. It adds a submode to greasepencil edit mode that allows for the transformation of greasepencil strokes using bezier curves. More information about the project can be found here: https://wiki.blender.org/wiki/User:Filedescriptor/GSoC_2020.
Diffstat (limited to 'source/blender/editors/gpencil/gpencil_edit.c')
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1588
1 files changed, 1132 insertions, 456 deletions
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 4ba75bcd604..f2c3804a067 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -52,6 +52,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_curve.h"
#include "BKE_gpencil_geom.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
@@ -145,6 +146,18 @@ static bool gpencil_editmode_toggle_poll(bContext *C)
return ED_gpencil_data_get_active(C) != NULL;
}
+static bool gpencil_stroke_not_in_curve_edit_mode(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
+
+ return (gpl != NULL && !GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd));
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -195,6 +208,22 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *op)
ob->mode = mode;
}
+ /* Recalculate editcurves for strokes where the geometry/vertex colors have changed */
+ if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
+ GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
+ {
+ if (gpc->flag & GP_CURVE_NEEDS_STROKE_UPDATE) {
+ BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
+ /* Update the selection from the stroke to the curve. */
+ BKE_gpencil_editcurve_stroke_sync_selection(gps, gps->editcurve);
+
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ }
+ }
+ GP_EDITABLE_CURVES_END(gps_iter);
+ }
+
/* setup other modes */
ED_gpencil_setup_modes(C, gpd, mode);
/* set cache as dirty */
@@ -813,7 +842,8 @@ void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot)
* \{ */
/* Make copies of selected point segments in a selected stroke */
-static void gpencil_duplicate_points(const bGPDstroke *gps,
+static void gpencil_duplicate_points(bGPdata *gpd,
+ const bGPDstroke *gps,
ListBase *new_strokes,
const char *layername)
{
@@ -853,7 +883,7 @@ static void gpencil_duplicate_points(const bGPDstroke *gps,
bGPDstroke *gpsd;
/* make a stupid copy first of the entire stroke (to get the flags too) */
- gpsd = BKE_gpencil_stroke_duplicate((bGPDstroke *)gps, false);
+ gpsd = BKE_gpencil_stroke_duplicate((bGPDstroke *)gps, false, true);
/* saves original layer name */
BLI_strncpy(gpsd->runtime.tmp_layerinfo, layername, sizeof(gpsd->runtime.tmp_layerinfo));
@@ -877,7 +907,7 @@ static void gpencil_duplicate_points(const bGPDstroke *gps,
}
}
- BKE_gpencil_stroke_geometry_update(gpsd);
+ BKE_gpencil_stroke_geometry_update(gpd, gpsd);
/* add to temp buffer */
gpsd->next = gpsd->prev = NULL;
@@ -894,6 +924,7 @@ static void gpencil_duplicate_points(const bGPDstroke *gps,
static int gpencil_duplicate_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
if (gpd == NULL) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
@@ -905,69 +936,80 @@ static int gpencil_duplicate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* for each visible (and editable) layer's selected strokes,
- * copy the strokes into a temporary buffer, then append
- * once all done
- */
- CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- ListBase new_strokes = {NULL, NULL};
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
-
- if (gpf == NULL) {
- continue;
- }
+ bool changed = false;
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ /* for each visible (and editable) layer's selected strokes,
+ * copy the strokes into a temporary buffer, then append
+ * once all done
+ */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ ListBase new_strokes = {NULL, NULL};
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
- /* make copies of selected strokes, and deselect these once we're done */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ if (gpf == NULL) {
continue;
}
- if (gps->flag & GP_STROKE_SELECT) {
- if (gps->totpoints == 1) {
- /* Special Case: If there's just a single point in this stroke... */
- bGPDstroke *gpsd;
+ /* make copies of selected strokes, and deselect these once we're done */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
- /* make direct copies of the stroke and its points */
- gpsd = BKE_gpencil_stroke_duplicate(gps, true);
+ if (gps->flag & GP_STROKE_SELECT) {
+ if (gps->totpoints == 1) {
+ /* Special Case: If there's just a single point in this stroke... */
+ bGPDstroke *gpsd;
- BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
+ /* make direct copies of the stroke and its points */
+ gpsd = BKE_gpencil_stroke_duplicate(gps, true, true);
- /* Initialize triangle information. */
- BKE_gpencil_stroke_geometry_update(gpsd);
+ BLI_strncpy(
+ gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
- /* add to temp buffer */
- gpsd->next = gpsd->prev = NULL;
- BLI_addtail(&new_strokes, gpsd);
- }
- else {
- /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
- gpencil_duplicate_points(gps, &new_strokes, gpl->info);
- }
+ /* Initialize triangle information. */
+ BKE_gpencil_stroke_geometry_update(gpd, gpsd);
- /* deselect original stroke, or else the originals get moved too
- * (when using the copy + move macro)
- */
- bGPDspoint *pt;
- int i;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
+ /* add to temp buffer */
+ gpsd->next = gpsd->prev = NULL;
+ BLI_addtail(&new_strokes, gpsd);
+ }
+ else {
+ /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
+ gpencil_duplicate_points(gpd, gps, &new_strokes, gpl->info);
+ }
+
+ /* deselect original stroke, or else the originals get moved too
+ * (when using the copy + move macro)
+ */
+ bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ gps->flag &= ~GP_STROKE_SELECT;
+
+ changed = true;
}
- gps->flag &= ~GP_STROKE_SELECT;
}
- }
- /* add all new strokes in temp buffer to the frame (preventing double-copies) */
- BLI_movelisttolist(&gpf->strokes, &new_strokes);
- BLI_assert(new_strokes.first == NULL);
+ /* add all new strokes in temp buffer to the frame (preventing double-copies) */
+ BLI_movelisttolist(&gpf->strokes, &new_strokes);
+ BLI_assert(new_strokes.first == NULL);
+ }
+ CTX_DATA_END;
}
- CTX_DATA_END;
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1028,7 +1070,7 @@ static void gpencil_copy_move_point(bGPDstroke *gps,
}
}
-static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
+static void gpencil_add_move_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps)
{
bGPDspoint *temp_points = NULL;
MDeformVert *temp_dverts = NULL;
@@ -1049,7 +1091,7 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
pt = &gps->points[i];
if (pt->flag == GP_SPOINT_SELECT) {
/* duplicate original stroke data */
- bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(gps, false);
+ bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(gps, false, true);
gps_new->prev = gps_new->next = NULL;
/* add new points array */
@@ -1067,8 +1109,8 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
gpencil_copy_move_point(gps_new, gps->points, gps->dvert, i, 0, true);
/* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gps);
- BKE_gpencil_stroke_geometry_update(gps_new);
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ BKE_gpencil_stroke_geometry_update(gpd, gps_new);
/* deselect orinal point */
pt->flag &= ~GP_SPOINT_SELECT;
@@ -1143,7 +1185,7 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
}
/* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gps);
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
MEM_SAFE_FREE(temp_points);
MEM_SAFE_FREE(temp_dverts);
@@ -1155,10 +1197,100 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
}
}
+static void gpencil_curve_extrude_points(bGPdata *gpd,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ bGPDcurve *gpc)
+{
+ const int old_num_points = gpc->tot_curve_points;
+ const bool first_select = gpc->curve_points[0].flag & GP_CURVE_POINT_SELECT;
+ bool last_select = gpc->curve_points[old_num_points - 1].flag & GP_CURVE_POINT_SELECT;
+
+ /* iterate over middle points */
+ for (int i = 1; i < gpc->tot_curve_points - 1; i++) {
+ bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
+
+ /* Create new stroke if selected point */
+ if (gpc_pt->flag & GP_CURVE_POINT_SELECT) {
+ bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(gps, false, false);
+ gps_new->points = NULL;
+ gps_new->flag &= ~GP_STROKE_CYCLIC;
+ gps_new->prev = gps_new->next = NULL;
+
+ gps_new->editcurve = BKE_gpencil_stroke_editcurve_new(2);
+ bGPDcurve *new_gpc = gps_new->editcurve;
+ for (int j = 0; j < new_gpc->tot_curve_points; j++) {
+ bGPDcurve_point *gpc_pt_new = &new_gpc->curve_points[j];
+ memcpy(gpc_pt_new, gpc_pt, sizeof(bGPDcurve_point));
+ gpc_pt_new->flag &= ~GP_CURVE_POINT_SELECT;
+ BEZT_DESEL_ALL(&gpc_pt_new->bezt);
+ }
+
+ /* select last point */
+ bGPDcurve_point *gpc_pt_last = &new_gpc->curve_points[1];
+ gpc_pt_last->flag |= GP_CURVE_POINT_SELECT;
+ BEZT_SEL_IDX(&gpc_pt_last->bezt, 1);
+ gps_new->editcurve->flag |= GP_CURVE_SELECT;
+
+ BLI_insertlinkafter(&gpf->strokes, gps, gps_new);
+
+ gps_new->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd, gps_new);
+
+ gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
+ BEZT_DESEL_ALL(&gpc_pt->bezt);
+ }
+ }
+
+ /* Edgcase for single curve point. */
+ if (gpc->tot_curve_points == 1) {
+ last_select = false;
+ }
+
+ if (first_select || last_select) {
+ int new_num_points = old_num_points;
+
+ if (first_select) {
+ new_num_points++;
+ }
+ if (last_select) {
+ new_num_points++;
+ }
+
+ /* Grow the array */
+ gpc->tot_curve_points = new_num_points;
+ gpc->curve_points = MEM_recallocN(gpc->curve_points, sizeof(bGPDcurve_point) * new_num_points);
+
+ if (first_select) {
+ /* shift points by one */
+ memmove(
+ &gpc->curve_points[1], &gpc->curve_points[0], sizeof(bGPDcurve_point) * old_num_points);
+
+ bGPDcurve_point *old_first = &gpc->curve_points[1];
+
+ old_first->flag &= ~GP_CURVE_POINT_SELECT;
+ BEZT_DESEL_ALL(&old_first->bezt);
+ }
+
+ if (last_select) {
+ bGPDcurve_point *old_last = &gpc->curve_points[gpc->tot_curve_points - 2];
+ bGPDcurve_point *new_last = &gpc->curve_points[gpc->tot_curve_points - 1];
+ memcpy(new_last, old_last, sizeof(bGPDcurve_point));
+
+ old_last->flag &= ~GP_CURVE_POINT_SELECT;
+ BEZT_DESEL_ALL(&old_last->bezt);
+ }
+
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ }
+}
+
static int gpencil_extrude_exec(bContext *C, wmOperator *op)
{
Object *obact = CTX_data_active_object(C);
bGPdata *gpd = (bGPdata *)obact->data;
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bGPDstroke *gps = NULL;
@@ -1167,6 +1299,7 @@ static int gpencil_extrude_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ bool changed = false;
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
@@ -1182,9 +1315,22 @@ static int gpencil_extrude_exec(bContext *C, wmOperator *op)
continue;
}
- if (gps->flag & GP_STROKE_SELECT) {
- gpencil_add_move_points(gpf, gps);
+ if (is_curve_edit) {
+ if (gps->editcurve == NULL) {
+ continue;
+ }
+ bGPDcurve *gpc = gps->editcurve;
+ if (gpc->flag & GP_CURVE_SELECT) {
+ gpencil_curve_extrude_points(gpd, gpf, gps, gpc);
+ }
+ }
+ else {
+ if (gps->flag & GP_STROKE_SELECT) {
+ gpencil_add_move_points(gpd, gpf, gps);
+ }
}
+
+ changed = true;
}
/* if not multiedit, exit loop*/
if (!is_multiedit) {
@@ -1195,10 +1341,13 @@ static int gpencil_extrude_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- /* updates */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
- DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ /* updates */
+ DEG_id_tag_update(&gpd->id,
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1352,6 +1501,7 @@ static int gpencil_strokes_copy_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
if (gpd == NULL) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
@@ -1366,56 +1516,62 @@ static int gpencil_strokes_copy_exec(bContext *C, wmOperator *op)
/* clear the buffer first */
ED_gpencil_strokes_copybuf_free();
- /* for each visible (and editable) layer's selected strokes,
- * copy the strokes into a temporary buffer, then append
- * once all done
- */
- CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
-
- if (gpf == NULL) {
- continue;
- }
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ /* for each visible (and editable) layer's selected strokes,
+ * copy the strokes into a temporary buffer, then append
+ * once all done
+ */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps;
- /* make copies of selected strokes, and deselect these once we're done */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ if (gpf == NULL) {
continue;
}
- if (gps->flag & GP_STROKE_SELECT) {
- if (gps->totpoints == 1) {
- /* Special Case: If there's just a single point in this stroke... */
- bGPDstroke *gpsd;
-
- /* make direct copies of the stroke and its points */
- gpsd = BKE_gpencil_stroke_duplicate(gps, false);
-
- /* saves original layer name */
- BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
- gpsd->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- gpsd->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
- }
+ /* make copies of selected strokes, and deselect these once we're done */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gpsd);
+ if (gps->flag & GP_STROKE_SELECT) {
+ if (gps->totpoints == 1) {
+ /* Special Case: If there's just a single point in this stroke... */
+ bGPDstroke *gpsd;
+
+ /* make direct copies of the stroke and its points */
+ gpsd = BKE_gpencil_stroke_duplicate(gps, false, true);
+
+ /* saves original layer name */
+ BLI_strncpy(
+ gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
+ gpsd->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ gpsd->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
+ }
- /* add to temp buffer */
- gpsd->next = gpsd->prev = NULL;
- BLI_addtail(&gpencil_strokes_copypastebuf, gpsd);
- }
- else {
- /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
- gpencil_duplicate_points(gps, &gpencil_strokes_copypastebuf, gpl->info);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, gpsd);
+
+ /* add to temp buffer */
+ gpsd->next = gpsd->prev = NULL;
+ BLI_addtail(&gpencil_strokes_copypastebuf, gpsd);
+ }
+ else {
+ /* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
+ gpencil_duplicate_points(gpd, gps, &gpencil_strokes_copypastebuf, gpl->info);
+ }
}
}
}
+ CTX_DATA_END;
}
- CTX_DATA_END;
/* Build up hash of material colors used in these strokes */
if (gpencil_strokes_copypastebuf.first) {
@@ -1493,6 +1649,7 @@ static int gpencil_strokes_paste_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); /* only use active for copy merge */
Scene *scene = CTX_data_scene(C);
bGPDframe *gpf;
@@ -1556,46 +1713,52 @@ static int gpencil_strokes_paste_exec(bContext *C, wmOperator *op)
/* Ensure that all the necessary colors exist */
new_colors = gpencil_copybuf_validate_colormap(C);
- /* Copy over the strokes from the buffer (and adjust the colors) */
- bGPDstroke *gps_init = (!on_back) ? gpencil_strokes_copypastebuf.first :
- gpencil_strokes_copypastebuf.last;
- for (bGPDstroke *gps = gps_init; gps; gps = (!on_back) ? gps->next : gps->prev) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- /* Need to verify if layer exists */
- if (type != GP_COPY_TO_ACTIVE) {
- gpl = BLI_findstring(&gpd->layers, gps->runtime.tmp_layerinfo, offsetof(bGPDlayer, info));
- if (gpl == NULL) {
- /* no layer - use active (only if layer deleted before paste) */
- gpl = BKE_gpencil_layer_active_get(gpd);
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ /* Copy over the strokes from the buffer (and adjust the colors) */
+ bGPDstroke *gps_init = (!on_back) ? gpencil_strokes_copypastebuf.first :
+ gpencil_strokes_copypastebuf.last;
+ for (bGPDstroke *gps = gps_init; gps; gps = (!on_back) ? gps->next : gps->prev) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ /* Need to verify if layer exists */
+ if (type != GP_COPY_TO_ACTIVE) {
+ gpl = BLI_findstring(
+ &gpd->layers, gps->runtime.tmp_layerinfo, offsetof(bGPDlayer, info));
+ if (gpl == NULL) {
+ /* no layer - use active (only if layer deleted before paste) */
+ gpl = BKE_gpencil_layer_active_get(gpd);
+ }
}
- }
- /* Ensure we have a frame to draw into
- * NOTE: Since this is an op which creates strokes,
- * we are obliged to add a new frame if one
- * doesn't exist already
- */
- gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
- if (gpf) {
- /* Create new stroke */
- bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, true);
- new_stroke->runtime.tmp_layerinfo[0] = '\0';
- new_stroke->next = new_stroke->prev = NULL;
+ /* Ensure we have a frame to draw into
+ * NOTE: Since this is an op which creates strokes,
+ * we are obliged to add a new frame if one
+ * doesn't exist already
+ */
+ gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ if (gpf) {
+ /* Create new stroke */
+ bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, true, true);
+ new_stroke->runtime.tmp_layerinfo[0] = '\0';
+ new_stroke->next = new_stroke->prev = NULL;
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(new_stroke);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
- if (on_back) {
- BLI_addhead(&gpf->strokes, new_stroke);
- }
- else {
- BLI_addtail(&gpf->strokes, new_stroke);
- }
+ if (on_back) {
+ BLI_addhead(&gpf->strokes, new_stroke);
+ }
+ else {
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
- /* Remap material */
- Material *ma = BLI_ghash_lookup(new_colors, POINTER_FROM_INT(new_stroke->mat_nr));
- new_stroke->mat_nr = BKE_gpencil_object_material_index_get(ob, ma);
- CLAMP_MIN(new_stroke->mat_nr, 0);
+ /* Remap material */
+ Material *ma = BLI_ghash_lookup(new_colors, POINTER_FROM_INT(new_stroke->mat_nr));
+ new_stroke->mat_nr = BKE_gpencil_object_material_index_get(ob, ma);
+ CLAMP_MIN(new_stroke->mat_nr, 0);
+ }
}
}
}
@@ -2018,10 +2181,10 @@ typedef enum eGP_DissolveMode {
/* Delete selected strokes */
static int gpencil_delete_selected_strokes(bContext *C)
{
- bool changed = false;
bGPdata *gpd = ED_gpencil_data_get_active(C);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ bool changed = false;
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
@@ -2042,16 +2205,9 @@ static int gpencil_delete_selected_strokes(bContext *C)
/* free stroke if selected */
if (gps->flag & GP_STROKE_SELECT) {
+ BLI_remlink(&gpf->strokes, gps);
/* free stroke memory arrays, then stroke itself */
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
- MEM_SAFE_FREE(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
changed = true;
}
@@ -2071,11 +2227,144 @@ static int gpencil_delete_selected_strokes(bContext *C)
/* ----------------------------------- */
-/* Delete selected points but keep the stroke */
-static int gpencil_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
+static bool gpencil_dissolve_selected_curve_points(bContext *C,
+ bGPdata *gpd,
+ eGP_DissolveMode mode)
+{
+ bool changed = false;
+ GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
+ {
+ if (gpc->flag & GP_CURVE_SELECT) {
+ int first = 0, last = 0;
+ int num_points_remaining = gpc->tot_curve_points;
+
+ switch (mode) {
+ case GP_DISSOLVE_POINTS:
+ for (int i = 0; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ if (cpt->flag & GP_CURVE_POINT_SELECT) {
+ num_points_remaining--;
+ }
+ }
+ break;
+ case GP_DISSOLVE_BETWEEN:
+ first = -1;
+ for (int i = 0; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ if (cpt->flag & GP_CURVE_POINT_SELECT) {
+ if (first < 0) {
+ first = i;
+ }
+ last = i;
+ }
+ }
+
+ for (int i = first + 1; i < last; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ if ((cpt->flag & GP_CURVE_POINT_SELECT) == 0) {
+ num_points_remaining--;
+ }
+ }
+ break;
+ case GP_DISSOLVE_UNSELECT:
+ for (int i = 0; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ if ((cpt->flag & GP_CURVE_POINT_SELECT) == 0) {
+ num_points_remaining--;
+ }
+ }
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ if (num_points_remaining < 1) {
+ /* Delete stroke */
+ BLI_remlink(&gpf_->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+ }
+ else {
+ bGPDcurve_point *new_points = MEM_callocN(sizeof(bGPDcurve_point) * num_points_remaining,
+ __func__);
+
+ int idx = 0;
+ switch (mode) {
+ case GP_DISSOLVE_POINTS:
+ for (int i = 0; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ bGPDcurve_point *new_cpt = &new_points[idx];
+ if ((cpt->flag & GP_CURVE_POINT_SELECT) == 0) {
+ *new_cpt = *cpt;
+ idx++;
+ }
+ }
+ break;
+ case GP_DISSOLVE_BETWEEN:
+ for (int i = 0; i < first; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ bGPDcurve_point *new_cpt = &new_points[idx];
+
+ *new_cpt = *cpt;
+ idx++;
+ }
+
+ for (int i = first; i < last; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ bGPDcurve_point *new_cpt = &new_points[idx];
+ if (cpt->flag & GP_CURVE_POINT_SELECT) {
+ *new_cpt = *cpt;
+ idx++;
+ }
+ }
+
+ for (int i = last; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ bGPDcurve_point *new_cpt = &new_points[idx];
+
+ *new_cpt = *cpt;
+ idx++;
+ }
+ break;
+ case GP_DISSOLVE_UNSELECT:
+ for (int i = 0; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ bGPDcurve_point *new_cpt = &new_points[idx];
+ if (cpt->flag & GP_CURVE_POINT_SELECT) {
+ *new_cpt = *cpt;
+ idx++;
+ }
+ }
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ if (gpc->curve_points != NULL) {
+ MEM_freeN(gpc->curve_points);
+ }
+
+ gpc->curve_points = new_points;
+ gpc->tot_curve_points = num_points_remaining;
+
+ BKE_gpencil_editcurve_recalculate_handles(gps);
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ }
+
+ changed = true;
+ }
+ }
+ GP_EDITABLE_CURVES_END(gps_iter);
+
+ return changed;
+}
+
+static bool gpencil_dissolve_selected_stroke_points(bContext *C,
+ bGPdata *gpd,
+ eGP_DissolveMode mode)
{
- Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = (bGPdata *)ob->data;
bool changed = false;
int first = 0;
int last = 0;
@@ -2135,18 +2424,8 @@ static int gpencil_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
/* if no points are left, we simply delete the entire stroke */
if (tot <= 0) {
/* remove the entire stroke */
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
- if (gps->triangles) {
- MEM_freeN(gps->triangles);
- }
- BLI_freelinkN(&gpf_->strokes, gps);
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ BLI_remlink(&gpf_->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
}
else {
/* just copy all points to keep into a smaller buffer */
@@ -2263,7 +2542,7 @@ static int gpencil_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
gps->totpoints = tot;
/* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gps);
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
/* deselect the stroke, since none of its selected points will still be selected */
gps->flag &= ~GP_STROKE_SELECT;
@@ -2277,6 +2556,24 @@ static int gpencil_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
+ return changed;
+}
+
+/* Delete selected points but keep the stroke */
+static int gpencil_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+ bool changed = false;
+
+ if (is_curve_edit) {
+ changed = gpencil_dissolve_selected_curve_points(C, gpd, mode);
+ }
+ else {
+ changed = gpencil_dissolve_selected_stroke_points(C, gpd, mode);
+ }
+
if (changed) {
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -2289,14 +2586,15 @@ static int gpencil_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
/* Temp data for storing information about an "island" of points
* that should be kept when splitting up a stroke. Used in:
- * gp_stroke_delete_tagged_points()
+ * gpencil_stroke_delete_tagged_points()
*/
typedef struct tGPDeleteIsland {
int start_idx;
int end_idx;
} tGPDeleteIsland;
-static void gpencil_stroke_join_islands(bGPDframe *gpf,
+static void gpencil_stroke_join_islands(bGPdata *gpd,
+ bGPDframe *gpf,
bGPDstroke *gps_first,
bGPDstroke *gps_last)
{
@@ -2305,7 +2603,7 @@ static void gpencil_stroke_join_islands(bGPDframe *gpf,
const int totpoints = gps_first->totpoints + gps_last->totpoints;
/* create new stroke */
- bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false);
+ bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false, true);
join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
join_stroke->totpoints = totpoints;
@@ -2373,7 +2671,7 @@ static void gpencil_stroke_join_islands(bGPDframe *gpf,
/* add new stroke at head */
BLI_addhead(&gpf->strokes, join_stroke);
/* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(join_stroke);
+ BKE_gpencil_stroke_geometry_update(gpd, join_stroke);
/* remove first stroke */
BLI_remlink(&gpf->strokes, gps_first);
@@ -2398,7 +2696,8 @@ static void gpencil_stroke_join_islands(bGPDframe *gpf,
* 2) Each island gets converted to a new stroke
* If the number of points is <= limit, the stroke is deleted
*/
-void gpencil_stroke_delete_tagged_points(bGPDframe *gpf,
+void gpencil_stroke_delete_tagged_points(bGPdata *gpd,
+ bGPDframe *gpf,
bGPDstroke *gps,
bGPDstroke *next_stroke,
int tag_flags,
@@ -2450,7 +2749,7 @@ void gpencil_stroke_delete_tagged_points(bGPDframe *gpf,
/* Create each new stroke... */
for (idx = 0; idx < num_islands; idx++) {
tGPDeleteIsland *island = &islands[idx];
- new_stroke = BKE_gpencil_stroke_duplicate(gps, false);
+ new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true);
/* if cyclic and first stroke, save to join later */
if ((is_cyclic) && (gps_first == NULL)) {
@@ -2521,7 +2820,7 @@ void gpencil_stroke_delete_tagged_points(bGPDframe *gpf,
}
else {
/* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(new_stroke);
+ BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
if (next_stroke) {
BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke);
@@ -2533,7 +2832,7 @@ void gpencil_stroke_delete_tagged_points(bGPDframe *gpf,
}
/* if cyclic, need to join last stroke with first stroke */
if ((is_cyclic) && (gps_first != NULL) && (gps_first != new_stroke)) {
- gpencil_stroke_join_islands(gpf, gps_first, new_stroke);
+ gpencil_stroke_join_islands(gpd, gpf, gps_first, new_stroke);
}
}
@@ -2545,11 +2844,118 @@ void gpencil_stroke_delete_tagged_points(bGPDframe *gpf,
BKE_gpencil_free_stroke(gps);
}
+static void gpencil_curve_delete_tagged_points(bGPdata *gpd,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ bGPDstroke *next_stroke,
+ bGPDcurve *gpc,
+ int tag_flags)
+{
+ if (gpc == NULL) {
+ return;
+ }
+ const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
+ const int idx_last = gpc->tot_curve_points - 1;
+ bGPDstroke *gps_first = NULL;
+ bGPDstroke *gps_last = NULL;
+
+ int idx_start = 0;
+ int idx_end = 0;
+ bool prev_selected = gpc->curve_points[0].flag & tag_flags;
+ for (int i = 1; i < gpc->tot_curve_points; i++) {
+ bool selected = gpc->curve_points[i].flag & tag_flags;
+ if (prev_selected == true && selected == false) {
+ idx_start = i;
+ }
+ /* Island ends if the current point is selected or if we reached the end of the stroke */
+ if ((prev_selected == false && selected == true) || (selected == false && i == idx_last)) {
+
+ idx_end = selected ? i - 1 : i;
+ int island_length = idx_end - idx_start + 1;
+
+ /* If an island has only a single curve point, there is no curve segment, so skip island */
+ if (island_length == 1) {
+ if (is_cyclic) {
+ if (idx_start > 0 && idx_end < idx_last) {
+ prev_selected = selected;
+ continue;
+ }
+ }
+ else {
+ prev_selected = selected;
+ continue;
+ }
+ }
+
+ bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, false, false);
+ new_stroke->points = NULL;
+ new_stroke->flag &= ~GP_STROKE_CYCLIC;
+ new_stroke->editcurve = BKE_gpencil_stroke_editcurve_new(island_length);
+
+ if (gps_first == NULL) {
+ gps_first = new_stroke;
+ }
+
+ bGPDcurve *new_gpc = new_stroke->editcurve;
+ memcpy(new_gpc->curve_points,
+ gpc->curve_points + idx_start,
+ sizeof(bGPDcurve_point) * island_length);
+
+ BKE_gpencil_editcurve_recalculate_handles(new_stroke);
+ new_stroke->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
+
+ if (next_stroke) {
+ BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke);
+ }
+ else {
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
+
+ gps_last = new_stroke;
+ }
+ prev_selected = selected;
+ }
+
+ /* join first and last stroke if cyclic */
+ if (is_cyclic && gps_first != NULL && gps_last != NULL && gps_first != gps_last) {
+ bGPDcurve *gpc_first = gps_first->editcurve;
+ bGPDcurve *gpc_last = gps_last->editcurve;
+ int first_tot_points = gpc_first->tot_curve_points;
+ int old_tot_points = gpc_last->tot_curve_points;
+
+ gpc_last->tot_curve_points = first_tot_points + old_tot_points;
+ gpc_last->curve_points = MEM_recallocN(gpc_last->curve_points,
+ sizeof(bGPDcurve_point) * gpc_last->tot_curve_points);
+ /* copy data from first to last */
+ memcpy(gpc_last->curve_points + old_tot_points,
+ gpc_first->curve_points,
+ sizeof(bGPDcurve_point) * first_tot_points);
+
+ BKE_gpencil_editcurve_recalculate_handles(gps_last);
+ gps_last->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, gps_last);
+
+ /* remove first one */
+ BLI_remlink(&gpf->strokes, gps_first);
+ BKE_gpencil_free_stroke(gps_first);
+ }
+
+ /* Delete the old stroke */
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+}
+
/* Split selected strokes into segments, splitting on selected points */
static int gpencil_delete_selected_points(bContext *C)
{
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bool changed = false;
@@ -2579,8 +2985,16 @@ static int gpencil_delete_selected_points(bContext *C)
/* deselect old stroke, since it will be used as template for the new strokes */
gps->flag &= ~GP_STROKE_SELECT;
- /* delete unwanted points by splitting stroke into several smaller ones */
- gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ if (is_curve_edit) {
+ bGPDcurve *gpc = gps->editcurve;
+ gpencil_curve_delete_tagged_points(
+ gpd, gpf, gps, gps->next, gpc, GP_CURVE_POINT_SELECT);
+ }
+ else {
+ /* delete unwanted points by splitting stroke into several smaller ones */
+ gpencil_stroke_delete_tagged_points(
+ gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ }
changed = true;
}
@@ -2743,7 +3157,9 @@ static int gpencil_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obact = CTX_data_active_object(C);
const float gridf = ED_view3d_grid_view_scale(scene, v3d, region, NULL);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+ bool changed = false;
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
@@ -2754,9 +3170,6 @@ static int gpencil_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- bGPDspoint *pt;
- int i;
-
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
@@ -2766,30 +3179,82 @@ static int gpencil_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
continue;
}
- /* TODO: if entire stroke is selected, offset entire stroke by same amount? */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- /* only if point is selected */
- if (pt->flag & GP_SPOINT_SELECT) {
- /* apply parent transformations */
- float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ if (is_curve_edit) {
+ if (gps->editcurve == NULL) {
+ continue;
+ }
+ float inv_diff_mat[4][4];
+ invert_m4_m4_safe(inv_diff_mat, diff_mat);
+
+ bGPDcurve *gpc = gps->editcurve;
+ for (int i = 0; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
+ BezTriple *bezt = &gpc_pt->bezt;
+ if (gpc_pt->flag & GP_CURVE_POINT_SELECT) {
+ float tmp0[3], tmp1[3], tmp2[3], offset[3];
+ mul_v3_m4v3(tmp0, diff_mat, bezt->vec[0]);
+ mul_v3_m4v3(tmp1, diff_mat, bezt->vec[1]);
+ mul_v3_m4v3(tmp2, diff_mat, bezt->vec[2]);
+
+ /* calculate the offset vector */
+ offset[0] = gridf * floorf(0.5f + tmp1[0] / gridf) - tmp1[0];
+ offset[1] = gridf * floorf(0.5f + tmp1[1] / gridf) - tmp1[1];
+ offset[2] = gridf * floorf(0.5f + tmp1[2] / gridf) - tmp1[2];
+
+ /* shift bezTriple */
+ add_v3_v3(bezt->vec[0], offset);
+ add_v3_v3(bezt->vec[1], offset);
+ add_v3_v3(bezt->vec[2], offset);
+
+ mul_v3_m4v3(tmp0, inv_diff_mat, bezt->vec[0]);
+ mul_v3_m4v3(tmp1, inv_diff_mat, bezt->vec[1]);
+ mul_v3_m4v3(tmp2, inv_diff_mat, bezt->vec[2]);
+ copy_v3_v3(bezt->vec[0], tmp0);
+ copy_v3_v3(bezt->vec[1], tmp1);
+ copy_v3_v3(bezt->vec[2], tmp2);
+
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ BKE_gpencil_editcurve_recalculate_handles(gps);
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ }
+ }
+ else {
+ /* TODO: if entire stroke is selected, offset entire stroke by same amount? */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ /* only if point is selected */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* apply parent transformations */
+ float fpt[3];
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
+ fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
+ fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
+ fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
- fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
- fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
- fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
+ /* return data */
+ copy_v3_v3(&pt->x, fpt);
+ gpencil_apply_parent_point(depsgraph, obact, gpl, pt);
- /* return data */
- copy_v3_v3(&pt->x, fpt);
- gpencil_apply_parent_point(depsgraph, obact, gpl, pt);
+ changed = true;
+ }
}
}
}
}
}
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
return OPERATOR_FINISHED;
}
@@ -2817,7 +3282,7 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot)
static int gpencil_snap_to_cursor(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
-
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obact = CTX_data_active_object(C);
@@ -2825,50 +3290,60 @@ static int gpencil_snap_to_cursor(bContext *C, wmOperator *op)
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
const float *cursor_global = scene->cursor.location;
- LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
- /* only editable and visible layers are considered */
- if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- bGPDframe *gpf = gpl->actframe;
- float diff_mat[4][4];
+ bool changed = false;
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* only editable and visible layers are considered */
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf = gpl->actframe;
+ float diff_mat[4][4];
- /* calculate difference matrix */
- BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ /* calculate difference matrix */
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
- LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- bGPDspoint *pt;
- int i;
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ bGPDspoint *pt;
+ int i;
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
- continue;
- }
- /* only continue if this stroke is selected (editable doesn't guarantee this)... */
- if ((gps->flag & GP_STROKE_SELECT) == 0) {
- continue;
- }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+ /* only continue if this stroke is selected (editable doesn't guarantee this)... */
+ if ((gps->flag & GP_STROKE_SELECT) == 0) {
+ continue;
+ }
- if (use_offset) {
- float offset[3];
+ if (use_offset) {
+ float offset[3];
- /* compute offset from first point of stroke to cursor */
- /* TODO: Allow using midpoint instead? */
- sub_v3_v3v3(offset, cursor_global, &gps->points->x);
+ /* compute offset from first point of stroke to cursor */
+ /* TODO: Allow using midpoint instead? */
+ sub_v3_v3v3(offset, cursor_global, &gps->points->x);
- /* apply offset to all points in the stroke */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- add_v3_v3(&pt->x, offset);
+ /* apply offset to all points in the stroke */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ add_v3_v3(&pt->x, offset);
+ }
+
+ changed = true;
}
- }
- else {
- /* affect each selected point */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- copy_v3_v3(&pt->x, cursor_global);
- gpencil_apply_parent_point(depsgraph, obact, gpl, pt);
+ else {
+ /* affect each selected point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ copy_v3_v3(&pt->x, cursor_global);
+ gpencil_apply_parent_point(depsgraph, obact, gpl, pt);
+
+ changed = true;
+ }
}
}
}
@@ -2876,9 +3351,12 @@ static int gpencil_snap_to_cursor(bContext *C, wmOperator *op)
}
}
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
return OPERATOR_FINISHED;
}
@@ -2910,23 +3388,16 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot)
/** \name Snapping Cursor to Selection Operator
* \{ */
-static int gpencil_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
+static bool gpencil_stroke_points_centroid(Depsgraph *depsgraph,
+ bContext *C,
+ Object *obact,
+ bGPdata *gpd,
+ float r_centroid[3],
+ float r_min[3],
+ float r_max[3],
+ size_t *count)
{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Object *obact = CTX_data_active_object(C);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, obact);
- bGPdata *gpd = (bGPdata *)ob_eval->data;
-
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
-
- float *cursor = scene->cursor.location;
- float centroid[3] = {0.0f};
- float min[3], max[3];
- size_t count = 0;
-
- INIT_MINMAX(min, max);
-
+ bool changed = false;
/* calculate midpoints from selected points */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
@@ -2960,29 +3431,61 @@ static int gpencil_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
float fpt[3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
- add_v3_v3(centroid, fpt);
- minmax_v3v3_v3(min, max, fpt);
+ add_v3_v3(r_centroid, fpt);
+ minmax_v3v3_v3(r_min, r_max, fpt);
- count++;
+ (*count)++;
}
}
+
+ changed = true;
}
}
}
- if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_BOUNDS) {
- mid_v3_v3v3(cursor, min, max);
+ return changed;
+}
+
+static int gpencil_snap_cursor_to_sel(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Object *obact = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ float *cursor = scene->cursor.location;
+ float centroid[3] = {0.0f};
+ float min[3], max[3];
+ size_t count = 0;
+
+ INIT_MINMAX(min, max);
+
+ bool changed = false;
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
}
- else { /* #V3D_AROUND_CENTER_MEDIAN. */
- zero_v3(cursor);
- if (count) {
- mul_v3_fl(centroid, 1.0f / (float)count);
- copy_v3_v3(cursor, centroid);
- }
+ else {
+ changed = gpencil_stroke_points_centroid(depsgraph, C, obact, gpd, centroid, min, max, &count);
}
- DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ if (changed) {
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_BOUNDS) {
+ mid_v3_v3v3(cursor, min, max);
+ }
+ else { /* #V3D_AROUND_CENTER_MEDIAN. */
+ zero_v3(cursor);
+ if (count) {
+ mul_v3_fl(centroid, 1.0f / (float)count);
+ copy_v3_v3(cursor, centroid);
+ }
+ }
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ }
return OPERATOR_FINISHED;
}
@@ -3030,6 +3533,7 @@ static int gpencil_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(o
}
}
}
+
/* clear value */
gpl->thickness = 0.0f;
gpl->line_change = 0;
@@ -3073,6 +3577,7 @@ static int gpencil_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
const int type = RNA_enum_get(op->ptr, "type");
const bool geometry = RNA_boolean_get(op->ptr, "geometry");
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
bGPDstroke *gps = NULL;
/* sanity checks */
@@ -3080,6 +3585,7 @@ static int gpencil_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ bool changed = false;
/* loop all selected strokes */
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
@@ -3103,6 +3609,7 @@ static int gpencil_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
continue;
}
+ bool before = (bool)(gps->flag & GP_STROKE_CYCLIC);
switch (type) {
case GP_STROKE_CYCLIC_CLOSE:
/* Close all (enable) */
@@ -3121,9 +3628,19 @@ static int gpencil_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
break;
}
- /* Create new geometry. */
- if ((gps->flag & GP_STROKE_CYCLIC) && (geometry)) {
- BKE_gpencil_stroke_close(gps);
+ if (before != (gps->flag & GP_STROKE_CYCLIC)) {
+ /* Create new geometry. */
+ if (is_curve_edit) {
+ BKE_gpencil_editcurve_recalculate_handles(gps);
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ }
+ else if ((gps->flag & GP_STROKE_CYCLIC) && geometry) {
+ BKE_gpencil_stroke_close(gps);
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ }
+
+ changed = true;
}
}
@@ -3136,13 +3653,31 @@ static int gpencil_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
+static bool gpencil_cyclical_set_curve_edit_poll_property(const bContext *C,
+ wmOperator *UNUSED(op),
+ const PropertyRNA *prop)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ if (gpd != NULL && GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
+ const char *prop_id = RNA_property_identifier(prop);
+ /* Only show type in curve edit mode */
+ if (!STREQ(prop_id, "type")) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
/**
* Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
* option to force opened/closed strokes instead of just toggle behavior.
@@ -3166,6 +3701,7 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = gpencil_stroke_cyclical_set_exec;
ot->poll = gpencil_active_layer_poll;
+ ot->poll_property = gpencil_cyclical_set_curve_edit_poll_property;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -3194,7 +3730,6 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
-
const int type = RNA_enum_get(op->ptr, "type");
/* sanity checks */
@@ -3202,6 +3737,7 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ bool changed = false;
/* loop all selected strokes */
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
if (gpl->actframe == NULL) {
@@ -3221,6 +3757,9 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op)
continue;
}
+ short prev_first = gps->caps[0];
+ short prev_last = gps->caps[1];
+
if (ELEM(type, GP_STROKE_CAPS_TOGGLE_BOTH, GP_STROKE_CAPS_TOGGLE_START)) {
++gps->caps[0];
if (gps->caps[0] >= GP_STROKE_CAP_MAX) {
@@ -3237,13 +3776,19 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op)
gps->caps[0] = GP_STROKE_CAP_ROUND;
gps->caps[1] = GP_STROKE_CAP_ROUND;
}
+
+ if (prev_first != gps->caps[0] || prev_last != gps->caps[1]) {
+ changed = true;
+ }
}
}
CTX_DATA_END;
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -3539,6 +4084,11 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+ if (is_curve_edit) {
+ return OPERATOR_CANCELLED;
+ }
+
if (activegpl->flag & GP_LAYER_LOCKED) {
return OPERATOR_CANCELLED;
}
@@ -3597,7 +4147,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op)
elem->used = true;
/* Create a new stroke. */
- bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(elem->gps, true);
+ bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(elem->gps, true, true);
gps_new->flag &= ~GP_STROKE_CYCLIC;
BLI_insertlinkbefore(&elem->gpf->strokes, elem->gps, gps_new);
@@ -3614,7 +4164,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op)
}
/* Calc geometry data for new stroke. */
- BKE_gpencil_stroke_geometry_update(gps_new);
+ BKE_gpencil_stroke_geometry_update(gpd, gps_new);
/* If join only, delete old strokes. */
if (type == GP_STROKE_JOIN) {
@@ -3670,7 +4220,7 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot)
/** \name Stroke Flip Operator
* \{ */
-static int gpencil_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_stroke_flip_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
@@ -3680,6 +4230,8 @@ static int gpencil_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+ bool changed = false;
/* read all selected strokes */
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *gpf = gpl->actframe;
@@ -3698,16 +4250,25 @@ static int gpencil_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
- /* flip stroke */
- gpencil_flip_stroke(gps);
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ /* flip stroke */
+ gpencil_flip_stroke(gps);
+ }
+
+ changed = true;
}
}
}
CTX_DATA_END;
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -3742,19 +4303,26 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
int oldframe = (int)DEG_get_ctime(depsgraph);
const eGP_ReprojectModes mode = RNA_enum_get(op->ptr, "type");
const bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
- /* Init space conversion stuff. */
- GP_SpaceConversion gsc = {NULL};
- SnapObjectContext *sctx = NULL;
- gpencil_point_conversion_init(C, &gsc);
/* Init snap context for geometry projection. */
+ SnapObjectContext *sctx = NULL;
sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C));
+ bool changed = false;
+ /* Init space conversion stuff. */
+ GP_SpaceConversion gsc = {NULL};
+ gpencil_point_conversion_init(C, &gsc);
int cfra_prv = INT_MIN;
/* Go through each editable + selected stroke, adjusting each of its points one by one... */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
- if (gps->flag & GP_STROKE_SELECT) {
+ bool curve_select = false;
+ if (is_curve_edit && gps->editcurve != NULL) {
+ curve_select = gps->editcurve->flag & GP_CURVE_SELECT;
+ }
+
+ if (gps->flag & GP_STROKE_SELECT || curve_select) {
/* update frame to get the new location of objects */
if ((mode == GP_REPROJECT_SURFACE) && (cfra_prv != gpf_->framenum)) {
@@ -3764,6 +4332,17 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
}
ED_gpencil_stroke_reproject(depsgraph, &gsc, sctx, gpl, gpf_, gps, mode, keep_original);
+
+ if (is_curve_edit && gps->editcurve != NULL) {
+ BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
+ /* Update the selection from the stroke to the curve. */
+ BKE_gpencil_editcurve_stroke_sync_selection(gps, gps->editcurve);
+
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ }
+
+ changed = true;
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
@@ -3776,9 +4355,12 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
ED_transform_snap_object_context_destroy(sctx);
}
- /* update changed data */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ /* update changed data */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
return OPERATOR_FINISHED;
}
@@ -3846,10 +4428,11 @@ static int gpencil_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op))
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- BKE_gpencil_stroke_geometry_update(gps);
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
}
}
}
+
/* update changed data */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -3943,134 +4526,176 @@ static int gpencil_count_subdivision_cuts(bGPDstroke *gps)
return totnewpoints;
}
-static int gpencil_stroke_subdivide_exec(bContext *C, wmOperator *op)
+static void gpencil_stroke_subdivide(bGPDstroke *gps, const int cuts)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDspoint *temp_points;
- const int cuts = RNA_int_get(op->ptr, "number_cuts");
-
int totnewpoints, oldtotpoints;
int i2;
+ /* loop as many times as cuts */
+ for (int s = 0; s < cuts; s++) {
+ totnewpoints = gpencil_count_subdivision_cuts(gps);
+ if (totnewpoints == 0) {
+ continue;
+ }
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
- /* sanity checks */
- if (ELEM(NULL, gpd)) {
- return OPERATOR_CANCELLED;
- }
+ MDeformVert *temp_dverts = NULL;
+ MDeformVert *dvert_final = NULL;
+ MDeformVert *dvert = NULL;
+ MDeformVert *dvert_next = NULL;
+ if (gps->dvert != NULL) {
+ temp_dverts = MEM_dupallocN(gps->dvert);
+ }
- /* Go through each editable + selected stroke */
- GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
- if (gps->flag & GP_STROKE_SELECT) {
- /* loop as many times as cuts */
- for (int s = 0; s < cuts; s++) {
- totnewpoints = gpencil_count_subdivision_cuts(gps);
- if (totnewpoints == 0) {
- continue;
- }
- /* duplicate points in a temp area */
- temp_points = MEM_dupallocN(gps->points);
- oldtotpoints = gps->totpoints;
-
- MDeformVert *temp_dverts = NULL;
- MDeformVert *dvert_final = NULL;
- MDeformVert *dvert = NULL;
- MDeformVert *dvert_next = NULL;
- if (gps->dvert != NULL) {
- temp_dverts = MEM_dupallocN(gps->dvert);
- }
+ /* resize the points arrays */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
- /* resize the points arrays */
- gps->totpoints += totnewpoints;
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
- if (gps->dvert != NULL) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
- }
+ /* loop and interpolate */
+ i2 = 0;
+ for (int i = 0; i < oldtotpoints; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
- /* loop and interpolate */
- i2 = 0;
- for (int i = 0; i < oldtotpoints; i++) {
- bGPDspoint *pt = &temp_points[i];
- bGPDspoint *pt_final = &gps->points[i2];
-
- /* copy current point */
- copy_v3_v3(&pt_final->x, &pt->x);
- pt_final->pressure = pt->pressure;
- pt_final->strength = pt->strength;
- pt_final->time = pt->time;
- pt_final->flag = pt->flag;
- copy_v4_v4(pt_final->vert_color, pt->vert_color);
-
- if (gps->dvert != NULL) {
- dvert = &temp_dverts[i];
- dvert_final = &gps->dvert[i2];
- dvert_final->totweight = dvert->totweight;
- dvert_final->dw = dvert->dw;
- }
- i2++;
+ /* copy current point */
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+ copy_v4_v4(pt_final->vert_color, pt->vert_color);
- /* if next point is selected add a half way point */
- if (pt->flag & GP_SPOINT_SELECT) {
- if (i + 1 < oldtotpoints) {
- if (temp_points[i + 1].flag & GP_SPOINT_SELECT) {
- pt_final = &gps->points[i2];
- if (gps->dvert != NULL) {
- dvert_final = &gps->dvert[i2];
- }
- /* Interpolate all values */
- bGPDspoint *next = &temp_points[i + 1];
- interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
- pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
- pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
- CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f);
- pt_final->time = interpf(pt->time, next->time, 0.5f);
- pt_final->flag |= GP_SPOINT_SELECT;
-
- /* interpolate weights */
- if (gps->dvert != NULL) {
- dvert = &temp_dverts[i];
- dvert_next = &temp_dverts[i + 1];
- dvert_final = &gps->dvert[i2];
-
- dvert_final->totweight = dvert->totweight;
- dvert_final->dw = MEM_dupallocN(dvert->dw);
-
- /* interpolate weight values */
- for (int d = 0; d < dvert->totweight; d++) {
- MDeformWeight *dw_a = &dvert->dw[d];
- if (dvert_next->totweight > d) {
- MDeformWeight *dw_b = &dvert_next->dw[d];
- MDeformWeight *dw_final = &dvert_final->dw[d];
- dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f);
- }
- }
- }
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_final = &gps->dvert[i2];
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+ }
+ i2++;
- i2++;
+ /* if next point is selected add a half way point */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (i + 1 < oldtotpoints) {
+ if (temp_points[i + 1].flag & GP_SPOINT_SELECT) {
+ pt_final = &gps->points[i2];
+ if (gps->dvert != NULL) {
+ dvert_final = &gps->dvert[i2];
+ }
+ /* Interpolate all values */
+ bGPDspoint *next = &temp_points[i + 1];
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
+ pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
+ CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f);
+ pt_final->time = interpf(pt->time, next->time, 0.5f);
+ pt_final->flag |= GP_SPOINT_SELECT;
+
+ /* interpolate weights */
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_next = &temp_dverts[i + 1];
+ dvert_final = &gps->dvert[i2];
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = MEM_dupallocN(dvert->dw);
+
+ /* interpolate weight values */
+ for (int d = 0; d < dvert->totweight; d++) {
+ MDeformWeight *dw_a = &dvert->dw[d];
+ if (dvert_next->totweight > d) {
+ MDeformWeight *dw_b = &dvert_next->dw[d];
+ MDeformWeight *dw_final = &dvert_final->dw[d];
+ dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f);
+ }
}
}
+
+ i2++;
}
}
- /* free temp memory */
- MEM_SAFE_FREE(temp_points);
- MEM_SAFE_FREE(temp_dverts);
}
+ }
+ /* free temp memory */
+ MEM_SAFE_FREE(temp_points);
+ MEM_SAFE_FREE(temp_dverts);
+ }
+}
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gps);
+static int gpencil_stroke_subdivide_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const int cuts = RNA_int_get(op->ptr, "number_cuts");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+
+ bool changed = false;
+ if (is_curve_edit) {
+ GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
+ {
+ if (gpc->flag & GP_CURVE_SELECT) {
+ BKE_gpencil_editcurve_subdivide(gps, cuts);
+ BKE_gpencil_editcurve_recalculate_handles(gps);
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ changed = true;
+ }
}
+ GP_EDITABLE_CURVES_END(gps_iter);
}
- GP_EDITABLE_STROKES_END(gpstroke_iter);
+ else {
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ gpencil_stroke_subdivide(gps, cuts);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ changed = true;
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
- /* smooth stroke */
- gpencil_smooth_stroke(C, op);
+ if (changed) {
+ /* smooth stroke */
+ gpencil_smooth_stroke(C, op);
+ }
+ }
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
+static bool gpencil_subdivide_curve_edit_poll_property(const bContext *C,
+ wmOperator *UNUSED(op),
+ const PropertyRNA *prop)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ if (gpd != NULL && GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
+ const char *prop_id = RNA_property_identifier(prop);
+ /* Only show number_cuts in curve edit mode */
+ if (!STREQ(prop_id, "number_cuts")) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -4085,6 +4710,7 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
/* api callbacks */
ot->exec = gpencil_stroke_subdivide_exec;
ot->poll = gpencil_active_layer_poll;
+ ot->poll_property = gpencil_subdivide_curve_edit_poll_property;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -4120,18 +4746,29 @@ static int gpencil_stroke_simplify_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* Go through each editable + selected stroke */
- GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
- if (gps->flag & GP_STROKE_SELECT) {
- /* simplify stroke using Ramer-Douglas-Peucker algorithm */
- BKE_gpencil_stroke_simplify_adaptive(gps, factor);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+
+ bool changed = false;
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* simplify stroke using Ramer-Douglas-Peucker algorithm */
+ BKE_gpencil_stroke_simplify_adaptive(gpd, gps, factor);
+ changed = true;
+ }
}
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
}
- GP_EDITABLE_STROKES_END(gpstroke_iter);
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -4169,19 +4806,30 @@ static int gpencil_stroke_simplify_fixed_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* Go through each editable + selected stroke */
- GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
- if (gps->flag & GP_STROKE_SELECT) {
- for (int i = 0; i < steps; i++) {
- BKE_gpencil_stroke_simplify_fixed(gps);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+
+ bool changed = false;
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ changed |= true;
+ for (int i = 0; i < steps; i++) {
+ BKE_gpencil_stroke_simplify_fixed(gpd, gps);
+ }
}
}
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
}
- GP_EDITABLE_STROKES_END(gpstroke_iter);
- /* notifiers */
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ if (changed) {
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -4223,7 +4871,7 @@ static int gpencil_stroke_sample_exec(bContext *C, wmOperator *op)
/* Go through each editable + selected stroke */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
- BKE_gpencil_stroke_sample(gps, length, true);
+ BKE_gpencil_stroke_sample(gpd, gps, length, true);
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
@@ -4246,7 +4894,7 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot)
/* api callbacks */
ot->exec = gpencil_stroke_sample_exec;
- ot->poll = gpencil_active_layer_poll;
+ ot->poll = gpencil_stroke_not_in_curve_edit_mode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -4263,7 +4911,7 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot)
/** \name Stroke Trim Operator
* \{ */
-static int gpencil_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_stroke_trim_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -4274,6 +4922,7 @@ static int gpencil_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op))
/* Go through each editable + selected stroke */
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
@@ -4293,7 +4942,12 @@ static int gpencil_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op))
}
if (gps->flag & GP_STROKE_SELECT) {
- BKE_gpencil_stroke_trim(gps);
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ BKE_gpencil_stroke_trim(gpd, gps);
+ }
}
}
/* if not multiedit, exit loop*/
@@ -4373,6 +5027,7 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
}
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_src);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd_src);
/* Create a new object. */
/* Take into account user preferences for duplicating actions. */
@@ -4434,27 +5089,32 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
/* selected points mode */
if (mode == GP_SEPARATE_POINT) {
- /* make copy of source stroke */
- bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps, true);
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps, true, true);
- /* Reassign material. */
- gps_dst->mat_nr = idx;
+ /* Reassign material. */
+ gps_dst->mat_nr = idx;
- /* link to destination frame */
- BLI_addtail(&gpf_dst->strokes, gps_dst);
+ /* link to destination frame */
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
- /* Invert selection status of all points in destination stroke */
- for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
- pt->flag ^= GP_SPOINT_SELECT;
- }
+ /* Invert selection status of all points in destination stroke */
+ for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
+ pt->flag ^= GP_SPOINT_SELECT;
+ }
- /* delete selected points from destination stroke */
- gpencil_stroke_delete_tagged_points(
- gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0);
+ /* delete selected points from destination stroke */
+ gpencil_stroke_delete_tagged_points(
+ gpd_dst, gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0);
- /* delete selected points from origin stroke */
- gpencil_stroke_delete_tagged_points(
- gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ /* delete selected points from origin stroke */
+ gpencil_stroke_delete_tagged_points(
+ gpd_src, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ }
}
/* selected strokes mode */
else if (mode == GP_SEPARATE_STROKE) {
@@ -4574,7 +5234,7 @@ void GPENCIL_OT_stroke_separate(wmOperatorType *ot)
/** \name Stroke Split Operator
* \{ */
-static int gpencil_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_stroke_split_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -4586,6 +5246,7 @@ static int gpencil_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
/* loop strokes and split parts */
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
@@ -4610,22 +5271,29 @@ static int gpencil_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
}
/* Split selected strokes. */
if (gps->flag & GP_STROKE_SELECT) {
- /* make copy of source stroke */
- bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps, true);
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps, true, true);
- /* link to same frame */
- BLI_addtail(&gpf->strokes, gps_dst);
+ /* link to same frame */
+ BLI_addtail(&gpf->strokes, gps_dst);
- /* invert selection status of all points in destination stroke */
- for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
- pt->flag ^= GP_SPOINT_SELECT;
- }
+ /* invert selection status of all points in destination stroke */
+ for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
+ pt->flag ^= GP_SPOINT_SELECT;
+ }
- /* delete selected points from destination stroke */
- gpencil_stroke_delete_tagged_points(gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0);
+ /* delete selected points from destination stroke */
+ gpencil_stroke_delete_tagged_points(
+ gpd, gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0);
- /* delete selected points from origin stroke */
- gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ /* delete selected points from origin stroke */
+ gpencil_stroke_delete_tagged_points(
+ gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ }
}
}
/* select again tagged points */
@@ -4705,7 +5373,7 @@ void GPENCIL_OT_stroke_smooth(wmOperatorType *ot)
/* api callbacks */
ot->exec = gpencil_stroke_smooth_exec;
- ot->poll = gpencil_active_layer_poll;
+ ot->poll = gpencil_stroke_not_in_curve_edit_mode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -4761,7 +5429,8 @@ typedef bool (*GPencilTestFn)(bGPDstroke *gps,
const float diff_mat[4][4],
void *user_data);
-static void gpencil_cutter_dissolve(bGPDlayer *hit_layer,
+static void gpencil_cutter_dissolve(bGPdata *gpd,
+ bGPDlayer *hit_layer,
bGPDstroke *hit_stroke,
const bool flat_caps)
{
@@ -4819,7 +5488,7 @@ static void gpencil_cutter_dissolve(bGPDlayer *hit_layer,
}
gpencil_stroke_delete_tagged_points(
- hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1);
+ gpd, hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1);
}
}
@@ -4877,7 +5546,7 @@ static int gpencil_cutter_lasso_select(bContext *C,
gps->flag |= GP_STROKE_SELECT;
float r_hita[3], r_hitb[3];
if (gps->totpoints > 1) {
- ED_gpencil_select_stroke_segment(gpl, gps, pt, true, true, scale, r_hita, r_hitb);
+ ED_gpencil_select_stroke_segment(gpd, gpl, gps, pt, true, true, scale, r_hita, r_hitb);
}
/* avoid infinite loops */
if (gps->totpoints > oldtot) {
@@ -4907,7 +5576,7 @@ static int gpencil_cutter_lasso_select(bContext *C,
}
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
if (gps->flag & GP_STROKE_SELECT) {
- gpencil_cutter_dissolve(gpl, gps, flat_caps);
+ gpencil_cutter_dissolve(gpd, gpl, gps, flat_caps);
}
}
}
@@ -5039,13 +5708,20 @@ static int gpencil_merge_by_distance_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* Go through each editable selected stroke */
- GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
- if (gps->flag & GP_STROKE_SELECT) {
- BKE_gpencil_stroke_merge_distance(gpf_, gps, threshold, unselected);
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+
+ if (is_curve_edit) {
+ /* TODO: merge curve points by distance */
+ }
+ else {
+ /* Go through each editable selected stroke */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ BKE_gpencil_stroke_merge_distance(gpd, gpf_, gps, threshold, unselected);
+ }
}
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
}
- GP_EDITABLE_STROKES_END(gpstroke_iter);
/* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);