[Bf-blender-cvs] [60fa80de0b2] master: Curves: Add custom profile bevel support

Hans Goudey noreply at git.blender.org
Wed Sep 16 17:20:52 CEST 2020


Commit: 60fa80de0b2c7138fc86b8b688f22a9d2623e8ed
Author: Hans Goudey
Date:   Wed Sep 16 10:20:38 2020 -0500
Branches: master
https://developer.blender.org/rB60fa80de0b2c7138fc86b8b688f22a9d2623e8ed

Curves: Add custom profile bevel support

This adds support for the same custom bevel profile widget used in
the bevel tool and modifier to the geometry generation for curves.

This is expecially useful for text and 2D curves with extrusion, as
it works much better than a weld & bevel modifier combination.
It can also be useful for adding quick detail to pipe-like objects.

The curve holds the CurveProfile struct and a new "Bevel Mode"
property decides which type of bevel to build, round, object, or
custom profile.

Although curves can already use another curve to make the bevel
geometry, this is a quicker way, and it also defines the profile of
just one corner of the bevel, so it isn't redundant. It's also nice
to have the same custom profile functionality wherever there is bevel.

Differential Revision: https://developer.blender.org/D8402

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

M	release/scripts/startup/bl_ui/properties_data_curve.py
M	source/blender/blenkernel/intern/curve.c
M	source/blender/blenkernel/intern/curve_bevel.c
M	source/blender/blenkernel/intern/curveprofile.c
M	source/blender/blenloader/intern/versioning_290.c
M	source/blender/makesdna/DNA_curve_defaults.h
M	source/blender/makesdna/DNA_curve_types.h
M	source/blender/makesrna/intern/rna_curve.c

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

diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index 7e7488f4cf1..1329f35d575 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -171,7 +171,7 @@ class DATA_PT_geometry_curve(CurveButtonsPanelCurve, Panel):
         col.prop(curve, "offset")
 
         sub = col.column()
-        sub.active = (curve.bevel_object is None)
+        sub.active = (curve.bevel_mode != 'OBJECT')
         sub.prop(curve, "extrude")
 
         col.prop(curve, "taper_object")
@@ -193,21 +193,19 @@ class DATA_PT_geometry_curve_bevel(CurveButtonsPanelCurve, Panel):
 
     def draw(self, context):
         layout = self.layout
-        layout.use_property_split = True
 
         curve = context.curve
+        layout.prop(curve, "bevel_mode", expand=True)
 
-        col = layout.column()
-        sub = col.column()
-        sub.active = (curve.bevel_object is None)
-        sub.prop(curve, "bevel_depth", text="Depth")
-        sub.prop(curve, "bevel_resolution", text="Resolution")
-
-        col.prop(curve, "bevel_object", text="Object")
+        layout.use_property_split = True
 
-        sub = col.column()
-        sub.active = curve.bevel_object is not None
-        sub.prop(curve, "use_fill_caps")
+        col = layout.column()
+        if curve.bevel_mode == 'OBJECT':
+            col.prop(curve, "bevel_object", text="Object")
+        else:
+            col.prop(curve, "bevel_depth", text="Depth")
+            col.prop(curve, "bevel_resolution", text="Resolution")
+        col.prop(curve, "use_fill_caps")
 
         if type(curve) is not TextCurve:
 
@@ -218,13 +216,17 @@ class DATA_PT_geometry_curve_bevel(CurveButtonsPanelCurve, Panel):
                 (curve.bevel_object is not None)
             )
             sub = col.column(align=True)
-            sub.prop(curve, "bevel_factor_start", text="Bevel Start")
+            sub.prop(curve, "bevel_factor_start", text="Start")
             sub.prop(curve, "bevel_factor_end", text="End")
 
             sub = col.column(align=True)
-            sub.prop(curve, "bevel_factor_mapping_start", text="Bevel Mapping Start")
+            sub.prop(curve, "bevel_factor_mapping_start", text="Mapping Start")
             sub.prop(curve, "bevel_factor_mapping_end", text="End")
 
+        # Put the large template at the end so it doesn't displace the other properties
+        if curve.bevel_mode == 'PROFILE':
+            col.template_curveprofile(curve, "bevel_profile")
+
 
 class DATA_PT_pathanim(CurveButtonsPanelCurve, Panel):
     bl_label = "Path Animation"
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 74efa45cc73..24be6708785 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -50,6 +50,7 @@
 
 #include "BKE_anim_data.h"
 #include "BKE_curve.h"
