diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_data_curve.py | 30 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curve.c | 15 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curve_bevel.c | 156 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curveprofile.c | 2 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_290.c | 12 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_curve_defaults.h | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_curve_types.h | 13 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_curve.c | 65 |
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"); |