diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2014-08-18 15:35:51 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2014-08-18 15:38:20 +0400 |
commit | 6c7467e0da9cf241b1eac7dfe91e6aefe1d985ce (patch) | |
tree | 29575be83368f2d641221d3bf3b3e93a17ae3865 /source/blender/blenkernel/intern/curve.c | |
parent | 05cb63ecf75095444c8ce2bc11b3067bb207d8bf (diff) |
Fix T41085: Blender crashes when using "spline" or "segments" for bevel curve factor.
Root of the issue goes to the fact that bevel list calculation might drop some points
if they're at the same position. This made spline length calculation goes wrong.
Now the length of the bevel segments is stored in the bevel list, so values are
always reliable.
Initial patch by Lukas Treyer with some tweaks from me.
Diffstat (limited to 'source/blender/blenkernel/intern/curve.c')
-rw-r--r-- | source/blender/blenkernel/intern/curve.c | 164 |
1 files changed, 150 insertions, 14 deletions
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index a6f7bd442af..8d776c277fe 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -2500,6 +2500,21 @@ 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); + } +} + void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) { /* @@ -2508,21 +2523,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; @@ -2531,7 +2554,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; @@ -2561,9 +2584,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; @@ -2571,7 +2600,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); @@ -2579,23 +2612,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; @@ -2611,6 +2674,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) { @@ -2623,6 +2688,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 */ @@ -2660,8 +2733,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++; @@ -2681,15 +2774,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, @@ -2697,6 +2797,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); } @@ -2717,15 +2842,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++; + } } } } @@ -2742,6 +2876,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 */ |