From 6c7467e0da9cf241b1eac7dfe91e6aefe1d985ce Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 18 Aug 2014 17:35:51 +0600 Subject: 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. --- source/blender/blenkernel/intern/displist.c | 168 +++++++++------------------- 1 file changed, 53 insertions(+), 115 deletions(-) (limited to 'source/blender/blenkernel/intern/displist.c') diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 43c13f1c896..e01ff24dad3 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -1356,31 +1356,57 @@ static void fillBevelCap(Nurb *nu, DispList *dlb, float *prev_fp, ListBase *disp BLI_addtail(dispbase, dl); } +static void calc_bevfac_segment_mapping(BevList *bl, float bevfac, float spline_length, int *r_bev, float *r_blend) +{ + float normlen, normsum = 0.0f; + float *seglen = bl->seglen; + int *segbevcount = bl->segbevcount; + int bevcount = 0, nr = bl->nr; + + float bev_fl = bevfac * (bl->nr - 1); + *r_bev = (int)bev_fl; + + while (bevcount < nr - 1) { + normlen = *seglen / spline_length; + if (normsum + normlen > bevfac){ + bev_fl = bevcount + (bevfac - normsum) / normlen * *segbevcount; + *r_bev = (int) bev_fl; + *r_blend = bev_fl - *r_bev; + break; + } + normsum += normlen; + bevcount += *segbevcount; + segbevcount++; + seglen++; + } +} -static void calc_bevfac_spline_mapping(BevList *bl, float bevfac, float spline_length, const float *bevp_array, +static void calc_bevfac_spline_mapping(BevList *bl, float bevfac, + float spline_length, int *r_bev, float *r_blend) { const float len_target = bevfac * spline_length; - float len = 0.0f; - float len_step = 0.0f; - int i; - for (i = 0; i < bl->nr - 1; i++) { - float len_next; - len_step = bevp_array[i]; - len_next = len + len_step; + BevPoint *bevp = bl->bevpoints; + float len_next = 0.0f, len = 0.0f; + int i = 0, nr = bl->nr; + + while (nr--) { + bevp++; + len_next = len + bevp->offset; if (len_next > len_target) { break; } len = len_next; + i++; } *r_bev = i; - *r_blend = (len_target - len) / len_step; + *r_blend = (len_target - len) / bevp->offset; } -static void calc_bevfac_mapping_default( - BevList *bl, - int *r_start, float *r_firstblend, int *r_steps, float *r_lastblend) +static void calc_bevfac_mapping_default(BevList *bl, + int *r_start, float *r_firstblend, + int *r_steps, float *r_lastblend) { *r_start = 0; *r_steps = bl->nr; @@ -1388,19 +1414,11 @@ static void calc_bevfac_mapping_default( *r_lastblend = 1.0f; } -static void calc_bevfac_mapping( - Curve *cu, BevList *bl, Nurb *nu, const bool use_render_resolution, +static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu, int *r_start, float *r_firstblend, int *r_steps, float *r_lastblend) { - const int resolu = (nu->type == CU_POLY) ? - 1 : (use_render_resolution && (cu->resolu_ren != 0)) ? - cu->resolu_ren : cu->resolu; - const int segcount = ((nu->type == CU_POLY) ? bl->nr : nu->pntsu) - 1; - - float l, startf, endf, tmpf, total_length = 0.0f; - float *bevp_array = NULL; - float *segments = NULL; - int end = 0, i, j; + float tmpf, total_length = 0.0f; + int end = 0, i; if ((BKE_nurb_check_valid_u(nu) == false) || /* not essential, but skips unnecessary calculation */ @@ -1411,57 +1429,12 @@ static void calc_bevfac_mapping( return; } - if ((cu->bevfac1_mapping != CU_BEVFAC_MAP_RESOLU) || - (cu->bevfac2_mapping != CU_BEVFAC_MAP_RESOLU)) + if (ELEM(cu->bevfac1_mapping, + CU_BEVFAC_MAP_SEGMENT, + CU_BEVFAC_MAP_SPLINE)) { - BezTriple *bezt, *bezt_prev; - BevPoint *bevp, *bevp_prev; - int bevp_i; - - bevp_array = MEM_mallocN(sizeof(*bevp_array) * (bl->nr - 1), "bevp_dists"); - segments = MEM_callocN(sizeof(*segments) * segcount, "bevp_segmentlengths"); - bevp_prev = bl->bevpoints; - bevp = bevp_prev + 1; - - if (nu->type == CU_BEZIER) { - bezt_prev = nu->bezt; - bezt = bezt_prev + 1; - for (i = 0, bevp_i = 0; i < segcount; i++, bezt_prev++, bezt++) { - float seglen = 0.0f; - if (bezt_prev->h2 == HD_VECT && bezt->h1 == HD_VECT) { - seglen = len_v3v3(bevp->vec, bevp_prev->vec); - BLI_assert(bevp_i < bl->nr - 1); - bevp_array[bevp_i++] = seglen; - - bevp_prev = bevp++; - } - else { - for (j = 0; j < resolu; j++, bevp_prev = bevp++) { - l = len_v3v3(bevp->vec, bevp_prev->vec); - seglen += l; - BLI_assert(bevp_i < bl->nr - 1); - bevp_array[bevp_i++] = l; - } - } - BLI_assert(i < segcount); - segments[i] = seglen; - total_length += seglen; - seglen = 0.0f; - } - } - else { - float seglen = 0.0f; - for (i = 1, j = 0; i < bl->nr; i++, bevp_prev = bevp++) { - BLI_assert(i - 1 < bl->nr); - bevp_array[i - 1] = len_v3v3(bevp->vec, bevp_prev->vec); - total_length += bevp_array[i - 1]; - seglen += bevp_array[i - 1]; - if ((i % resolu) == 0 || (bl->nr - 1) == i) { - BLI_assert(j < segcount); - segments[j++] = seglen; - seglen = 0.0f; - } - } + for (i = 0; i < SEGMENTSU(nu); i++) { + total_length += bl->seglen[i]; } } @@ -1470,31 +1443,18 @@ static void calc_bevfac_mapping( { const float start_fl = cu->bevfac1 * (bl->nr - 1); *r_start = (int)start_fl; - *r_firstblend = 1.0f - (start_fl - (*r_start)); break; } case CU_BEVFAC_MAP_SEGMENT: { - float sum = 0.0f; - const float start_fl = cu->bevfac1 * (bl->nr - 1); - *r_start = (int)start_fl; - - for (i = 0; i < segcount; i++) { - l = segments[i] / total_length; - if (sum + l > cu->bevfac1) { - startf = i * resolu + (cu->bevfac1 - sum) / l * resolu; - *r_start = (int) startf; - *r_firstblend = 1.0f - (startf - *r_start); - break; - } - sum += l; - } + calc_bevfac_segment_mapping(bl, cu->bevfac1, total_length, r_start, r_firstblend); + *r_firstblend = 1.0f - *r_firstblend; break; } case CU_BEVFAC_MAP_SPLINE: { - calc_bevfac_spline_mapping(bl, cu->bevfac1, total_length, bevp_array, r_start, r_firstblend); + calc_bevfac_spline_mapping(bl, cu->bevfac1, total_length, r_start, r_firstblend); *r_firstblend = 1.0f - *r_firstblend; break; } @@ -1512,27 +1472,13 @@ static void calc_bevfac_mapping( } case CU_BEVFAC_MAP_SEGMENT: { - float sum = 0.0f; - const float end_fl = cu->bevfac2 * (bl->nr - 1); - end = (int)end_fl; - + calc_bevfac_segment_mapping(bl, cu->bevfac2, total_length, &end, r_lastblend); *r_steps = end - *r_start + 2; - for (i = 0; i < segcount; i++) { - l = segments[i] / total_length; - if (sum + l > cu->bevfac2) { - endf = i * resolu + (cu->bevfac2 - sum) / l * resolu; - end = (int)endf; - *r_lastblend = (endf - end); - *r_steps = end - *r_start + 2; - break; - } - sum += l; - } break; } case CU_BEVFAC_MAP_SPLINE: { - calc_bevfac_spline_mapping(bl, cu->bevfac2, total_length, bevp_array, &end, r_lastblend); + calc_bevfac_spline_mapping(bl, cu->bevfac2, total_length, &end, r_lastblend); *r_steps = end - *r_start + 2; break; } @@ -1550,13 +1496,6 @@ static void calc_bevfac_mapping( *r_steps = bl->nr - *r_start; *r_lastblend = 1.0f; } - - if (bevp_array) { - MEM_freeN(bevp_array); - } - if (segments) { - MEM_freeN(segments); - } } static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispbase, @@ -1575,7 +1514,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba ListBase dlbev; ListBase nubase = {NULL, NULL}; - BLI_freelistN(&(ob->curve_cache->bev)); + BKE_curve_bevelList_free(&ob->curve_cache->bev); /* We only re-evlauate path if evaluation is not happening for orco. * If the calculation happens for orco, we should never free data which @@ -1667,8 +1606,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba continue; } - calc_bevfac_mapping(cu, bl, nu, use_render_resolution, - &start, &firstblend, &steps, &lastblend); + calc_bevfac_mapping(cu, bl, nu, &start, &firstblend, &steps, &lastblend); } for (dlb = dlbev.first; dlb; dlb = dlb->next) { -- cgit v1.2.3