+#include "BKE_curveprofile.h"
 #include "BKE_displist.h"
 #include "BKE_font.h"
 #include "BKE_idtype.h"
@@ -95,6 +96,8 @@ static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
   curve_dst->tb = MEM_dupallocN(curve_src->tb);
   curve_dst->batch_cache = NULL;
 
+  curve_dst->bevel_profile = BKE_curveprofile_copy(curve_src->bevel_profile);
+
   if (curve_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
     BKE_id_copy_ex(bmain, &curve_src->key->id, (ID **)&curve_dst->key, flag);
     /* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */
@@ -116,6 +119,8 @@ static void curve_free_data(ID *id)
 
   BKE_curve_editNurb_free(curve);
 
+  BKE_curveprofile_free(curve->bevel_profile);
+
   MEM_SAFE_FREE(curve->mat);
   MEM_SAFE_FREE(curve->str);
   MEM_SAFE_FREE(curve->strinfo);
@@ -181,6 +186,10 @@ static void curve_blend_write(BlendWriter *writer, ID *id, const void *id_addres
           }
         }
       }
+
+      if (cu->bevel_profile != NULL) {
+        BKE_curveprofile_blend_write(writer, cu->bevel_profile);
+      }
     }
   }
 }
@@ -251,6 +260,11 @@ static void curve_blend_read_data(BlendDataReader *reader, ID *id)
     }
   }
   cu->texflag &= ~CU_AUTOSPACE_EVALUATED;
+
+  BLO_read_data_address(reader, &cu->bevel_profile);
+  if (cu->bevel_profile != NULL) {
+    BKE_curveprofile_blend_read(reader, cu->bevel_profile);
+  }
 }
 
 static void curve_blend_read_lib(BlendLibReader *reader, ID *id)
@@ -397,6 +411,7 @@ void BKE_curve_init(Curve *cu, const short curve_type)
   else if (cu->type == OB_SURF) {
     cu->resolv = 4;
   }
+  cu->bevel_profile = NULL;
 }
 
 Curve *BKE_curve_add(Main *bmain, const char *name, int type)
diff --git a/source/blender/blenkernel/intern/curve_bevel.c b/source/blender/blenkernel/intern/curve_bevel.c
index edf5b82f822..911a98cb607 100644
--- a/source/blender/blenkernel/intern/curve_bevel.c
+++ b/source/blender/blenkernel/intern/curve_bevel.c
@@ -23,15 +23,18 @@
 
 #include <string.h>
 
+#include "BLI_alloca.h"
 #include "BLI_listbase.h"
 #include "BLI_math_base.h"
 
 #include "MEM_guardedalloc.h"
 
 #include "DNA_curve_types.h"
+#include "DNA_curveprofile_types.h"
 #include "DNA_object_types.h"
 
 #include "BKE_curve.h"
+#include "BKE_curveprofile.h"
 #include "BKE_displist.h"
 
 typedef enum CurveBevelFillType {
@@ -53,6 +56,33 @@ static CurveBevelFillType curve_bevel_get_fill_type(const Curve *curve)
   return (curve->flag & CU_FRONT) ? FRONT : BACK;
 }
 
