Commit: 274c8ae9e27a7ba5290c72c72cbc2fcdb6d7b056
Author: Falk David
Date: Mon Aug 24 15:23:36 2020 +0200
Branches: soc-2020-greasepencil-curve
https://developer.blender.org/rB274c8ae9e27a7ba5290c72c72cbc2fcdb6d7b056
GPencil: Handle strokes with one or two points
Generating the curve for a stroke with one or two strokes could
crash because it was not handled properly.
===================================================================
M source/blender/blenkernel/BKE_gpencil_curve.h
M source/blender/blenkernel/intern/gpencil_curve.c
M source/blender/editors/gpencil/gpencil_edit.c
M source/blender/editors/gpencil/gpencil_edit_curve.c
M source/blender/editors/gpencil/gpencil_select.c
M source/blender/editors/gpencil/gpencil_utils.c
===================================================================
diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h
b/source/blender/blenkernel/BKE_gpencil_curve.h
index 3c52b67dfdc..e8c4139384f 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -44,10 +44,11 @@ void BKE_gpencil_convert_curve(struct Main *bmain,
struct bGPDcurve *BKE_gpencil_stroke_editcurve_generate(struct bGPDstroke *gps,
const float
error_threshold,
- const float
corner_angle);
-void BKE_gpencil_stroke_editcurve_update(struct bGPDstroke *gps,
- const float error_threshold,
- const float corner_angle);
+ const float
corner_angle,
+ const float
stroke_radius);
+void BKE_gpencil_stroke_editcurve_update(struct bGPdata *gpd,
+ struct bGPDlayer *gpl,
+ struct bGPDstroke *gps);
void BKE_gpencil_editcurve_stroke_sync_selection(struct bGPDstroke *gps,
struct bGPDcurve *gpc);
void BKE_gpencil_stroke_editcurve_sync_selection(struct bGPDstroke *gps,
struct bGPDcurve *gpc);
void BKE_gpencil_strokes_selected_update_editcurve(struct bGPdata *gpd);
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c
b/source/blender/blenkernel/intern/gpencil_curve.c
index 0ae6fb6a267..0b4a438c67d 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -563,26 +563,25 @@ void BKE_gpencil_convert_curve(Main *bmain,
/** \name Editcurve kernel functions
* \{ */
-/**
- * Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil
stroke points.
- */
-bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
- const float error_threshold,
- const float corner_angle)
+static bGPDcurve *gpencil_stroke_editcurve_generate_edgecases(bGPDstroke *gps,
+ const float
stroke_radius)
{
- if (gps->totpoints < 1) {
- return NULL;
- }
- else if (gps->totpoints == 1) {
+ BLI_assert(gps->totpoints < 3);
+
+ if (gps->totpoints == 1) {
bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_new(1);
bGPDspoint *pt = &gps->points[0];
bGPDcurve_point *cpt = &editcurve->curve_points[0];
BezTriple *bezt = &cpt->bezt;
+ /* Handles are twice as long as the radius of the point. */
+ float offset = (pt->pressure * stroke_radius) * 2.0f;
+
float tmp_vec[3];
for (int j = 0; j < 3; j++) {
copy_v3_v3(tmp_vec, &pt->x);
- tmp_vec[0] += (j - 1);
+ /* Move handles along the x-axis away from the control point */
+ tmp_vec[0] += (float)(j - 1) * offset;
copy_v3_v3(bezt->vec[j], tmp_vec);
}
@@ -591,13 +590,63 @@ bGPDcurve
*BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
copy_v4_v4(cpt->vert_color, pt->vert_color);
/* default handle type */
- bezt->h1 = HD_ALIGN;
- bezt->h2 = HD_ALIGN;
+ bezt->h1 = HD_FREE;
+ bezt->h2 = HD_FREE;
cpt->point_index = 0;
return editcurve;
}
+ if (gps->totpoints == 2) {
+ bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_new(2);
+ bGPDspoint *first_pt = &gps->points[0];
+ bGPDspoint *last_pt = &gps->points[1];
+
+ float length = len_v3v3(&first_pt->x, &last_pt->x);
+ float offset = length / 3;
+ float dir[3];
+ sub_v3_v3v3(dir, &last_pt->x, &first_pt->x);
+
+ for (int i = 0; i < 2; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ bGPDcurve_point *cpt = &editcurve->curve_points[i];
+ BezTriple *bezt = &cpt->bezt;
+
+ float tmp_vec[3];
+ for (int j = 0; j < 3; j++) {
+ copy_v3_v3(tmp_vec, dir);
+ normalize_v3_length(tmp_vec, (float)(j - 1) * offset);
+ add_v3_v3v3(bezt->vec[j], &pt->x, tmp_vec);
+ }
+
+ cpt->pressure = pt->pressure;
+ cpt->strength = pt->strength;
+ copy_v4_v4(cpt->vert_color, pt->vert_color);
+
+ /* default handle type */
+ bezt->h1 = HD_VECT;
+ bezt->h2 = HD_VECT;
+
+ cpt->point_index = 0;
+ }
+
+ return editcurve;
+ }
+
+ return NULL;
+}
+
+/**
+ * Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil
stroke points.
+ */
+bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
+ const float error_threshold,
+ const float corner_angle,
+ const float stroke_radius)
+{
+ if (gps->totpoints < 3) {
+ return gpencil_stroke_editcurve_generate_edgecases(gps, stroke_radius);
+ }
#define POINT_DIM 9
float *points = MEM_callocN(sizeof(float) * gps->totpoints * POINT_DIM,
__func__);
@@ -704,9 +753,7 @@ bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke
*gps,
/**
* Updates the editcurve for a stroke. Frees the old curve if one exists and
generates a new one.
*/
-void BKE_gpencil_stroke_editcurve_update(bGPDstroke *gps,
- const float error_threshold,
- const float corner_angle)
+void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl,
bGPDstroke *gps)
{
if (gps == NULL || gps->totpoints < 0) {
return;
@@ -716,7 +763,11 @@ void BKE_gpencil_stroke_editcurve_update(bGPDstroke *gps,
BKE_gpencil_free_stroke_editcurve(gps);
}
- bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_generate(gps,
error_threshold, corner_angle);
+ float defaultpixsize = 1000.0f / gpd->pixfactor;
+ float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize)
/ 2.0f;
+
+ bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_generate(
+ gps, gpd->curve_edit_threshold, gpd->curve_corner_angle, stroke_radius);
if (editcurve == NULL) {
return;
}
@@ -1012,7 +1063,8 @@ void
BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
if (curve_point_array_len == 0) {
return;
}
- else if (curve_point_array_len == 1) {
+ /* Handle case for single curve point. */
+ if (curve_point_array_len == 1) {
bGPDcurve_point *cpt = &curve_point_array[0];
/* resize stroke point array */
gps->totpoints = 1;
@@ -1022,7 +1074,7 @@ void
BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
}
bGPDspoint *pt = &gps->points[0];
- copy_v3_v3(&pt->x, cpt->bezt.vec[0]);
+ copy_v3_v3(&pt->x, cpt->bezt.vec[1]);
pt->pressure = cpt->pressure;
pt->strength = cpt->strength;
@@ -1095,7 +1147,8 @@ void BKE_gpencil_editcurve_recalculate_handles(bGPDstroke
*gps)
}
if (gpc->tot_curve_points == 1) {
- BKE_nurb_handle_calc(&(gpc->curve_points[0].bezt), NULL, NULL, false, 0);
+ BKE_nurb_handle_calc(
+ &(gpc->curve_points[0].bezt), NULL, &(gpc->curve_points[0].bezt),
false, 0);
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
}
@@ -1307,16 +1360,14 @@ void
BKE_gpencil_strokes_selected_update_editcurve(bGPdata *gpd)
/* Generate the curve if there is none or the stroke was changed */
if (gps->editcurve == NULL) {
- BKE_gpencil_stroke_editcurve_update(
- gps, gpd->curve_edit_threshold, gpd->curve_corner_angle);
+ BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
/* Continue if curve could not be generated. */
if (gps->editcurve == NULL) {
continue;
}
}
else if (gps->editcurve->flag & GP_CURVE_NEEDS_STROKE_UPDATE) {
- BKE_gpencil_stroke_editcurve_update(
- gps, gpd->curve_edit_threshold, gpd->curve_corner_angle);
+ 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);
diff --git a/source/blender/editors/gpencil/gpencil_edit.c
b/source/blender/editors/gpencil/gpencil_edit.c
index 5f845a85fa6..f1b66b2c2a6 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -209,8 +209,7 @@ static int gpencil_editmode_toggle_exec(bContext *C,
wmOperator *op)
GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
{
if (gpc->flag & GP_CURVE_NEEDS_STROKE_UPDATE) {
- BKE_gpencil_stroke_editcurve_update(
- gps, gpd->curve_edit_threshold, gpd->curve_corner_angle);
+ 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);
@@ -1194,7 +1193,7 @@ static void gpencil_curve_extrude_points(bGPdata *gpd,
{
const int old_num_points = gpc->tot_curve_points;
const bool first_select = gpc->curve_points[0].flag & GP_CURVE_POINT_SELECT;
- const bool last_select = gpc->curve_points[old_num_points - 1].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++) {
@@ -1231,6 +1230,11 @@ static void gpencil_curve_extrude_points(bGPdata *gpd,
}
}
+ /* 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;
@@ -4237,8 +4241,7 @@ 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(
- gps, gpd->curve_edit_threshold, gpd->curve_corner_angle);
+ BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
/* Update the selection from the strok
@@ Diff output truncated at 10240 characters. @@
_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs