diff options
Diffstat (limited to 'source/blender/blenkernel/intern/curve.c')
-rw-r--r-- | source/blender/blenkernel/intern/curve.c | 296 |
1 files changed, 276 insertions, 20 deletions
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 0abe956b599..9275b626b49 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -52,6 +52,7 @@ #include "BKE_animsys.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_font.h" #include "BKE_global.h" @@ -642,8 +643,9 @@ void BKE_nurb_test2D(Nurb *nu) } } -/* if use_radius is truth, minmax will take points' radius into account, - * which will make boundbox closer to bevelled curve. +/** + * if use_radius is truth, minmax will take points' radius into account, + * which will make boundbox closer to beveled curve. */ void BKE_nurb_minmax(Nurb *nu, bool use_radius, float min[3], float max[3]) { @@ -2498,6 +2500,22 @@ static void bevlist_firstlast_direction_calc_from_bpoint(Nurb *nu, BevList *bl) } } +void BKE_curve_bevelList_free(ListBase *bev) +{ + BevList *bl, *blnext; + for (bl = bev->first; bl != NULL; bl = blnext) { + blnext = bl->next; + if (bl->seglen != NULL) { + MEM_freeN(bl->seglen); + } + if (bl->segbevcount != NULL) { + MEM_freeN(bl->segbevcount); + } + MEM_freeN(bl); + } + bev->first = bev->last = NULL; +} + void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) { /* @@ -2506,21 +2524,29 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) * - separate in individual blocks with BoundBox * - AutoHole detection */ - Curve *cu; + + /* this function needs an object, because of tflag and upflag */ + Curve *cu = ob->data; Nurb *nu; BezTriple *bezt, *prevbezt; BPoint *bp; BevList *bl, *blnew, *blnext; BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0; + const float treshold = 0.00001f; float min, inp; + float *seglen; struct BevelSort *sortdata, *sd, *sd1; - int a, b, nr, poly, resolu = 0, len = 0; + int a, b, nr, poly, resolu = 0, len = 0, segcount; + int *segbevcount; bool do_tilt, do_radius, do_weight; bool is_editmode = false; ListBase *bev; - /* this function needs an object, because of tflag and upflag */ - cu = ob->data; + /* segbevcount alsp requires seglen. */ + const bool need_seglen = + ELEM(cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) || + ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE); + bev = &ob->curve_cache->bev; @@ -2529,7 +2555,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) /* STEP 1: MAKE POLYS */ - BLI_freelistN(&(ob->curve_cache->bev)); + BKE_curve_bevelList_free(&ob->curve_cache->bev); nu = nurbs->first; if (cu->editnurb && ob->type != OB_FONT) { is_editmode = 1; @@ -2559,9 +2585,15 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) else resolu = nu->resolu; + segcount = SEGMENTSU(nu); + if (nu->type == CU_POLY) { len = nu->pntsu; bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList2"); + if (need_seglen) { + bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelList2_seglen"); + bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelList2_segbevcount"); + } BLI_addtail(bev, bl); bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; @@ -2569,7 +2601,11 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) bl->dupe_nr = 0; bl->charidx = nu->charidx; bevp = bl->bevpoints; + bevp->offset = 0; bp = nu->bp; + seglen = bl->seglen; + segbevcount = bl->segbevcount; + BLI_assert(segcount >= len); while (len--) { copy_v3_v3(bevp->vec, bp->vec); @@ -2577,23 +2613,53 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) bevp->radius = bp->radius; bevp->weight = bp->weight; bevp->split_tag = true; - bevp++; bp++; + if (seglen != NULL) { + *seglen = len_v3v3(bevp->vec, bp->vec); + bevp++; + bevp->offset = *seglen; + if (*seglen > treshold) *segbevcount = 1; + else *segbevcount = 0; + seglen++; + segbevcount++; + } + else { + bevp++; + } } if ((nu->flagu & CU_NURB_CYCLIC) == 0) { bevlist_firstlast_direction_calc_from_bpoint(nu, bl); + if (seglen != NULL) { + *seglen = len_v3v3(bevp->vec, nu->bp->vec); + bl->bevpoints->offset = *seglen; + *segbevcount = 1; + } } } else if (nu->type == CU_BEZIER) { /* in case last point is not cyclic */ - len = resolu * (nu->pntsu + (nu->flagu & CU_NURB_CYCLIC) - 1) + 1; + len = segcount * resolu + 1; + bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelBPoints"); + if (need_seglen) { + bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelBPoints_seglen"); + bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelBPoints_segbevcount"); + } BLI_addtail(bev, bl); bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; bl->charidx = nu->charidx; + bevp = bl->bevpoints; + seglen = bl->seglen; + segbevcount = bl->segbevcount; + + bevp->offset = 0; + if (seglen != NULL) { + *seglen = 0; + *segbevcount = 0; + } a = nu->pntsu - 1; bezt = nu->bezt; @@ -2609,6 +2675,8 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) sub_v3_v3v3(bevp->dir, prevbezt->vec[2], prevbezt->vec[1]); normalize_v3(bevp->dir); + BLI_assert(segcount >= a); + while (a--) { if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) { @@ -2621,6 +2689,14 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) bevp++; bl->nr++; bl->dupe_nr = 1; + if (seglen != NULL) { + *seglen = len_v3v3(prevbezt->vec[1], bezt->vec[1]); + bevp->offset = *seglen; + seglen++; + /* match segbevcount to the cleaned up bevel lists (see STEP 2) */ + if (bevp->offset > treshold) *segbevcount = 1; + segbevcount++; + } } else { /* always do all three, to prevent data hanging around */ @@ -2658,8 +2734,28 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) else if (prevbezt->h2 == 0 || prevbezt->h2 == HD_VECT) bevp->split_tag = true; } + + /* seglen */ + if (seglen != NULL) { + *seglen = 0; + *segbevcount = 0; + for (j = 0; j < resolu; j++) { + bevp0 = bevp; + bevp++; + bevp->offset = len_v3v3(bevp0->vec, bevp->vec); + /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */ + if (bevp->offset > treshold) { + *seglen += bevp->offset; + *segbevcount += 1; + } + } + seglen++; + segbevcount++; + } + else { + bevp += resolu; + } bl->nr += resolu; - bevp += resolu; } prevbezt = bezt; bezt++; @@ -2679,15 +2775,22 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) } else if (nu->type == CU_NURBS) { if (nu->pntsv == 1) { - len = (resolu * SEGMENTSU(nu)); + len = (resolu * segcount); bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList3"); + if (need_seglen) { + bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelList3_seglen"); + bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelList3_segbevcount"); + } BLI_addtail(bev, bl); bl->nr = len; bl->dupe_nr = 0; bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; bl->charidx = nu->charidx; + bevp = bl->bevpoints; + seglen = bl->seglen; + segbevcount = bl->segbevcount; BKE_nurb_makeCurve(nu, &bevp->vec[0], do_tilt ? &bevp->alfa : NULL, @@ -2695,6 +2798,31 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) do_weight ? &bevp->weight : NULL, resolu, sizeof(BevPoint)); + /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */ + if (seglen != NULL) { + nr = segcount; + bevp0 = bevp; + bevp++; + while (nr) { + int j; + *seglen = 0; + *segbevcount = 0; + /* We keep last bevel segment zero-length. */ + for (j = 0; j < ((nr == 1) ? (resolu - 1) : resolu); j++) { + bevp->offset = len_v3v3(bevp0->vec, bevp->vec); + if (bevp->offset > treshold) { + *seglen += bevp->offset; + *segbevcount += 1; + } + bevp0 = bevp; + bevp++; + } + seglen++; + segbevcount++; + nr--; + } + } + if ((nu->flagu & CU_NURB_CYCLIC) == 0) { bevlist_firstlast_direction_calc_from_bpoint(nu, bl); } @@ -2715,15 +2843,24 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) } else { bevp0 = bl->bevpoints; + bevp0->offset = 0; bevp1 = bevp0 + 1; } nr--; while (nr--) { - if (fabsf(bevp0->vec[0] - bevp1->vec[0]) < 0.00001f) { - if (fabsf(bevp0->vec[1] - bevp1->vec[1]) < 0.00001f) { - if (fabsf(bevp0->vec[2] - bevp1->vec[2]) < 0.00001f) { - bevp0->dupe_tag = true; - bl->dupe_nr++; + if (seglen != NULL) { + if (fabsf(bevp1->offset) < treshold) { + bevp0->dupe_tag = true; + bl->dupe_nr++; + } + } + else { + if (fabsf(bevp0->vec[0] - bevp1->vec[0]) < 0.00001f) { + if (fabsf(bevp0->vec[1] - bevp1->vec[1]) < 0.00001f) { + if (fabsf(bevp0->vec[2] - bevp1->vec[2]) < 0.00001f) { + bevp0->dupe_tag = true; + bl->dupe_nr++; + } } } } @@ -2740,6 +2877,8 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */ blnew = MEM_mallocN(sizeof(BevList) + nr * sizeof(BevPoint), "makeBevelList4"); memcpy(blnew, bl, sizeof(BevList)); + blnew->segbevcount = bl->segbevcount; + blnew->seglen = bl->seglen; blnew->nr = 0; BLI_remlink(bev, bl); BLI_insertlinkbefore(bev, blnext, blnew); /* to make sure bevlijst is tuned with nurblist */ @@ -3070,7 +3209,13 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n madd_v3_v3v3fl(p2_h2, p2, dvec_b, 1.0f / 3.0f); } - if (skip_align || (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) { + if (skip_align || + /* when one handle is free, alignming makes no sense, see: T35952 */ + (ELEM(HD_FREE, bezt->h1, bezt->h2)) || + /* also when no handles are aligned, skip this step */ + (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && + !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) + { /* handles need to be updated during animation and applying stuff like hooks, * but in such situations it's quite difficult to distinguish in which order * align handles should be aligned so skip them for now */ @@ -3168,6 +3313,31 @@ void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */ calchandlesNurb_intern(nu, false); } +/** + * Workaround #BKE_nurb_handles_calc logic + * that makes unselected align to the selected handle. + */ +static void nurbList_handles_swap_select(Nurb *nu) +{ + BezTriple *bezt; + int i; + + for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) { + if ((bezt->f1 & SELECT) != (bezt->f3 & SELECT)) { + bezt->f1 ^= SELECT; + bezt->f3 ^= SELECT; + } + } +} + +/* internal use only (weak) */ +static void nurb_handles_calc__align_selected(Nurb *nu) +{ + nurbList_handles_swap_select(nu); + BKE_nurb_handles_calc(nu); + nurbList_handles_swap_select(nu); +} + /* similar to BKE_nurb_handle_calc but for curves and * figures out the previous and next for us */ void BKE_nurb_handle_calc_simple(Nurb *nu, BezTriple *bezt) @@ -3365,7 +3535,9 @@ void BKE_nurbList_handles_set(ListBase *editnurb, const char code) } bezt++; } - BKE_nurb_handles_calc(nu); + + /* like BKE_nurb_handles_calc but moves selected */ + nurb_handles_calc__align_selected(nu); } nu = nu->next; } @@ -3409,7 +3581,9 @@ void BKE_nurbList_handles_set(ListBase *editnurb, const char code) bezt++; } - BKE_nurb_handles_calc(nu); + + /* like BKE_nurb_handles_calc but moves selected */ + nurb_handles_calc__align_selected(nu); } } } @@ -4143,7 +4317,50 @@ bool BKE_curve_center_bounds(Curve *cu, float cent[3]) return false; } -void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys) + +void BKE_curve_transform_ex(Curve *cu, float mat[4][4], bool do_keys, float unit_scale) +{ + Nurb *nu; + BPoint *bp; + BezTriple *bezt; + int i; + + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + i = nu->pntsu; + for (bezt = nu->bezt; i--; bezt++) { + mul_m4_v3(mat, bezt->vec[0]); + mul_m4_v3(mat, bezt->vec[1]); + mul_m4_v3(mat, bezt->vec[2]); + bezt->radius *= unit_scale; + } + BKE_nurb_handles_calc(nu); + } + else { + i = nu->pntsu * nu->pntsv; + for (bp = nu->bp; i--; bp++) + mul_m4_v3(mat, bp->vec); + } + } + + if (do_keys && cu->key) { + KeyBlock *kb; + for (kb = cu->key->block.first; kb; kb = kb->next) { + float *fp = kb->data; + for (i = kb->totelem; i--; fp += 3) { + mul_m4_v3(mat, fp); + } + } + } +} + +void BKE_curve_transform(Curve *cu, float mat[4][4], bool do_keys) +{ + float unit_scale = mat4_to_scale(mat); + BKE_curve_transform_ex(cu, mat, do_keys, unit_scale); +} + +void BKE_curve_translate(Curve *cu, float offset[3], bool do_keys) { ListBase *nurb_lb = BKE_curve_nurbs_get(cu); Nurb *nu; @@ -4230,6 +4447,45 @@ void BKE_curve_material_index_clear(Curve *cu) } } +int BKE_curve_material_index_validate(Curve *cu) +{ + const int curvetype = BKE_curve_type_get(cu); + bool is_valid = true; + + if (curvetype == OB_FONT) { + CharInfo *info = cu->strinfo; + const int max_idx = max_ii(0, cu->totcol); /* OB_FONT use 1 as first mat index, not 0!!! */ + int i; + for (i = cu->len_wchar - 1; i >= 0; i--, info++) { + if (info->mat_nr > max_idx) { + info->mat_nr = 0; + is_valid = false; + } + } + } + else { + Nurb *nu; + const int max_idx = max_ii(0, cu->totcol - 1); + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->mat_nr > max_idx) { + nu->mat_nr = 0; + if (curvetype == OB_CURVE) { + nu->charidx = 0; + } + is_valid = false; + } + } + } + + if (!is_valid) { + DAG_id_tag_update(&cu->id, OB_RECALC_DATA); + return true; + } + else { + return false; + } +} + void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect) { r_rect->xmin = cu->xof + tb->x; |