[Bf-blender-cvs] [d5bebb33b23] greasepencil-object: GPencil: New Close Stroke operator

Antonioya noreply at git.blender.org
Sat Jun 29 16:43:18 CEST 2019


Commit: d5bebb33b23d8630e43f369e25ea779d05275b02
Author: Antonioya
Date:   Sat Jun 29 16:24:59 2019 +0200
Branches: greasepencil-object
https://developer.blender.org/rBd5bebb33b23d8630e43f369e25ea779d05275b02

GPencil: New Close Stroke operator

This operator allows to close a stoke generating geometry for the closing gap.

This is totally different of Cyclic, because this was only a visual closing, but as there wasn't new geometry, you could sculpt or edit and need manual subdivide.

===================================================================

M	source/blender/blenkernel/BKE_gpencil.h
M	source/blender/blenkernel/intern/gpencil.c
M	source/blender/editors/gpencil/gpencil_edit.c
M	source/blender/editors/gpencil/gpencil_intern.h
M	source/blender/editors/gpencil/gpencil_ops.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 6e8efd1b194..742546680a4 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -291,6 +291,7 @@ bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf);
 bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence);
 bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence);
 bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_close_stroke(struct bGPDstroke *gps);
 
 void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
 float BKE_gpencil_multiframe_falloff_calc(
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 842fa85bf76..e1204883a2d 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -1958,3 +1958,83 @@ bool BKE_gpencil_trim_stroke(bGPDstroke *gps)
   }
   return intersect;
 }
+
+/**
+ * Close stroke
+ * \param gps: Stroke to close
+ */
+bool BKE_gpencil_close_stroke(bGPDstroke *gps)
+{
+  bGPDspoint *pt1 = NULL;
+  bGPDspoint *pt2 = NULL;
+
+  /* Only can close a stroke with 3 points or more. */
+  if (gps->totpoints < 3) {
+    return false;
+  }
+
+  /* Calc average distance between points to get same level of sampling. */
+  float dist_tot = 0.0f;
+  for (int i = 0; i < gps->totpoints - 1; i++) {
+    pt1 = &gps->points[i];
+    pt2 = &gps->points[i + 1];
+    dist_tot += len_v3v3(&pt1->x, &pt2->x);
+  }
+  /* Calc the average distance. */
+  float dist_avg = dist_tot / (gps->totpoints - 1);
+
+  /* Calc distance between last and first point. */
+  pt1 = &gps->points[gps->totpoints - 1];
+  pt2 = &gps->points[0];
+  float dist_close = len_v3v3(&pt1->x, &pt2->x);
+
+  /* Calc number of points required using the average distance. */
+  int tot_newpoints = MAX2(dist_close / dist_avg, 1);
+
+  /* Resize stroke array. */
+  int old_tot = gps->totpoints;
+  gps->totpoints += tot_newpoints;
+  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);
+  }
+
+  /* Generate new points */
+  pt1 = &gps->points[old_tot - 1];
+  pt2 = &gps->points[0];
+  bGPDspoint *pt = &gps->points[old_tot];
+  for (int i = 1; i < tot_newpoints + 1; i++, pt++) {
+    float step = ((float)i / (float)tot_newpoints);
+    /* Clamp last point to be near, but not on top of first point. */
+    CLAMP(step, 0.0f, 0.99f);
+
+    /* Average point. */
+    interp_v3_v3v3(&pt->x, &pt1->x, &pt2->x, step);
+    pt->pressure = interpf(pt1->pressure, pt2->pressure, step);
+    pt->strength = interpf(pt1->strength, pt2->strength, step);
+    pt->flag = 0;
+
+    /* Set weights. */
+    if (gps->dvert != NULL) {
+      MDeformVert *dvert1 = &gps->dvert[old_tot - 1];
+      MDeformWeight *dw1 = defvert_verify_index(dvert1, 0);
+      float weight_1 = dw1 ? dw1->weight : 0.0f;
+
+      MDeformVert *dvert2 = &gps->dvert[0];
+      MDeformWeight *dw2 = defvert_verify_index(dvert2, 0);
+      float weight_2 = dw2 ? dw2->weight : 0.0f;
+
+      MDeformVert *dvert_final = &gps->dvert[old_tot + i - 1];
+      dvert_final->totweight = 0;
+      MDeformWeight *dw = defvert_verify_index(dvert_final, 0);
+      if (dvert_final->dw) {
+        dw->weight = interpf(weight_2, weight_1, step);
+      }
+    }
+  }
+
+  /* Enable cyclic flag. */
+  gps->flag |= GP_STROKE_CYCLIC;
+
+  return true;
+}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index f07b22a7b96..2f68369db9e 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -4588,3 +4588,68 @@ bool ED_object_gpencil_exit(struct Main *bmain, Object *ob)
   }
   return ok;
 }
+
+/* Add geometry to stroke for closing the path */
+static int gpencil_close_exec(bContext *C, wmOperator *op)
+{
+  Object *obact = CTX_data_active_object(C);
+  bGPdata *gpd = (bGPdata *)obact->data;
+  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+  bGPDstroke *gps = NULL;
+
+  if (gpd == NULL) {
+    BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+    return OPERATOR_CANCELLED;
+  }
+
+  CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+    bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
+
+    for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+      if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+        if (gpf == NULL) {
+          continue;
+        }
+
+        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;
+          }
+
+          if (gps->flag & GP_STROKE_SELECT) {
+            /* generate geometry */
+            BKE_gpencil_close_stroke(gps);
+          }
+        }
+        /* if not multiedit, exit loop*/
+        if (!is_multiedit) {
+          break;
+        }
+      }
+    }
+  }
+  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);
+
+  return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_close(wmOperatorType *ot)
+{
+  /* identifiers */
+  ot->name = "Stroke Close";
+  ot->description = "Add geometry to close stroke";
+  ot->idname = "GPENCIL_OT_stroke_close";
+
+  /* callbacks */
+  ot->exec = gpencil_close_exec;
+  ot->poll = gp_active_layer_poll;
+
+  /* flag */
+  ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index a9acd8057c1..3778ea1023f 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -489,6 +489,7 @@ void GPENCIL_OT_stroke_smooth(struct wmOperatorType *ot);
 void GPENCIL_OT_stroke_merge(struct wmOperatorType *ot);
 void GPENCIL_OT_stroke_cutter(struct wmOperatorType *ot);
 void GPENCIL_OT_stroke_trim(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_close(struct wmOperatorType *ot);
 
 void GPENCIL_OT_brush_presets_create(struct wmOperatorType *ot);
 
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index db4c601709c..b1edcf5499b 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -309,6 +309,7 @@ void ED_operatortypes_gpencil(void)
   WM_operatortype_append(GPENCIL_OT_stroke_merge);
   WM_operatortype_append(GPENCIL_OT_stroke_cutter);
   WM_operatortype_append(GPENCIL_OT_stroke_trim);
+  WM_operatortype_append(GPENCIL_OT_stroke_close);
 
   WM_operatortype_append(GPENCIL_OT_brush_presets_create);



More information about the Bf-blender-cvs mailing list