+static void bevel_quarter_fill(Curve *curve, float *quarter_coords_x, float *quarter_coords_y)
+{
+  if (curve->bevel_mode == CU_BEV_MODE_ROUND) {
+    float angle = 0.0f;
+    const float dangle = (float)M_PI_2 / (curve->bevresol + 1);
+    for (int i = 0; i < curve->bevresol + 1; i++) {
+      quarter_coords_x[i] = (float)(cosf(angle) * (curve->ext2));
+      quarter_coords_y[i] = (float)(sinf(angle) * (curve->ext2));
+      angle += dangle;
+    }
+  }
+  else {
+    /* The curve profile evaluation should be done when the resolution is set. */
+    BLI_assert(curve->bevel_profile->segments != NULL);
+    BLI_assert(curve->bevel_profile->segments_len == curve->bevresol + 1);
+
+    /* If there aren't enough samples, the curveprofile won't
+     * sample the start vertex, so set it manually instead. */
+    quarter_coords_x[0] = curve->ext2;
+    quarter_coords_y[0] = 0.0f;
+    for (int i = 1; i < curve->bevresol + 1; i++) {
+      quarter_coords_x[i] = (float)(curve->bevel_profile->segments[i].x * (curve->ext2));
+      quarter_coords_y[i] = (float)(curve->bevel_profile->segments[i].y * (curve->ext2));
+    }
+  }
+}
+
 static void curve_bevel_make_extrude_and_fill(Curve *cu,
                                               ListBase *disp,
                                               const bool use_extrude,
@@ -60,10 +90,20 @@ static void curve_bevel_make_extrude_and_fill(Curve *cu,
 {
   DispList *dl = MEM_callocN(sizeof(DispList), __func__);
 
+  /* Calculate the profile of the bevel once to reuse it for each quarter. We will need
+   * to flip around the indices for every other section in order to build around the circle
+   * in a consistent direction.
+   *
+   * These should be small enough for stack allocations because the current limit
+   * for #Curve.bevresol is 32.  */
+  float *quarter_coords_x = alloca(sizeof(float) * (cu->bevresol + 1));
+  float *quarter_coords_y = alloca(sizeof(float) * (cu->bevresol + 1));
+  bevel_quarter_fill(cu, quarter_coords_x, quarter_coords_y);
+
   int nr;
   if (fill_type == FULL) {
     /* The full loop. */
-    nr = 4 * cu->bevresol + 6;
+    nr = 4 * cu->bevresol + (use_extrude ? 6 : 4);
     dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
   }
   else if (fill_type == HALF) {
@@ -85,65 +125,69 @@ static void curve_bevel_make_extrude_and_fill(Curve *cu,
   dl->nr = nr;
 
   float *fp = dl->verts;
-  const float dangle = (float)M_PI_2 / (cu->bevresol + 1);
-  float angle = 0.0f;
 
   /* Build the back section. */
   if (ELEM(fill_type, BACK, HALF, FULL)) {
-    angle = (float)M_PI_2 * 3.0f;
-    for (int i = 0; i < cu->bevresol + 2; i++) {
+    /* Add the bottom vertex. */
+    fp[0] = 0.0f;
+    fp[1] = 0.0f;
+    fp[2] = -cu->ext1 - cu->ext2;
+    fp += 3;
+
+    for (int i = cu->bevresol; i >= 0; i--) {
       fp[0] = 0.0f;
-      fp[1] = (float)(cosf(angle) * (cu->ext2));
-      fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
-      angle += dangle;
+      fp[1] = quarter_coords_x[i];
+      fp[2] = -quarter_coords_y[i] - cu->ext1;
       fp += 3;
     }
-    if (use_extrude && fill_type == BACK) {
-      /* Add the extrusion if we're only building the back. */
-      fp[0] = 0.0f;
-      fp[1] = cu->ext2;
-      fp[2] = cu->ext1;
-    }
+  }
+
+  /* Add the extrusion if we're only building either the back or the front. */
+  if (use_extrude && ELEM(fill_type, FRONT, BACK)) {
+    fp[0] = 0.0f;
+    fp[1] = cu->ext2;
+    fp[2] = (fill_type == FRONT) ? -cu->ext1 : cu->ext1;
+    fp += 3;
   }
 
   /* Build the front section. */
   if (ELEM(fill_type, FRONT, HALF, FULL)) {
-    if (use_extrude && fill_type == FRONT) {
-      /* Add the extrusion if we're only building the front. */
-      fp[0] = 0.0f;
-      fp[1] = cu->ext2;
-      fp[2] = -cu->ext1;
-      fp += 3;
-    }
     /* Don't duplicate the last back vertex. */
-    angle = (!use_extrude && ELEM(fill_type, HALF, FULL)) ? dangle : 0;
-    int front_len = (!use_extrude && ELEM(fill_type, HALF, FULL)) ? cu->bevresol + 1 :
-                                                                    cu->bevresol + 2;
-    for (int i = 0; i < front_len; i++) {
+    const int front_start = (!use_extrude && ELEM(fill_type, HALF, FULL)) ? 1 : 0;
+    for (int i = front_start; i < cu->bevresol + 1; i++) {
       fp[0] = 0.0f;
-      fp[1] = (float)(cosf(angle) * (cu->ext2));
-      fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
-      angle += dangle;
+      fp[1] = quarter_coords_x[i];
+      fp[2] = quarter_coords_y[i] + cu->ext1;
       fp += 3;
     }
+    /* Add the top vertex. */
+    fp[0] = 0.0f;
+    fp[1] = 0.0f;
+    fp[2] = cu->ext1 + cu->ext2;
+    fp += 3;
   }
 
   /* Build the other half only if we're building the full loop. */
   if (fill_type == FULL) {
-    for (int i = 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list