[Bf-blender-cvs] [f16a50ba946] soc-2020-greasepencil-curve: GPencil: Implement adaptive editcurve resolution

Falk David noreply at git.blender.org
Wed Jul 22 16:11:33 CEST 2020


Commit: f16a50ba946ae4ddea18d4f7058fef3a359078b8
Author: Falk David
Date:   Wed Jul 22 16:10:25 2020 +0200
Branches: soc-2020-greasepencil-curve
https://developer.blender.org/rBf16a50ba946ae4ddea18d4f7058fef3a359078b8

GPencil: Implement adaptive editcurve resolution

With adaptive curve resolution the arclength of a curve segment is
used to calculate the number of points between two control points.
This means that in general the stroke points are more spaced out.

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

M	release/scripts/startup/bl_ui/space_view3d.py
M	source/blender/blenkernel/BKE_gpencil_curve.h
M	source/blender/blenkernel/intern/gpencil_curve.c
M	source/blender/blenkernel/intern/gpencil_geom.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
M	source/blender/makesdna/DNA_gpencil_types.h
M	source/blender/makesrna/intern/rna_gpencil.c

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

diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 007b8c933ce..0faca0b3413 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -6990,6 +6990,7 @@ class VIEW3D_PT_gpencil_curve_edit(Panel):
 
         layout = self.layout
         col = layout.column(align=True)
+        col.prop(gpd, "use_adaptive_curve_resolution")
         col.prop(gpd, "edit_curve_resolution")
         col.prop(gpd, "curve_edit_threshold")
 
diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h
index b066e901211..28791acc47a 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -50,7 +50,7 @@ void BKE_gpencil_editcurve_stroke_sync_selection(struct bGPDstroke *gps, struct
 void BKE_gpencil_stroke_editcurve_sync_selection(struct bGPDstroke *gps, struct bGPDcurve *gpc);
 void BKE_gpencil_strokes_selected_update_editcurve(struct bGPdata *gpd);
 void BKE_gpencil_strokes_selected_sync_selection_editcurve(struct bGPdata *gpd);
-void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps);
+void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps, const uint resolution, bool is_adaptive);
 void BKE_gpencil_editcurve_recalculate_handles(struct bGPDstroke *gps);
 void BKE_gpencil_editcurve_subdivide(struct bGPDstroke *gps, const int cuts);
 
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index eb3c78f2827..e38c79f3a0f 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -665,6 +665,7 @@ static void gpencil_interpolate_fl_from_to(
   float *r = point_offset;
   for (int i = 0; i <= it; i++) {
     float fac = (float)i / (float)it;
+    // fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; // smooth
     *r = interpf(to, from, fac);
     r = POINTER_OFFSET(r, stride);
   }
@@ -677,12 +678,27 @@ static void gpencil_interpolate_v4_from_to(
   float *r = point_offset;
   for (int i = 0; i <= it; i++) {
     float fac = (float)i / (float)it;
+    // fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; // smooth
     interp_v4_v4v4(r, from, to, fac);
     r = POINTER_OFFSET(r, stride);
   }
 }
 
-static void gpencil_calculate_stroke_points_curve_point(
+static float gpencil_approximate_curve_segment_arclength(bGPDcurve_point *cpt_start,
+                                                         bGPDcurve_point *cpt_end)
+{
+  BezTriple *bezt_start = &cpt_start->bezt;
+  BezTriple *bezt_end = &cpt_end->bezt;
+
+  float chord_len = len_v3v3(bezt_start->vec[1], bezt_end->vec[1]);
+  float net_len = len_v3v3(bezt_start->vec[1], bezt_start->vec[2]);
+  net_len += len_v3v3(bezt_start->vec[2], bezt_end->vec[0]);
+  net_len += len_v3v3(bezt_end->vec[0], bezt_end->vec[1]);
+
+  return (chord_len + net_len) / 2.0f;
+}
+
+static void gpencil_calculate_stroke_points_curve_segment(
     bGPDcurve_point *cpt, bGPDcurve_point *cpt_next, float *points_offset, int resolu, int stride)
 {
   /* sample points on all 3 axis between two curve points */
@@ -714,51 +730,141 @@ static void gpencil_calculate_stroke_points_curve_point(
                                  stride);
 }
 
-/**
- * Recalculate stroke points with the editcurve of the stroke.
- */
-void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps)
+static float *gpencil_stroke_points_from_editcurve_adaptive_resolu(
+    bGPDcurve_point *curve_point_array,
+    int curve_point_array_len,
+    int resolution,
+    bool is_cyclic,
+    int *r_points_len)
 {
-  if (gps == NULL || gps->editcurve == NULL) {
-    return;
+  /* One stride contains: x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor */
+  const uint stride = sizeof(float[9]);
+  const uint cpt_last = curve_point_array_len - 1;
+  const uint num_segments = (is_cyclic) ? curve_point_array_len : curve_point_array_len - 1;
+  int *segment_point_lengths = MEM_callocN(sizeof(int) * num_segments, __func__);
+
+  uint points_len = 0;
+  for (int i = 0; i < cpt_last; i++) {
+    bGPDcurve_point *cpt = &curve_point_array[i];
+    bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
+    float arclen = gpencil_approximate_curve_segment_arclength(cpt, cpt_next);
+    int segment_resolu = (int)floorf(arclen * resolution);
+
+    segment_point_lengths[i] = segment_resolu;
+    points_len += segment_resolu;
   }
 
-  bGPDcurve *editcurve = gps->editcurve;
-  bGPDcurve_point *curve_point_array = editcurve->curve_points;
-  int curve_point_array_len = editcurve->tot_curve_points;
-  int resolu = editcurve->resolution;
-  bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
+  if (is_cyclic) {
+    bGPDcurve_point *cpt = &curve_point_array[cpt_last];
+    bGPDcurve_point *cpt_next = &curve_point_array[0];
+    float arclen = gpencil_approximate_curve_segment_arclength(cpt, cpt_next);
+    int segment_resolu = (int)floorf(arclen * resolution);
 
-  const uint array_last = curve_point_array_len - 1;
+    segment_point_lengths[cpt_last] = segment_resolu;
+    points_len += segment_resolu;
+  }
+  points_len += 1;
+
+  float(*r_points)[9] = MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__);
+  float *points_offset = &r_points[0][0];
+  int point_index = 0;
+  for (int i = 0; i < cpt_last; i++) {
+    bGPDcurve_point *cpt_curr = &curve_point_array[i];
+    bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
+    int segment_resolu = segment_point_lengths[i];
+    gpencil_calculate_stroke_points_curve_segment(
+        cpt_curr, cpt_next, points_offset, segment_resolu, stride);
+    /* update the index */
+    cpt_curr->point_index = point_index;
+    point_index += segment_resolu;
+    points_offset = POINTER_OFFSET(points_offset, segment_resolu * stride);
+  }
+
+  bGPDcurve_point *cpt_curr = &curve_point_array[cpt_last];
+  cpt_curr->point_index = point_index;
+  if (is_cyclic) {
+    bGPDcurve_point *cpt_next = &curve_point_array[0];
+    int segment_resolu = segment_point_lengths[cpt_last];
+    gpencil_calculate_stroke_points_curve_segment(
+        cpt_curr, cpt_next, points_offset, segment_resolu, stride);
+  }
+
+  MEM_freeN(segment_point_lengths);
+
+  *r_points_len = points_len;
+  return (float(*))r_points;
+}
+
+/**
+ * Helper: calculate the points on a curve with a fixed resolution.
+ */
+static float *gpencil_stroke_points_from_editcurve_fixed_resolu(bGPDcurve_point *curve_point_array,
+                                                                int curve_point_array_len,
+                                                                int resolution,
+                                                                bool is_cyclic,
+                                                                int *r_points_len)
+{
   /* One stride contains: x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor */
   const uint stride = sizeof(float[9]);
-  const uint resolu_stride = resolu * stride;
+  const uint array_last = curve_point_array_len - 1;
+  const uint resolu_stride = resolution * stride;
   const uint points_len = BKE_curve_calc_coords_axis_len(
-      curve_point_array_len, resolu, is_cyclic, false);
+      curve_point_array_len, resolution, is_cyclic, false);
 
-  float(*points)[9] = MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__);
-  float *points_offset = &points[0][0];
+  float(*r_points)[9] = MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__);
+  float *points_offset = &r_points[0][0];
   for (unsigned int i = 0; i < array_last; i++) {
     bGPDcurve_point *cpt_curr = &curve_point_array[i];
     bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
 
-    gpencil_calculate_stroke_points_curve_point(cpt_curr, cpt_next, points_offset, resolu, stride);
+    gpencil_calculate_stroke_points_curve_segment(
+        cpt_curr, cpt_next, points_offset, resolution, stride);
     /* update the index */
-    cpt_curr->point_index = i * resolu;
+    cpt_curr->point_index = i * resolution;
     points_offset = POINTER_OFFSET(points_offset, resolu_stride);
   }
 
