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:
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py30
-rw-r--r--source/blender/blenkernel/intern/curve.c15
-rw-r--r--source/blender/blenkernel/intern/curve_bevel.c156
-rw-r--r--source/blender/blenkernel/intern/curveprofile.c2
-rw-r--r--source/blender/blenloader/intern/versioning_290.c12
-rw-r--r--source/blender/makesdna/DNA_curve_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_curve_types.h13
-rw-r--r--source/blender/makesrna/intern/rna_curve.c65
8 files changed, 224 insertions, 70 deletions
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 = 0; i < cu->bevresol + 1; i++) {
+ 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) {
+ /* Add the extrusion. */
+ fp[0] = 0.0f;
+ fp[1] = -cu->ext2;
+ fp[2] = cu->ext1;
fp += 3;
}
- angle = (float)M_PI;
for (int i = 0; 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;
}
}
@@ -193,6 +237,9 @@ static void curve_bevel_make_only_extrude(Curve *cu, ListBase *disp)
static void curve_bevel_make_from_object(Curve *cu, ListBase *disp)
{
+ if (cu->bevobj == NULL) {
+ return;
+ }
if (cu->bevobj->type != OB_CURVE) {
return;
}
@@ -244,29 +291,30 @@ void BKE_curve_bevel_make(Object *ob, ListBase *disp)
{
Curve *curve = ob->data;
- const bool use_extrude = curve->ext1 != 0.0f;
- const bool use_bevel = curve->ext2 != 0.0f;
-
BLI_listbase_clear(disp);
- if (curve->bevobj) {
- curve_bevel_make_from_object(curve, disp);
- }
- else if (!(use_extrude || use_bevel)) {
- /* Pass. */
- }
- else if (use_extrude && !use_bevel) {
- curve_bevel_make_only_extrude(curve, disp);
+ if (curve->bevel_mode == CU_BEV_MODE_OBJECT) {
+ if (curve->bevobj != NULL) {
+ curve_bevel_make_from_object(curve, disp);
+ }
}
else {
- CurveBevelFillType fill_type = curve_bevel_get_fill_type(curve);
-
- if (!use_extrude && fill_type == FULL) {
- curve_bevel_make_full_circle(curve, disp);
+ const bool use_extrude = curve->ext1 != 0.0f;
+ const bool use_bevel = curve->ext2 != 0.0f;
+ /* Pass. */
+ if (use_extrude && !use_bevel) {
+ curve_bevel_make_only_extrude(curve, disp);
}
- else {
- /* The general case for nonzero extrusion or an incomplete loop. */
- curve_bevel_make_extrude_and_fill(curve, disp, use_extrude, fill_type);
+ else if (use_extrude || use_bevel) {
+ CurveBevelFillType fill_type = curve_bevel_get_fill_type(curve);
+
+ if (!use_extrude && fill_type == FULL && curve->bevel_mode == CU_BEV_MODE_ROUND) {
+ curve_bevel_make_full_circle(curve, disp);
+ }
+ else {
+ /* The general case for nonzero extrusion or an incomplete loop. */
+ curve_bevel_make_extrude_and_fill(curve, disp, use_extrude, fill_type);
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/curveprofile.c b/source/blender/blenkernel/intern/curveprofile.c
index f52619f8c3a..b7017253be1 100644
--- a/source/blender/blenkernel/intern/curveprofile.c
+++ b/source/blender/blenkernel/intern/curveprofile.c
@@ -1122,4 +1122,6 @@ void BKE_curveprofile_blend_read(struct BlendDataReader *reader, struct CurvePro
for (int i = 0; i < profile->path_len; i++) {
profile->path[i].profile = profile;
}
+
+ BKE_curveprofile_init(profile, profile->segments_len);
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 064b6139fde..63c3140c084 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -694,5 +694,17 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Add custom profile and bevel mode to curve bevels. */
+ if (!DNA_struct_elem_find(fd->filesdna, "Curve", "char", "bevel_mode")) {
+ LISTBASE_FOREACH (Curve *, curve, &bmain->curves) {
+ if (curve->bevobj != NULL) {
+ curve->bevel_mode = CU_BEV_MODE_OBJECT;
+ }
+ else {
+ curve->bevel_mode = CU_BEV_MODE_ROUND;
+ }
+ }
+ }
}
}
diff --git a/source/blender/makesdna/DNA_curve_defaults.h b/source/blender/makesdna/DNA_curve_defaults.h
index 0cb3960dbd7..07dd0aeb08d 100644
--- a/source/blender/makesdna/DNA_curve_defaults.h
+++ b/source/blender/makesdna/DNA_curve_defaults.h
@@ -49,6 +49,7 @@
.bevfac1_mapping = CU_BEVFAC_MAP_RESOLU, \
.bevfac2_mapping = CU_BEVFAC_MAP_RESOLU, \
.bevresol = 4, \
+ .bevel_mode = CU_BEV_MODE_ROUND, \
}
/** \} */
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 8d5b5602c2e..2f362034b78 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -31,6 +31,7 @@
#define MAXTEXTBOX 256 /* used in readfile.c and editfont.c */
struct AnimData;
+struct CurveProfile;
struct EditFont;
struct GHash;
struct Ipo;
@@ -232,6 +233,8 @@ typedef struct Curve {
struct Key *key;
struct Material **mat;
+ struct CurveProfile *bevel_profile;
+
/* texture space, copied as one block in editobject.c */
float loc[3];
float size[3];
@@ -261,7 +264,8 @@ typedef struct Curve {
char overflow;
char spacemode, align_y;
- char _pad[3];
+ char bevel_mode;
+ char _pad[2];
/* font part */
short lines;
@@ -385,6 +389,13 @@ enum {
CU_ALIGN_Y_BOTTOM = 4,
};
+/* Curve.bevel_mode */
+enum {
+ CU_BEV_MODE_ROUND = 0,
+ CU_BEV_MODE_OBJECT = 1,
+ CU_BEV_MODE_CURVE_PROFILE = 2,
+};
+
/* Curve.overflow. */
enum {
CU_OVERFLOW_NONE = 0,
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 1768d79fe8f..854c8757d4d 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -167,6 +167,7 @@ static const EnumPropertyItem curve2d_fill_mode_items[] = {
# include "DNA_object_types.h"
# include "BKE_curve.h"
+# include "BKE_curveprofile.h"
# include "BKE_main.h"
# include "DEG_depsgraph.h"
@@ -463,6 +464,35 @@ static void rna_Curve_bevelObject_set(PointerRNA *ptr,
}
}
+/**
+ * Special update function for setting the number of segments of the curve
+ * that also resamples the segments in the custom profile.
+ */
+static void rna_Curve_bevel_resolution_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Curve *cu = (Curve *)ptr->data;
+
+ if (cu->bevel_mode == CU_BEV_MODE_CURVE_PROFILE) {
+ BKE_curveprofile_init(cu->bevel_profile, cu->bevresol + 1);
+ }
+
+ rna_Curve_update_data(bmain, scene, ptr);
+}
+
+static void rna_Curve_bevel_mode_set(PointerRNA *ptr, int value)
+{
+ Curve *cu = (Curve *)ptr->owner_id;
+
+ if (value == CU_BEV_MODE_CURVE_PROFILE) {
+ if (cu->bevel_profile == NULL) {
+ cu->bevel_profile = BKE_curveprofile_add(PROF_PRESET_LINE);
+ BKE_curveprofile_init(cu->bevel_profile, cu->bevresol + 1);
+ }
+ }
+
+ cu->bevel_mode = value;
+}
+
static bool rna_Curve_otherObject_poll(PointerRNA *ptr, PointerRNA value)
{
Curve *cu = (Curve *)ptr->owner_id;
@@ -1527,6 +1557,25 @@ static void rna_def_curve(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem bevel_mode_items[] = {
+ {CU_BEV_MODE_ROUND,
+ "ROUND",
+ 0,
+ "Round",
+ "Use circle for the section of the curve's bevel geometry"},
+ {CU_BEV_MODE_OBJECT,
+ "OBJECT",
+ 0,
+ "Object",
+ "Use an object for the section of the curve's bevel goemetry segment"},
+ {CU_BEV_MODE_CURVE_PROFILE,
+ "PROFILE",
+ 0,
+ "Profile",
+ "Use a custom profile for each quarter of curve's bevel geometry"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "Curve", "ID");
RNA_def_struct_ui_text(srna, "Curve", "Curve data-block storing curves, splines and NURBS");
RNA_def_struct_ui_icon(srna, ICON_CURVE_DATA);
@@ -1559,6 +1608,20 @@ static void rna_def_curve(BlenderRNA *brna)
rna_def_path(brna, srna);
+ prop = RNA_def_property(srna, "bevel_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "bevel_mode");
+ RNA_def_property_enum_items(prop, bevel_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Bevel Mode", "Determine how to build the curve's bevel geometry");
+ RNA_def_property_enum_funcs(prop, NULL, "rna_Curve_bevel_mode_set", NULL);
+ RNA_def_property_update(prop, 0, "rna_Curve_update_data");
+
+ prop = RNA_def_property(srna, "bevel_profile", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "CurveProfile");
+ RNA_def_property_pointer_sdna(prop, NULL, "bevel_profile");
+ RNA_def_property_ui_text(prop, "Custom Profile Path", "The path for the curve's custom profile");
+ RNA_def_property_update(prop, 0, "rna_Curve_update_data");
+
/* Number values */
prop = RNA_def_property(srna, "bevel_resolution", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "bevresol");
@@ -1568,7 +1631,7 @@ static void rna_def_curve(BlenderRNA *brna)
prop,
"Bevel Resolution",
"Bevel resolution when depth is non-zero and no specific bevel object has been defined");
- RNA_def_property_update(prop, 0, "rna_Curve_update_data");
+ RNA_def_property_update(prop, 0, "rna_Curve_bevel_resolution_update");
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "width");