+  bGPDcurve_point *cpt_curr = &curve_point_array[array_last];
+  cpt_curr->point_index = array_last * resolution;
   if (is_cyclic) {
-    bGPDcurve_point *cpt_curr = &curve_point_array[array_last];
     bGPDcurve_point *cpt_next = &curve_point_array[0];
+    gpencil_calculate_stroke_points_curve_segment(
+        cpt_curr, cpt_next, points_offset, resolution, stride);
+  }
+
+  *r_points_len = points_len;
+  return (float(*))r_points;
+}
+
+/**
+ * Recalculate stroke points with the editcurve of the stroke.
+ */
+void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
+                                                       const uint resolution,
+                                                       bool adaptive)
+{
+  if (gps == NULL || gps->editcurve == NULL) {
+    return;
+  }
 
-    gpencil_calculate_stroke_points_curve_point(cpt_curr, cpt_next, points_offset, resolu, stride);
+  bGPDcurve *editcurve = gps->editcurve;
+  bGPDcurve_point *curve_point_array = editcurve->curve_points;
+  int curve_point_array_len = editcurve->tot_curve_points;
+  bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
 
-    cpt_curr->point_index = array_last * resolu;
+  int points_len = 0;
+  float(*points)[9] = NULL;
+  if (adaptive) {
+    points = (float(*)[9])gpencil_stroke_points_from_editcurve_adaptive_resolu(
+        curve_point_array, curve_point_array_len, resolution, is_cyclic, &points_len);
   }
   else {
-    bGPDcurve_point *cpt_curr = &curve_point_array[array_last];
-    cpt_curr->point_index = array_last * resolu;
+    points = (float(*)[9])gpencil_stroke_points_from_editcurve_fixed_resolu(
+        curve_point_array, curve_point_array_len, resolution, is_cyclic, &points_len);
+  }
+
+  if (points == NULL || points_len == 0) {
+    return;
   }
 
   /* resize stroke point array */
@@ -1012,7 +1118,7 @@ void BKE_gpencil_strokes_selected_update_editcurve(bGPdata *gpd)
           if (!(gps->flag & GP_STROKE_SELECT)) {
             continue;
           }
-        
+
           /

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list