diff options
Diffstat (limited to 'source/blender/blenkernel/intern/curve.c')
-rw-r--r-- | source/blender/blenkernel/intern/curve.c | 8849 |
1 files changed, 4477 insertions, 4372 deletions
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 0ab5a6ca963..f28e14be512 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -21,7 +21,6 @@ * \ingroup bke */ - #include <math.h> // floor #include <string.h> #include <stdlib.h> @@ -63,128 +62,134 @@ /* local */ static CLG_LogRef LOG = {"bke.curve"}; -static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], const float v4[3], - short cox, short coy, - float *lambda, float *mu, float vec[3]); +static int cu_isectLL(const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3], + short cox, + short coy, + float *lambda, + float *mu, + float vec[3]); /* frees editcurve entirely */ void BKE_curve_editfont_free(Curve *cu) { - if (cu->editfont) { - EditFont *ef = cu->editfont; + if (cu->editfont) { + EditFont *ef = cu->editfont; - if (ef->textbuf) - MEM_freeN(ef->textbuf); - if (ef->textbufinfo) - MEM_freeN(ef->textbufinfo); - if (ef->selboxes) - MEM_freeN(ef->selboxes); + if (ef->textbuf) + MEM_freeN(ef->textbuf); + if (ef->textbufinfo) + MEM_freeN(ef->textbufinfo); + if (ef->selboxes) + MEM_freeN(ef->selboxes); - MEM_freeN(ef); - cu->editfont = NULL; - } + MEM_freeN(ef); + cu->editfont = NULL; + } } static void curve_editNurb_keyIndex_cv_free_cb(void *val) { - CVKeyIndex *index = val; - MEM_freeN(index->orig_cv); - MEM_freeN(val); + CVKeyIndex *index = val; + MEM_freeN(index->orig_cv); + MEM_freeN(val); } void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv) { - BLI_assert(keyindex != NULL); - BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb); + BLI_assert(keyindex != NULL); + BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb); } void BKE_curve_editNurb_keyIndex_free(GHash **keyindex) { - if (!(*keyindex)) { - return; - } - BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb); - *keyindex = NULL; + if (!(*keyindex)) { + return; + } + BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb); + *keyindex = NULL; } void BKE_curve_editNurb_free(Curve *cu) { - if (cu->editnurb) { - BKE_nurbList_free(&cu->editnurb->nurbs); - BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex); - MEM_freeN(cu->editnurb); - cu->editnurb = NULL; - } + if (cu->editnurb) { + BKE_nurbList_free(&cu->editnurb->nurbs); + BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex); + MEM_freeN(cu->editnurb); + cu->editnurb = NULL; + } } /** Free (or release) any data used by this curve (does not free the curve itself). */ void BKE_curve_free(Curve *cu) { - BKE_animdata_free((ID *)cu, false); + BKE_animdata_free((ID *)cu, false); - BKE_curve_batch_cache_free(cu); + BKE_curve_batch_cache_free(cu); - BKE_nurbList_free(&cu->nurb); - BKE_curve_editfont_free(cu); + BKE_nurbList_free(&cu->nurb); + BKE_curve_editfont_free(cu); - BKE_curve_editNurb_free(cu); + BKE_curve_editNurb_free(cu); - MEM_SAFE_FREE(cu->mat); - MEM_SAFE_FREE(cu->str); - MEM_SAFE_FREE(cu->strinfo); - MEM_SAFE_FREE(cu->bb); - MEM_SAFE_FREE(cu->tb); + MEM_SAFE_FREE(cu->mat); + MEM_SAFE_FREE(cu->str); + MEM_SAFE_FREE(cu->strinfo); + MEM_SAFE_FREE(cu->bb); + MEM_SAFE_FREE(cu->tb); } void BKE_curve_init(Curve *cu) { - /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cu, id)); */ /* cu->type is already initialized... */ - - copy_v3_fl(cu->size, 1.0f); - cu->flag = CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS; - cu->pathlen = 100; - cu->resolu = cu->resolv = (cu->type == OB_SURF) ? 4 : 12; - cu->width = 1.0; - cu->wordspace = 1.0; - cu->spacing = cu->linedist = 1.0; - cu->fsize = 1.0; - cu->ulheight = 0.05; - cu->texflag = CU_AUTOSPACE; - cu->smallcaps_scale = 0.75f; - /* XXX: this one seems to be the best one in most cases, at least for curve deform... */ - cu->twist_mode = CU_TWIST_MINIMUM; - cu->bevfac1 = 0.0f; - cu->bevfac2 = 1.0f; - cu->bevfac1_mapping = CU_BEVFAC_MAP_RESOLU; - cu->bevfac2_mapping = CU_BEVFAC_MAP_RESOLU; - cu->bevresol = 4; - - cu->bb = BKE_boundbox_alloc_unit(); - - if (cu->type == OB_FONT) { - cu->flag |= CU_FRONT | CU_BACK; - cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get(); - cu->vfont->id.us += 4; - cu->str = MEM_malloc_arrayN(12, sizeof(unsigned char), "str"); - BLI_strncpy(cu->str, "Text", 12); - cu->len = cu->len_wchar = cu->pos = 4; - cu->strinfo = MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new"); - cu->totbox = cu->actbox = 1; - cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox"); - cu->tb[0].w = cu->tb[0].h = 0.0; - } + /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cu, id)); */ /* cu->type is already initialized... */ + + copy_v3_fl(cu->size, 1.0f); + cu->flag = CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS; + cu->pathlen = 100; + cu->resolu = cu->resolv = (cu->type == OB_SURF) ? 4 : 12; + cu->width = 1.0; + cu->wordspace = 1.0; + cu->spacing = cu->linedist = 1.0; + cu->fsize = 1.0; + cu->ulheight = 0.05; + cu->texflag = CU_AUTOSPACE; + cu->smallcaps_scale = 0.75f; + /* XXX: this one seems to be the best one in most cases, at least for curve deform... */ + cu->twist_mode = CU_TWIST_MINIMUM; + cu->bevfac1 = 0.0f; + cu->bevfac2 = 1.0f; + cu->bevfac1_mapping = CU_BEVFAC_MAP_RESOLU; + cu->bevfac2_mapping = CU_BEVFAC_MAP_RESOLU; + cu->bevresol = 4; + + cu->bb = BKE_boundbox_alloc_unit(); + + if (cu->type == OB_FONT) { + cu->flag |= CU_FRONT | CU_BACK; + cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get(); + cu->vfont->id.us += 4; + cu->str = MEM_malloc_arrayN(12, sizeof(unsigned char), "str"); + BLI_strncpy(cu->str, "Text", 12); + cu->len = cu->len_wchar = cu->pos = 4; + cu->strinfo = MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new"); + cu->totbox = cu->actbox = 1; + cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox"); + cu->tb[0].w = cu->tb[0].h = 0.0; + } } Curve *BKE_curve_add(Main *bmain, const char *name, int type) { - Curve *cu; + Curve *cu; - cu = BKE_libblock_alloc(bmain, ID_CU, name, 0); - cu->type = type; + cu = BKE_libblock_alloc(bmain, ID_CU, name, 0); + cu->type = type; - BKE_curve_init(cu); + BKE_curve_init(cu); - return cu; + return cu; } /** @@ -197,240 +202,249 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type) */ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const int flag) { - BLI_listbase_clear(&cu_dst->nurb); - BKE_nurbList_duplicate(&(cu_dst->nurb), &(cu_src->nurb)); + BLI_listbase_clear(&cu_dst->nurb); + BKE_nurbList_duplicate(&(cu_dst->nurb), &(cu_src->nurb)); - cu_dst->mat = MEM_dupallocN(cu_src->mat); + cu_dst->mat = MEM_dupallocN(cu_src->mat); - cu_dst->str = MEM_dupallocN(cu_src->str); - cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo); - cu_dst->tb = MEM_dupallocN(cu_src->tb); - cu_dst->bb = MEM_dupallocN(cu_src->bb); - cu_dst->batch_cache = NULL; + cu_dst->str = MEM_dupallocN(cu_src->str); + cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo); + cu_dst->tb = MEM_dupallocN(cu_src->tb); + cu_dst->bb = MEM_dupallocN(cu_src->bb); + cu_dst->batch_cache = NULL; - if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { - BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag); - } + if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { + BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag); + } - cu_dst->editnurb = NULL; - cu_dst->editfont = NULL; + cu_dst->editnurb = NULL; + cu_dst->editfont = NULL; } Curve *BKE_curve_copy(Main *bmain, const Curve *cu) { - Curve *cu_copy; - BKE_id_copy(bmain, &cu->id, (ID **)&cu_copy); - return cu_copy; + Curve *cu_copy; + BKE_id_copy(bmain, &cu->id, (ID **)&cu_copy); + return cu_copy; } void BKE_curve_make_local(Main *bmain, Curve *cu, const bool lib_local) { - BKE_id_make_local_generic(bmain, &cu->id, true, lib_local); + BKE_id_make_local_generic(bmain, &cu->id, true, lib_local); } /* Get list of nurbs from editnurbs structure */ ListBase *BKE_curve_editNurbs_get(Curve *cu) { - if (cu->editnurb) { - return &cu->editnurb->nurbs; - } + if (cu->editnurb) { + return &cu->editnurb->nurbs; + } - return NULL; + return NULL; } short BKE_curve_type_get(Curve *cu) { - Nurb *nu; - int type = cu->type; + Nurb *nu; + int type = cu->type; - if (cu->vfont) { - return OB_FONT; - } + if (cu->vfont) { + return OB_FONT; + } - if (!cu->type) { - type = OB_CURVE; + if (!cu->type) { + type = OB_CURVE; - for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu->pntsv > 1) { - type = OB_SURF; - } - } - } + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->pntsv > 1) { + type = OB_SURF; + } + } + } - return type; + return type; } void BKE_curve_curve_dimension_update(Curve *cu) { - ListBase *nurbs = BKE_curve_nurbs_get(cu); - Nurb *nu = nurbs->first; + ListBase *nurbs = BKE_curve_nurbs_get(cu); + Nurb *nu = nurbs->first; - if (cu->flag & CU_3D) { - for (; nu; nu = nu->next) { - nu->flag &= ~CU_2D; - } - } - else { - for (; nu; nu = nu->next) { - nu->flag |= CU_2D; - BKE_nurb_test_2d(nu); + if (cu->flag & CU_3D) { + for (; nu; nu = nu->next) { + nu->flag &= ~CU_2D; + } + } + else { + for (; nu; nu = nu->next) { + nu->flag |= CU_2D; + BKE_nurb_test_2d(nu); - /* since the handles are moved they need to be auto-located again */ - if (nu->type == CU_BEZIER) - BKE_nurb_handles_calc(nu); - } - } + /* since the handles are moved they need to be auto-located again */ + if (nu->type == CU_BEZIER) + BKE_nurb_handles_calc(nu); + } + } } void BKE_curve_type_test(Object *ob) { - ob->type = BKE_curve_type_get(ob->data); + ob->type = BKE_curve_type_get(ob->data); - if (ob->type == OB_CURVE) - BKE_curve_curve_dimension_update((Curve *)ob->data); + if (ob->type == OB_CURVE) + BKE_curve_curve_dimension_update((Curve *)ob->data); } void BKE_curve_boundbox_calc(Curve *cu, float r_loc[3], float r_size[3]) { - BoundBox *bb; - float min[3], max[3]; - float mloc[3], msize[3]; + BoundBox *bb; + float min[3], max[3]; + float mloc[3], msize[3]; - if (cu->bb == NULL) cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox"); - bb = cu->bb; + if (cu->bb == NULL) + cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox"); + bb = cu->bb; - if (!r_loc) r_loc = mloc; - if (!r_size) r_size = msize; + if (!r_loc) + r_loc = mloc; + if (!r_size) + r_size = msize; - INIT_MINMAX(min, max); - if (!BKE_curve_minmax(cu, true, min, max)) { - min[0] = min[1] = min[2] = -1.0f; - max[0] = max[1] = max[2] = 1.0f; - } + INIT_MINMAX(min, max); + if (!BKE_curve_minmax(cu, true, min, max)) { + min[0] = min[1] = min[2] = -1.0f; + max[0] = max[1] = max[2] = 1.0f; + } - mid_v3_v3v3(r_loc, min, max); + mid_v3_v3v3(r_loc, min, max); - r_size[0] = (max[0] - min[0]) / 2.0f; - r_size[1] = (max[1] - min[1]) / 2.0f; - r_size[2] = (max[2] - min[2]) / 2.0f; + r_size[0] = (max[0] - min[0]) / 2.0f; + r_size[1] = (max[1] - min[1]) / 2.0f; + r_size[2] = (max[2] - min[2]) / 2.0f; - BKE_boundbox_init_from_minmax(bb, min, max); + BKE_boundbox_init_from_minmax(bb, min, max); - bb->flag &= ~BOUNDBOX_DIRTY; + bb->flag &= ~BOUNDBOX_DIRTY; } BoundBox *BKE_curve_boundbox_get(Object *ob) { - /* This is Object-level data access, DO NOT touch to Mesh's bb, would be totally thread-unsafe. */ - if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { - Curve *cu = ob->data; - float min[3], max[3]; + /* This is Object-level data access, DO NOT touch to Mesh's bb, would be totally thread-unsafe. */ + if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { + Curve *cu = ob->data; + float min[3], max[3]; - INIT_MINMAX(min, max); - BKE_curve_minmax(cu, true, min, max); + INIT_MINMAX(min, max); + BKE_curve_minmax(cu, true, min, max); - if (ob->runtime.bb == NULL) { - ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__); - } - BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); - ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; - } + if (ob->runtime.bb == NULL) { + ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__); + } + BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); + ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; + } - return ob->runtime.bb; + return ob->runtime.bb; } void BKE_curve_texspace_calc(Curve *cu) { - float loc[3], size[3]; - int a; + float loc[3], size[3]; + int a; - BKE_curve_boundbox_calc(cu, loc, size); + BKE_curve_boundbox_calc(cu, loc, size); - if (cu->texflag & CU_AUTOSPACE) { - for (a = 0; a < 3; a++) { - if (size[a] == 0.0f) size[a] = 1.0f; - else if (size[a] > 0.0f && size[a] < 0.00001f) size[a] = 0.00001f; - else if (size[a] < 0.0f && size[a] > -0.00001f) size[a] = -0.00001f; - } + if (cu->texflag & CU_AUTOSPACE) { + for (a = 0; a < 3; a++) { + if (size[a] == 0.0f) + size[a] = 1.0f; + else if (size[a] > 0.0f && size[a] < 0.00001f) + size[a] = 0.00001f; + else if (size[a] < 0.0f && size[a] > -0.00001f) + size[a] = -0.00001f; + } - copy_v3_v3(cu->loc, loc); - copy_v3_v3(cu->size, size); - zero_v3(cu->rot); - } + copy_v3_v3(cu->loc, loc); + copy_v3_v3(cu->size, size); + zero_v3(cu->rot); + } } BoundBox *BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_rot[3], float r_size[3]) { - if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { - BKE_curve_texspace_calc(cu); - } + if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { + BKE_curve_texspace_calc(cu); + } - if (r_loc) copy_v3_v3(r_loc, cu->loc); - if (r_rot) copy_v3_v3(r_rot, cu->rot); - if (r_size) copy_v3_v3(r_size, cu->size); + if (r_loc) + copy_v3_v3(r_loc, cu->loc); + if (r_rot) + copy_v3_v3(r_rot, cu->rot); + if (r_size) + copy_v3_v3(r_size, cu->size); - return cu->bb; + return cu->bb; } bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3]) { - Nurb *nu; - int tot = 0; - - for (nu = nurb->first; nu; nu = nu->next) { - int tot_nu; - if (nu->type == CU_BEZIER) { - tot_nu = nu->pntsu; - if (index - tot < tot_nu) { - copy_v3_v3(r_co, nu->bezt[index - tot].vec[1]); - return true; - } - } - else { - tot_nu = nu->pntsu * nu->pntsv; - if (index - tot < tot_nu) { - copy_v3_v3(r_co, nu->bp[index - tot].vec); - return true; - } - } - tot += tot_nu; - } - - return false; + Nurb *nu; + int tot = 0; + + for (nu = nurb->first; nu; nu = nu->next) { + int tot_nu; + if (nu->type == CU_BEZIER) { + tot_nu = nu->pntsu; + if (index - tot < tot_nu) { + copy_v3_v3(r_co, nu->bezt[index - tot].vec[1]); + return true; + } + } + else { + tot_nu = nu->pntsu * nu->pntsv; + if (index - tot < tot_nu) { + copy_v3_v3(r_co, nu->bp[index - tot].vec); + return true; + } + } + tot += tot_nu; + } + + return false; } int BKE_nurbList_verts_count(ListBase *nurb) { - Nurb *nu; - int tot = 0; + Nurb *nu; + int tot = 0; - nu = nurb->first; - while (nu) { - if (nu->bezt) - tot += 3 * nu->pntsu; - else if (nu->bp) - tot += nu->pntsu * nu->pntsv; + nu = nurb->first; + while (nu) { + if (nu->bezt) + tot += 3 * nu->pntsu; + else if (nu->bp) + tot += nu->pntsu * nu->pntsv; - nu = nu->next; - } - return tot; + nu = nu->next; + } + return tot; } int BKE_nurbList_verts_count_without_handles(ListBase *nurb) { - Nurb *nu; - int tot = 0; + Nurb *nu; + int tot = 0; - nu = nurb->first; - while (nu) { - if (nu->bezt) - tot += nu->pntsu; - else if (nu->bp) - tot += nu->pntsu * nu->pntsv; + nu = nurb->first; + while (nu) { + if (nu->bezt) + tot += nu->pntsu; + else if (nu->bp) + tot += nu->pntsu * nu->pntsv; - nu = nu->next; - } - return tot; + nu = nu->next; + } + return tot; } /* **************** NURBS ROUTINES ******************** */ @@ -438,148 +452,148 @@ int BKE_nurbList_verts_count_without_handles(ListBase *nurb) void BKE_nurb_free(Nurb *nu) { - if (nu == NULL) return; - - if (nu->bezt) - MEM_freeN(nu->bezt); - nu->bezt = NULL; - if (nu->bp) - MEM_freeN(nu->bp); - nu->bp = NULL; - if (nu->knotsu) - MEM_freeN(nu->knotsu); - nu->knotsu = NULL; - if (nu->knotsv) - MEM_freeN(nu->knotsv); - nu->knotsv = NULL; - /* if (nu->trim.first) freeNurblist(&(nu->trim)); */ + if (nu == NULL) + return; - MEM_freeN(nu); + if (nu->bezt) + MEM_freeN(nu->bezt); + nu->bezt = NULL; + if (nu->bp) + MEM_freeN(nu->bp); + nu->bp = NULL; + if (nu->knotsu) + MEM_freeN(nu->knotsu); + nu->knotsu = NULL; + if (nu->knotsv) + MEM_freeN(nu->knotsv); + nu->knotsv = NULL; + /* if (nu->trim.first) freeNurblist(&(nu->trim)); */ + MEM_freeN(nu); } - void BKE_nurbList_free(ListBase *lb) { - Nurb *nu, *next; + Nurb *nu, *next; - if (lb == NULL) return; + if (lb == NULL) + return; - nu = lb->first; - while (nu) { - next = nu->next; - BKE_nurb_free(nu); - nu = next; - } - BLI_listbase_clear(lb); + nu = lb->first; + while (nu) { + next = nu->next; + BKE_nurb_free(nu); + nu = next; + } + BLI_listbase_clear(lb); } Nurb *BKE_nurb_duplicate(const Nurb *nu) { - Nurb *newnu; - int len; - - newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplicateNurb"); - if (newnu == NULL) return NULL; - memcpy(newnu, nu, sizeof(Nurb)); - - if (nu->bezt) { - newnu->bezt = - (BezTriple *)MEM_malloc_arrayN(nu->pntsu, sizeof(BezTriple), "duplicateNurb2"); - memcpy(newnu->bezt, nu->bezt, nu->pntsu * sizeof(BezTriple)); - } - else { - len = nu->pntsu * nu->pntsv; - newnu->bp = - (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3"); - memcpy(newnu->bp, nu->bp, len * sizeof(BPoint)); - - newnu->knotsu = newnu->knotsv = NULL; - - if (nu->knotsu) { - len = KNOTSU(nu); - if (len) { - newnu->knotsu = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4"); - memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len); - } - } - if (nu->pntsv > 1 && nu->knotsv) { - len = KNOTSV(nu); - if (len) { - newnu->knotsv = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5"); - memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len); - } - } - } - return newnu; + Nurb *newnu; + int len; + + newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplicateNurb"); + if (newnu == NULL) + return NULL; + memcpy(newnu, nu, sizeof(Nurb)); + + if (nu->bezt) { + newnu->bezt = (BezTriple *)MEM_malloc_arrayN(nu->pntsu, sizeof(BezTriple), "duplicateNurb2"); + memcpy(newnu->bezt, nu->bezt, nu->pntsu * sizeof(BezTriple)); + } + else { + len = nu->pntsu * nu->pntsv; + newnu->bp = (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3"); + memcpy(newnu->bp, nu->bp, len * sizeof(BPoint)); + + newnu->knotsu = newnu->knotsv = NULL; + + if (nu->knotsu) { + len = KNOTSU(nu); + if (len) { + newnu->knotsu = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4"); + memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len); + } + } + if (nu->pntsv > 1 && nu->knotsv) { + len = KNOTSV(nu); + if (len) { + newnu->knotsv = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5"); + memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len); + } + } + } + return newnu; } /* copy the nurb but allow for different number of points (to be copied after this) */ Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv) { - Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb"); - memcpy(newnu, src, sizeof(Nurb)); + Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb"); + memcpy(newnu, src, sizeof(Nurb)); - if (pntsu == 1) SWAP(int, pntsu, pntsv); - newnu->pntsu = pntsu; - newnu->pntsv = pntsv; + if (pntsu == 1) + SWAP(int, pntsu, pntsv); + newnu->pntsu = pntsu; + newnu->pntsv = pntsv; - /* caller can manually handle these arrays */ - newnu->knotsu = NULL; - newnu->knotsv = NULL; + /* caller can manually handle these arrays */ + newnu->knotsu = NULL; + newnu->knotsv = NULL; - if (src->bezt) { - newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2"); - } - else { - newnu->bp = (BPoint *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BPoint), "copyNurb3"); - } + if (src->bezt) { + newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2"); + } + else { + newnu->bp = (BPoint *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BPoint), "copyNurb3"); + } - return newnu; + return newnu; } void BKE_nurbList_duplicate(ListBase *lb1, const ListBase *lb2) { - Nurb *nu, *nun; + Nurb *nu, *nun; - BKE_nurbList_free(lb1); + BKE_nurbList_free(lb1); - nu = lb2->first; - while (nu) { - nun = BKE_nurb_duplicate(nu); - BLI_addtail(lb1, nun); + nu = lb2->first; + while (nu) { + nun = BKE_nurb_duplicate(nu); + BLI_addtail(lb1, nun); - nu = nu->next; - } + nu = nu->next; + } } void BKE_nurb_test_2d(Nurb *nu) { - BezTriple *bezt; - BPoint *bp; - int a; - - if ((nu->flag & CU_2D) == 0) - return; - - if (nu->type == CU_BEZIER) { - a = nu->pntsu; - bezt = nu->bezt; - while (a--) { - bezt->vec[0][2] = 0.0; - bezt->vec[1][2] = 0.0; - bezt->vec[2][2] = 0.0; - bezt++; - } - } - else { - a = nu->pntsu * nu->pntsv; - bp = nu->bp; - while (a--) { - bp->vec[2] = 0.0; - bp++; - } - } + BezTriple *bezt; + BPoint *bp; + int a; + + if ((nu->flag & CU_2D) == 0) + return; + + if (nu->type == CU_BEZIER) { + a = nu->pntsu; + bezt = nu->bezt; + while (a--) { + bezt->vec[0][2] = 0.0; + bezt->vec[1][2] = 0.0; + bezt->vec[2][2] = 0.0; + bezt++; + } + } + else { + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a--) { + bp->vec[2] = 0.0; + bp++; + } + } } /** @@ -588,603 +602,599 @@ void BKE_nurb_test_2d(Nurb *nu) */ void BKE_nurb_minmax(Nurb *nu, bool use_radius, float min[3], float max[3]) { - BezTriple *bezt; - BPoint *bp; - int a; - float point[3]; - - if (nu->type == CU_BEZIER) { - a = nu->pntsu; - bezt = nu->bezt; - while (a--) { - if (use_radius) { - float radius_vector[3]; - radius_vector[0] = radius_vector[1] = radius_vector[2] = bezt->radius; - - add_v3_v3v3(point, bezt->vec[1], radius_vector); - minmax_v3v3_v3(min, max, point); - - sub_v3_v3v3(point, bezt->vec[1], radius_vector); - minmax_v3v3_v3(min, max, point); - } - else { - minmax_v3v3_v3(min, max, bezt->vec[1]); - } - minmax_v3v3_v3(min, max, bezt->vec[0]); - minmax_v3v3_v3(min, max, bezt->vec[2]); - bezt++; - } - } - else { - a = nu->pntsu * nu->pntsv; - bp = nu->bp; - while (a--) { - if (nu->pntsv == 1 && use_radius) { - float radius_vector[3]; - radius_vector[0] = radius_vector[1] = radius_vector[2] = bp->radius; - - add_v3_v3v3(point, bp->vec, radius_vector); - minmax_v3v3_v3(min, max, point); - - sub_v3_v3v3(point, bp->vec, radius_vector); - minmax_v3v3_v3(min, max, point); - } - else { - /* Surfaces doesn't use bevel, so no need to take radius into account. */ - minmax_v3v3_v3(min, max, bp->vec); - } - bp++; - } - } + BezTriple *bezt; + BPoint *bp; + int a; + float point[3]; + + if (nu->type == CU_BEZIER) { + a = nu->pntsu; + bezt = nu->bezt; + while (a--) { + if (use_radius) { + float radius_vector[3]; + radius_vector[0] = radius_vector[1] = radius_vector[2] = bezt->radius; + + add_v3_v3v3(point, bezt->vec[1], radius_vector); + minmax_v3v3_v3(min, max, point); + + sub_v3_v3v3(point, bezt->vec[1], radius_vector); + minmax_v3v3_v3(min, max, point); + } + else { + minmax_v3v3_v3(min, max, bezt->vec[1]); + } + minmax_v3v3_v3(min, max, bezt->vec[0]); + minmax_v3v3_v3(min, max, bezt->vec[2]); + bezt++; + } + } + else { + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a--) { + if (nu->pntsv == 1 && use_radius) { + float radius_vector[3]; + radius_vector[0] = radius_vector[1] = radius_vector[2] = bp->radius; + + add_v3_v3v3(point, bp->vec, radius_vector); + minmax_v3v3_v3(min, max, point); + + sub_v3_v3v3(point, bp->vec, radius_vector); + minmax_v3v3_v3(min, max, point); + } + else { + /* Surfaces doesn't use bevel, so no need to take radius into account. */ + minmax_v3v3_v3(min, max, bp->vec); + } + bp++; + } + } } float BKE_nurb_calc_length(const Nurb *nu, int resolution) { - BezTriple *bezt, *prevbezt; - BPoint *bp, *prevbp; - int a, b; - float length = 0.0f; - int resolu = resolution ? resolution : nu->resolu; - int pntsu = nu->pntsu; - float *points, *pntsit, *prevpntsit; - - if (nu->type == CU_POLY) { - a = nu->pntsu - 1; - bp = nu->bp; - if (nu->flagu & CU_NURB_CYCLIC) { - ++a; - prevbp = nu->bp + (nu->pntsu - 1); - } - else { - prevbp = bp; - bp++; - } - - while (a--) { - length += len_v3v3(prevbp->vec, bp->vec); - prevbp = bp; - ++bp; - } - } - else if (nu->type == CU_BEZIER) { - points = MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier"); - a = nu->pntsu - 1; - bezt = nu->bezt; - if (nu->flagu & CU_NURB_CYCLIC) { - ++a; - prevbezt = nu->bezt + (nu->pntsu - 1); - } - else { - prevbezt = bezt; - ++bezt; - } - - while (a--) { - if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) { - length += len_v3v3(prevbezt->vec[1], bezt->vec[1]); - } - else { - for (int j = 0; j < 3; j++) { - BKE_curve_forward_diff_bezier( - prevbezt->vec[1][j], prevbezt->vec[2][j], - bezt->vec[0][j], bezt->vec[1][j], - points + j, resolu, 3 * sizeof(float)); - } - - prevpntsit = pntsit = points; - b = resolu; - while (b--) { - pntsit += 3; - length += len_v3v3(prevpntsit, pntsit); - prevpntsit = pntsit; - } - } - prevbezt = bezt; - ++bezt; - } - - MEM_freeN(points); - } - else if (nu->type == CU_NURBS) { - if (nu->pntsv == 1) { - /* important to zero for BKE_nurb_makeCurve. */ - points = MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs"); - - BKE_nurb_makeCurve( - nu, points, - NULL, NULL, NULL, - resolu, sizeof(float[3])); - - if (nu->flagu & CU_NURB_CYCLIC) { - b = pntsu * resolu + 1; - prevpntsit = points + 3 * (pntsu * resolu - 1); - pntsit = points; - } - else { - b = (pntsu - 1) * resolu; - prevpntsit = points; - pntsit = points + 3; - } - - while (--b) { - length += len_v3v3(prevpntsit, pntsit); - prevpntsit = pntsit; - pntsit += 3; - } - - MEM_freeN(points); - } - } - - return length; + BezTriple *bezt, *prevbezt; + BPoint *bp, *prevbp; + int a, b; + float length = 0.0f; + int resolu = resolution ? resolution : nu->resolu; + int pntsu = nu->pntsu; + float *points, *pntsit, *prevpntsit; + + if (nu->type == CU_POLY) { + a = nu->pntsu - 1; + bp = nu->bp; + if (nu->flagu & CU_NURB_CYCLIC) { + ++a; + prevbp = nu->bp + (nu->pntsu - 1); + } + else { + prevbp = bp; + bp++; + } + + while (a--) { + length += len_v3v3(prevbp->vec, bp->vec); + prevbp = bp; + ++bp; + } + } + else if (nu->type == CU_BEZIER) { + points = MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier"); + a = nu->pntsu - 1; + bezt = nu->bezt; + if (nu->flagu & CU_NURB_CYCLIC) { + ++a; + prevbezt = nu->bezt + (nu->pntsu - 1); + } + else { + prevbezt = bezt; + ++bezt; + } + + while (a--) { + if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) { + length += len_v3v3(prevbezt->vec[1], bezt->vec[1]); + } + else { + for (int j = 0; j < 3; j++) { + BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], + prevbezt->vec[2][j], + bezt->vec[0][j], + bezt->vec[1][j], + points + j, + resolu, + 3 * sizeof(float)); + } + + prevpntsit = pntsit = points; + b = resolu; + while (b--) { + pntsit += 3; + length += len_v3v3(prevpntsit, pntsit); + prevpntsit = pntsit; + } + } + prevbezt = bezt; + ++bezt; + } + + MEM_freeN(points); + } + else if (nu->type == CU_NURBS) { + if (nu->pntsv == 1) { + /* important to zero for BKE_nurb_makeCurve. */ + points = MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs"); + + BKE_nurb_makeCurve(nu, points, NULL, NULL, NULL, resolu, sizeof(float[3])); + + if (nu->flagu & CU_NURB_CYCLIC) { + b = pntsu * resolu + 1; + prevpntsit = points + 3 * (pntsu * resolu - 1); + pntsit = points; + } + else { + b = (pntsu - 1) * resolu; + prevpntsit = points; + pntsit = points + 3; + } + + while (--b) { + length += len_v3v3(prevpntsit, pntsit); + prevpntsit = pntsit; + pntsit += 3; + } + + MEM_freeN(points); + } + } + + return length; } /* be sure to call makeknots after this */ void BKE_nurb_points_add(Nurb *nu, int number) { - BPoint *bp; - int i; + BPoint *bp; + int i; - nu->bp = MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint)); + nu->bp = MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint)); - for (i = 0, bp = &nu->bp[nu->pntsu]; i < number; i++, bp++) { - bp->radius = 1.0f; - } + for (i = 0, bp = &nu->bp[nu->pntsu]; i < number; i++, bp++) { + bp->radius = 1.0f; + } - nu->pntsu += number; + nu->pntsu += number; } void BKE_nurb_bezierPoints_add(Nurb *nu, int number) { - BezTriple *bezt; - int i; + BezTriple *bezt; + int i; - nu->bezt = MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple)); + nu->bezt = MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple)); - for (i = 0, bezt = &nu->bezt[nu->pntsu]; i < number; i++, bezt++) { - bezt->radius = 1.0f; - } + for (i = 0, bezt = &nu->bezt[nu->pntsu]; i < number; i++, bezt++) { + bezt->radius = 1.0f; + } - nu->pntsu += number; + nu->pntsu += number; } - -int BKE_nurb_index_from_uv( - Nurb *nu, - int u, int v) +int BKE_nurb_index_from_uv(Nurb *nu, int u, int v) { - const int totu = nu->pntsu; - const int totv = nu->pntsv; + const int totu = nu->pntsu; + const int totv = nu->pntsv; - if (nu->flagu & CU_NURB_CYCLIC) { - u = mod_i(u, totu); - } - else if (u < 0 || u >= totu) { - return -1; - } + if (nu->flagu & CU_NURB_CYCLIC) { + u = mod_i(u, totu); + } + else if (u < 0 || u >= totu) { + return -1; + } - if (nu->flagv & CU_NURB_CYCLIC) { - v = mod_i(v, totv); - } - else if (v < 0 || v >= totv) { - return -1; - } + if (nu->flagv & CU_NURB_CYCLIC) { + v = mod_i(v, totv); + } + else if (v < 0 || v >= totv) { + return -1; + } - return (v * totu) + u; + return (v * totu) + u; } -void BKE_nurb_index_to_uv( - Nurb *nu, int index, - int *r_u, int *r_v) +void BKE_nurb_index_to_uv(Nurb *nu, int index, int *r_u, int *r_v) { - const int totu = nu->pntsu; - const int totv = nu->pntsv; - BLI_assert(index >= 0 && index < (nu->pntsu * nu->pntsv)); - *r_u = (index % totu); - *r_v = (index / totu) % totv; + const int totu = nu->pntsu; + const int totv = nu->pntsv; + BLI_assert(index >= 0 && index < (nu->pntsu * nu->pntsv)); + *r_u = (index % totu); + *r_v = (index / totu) % totv; } BezTriple *BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt) { - BezTriple *bezt_next; + BezTriple *bezt_next; - BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu)); + BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu)); - if (bezt == &nu->bezt[nu->pntsu - 1]) { - if (nu->flagu & CU_NURB_CYCLIC) { - bezt_next = nu->bezt; - } - else { - bezt_next = NULL; - } - } - else { - bezt_next = bezt + 1; - } + if (bezt == &nu->bezt[nu->pntsu - 1]) { + if (nu->flagu & CU_NURB_CYCLIC) { + bezt_next = nu->bezt; + } + else { + bezt_next = NULL; + } + } + else { + bezt_next = bezt + 1; + } - return bezt_next; + return bezt_next; } BPoint *BKE_nurb_bpoint_get_next(Nurb *nu, BPoint *bp) { - BPoint *bp_next; + BPoint *bp_next; - BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu)); + BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu)); - if (bp == &nu->bp[nu->pntsu - 1]) { - if (nu->flagu & CU_NURB_CYCLIC) { - bp_next = nu->bp; - } - else { - bp_next = NULL; - } - } - else { - bp_next = bp + 1; - } + if (bp == &nu->bp[nu->pntsu - 1]) { + if (nu->flagu & CU_NURB_CYCLIC) { + bp_next = nu->bp; + } + else { + bp_next = NULL; + } + } + else { + bp_next = bp + 1; + } - return bp_next; + return bp_next; } BezTriple *BKE_nurb_bezt_get_prev(Nurb *nu, BezTriple *bezt) { - BezTriple *bezt_prev; + BezTriple *bezt_prev; - BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu)); - BLI_assert(nu->pntsv <= 1); + BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu)); + BLI_assert(nu->pntsv <= 1); - if (bezt == nu->bezt) { - if (nu->flagu & CU_NURB_CYCLIC) { - bezt_prev = &nu->bezt[nu->pntsu - 1]; - } - else { - bezt_prev = NULL; - } - } - else { - bezt_prev = bezt - 1; - } + if (bezt == nu->bezt) { + if (nu->flagu & CU_NURB_CYCLIC) { + bezt_prev = &nu->bezt[nu->pntsu - 1]; + } + else { + bezt_prev = NULL; + } + } + else { + bezt_prev = bezt - 1; + } - return bezt_prev; + return bezt_prev; } BPoint *BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp) { - BPoint *bp_prev; + BPoint *bp_prev; - BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu)); - BLI_assert(nu->pntsv == 1); + BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu)); + BLI_assert(nu->pntsv == 1); - if (bp == nu->bp) { - if (nu->flagu & CU_NURB_CYCLIC) { - bp_prev = &nu->bp[nu->pntsu - 1]; - } - else { - bp_prev = NULL; - } - } - else { - bp_prev = bp - 1; - } + if (bp == nu->bp) { + if (nu->flagu & CU_NURB_CYCLIC) { + bp_prev = &nu->bp[nu->pntsu - 1]; + } + else { + bp_prev = NULL; + } + } + else { + bp_prev = bp - 1; + } - return bp_prev; + return bp_prev; } void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), BezTriple *bezt, float r_normal[3]) { - /* calculate the axis matrix from the spline */ - float dir_prev[3], dir_next[3]; + /* calculate the axis matrix from the spline */ + float dir_prev[3], dir_next[3]; - sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]); - sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]); + sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]); + sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]); - normalize_v3(dir_prev); - normalize_v3(dir_next); + normalize_v3(dir_prev); + normalize_v3(dir_next); - add_v3_v3v3(r_normal, dir_prev, dir_next); - normalize_v3(r_normal); + add_v3_v3v3(r_normal, dir_prev, dir_next); + normalize_v3(r_normal); } void BKE_nurb_bezt_calc_plane(struct Nurb *nu, BezTriple *bezt, float r_plane[3]) { - float dir_prev[3], dir_next[3]; + float dir_prev[3], dir_next[3]; - sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]); - sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]); + sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]); + sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]); - normalize_v3(dir_prev); - normalize_v3(dir_next); + normalize_v3(dir_prev); + normalize_v3(dir_next); - cross_v3_v3v3(r_plane, dir_prev, dir_next); - if (normalize_v3(r_plane) < FLT_EPSILON) { - BezTriple *bezt_prev = BKE_nurb_bezt_get_prev(nu, bezt); - BezTriple *bezt_next = BKE_nurb_bezt_get_next(nu, bezt); + cross_v3_v3v3(r_plane, dir_prev, dir_next); + if (normalize_v3(r_plane) < FLT_EPSILON) { + BezTriple *bezt_prev = BKE_nurb_bezt_get_prev(nu, bezt); + BezTriple *bezt_next = BKE_nurb_bezt_get_next(nu, bezt); - if (bezt_prev) { - sub_v3_v3v3(dir_prev, bezt_prev->vec[1], bezt->vec[1]); - normalize_v3(dir_prev); - } - if (bezt_next) { - sub_v3_v3v3(dir_next, bezt->vec[1], bezt_next->vec[1]); - normalize_v3(dir_next); - } - cross_v3_v3v3(r_plane, dir_prev, dir_next); - } + if (bezt_prev) { + sub_v3_v3v3(dir_prev, bezt_prev->vec[1], bezt->vec[1]); + normalize_v3(dir_prev); + } + if (bezt_next) { + sub_v3_v3v3(dir_next, bezt->vec[1], bezt_next->vec[1]); + normalize_v3(dir_next); + } + cross_v3_v3v3(r_plane, dir_prev, dir_next); + } - /* matches with bones more closely */ - { - float dir_mid[3], tvec[3]; - add_v3_v3v3(dir_mid, dir_prev, dir_next); - cross_v3_v3v3(tvec, r_plane, dir_mid); - copy_v3_v3(r_plane, tvec); - } + /* matches with bones more closely */ + { + float dir_mid[3], tvec[3]; + add_v3_v3v3(dir_mid, dir_prev, dir_next); + cross_v3_v3v3(tvec, r_plane, dir_mid); + copy_v3_v3(r_plane, tvec); + } - normalize_v3(r_plane); + normalize_v3(r_plane); } void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, BPoint *bp, float r_normal[3]) { - BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp); - BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp); + BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp); + BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp); - zero_v3(r_normal); + zero_v3(r_normal); - if (bp_prev) { - float dir_prev[3]; - sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec); - normalize_v3(dir_prev); - add_v3_v3(r_normal, dir_prev); - } - if (bp_next) { - float dir_next[3]; - sub_v3_v3v3(dir_next, bp->vec, bp_next->vec); - normalize_v3(dir_next); - add_v3_v3(r_normal, dir_next); - } + if (bp_prev) { + float dir_prev[3]; + sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec); + normalize_v3(dir_prev); + add_v3_v3(r_normal, dir_prev); + } + if (bp_next) { + float dir_next[3]; + sub_v3_v3v3(dir_next, bp->vec, bp_next->vec); + normalize_v3(dir_next); + add_v3_v3(r_normal, dir_next); + } - normalize_v3(r_normal); + normalize_v3(r_normal); } void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3]) { - BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp); - BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp); + BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp); + BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp); - float dir_prev[3] = {0.0f}, dir_next[3] = {0.0f}; + float dir_prev[3] = {0.0f}, dir_next[3] = {0.0f}; - if (bp_prev) { - sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec); - normalize_v3(dir_prev); - } - if (bp_next) { - sub_v3_v3v3(dir_next, bp->vec, bp_next->vec); - normalize_v3(dir_next); - } - cross_v3_v3v3(r_plane, dir_prev, dir_next); + if (bp_prev) { + sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec); + normalize_v3(dir_prev); + } + if (bp_next) { + sub_v3_v3v3(dir_next, bp->vec, bp_next->vec); + normalize_v3(dir_next); + } + cross_v3_v3v3(r_plane, dir_prev, dir_next); - /* matches with bones more closely */ - { - float dir_mid[3], tvec[3]; - add_v3_v3v3(dir_mid, dir_prev, dir_next); - cross_v3_v3v3(tvec, r_plane, dir_mid); - copy_v3_v3(r_plane, tvec); - } + /* matches with bones more closely */ + { + float dir_mid[3], tvec[3]; + add_v3_v3v3(dir_mid, dir_prev, dir_next); + cross_v3_v3v3(tvec, r_plane, dir_mid); + copy_v3_v3(r_plane, tvec); + } - normalize_v3(r_plane); + normalize_v3(r_plane); } /* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */ - static void calcknots(float *knots, const int pnts, const short order, const short flag) { - /* knots: number of pnts NOT corrected for cyclic */ - const int pnts_order = pnts + order; - float k; - int a; - - switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) { - case CU_NURB_ENDPOINT: - k = 0.0; - for (a = 1; a <= pnts_order; a++) { - knots[a - 1] = k; - if (a >= order && a <= pnts) - k += 1.0f; - } - break; - case CU_NURB_BEZIER: - /* Warning, the order MUST be 2 or 4, - * if this is not enforced, the displist will be corrupt */ - if (order == 4) { - k = 0.34; - for (a = 0; a < pnts_order; a++) { - knots[a] = floorf(k); - k += (1.0f / 3.0f); - } - } - else if (order == 3) { - k = 0.6f; - for (a = 0; a < pnts_order; a++) { - if (a >= order && a <= pnts) - k += 0.5f; - knots[a] = floorf(k); - } - } - else { - CLOG_ERROR(&LOG, "bez nurb curve order is not 3 or 4, should never happen"); - } - break; - default: - for (a = 0; a < pnts_order; a++) { - knots[a] = (float)a; - } - break; - } + /* knots: number of pnts NOT corrected for cyclic */ + const int pnts_order = pnts + order; + float k; + int a; + + switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) { + case CU_NURB_ENDPOINT: + k = 0.0; + for (a = 1; a <= pnts_order; a++) { + knots[a - 1] = k; + if (a >= order && a <= pnts) + k += 1.0f; + } + break; + case CU_NURB_BEZIER: + /* Warning, the order MUST be 2 or 4, + * if this is not enforced, the displist will be corrupt */ + if (order == 4) { + k = 0.34; + for (a = 0; a < pnts_order; a++) { + knots[a] = floorf(k); + k += (1.0f / 3.0f); + } + } + else if (order == 3) { + k = 0.6f; + for (a = 0; a < pnts_order; a++) { + if (a >= order && a <= pnts) + k += 0.5f; + knots[a] = floorf(k); + } + } + else { + CLOG_ERROR(&LOG, "bez nurb curve order is not 3 or 4, should never happen"); + } + break; + default: + for (a = 0; a < pnts_order; a++) { + knots[a] = (float)a; + } + break; + } } static void makecyclicknots(float *knots, int pnts, short order) /* pnts, order: number of pnts NOT corrected for cyclic */ { - int a, b, order2, c; + int a, b, order2, c; - if (knots == NULL) - return; + if (knots == NULL) + return; - order2 = order - 1; + order2 = order - 1; - /* do first long rows (order -1), remove identical knots at endpoints */ - if (order > 2) { - b = pnts + order2; - for (a = 1; a < order2; a++) { - if (knots[b] != knots[b - a]) - break; - } - if (a == order2) - knots[pnts + order - 2] += 1.0f; - } + /* do first long rows (order -1), remove identical knots at endpoints */ + if (order > 2) { + b = pnts + order2; + for (a = 1; a < order2; a++) { + if (knots[b] != knots[b - a]) + break; + } + if (a == order2) + knots[pnts + order - 2] += 1.0f; + } - b = order; - c = pnts + order + order2; - for (a = pnts + order2; a < c; a++) { - knots[a] = knots[a - 1] + (knots[b] - knots[b - 1]); - b--; - } + b = order; + c = pnts + order + order2; + for (a = pnts + order2; a < c; a++) { + knots[a] = knots[a - 1] + (knots[b] - knots[b - 1]); + b--; + } } - - static void makeknots(Nurb *nu, short uv) { - if (nu->type == CU_NURBS) { - if (uv == 1) { - if (nu->knotsu) - MEM_freeN(nu->knotsu); - if (BKE_nurb_check_valid_u(nu)) { - nu->knotsu = MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots"); - if (nu->flagu & CU_NURB_CYCLIC) { - calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */ - makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu); - } - else { - calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu); - } - } - else - nu->knotsu = NULL; - } - else if (uv == 2) { - if (nu->knotsv) - MEM_freeN(nu->knotsv); - if (BKE_nurb_check_valid_v(nu)) { - nu->knotsv = MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots"); - if (nu->flagv & CU_NURB_CYCLIC) { - calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */ - makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv); - } - else { - calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv); - } - } - else { - nu->knotsv = NULL; - } - } - } + if (nu->type == CU_NURBS) { + if (uv == 1) { + if (nu->knotsu) + MEM_freeN(nu->knotsu); + if (BKE_nurb_check_valid_u(nu)) { + nu->knotsu = MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots"); + if (nu->flagu & CU_NURB_CYCLIC) { + calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */ + makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu); + } + else { + calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu); + } + } + else + nu->knotsu = NULL; + } + else if (uv == 2) { + if (nu->knotsv) + MEM_freeN(nu->knotsv); + if (BKE_nurb_check_valid_v(nu)) { + nu->knotsv = MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots"); + if (nu->flagv & CU_NURB_CYCLIC) { + calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */ + makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv); + } + else { + calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv); + } + } + else { + nu->knotsv = NULL; + } + } + } } void BKE_nurb_knot_calc_u(Nurb *nu) { - makeknots(nu, 1); + makeknots(nu, 1); } void BKE_nurb_knot_calc_v(Nurb *nu) { - makeknots(nu, 2); -} - -static void basisNurb(float t, short order, int pnts, float *knots, float *basis, int *start, int *end) -{ - float d, e; - int i, i1 = 0, i2 = 0, j, orderpluspnts, opp2, o2; - - orderpluspnts = order + pnts; - opp2 = orderpluspnts - 1; - - /* this is for float inaccuracy */ - if (t < knots[0]) - t = knots[0]; - else if (t > knots[opp2]) - t = knots[opp2]; - - /* this part is order '1' */ - o2 = order + 1; - for (i = 0; i < opp2; i++) { - if (knots[i] != knots[i + 1] && t >= knots[i] && t <= knots[i + 1]) { - basis[i] = 1.0; - i1 = i - o2; - if (i1 < 0) i1 = 0; - i2 = i; - i++; - while (i < opp2) { - basis[i] = 0.0; - i++; - } - break; - } - else - basis[i] = 0.0; - } - basis[i] = 0.0; - - /* this is order 2, 3, ... */ - for (j = 2; j <= order; j++) { - - if (i2 + j >= orderpluspnts) i2 = opp2 - j; - - for (i = i1; i <= i2; i++) { - if (basis[i] != 0.0f) - d = ((t - knots[i]) * basis[i]) / (knots[i + j - 1] - knots[i]); - else - d = 0.0f; - - if (basis[i + 1] != 0.0f) - e = ((knots[i + j] - t) * basis[i + 1]) / (knots[i + j] - knots[i + 1]); - else - e = 0.0; - - basis[i] = d + e; - } - } - - *start = 1000; - *end = 0; - - for (i = i1; i <= i2; i++) { - if (basis[i] > 0.0f) { - *end = i; - if (*start == 1000) *start = i; - } - } + makeknots(nu, 2); +} + +static void basisNurb( + float t, short order, int pnts, float *knots, float *basis, int *start, int *end) +{ + float d, e; + int i, i1 = 0, i2 = 0, j, orderpluspnts, opp2, o2; + + orderpluspnts = order + pnts; + opp2 = orderpluspnts - 1; + + /* this is for float inaccuracy */ + if (t < knots[0]) + t = knots[0]; + else if (t > knots[opp2]) + t = knots[opp2]; + + /* this part is order '1' */ + o2 = order + 1; + for (i = 0; i < opp2; i++) { + if (knots[i] != knots[i + 1] && t >= knots[i] && t <= knots[i + 1]) { + basis[i] = 1.0; + i1 = i - o2; + if (i1 < 0) + i1 = 0; + i2 = i; + i++; + while (i < opp2) { + basis[i] = 0.0; + i++; + } + break; + } + else + basis[i] = 0.0; + } + basis[i] = 0.0; + + /* this is order 2, 3, ... */ + for (j = 2; j <= order; j++) { + + if (i2 + j >= orderpluspnts) + i2 = opp2 - j; + + for (i = i1; i <= i2; i++) { + if (basis[i] != 0.0f) + d = ((t - knots[i]) * basis[i]) / (knots[i + j - 1] - knots[i]); + else + d = 0.0f; + + if (basis[i + 1] != 0.0f) + e = ((knots[i + j] - t) * basis[i + 1]) / (knots[i + j] - knots[i + 1]); + else + e = 0.0; + + basis[i] = d + e; + } + } + + *start = 1000; + *end = 0; + + for (i = i1; i <= i2; i++) { + if (basis[i] > 0.0f) { + *end = i; + if (*start == 1000) + *start = i; + } + } } /** @@ -1192,173 +1202,174 @@ static void basisNurb(float t, short order, int pnts, float *knots, float *basis */ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv) { - BPoint *bp; - float *basisu, *basis, *basisv, *sum, *fp, *in; - float u, v, ustart, uend, ustep, vstart, vend, vstep, sumdiv; - int i, j, iofs, jofs, cycl, len, curu, curv; - int istart, iend, jsta, jen, *jstart, *jend, ratcomp; - - int totu = nu->pntsu * resolu, totv = nu->pntsv * resolv; - - if (nu->knotsu == NULL || nu->knotsv == NULL) - return; - if (nu->orderu > nu->pntsu) - return; - if (nu->orderv > nu->pntsv) - return; - if (coord_array == NULL) - return; - - /* allocate and initialize */ - len = totu * totv; - if (len == 0) - return; - - sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbfaces1"); - - bp = nu->bp; - i = nu->pntsu * nu->pntsv; - ratcomp = 0; - while (i--) { - if (bp->vec[3] != 1.0f) { - ratcomp = 1; - break; - } - bp++; - } - - fp = nu->knotsu; - ustart = fp[nu->orderu - 1]; - if (nu->flagu & CU_NURB_CYCLIC) - uend = fp[nu->pntsu + nu->orderu - 1]; - else - uend = fp[nu->pntsu]; - ustep = (uend - ustart) / ((nu->flagu & CU_NURB_CYCLIC) ? totu : totu - 1); - - basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbfaces3"); - - fp = nu->knotsv; - vstart = fp[nu->orderv - 1]; - - if (nu->flagv & CU_NURB_CYCLIC) - vend = fp[nu->pntsv + nu->orderv - 1]; - else - vend = fp[nu->pntsv]; - vstep = (vend - vstart) / ((nu->flagv & CU_NURB_CYCLIC) ? totv : totv - 1); - - len = KNOTSV(nu); - basisv = (float *)MEM_malloc_arrayN(len * totv, sizeof(float), "makeNurbfaces3"); - jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4"); - jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5"); - - /* precalculation of basisv and jstart, jend */ - if (nu->flagv & CU_NURB_CYCLIC) - cycl = nu->orderv - 1; - else cycl = 0; - v = vstart; - basis = basisv; - curv = totv; - while (curv--) { - basisNurb(v, nu->orderv, nu->pntsv + cycl, nu->knotsv, basis, jstart + curv, jend + curv); - basis += KNOTSV(nu); - v += vstep; - } - - if (nu->flagu & CU_NURB_CYCLIC) - cycl = nu->orderu - 1; - else - cycl = 0; - in = coord_array; - u = ustart; - curu = totu; - while (curu--) { - basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend); - - basis = basisv; - curv = totv; - while (curv--) { - jsta = jstart[curv]; - jen = jend[curv]; - - /* calculate sum */ - sumdiv = 0.0; - fp = sum; - - for (j = jsta; j <= jen; j++) { - - if (j >= nu->pntsv) - jofs = (j - nu->pntsv); - else - jofs = j; - bp = nu->bp + nu->pntsu * jofs + istart - 1; - - for (i = istart; i <= iend; i++, fp++) { - if (i >= nu->pntsu) { - iofs = i - nu->pntsu; - bp = nu->bp + nu->pntsu * jofs + iofs; - } - else - bp++; - - if (ratcomp) { - *fp = basisu[i] * basis[j] * bp->vec[3]; - sumdiv += *fp; - } - else - *fp = basisu[i] * basis[j]; - } - } - - if (ratcomp) { - fp = sum; - for (j = jsta; j <= jen; j++) { - for (i = istart; i <= iend; i++, fp++) { - *fp /= sumdiv; - } - } - } - - zero_v3(in); - - /* one! (1.0) real point now */ - fp = sum; - for (j = jsta; j <= jen; j++) { - - if (j >= nu->pntsv) - jofs = (j - nu->pntsv); - else - jofs = j; - bp = nu->bp + nu->pntsu * jofs + istart - 1; - - for (i = istart; i <= iend; i++, fp++) { - if (i >= nu->pntsu) { - iofs = i - nu->pntsu; - bp = nu->bp + nu->pntsu * jofs + iofs; - } - else - bp++; - - if (*fp != 0.0f) { - madd_v3_v3fl(in, bp->vec, *fp); - } - } - } - - in += 3; - basis += KNOTSV(nu); - } - u += ustep; - if (rowstride != 0) { - in = (float *)(((unsigned char *)in) + (rowstride - 3 * totv * sizeof(*in))); - } - } - - /* free */ - MEM_freeN(sum); - MEM_freeN(basisu); - MEM_freeN(basisv); - MEM_freeN(jstart); - MEM_freeN(jend); + BPoint *bp; + float *basisu, *basis, *basisv, *sum, *fp, *in; + float u, v, ustart, uend, ustep, vstart, vend, vstep, sumdiv; + int i, j, iofs, jofs, cycl, len, curu, curv; + int istart, iend, jsta, jen, *jstart, *jend, ratcomp; + + int totu = nu->pntsu * resolu, totv = nu->pntsv * resolv; + + if (nu->knotsu == NULL || nu->knotsv == NULL) + return; + if (nu->orderu > nu->pntsu) + return; + if (nu->orderv > nu->pntsv) + return; + if (coord_array == NULL) + return; + + /* allocate and initialize */ + len = totu * totv; + if (len == 0) + return; + + sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbfaces1"); + + bp = nu->bp; + i = nu->pntsu * nu->pntsv; + ratcomp = 0; + while (i--) { + if (bp->vec[3] != 1.0f) { + ratcomp = 1; + break; + } + bp++; + } + + fp = nu->knotsu; + ustart = fp[nu->orderu - 1]; + if (nu->flagu & CU_NURB_CYCLIC) + uend = fp[nu->pntsu + nu->orderu - 1]; + else + uend = fp[nu->pntsu]; + ustep = (uend - ustart) / ((nu->flagu & CU_NURB_CYCLIC) ? totu : totu - 1); + + basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbfaces3"); + + fp = nu->knotsv; + vstart = fp[nu->orderv - 1]; + + if (nu->flagv & CU_NURB_CYCLIC) + vend = fp[nu->pntsv + nu->orderv - 1]; + else + vend = fp[nu->pntsv]; + vstep = (vend - vstart) / ((nu->flagv & CU_NURB_CYCLIC) ? totv : totv - 1); + + len = KNOTSV(nu); + basisv = (float *)MEM_malloc_arrayN(len * totv, sizeof(float), "makeNurbfaces3"); + jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4"); + jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5"); + + /* precalculation of basisv and jstart, jend */ + if (nu->flagv & CU_NURB_CYCLIC) + cycl = nu->orderv - 1; + else + cycl = 0; + v = vstart; + basis = basisv; + curv = totv; + while (curv--) { + basisNurb(v, nu->orderv, nu->pntsv + cycl, nu->knotsv, basis, jstart + curv, jend + curv); + basis += KNOTSV(nu); + v += vstep; + } + + if (nu->flagu & CU_NURB_CYCLIC) + cycl = nu->orderu - 1; + else + cycl = 0; + in = coord_array; + u = ustart; + curu = totu; + while (curu--) { + basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend); + + basis = basisv; + curv = totv; + while (curv--) { + jsta = jstart[curv]; + jen = jend[curv]; + + /* calculate sum */ + sumdiv = 0.0; + fp = sum; + + for (j = jsta; j <= jen; j++) { + + if (j >= nu->pntsv) + jofs = (j - nu->pntsv); + else + jofs = j; + bp = nu->bp + nu->pntsu * jofs + istart - 1; + + for (i = istart; i <= iend; i++, fp++) { + if (i >= nu->pntsu) { + iofs = i - nu->pntsu; + bp = nu->bp + nu->pntsu * jofs + iofs; + } + else + bp++; + + if (ratcomp) { + *fp = basisu[i] * basis[j] * bp->vec[3]; + sumdiv += *fp; + } + else + *fp = basisu[i] * basis[j]; + } + } + + if (ratcomp) { + fp = sum; + for (j = jsta; j <= jen; j++) { + for (i = istart; i <= iend; i++, fp++) { + *fp /= sumdiv; + } + } + } + + zero_v3(in); + + /* one! (1.0) real point now */ + fp = sum; + for (j = jsta; j <= jen; j++) { + + if (j >= nu->pntsv) + jofs = (j - nu->pntsv); + else + jofs = j; + bp = nu->bp + nu->pntsu * jofs + istart - 1; + + for (i = istart; i <= iend; i++, fp++) { + if (i >= nu->pntsu) { + iofs = i - nu->pntsu; + bp = nu->bp + nu->pntsu * jofs + iofs; + } + else + bp++; + + if (*fp != 0.0f) { + madd_v3_v3fl(in, bp->vec, *fp); + } + } + } + + in += 3; + basis += KNOTSV(nu); + } + u += ustep; + if (rowstride != 0) { + in = (float *)(((unsigned char *)in) + (rowstride - 3 * totv * sizeof(*in))); + } + } + + /* free */ + MEM_freeN(sum); + MEM_freeN(basisu); + MEM_freeN(basisv); + MEM_freeN(jstart); + MEM_freeN(jend); } /** @@ -1366,129 +1377,136 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r * \param tilt_array: set when non-NULL * \param radius_array: set when non-NULL */ -void BKE_nurb_makeCurve( - const Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array, - int resolu, int stride) -{ - const float eps = 1e-6f; - BPoint *bp; - float u, ustart, uend, ustep, sumdiv; - float *basisu, *sum, *fp; - float *coord_fp = coord_array, *tilt_fp = tilt_array, *radius_fp = radius_array, *weight_fp = weight_array; - int i, len, istart, iend, cycl; - - if (nu->knotsu == NULL) - return; - if (nu->orderu > nu->pntsu) - return; - if (coord_array == NULL) - return; - - /* allocate and initialize */ - len = nu->pntsu; - if (len == 0) - return; - sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbcurve1"); - - resolu = (resolu * SEGMENTSU(nu)); - - if (resolu == 0) { - MEM_freeN(sum); - return; - } - - fp = nu->knotsu; - ustart = fp[nu->orderu - 1]; - if (nu->flagu & CU_NURB_CYCLIC) - uend = fp[nu->pntsu + nu->orderu - 1]; - else - uend = fp[nu->pntsu]; - ustep = (uend - ustart) / (resolu - ((nu->flagu & CU_NURB_CYCLIC) ? 0 : 1)); - - basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbcurve3"); - - if (nu->flagu & CU_NURB_CYCLIC) - cycl = nu->orderu - 1; - else - cycl = 0; - - u = ustart; - while (resolu--) { - basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend); - - /* calc sum */ - sumdiv = 0.0; - fp = sum; - bp = nu->bp + istart - 1; - for (i = istart; i <= iend; i++, fp++) { - if (i >= nu->pntsu) - bp = nu->bp + (i - nu->pntsu); - else - bp++; - - *fp = basisu[i] * bp->vec[3]; - sumdiv += *fp; - } - if ((sumdiv != 0.0f) && (sumdiv < 1.0f - eps || sumdiv > 1.0f + eps)) { - /* is normalizing needed? */ - fp = sum; - for (i = istart; i <= iend; i++, fp++) { - *fp /= sumdiv; - } - } - - zero_v3(coord_fp); - - /* one! (1.0) real point */ - fp = sum; - bp = nu->bp + istart - 1; - for (i = istart; i <= iend; i++, fp++) { - if (i >= nu->pntsu) - bp = nu->bp + (i - nu->pntsu); - else - bp++; - - if (*fp != 0.0f) { - madd_v3_v3fl(coord_fp, bp->vec, *fp); - - if (tilt_fp) - (*tilt_fp) += (*fp) * bp->tilt; - - if (radius_fp) - (*radius_fp) += (*fp) * bp->radius; - - if (weight_fp) - (*weight_fp) += (*fp) * bp->weight; - } - } - - coord_fp = POINTER_OFFSET(coord_fp, stride); - - if (tilt_fp) - tilt_fp = POINTER_OFFSET(tilt_fp, stride); - if (radius_fp) - radius_fp = POINTER_OFFSET(radius_fp, stride); - if (weight_fp) - weight_fp = POINTER_OFFSET(weight_fp, stride); - - u += ustep; - } - - /* free */ - MEM_freeN(sum); - MEM_freeN(basisu); +void BKE_nurb_makeCurve(const Nurb *nu, + float *coord_array, + float *tilt_array, + float *radius_array, + float *weight_array, + int resolu, + int stride) +{ + const float eps = 1e-6f; + BPoint *bp; + float u, ustart, uend, ustep, sumdiv; + float *basisu, *sum, *fp; + float *coord_fp = coord_array, *tilt_fp = tilt_array, *radius_fp = radius_array, + *weight_fp = weight_array; + int i, len, istart, iend, cycl; + + if (nu->knotsu == NULL) + return; + if (nu->orderu > nu->pntsu) + return; + if (coord_array == NULL) + return; + + /* allocate and initialize */ + len = nu->pntsu; + if (len == 0) + return; + sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbcurve1"); + + resolu = (resolu * SEGMENTSU(nu)); + + if (resolu == 0) { + MEM_freeN(sum); + return; + } + + fp = nu->knotsu; + ustart = fp[nu->orderu - 1]; + if (nu->flagu & CU_NURB_CYCLIC) + uend = fp[nu->pntsu + nu->orderu - 1]; + else + uend = fp[nu->pntsu]; + ustep = (uend - ustart) / (resolu - ((nu->flagu & CU_NURB_CYCLIC) ? 0 : 1)); + + basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbcurve3"); + + if (nu->flagu & CU_NURB_CYCLIC) + cycl = nu->orderu - 1; + else + cycl = 0; + + u = ustart; + while (resolu--) { + basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend); + + /* calc sum */ + sumdiv = 0.0; + fp = sum; + bp = nu->bp + istart - 1; + for (i = istart; i <= iend; i++, fp++) { + if (i >= nu->pntsu) + bp = nu->bp + (i - nu->pntsu); + else + bp++; + + *fp = basisu[i] * bp->vec[3]; + sumdiv += *fp; + } + if ((sumdiv != 0.0f) && (sumdiv < 1.0f - eps || sumdiv > 1.0f + eps)) { + /* is normalizing needed? */ + fp = sum; + for (i = istart; i <= iend; i++, fp++) { + *fp /= sumdiv; + } + } + + zero_v3(coord_fp); + + /* one! (1.0) real point */ + fp = sum; + bp = nu->bp + istart - 1; + for (i = istart; i <= iend; i++, fp++) { + if (i >= nu->pntsu) + bp = nu->bp + (i - nu->pntsu); + else + bp++; + + if (*fp != 0.0f) { + madd_v3_v3fl(coord_fp, bp->vec, *fp); + + if (tilt_fp) + (*tilt_fp) += (*fp) * bp->tilt; + + if (radius_fp) + (*radius_fp) += (*fp) * bp->radius; + + if (weight_fp) + (*weight_fp) += (*fp) * bp->weight; + } + } + + coord_fp = POINTER_OFFSET(coord_fp, stride); + + if (tilt_fp) + tilt_fp = POINTER_OFFSET(tilt_fp, stride); + if (radius_fp) + radius_fp = POINTER_OFFSET(radius_fp, stride); + if (weight_fp) + weight_fp = POINTER_OFFSET(weight_fp, stride); + + u += ustep; + } + + /* free */ + MEM_freeN(sum); + MEM_freeN(basisu); } /** * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis. */ -unsigned int BKE_curve_calc_coords_axis_len( - const unsigned int bezt_array_len, const unsigned int resolu, - const bool is_cyclic, const bool use_cyclic_duplicate_endpoint) +unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len, + const unsigned int resolu, + const bool is_cyclic, + const bool use_cyclic_duplicate_endpoint) { - const unsigned int segments = bezt_array_len - (is_cyclic ? 0 : 1); - const unsigned int points_len = (segments * resolu) + (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1); - return points_len; + const unsigned int segments = bezt_array_len - (is_cyclic ? 0 : 1); + const unsigned int points_len = (segments * resolu) + + (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1); + return points_len; } /** @@ -1497,780 +1515,818 @@ unsigned int BKE_curve_calc_coords_axis_len( * * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array. */ -void BKE_curve_calc_coords_axis( - const BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, - const bool is_cyclic, const bool use_cyclic_duplicate_endpoint, - /* array params */ - const unsigned int axis, const unsigned int stride, - float *r_points) -{ - const unsigned int points_len = BKE_curve_calc_coords_axis_len( - bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint); - float *r_points_offset = r_points; - - const unsigned int resolu_stride = resolu * stride; - const unsigned int bezt_array_last = bezt_array_len - 1; - - for (unsigned int i = 0; i < bezt_array_last; i++) { - const BezTriple *bezt_curr = &bezt_array[i]; - const BezTriple *bezt_next = &bezt_array[i + 1]; - BKE_curve_forward_diff_bezier( - bezt_curr->vec[1][axis], bezt_curr->vec[2][axis], - bezt_next->vec[0][axis], bezt_next->vec[1][axis], - r_points_offset, (int)resolu, stride); - r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride); - } - - if (is_cyclic) { - const BezTriple *bezt_curr = &bezt_array[bezt_array_last]; - const BezTriple *bezt_next = &bezt_array[0]; - BKE_curve_forward_diff_bezier( - bezt_curr->vec[1][axis], bezt_curr->vec[2][axis], - bezt_next->vec[0][axis], bezt_next->vec[1][axis], - r_points_offset, (int)resolu, stride); - r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride); - if (use_cyclic_duplicate_endpoint) { - *r_points_offset = *r_points; - r_points_offset = POINTER_OFFSET(r_points_offset, stride); - } - } - else { - float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride); - *r_points_last = bezt_array[bezt_array_last].vec[1][axis]; - r_points_offset = POINTER_OFFSET(r_points_offset, stride); - } - - BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset); - UNUSED_VARS_NDEBUG(points_len); +void BKE_curve_calc_coords_axis(const BezTriple *bezt_array, + const unsigned int bezt_array_len, + const unsigned int resolu, + const bool is_cyclic, + const bool use_cyclic_duplicate_endpoint, + /* array params */ + const unsigned int axis, + const unsigned int stride, + float *r_points) +{ + const unsigned int points_len = BKE_curve_calc_coords_axis_len( + bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint); + float *r_points_offset = r_points; + + const unsigned int resolu_stride = resolu * stride; + const unsigned int bezt_array_last = bezt_array_len - 1; + + for (unsigned int i = 0; i < bezt_array_last; i++) { + const BezTriple *bezt_curr = &bezt_array[i]; + const BezTriple *bezt_next = &bezt_array[i + 1]; + BKE_curve_forward_diff_bezier(bezt_curr->vec[1][axis], + bezt_curr->vec[2][axis], + bezt_next->vec[0][axis], + bezt_next->vec[1][axis], + r_points_offset, + (int)resolu, + stride); + r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride); + } + + if (is_cyclic) { + const BezTriple *bezt_curr = &bezt_array[bezt_array_last]; + const BezTriple *bezt_next = &bezt_array[0]; + BKE_curve_forward_diff_bezier(bezt_curr->vec[1][axis], + bezt_curr->vec[2][axis], + bezt_next->vec[0][axis], + bezt_next->vec[1][axis], + r_points_offset, + (int)resolu, + stride); + r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride); + if (use_cyclic_duplicate_endpoint) { + *r_points_offset = *r_points; + r_points_offset = POINTER_OFFSET(r_points_offset, stride); + } + } + else { + float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride); + *r_points_last = bezt_array[bezt_array_last].vec[1][axis]; + r_points_offset = POINTER_OFFSET(r_points_offset, stride); + } + + BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset); + UNUSED_VARS_NDEBUG(points_len); } /* forward differencing method for bezier curve */ -void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride) -{ - float rt0, rt1, rt2, rt3, f; - int a; - - f = (float)it; - rt0 = q0; - rt1 = 3.0f * (q1 - q0) / f; - f *= f; - rt2 = 3.0f * (q0 - 2.0f * q1 + q2) / f; - f *= it; - rt3 = (q3 - q0 + 3.0f * (q1 - q2)) / f; - - q0 = rt0; - q1 = rt1 + rt2 + rt3; - q2 = 2 * rt2 + 6 * rt3; - q3 = 6 * rt3; - - for (a = 0; a <= it; a++) { - *p = q0; - p = POINTER_OFFSET(p, stride); - q0 += q1; - q1 += q2; - q2 += q3; - } +void BKE_curve_forward_diff_bezier( + float q0, float q1, float q2, float q3, float *p, int it, int stride) +{ + float rt0, rt1, rt2, rt3, f; + int a; + + f = (float)it; + rt0 = q0; + rt1 = 3.0f * (q1 - q0) / f; + f *= f; + rt2 = 3.0f * (q0 - 2.0f * q1 + q2) / f; + f *= it; + rt3 = (q3 - q0 + 3.0f * (q1 - q2)) / f; + + q0 = rt0; + q1 = rt1 + rt2 + rt3; + q2 = 2 * rt2 + 6 * rt3; + q3 = 6 * rt3; + + for (a = 0; a <= it; a++) { + *p = q0; + p = POINTER_OFFSET(p, stride); + q0 += q1; + q1 += q2; + q2 += q3; + } } /* forward differencing method for first derivative of cubic bezier curve */ -void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride) -{ - float rt0, rt1, rt2, f; - int a; - - f = 1.0f / (float)it; - - rt0 = 3.0f * (q1 - q0); - rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2)); - rt2 = 6.0f * (q0 + q2) - 12.0f * q1; - - q0 = rt0; - q1 = f * (rt1 + rt2); - q2 = 2.0f * f * rt1; - - for (a = 0; a <= it; a++) { - *p = q0; - p = POINTER_OFFSET(p, stride); - q0 += q1; - q1 += q2; - } -} - -static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3], const float p2[3], const float p3[3], - float p[3], int it, int stride) -{ - /* note that these are not perpendicular to the curve - * they need to be rotated for this, - * - * This could also be optimized like BKE_curve_forward_diff_bezier */ - int a; - for (a = 0; a <= it; a++) { - float t = (float)a / (float)it; - - int i; - for (i = 0; i < 3; i++) { - p[i] = (-6.0f * t + 6.0f) * p0[i] + - ( 18.0f * t - 12.0f) * p1[i] + - (-18.0f * t + 6.0f) * p2[i] + - ( 6.0f * t) * p3[i]; - } - normalize_v3(p); - p = POINTER_OFFSET(p, stride); - } +void BKE_curve_forward_diff_tangent_bezier( + float q0, float q1, float q2, float q3, float *p, int it, int stride) +{ + float rt0, rt1, rt2, f; + int a; + + f = 1.0f / (float)it; + + rt0 = 3.0f * (q1 - q0); + rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2)); + rt2 = 6.0f * (q0 + q2) - 12.0f * q1; + + q0 = rt0; + q1 = f * (rt1 + rt2); + q2 = 2.0f * f * rt1; + + for (a = 0; a <= it; a++) { + *p = q0; + p = POINTER_OFFSET(p, stride); + q0 += q1; + q1 += q2; + } +} + +static void forward_diff_bezier_cotangent(const float p0[3], + const float p1[3], + const float p2[3], + const float p3[3], + float p[3], + int it, + int stride) +{ + /* note that these are not perpendicular to the curve + * they need to be rotated for this, + * + * This could also be optimized like BKE_curve_forward_diff_bezier */ + int a; + for (a = 0; a <= it; a++) { + float t = (float)a / (float)it; + + int i; + for (i = 0; i < 3; i++) { + p[i] = (-6.0f * t + 6.0f) * p0[i] + (18.0f * t - 12.0f) * p1[i] + + (-18.0f * t + 6.0f) * p2[i] + (6.0f * t) * p3[i]; + } + normalize_v3(p); + p = POINTER_OFFSET(p, stride); + } } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ float *BKE_curve_surf_make_orco(Object *ob) { - /* Note: this function is used in convertblender only atm, so - * suppose nonzero curve's render resolution should always be used */ - Curve *cu = ob->data; - Nurb *nu; - int a, b, tot = 0; - int sizeu, sizev; - int resolu, resolv; - float *fp, *coord_array; - - /* first calculate the size of the datablock */ - nu = cu->nurb.first; - while (nu) { - /* as we want to avoid the seam in a cyclic nurbs - * texture wrapping, reserve extra orco data space to save these extra needed - * vertex based UV coordinates for the meridian vertices. - * Vertices on the 0/2pi boundary are not duplicated inside the displist but later in - * the renderface/vert construction. - * - * See also convertblender.c: init_render_surf() - */ - - resolu = cu->resolu_ren ? cu->resolu_ren : nu->resolu; - resolv = cu->resolv_ren ? cu->resolv_ren : nu->resolv; - - sizeu = nu->pntsu * resolu; - sizev = nu->pntsv * resolv; - if (nu->flagu & CU_NURB_CYCLIC) sizeu++; - if (nu->flagv & CU_NURB_CYCLIC) sizev++; - if (nu->pntsv > 1) tot += sizeu * sizev; - - nu = nu->next; - } - /* makeNurbfaces wants zeros */ - fp = coord_array = MEM_calloc_arrayN(tot, 3 * sizeof(float), "make_orco"); - - nu = cu->nurb.first; - while (nu) { - resolu = cu->resolu_ren ? cu->resolu_ren : nu->resolu; - resolv = cu->resolv_ren ? cu->resolv_ren : nu->resolv; - - if (nu->pntsv > 1) { - sizeu = nu->pntsu * resolu; - sizev = nu->pntsv * resolv; - - if (nu->flagu & CU_NURB_CYCLIC) - sizeu++; - if (nu->flagv & CU_NURB_CYCLIC) - sizev++; - - if (cu->flag & CU_UV_ORCO) { - for (b = 0; b < sizeu; b++) { - for (a = 0; a < sizev; a++) { - - if (sizev < 2) - fp[0] = 0.0f; - else - fp[0] = -1.0f + 2.0f * ((float)a) / (sizev - 1); - - if (sizeu < 2) - fp[1] = 0.0f; - else - fp[1] = -1.0f + 2.0f * ((float)b) / (sizeu - 1); - - fp[2] = 0.0; - - fp += 3; - } - } - } - else { - int size = (nu->pntsu * resolu) * (nu->pntsv * resolv) * 3 * sizeof(float); - float *_tdata = MEM_mallocN(size, "temp data"); - float *tdata = _tdata; - - BKE_nurb_makeFaces(nu, tdata, 0, resolu, resolv); - - for (b = 0; b < sizeu; b++) { - int use_b = b; - if (b == sizeu - 1 && (nu->flagu & CU_NURB_CYCLIC)) - use_b = false; - - for (a = 0; a < sizev; a++) { - int use_a = a; - if (a == sizev - 1 && (nu->flagv & CU_NURB_CYCLIC)) - use_a = false; - - tdata = _tdata + 3 * (use_b * (nu->pntsv * resolv) + use_a); - - fp[0] = (tdata[0] - cu->loc[0]) / cu->size[0]; - fp[1] = (tdata[1] - cu->loc[1]) / cu->size[1]; - fp[2] = (tdata[2] - cu->loc[2]) / cu->size[2]; - fp += 3; - } - } - - MEM_freeN(_tdata); - } - } - nu = nu->next; - } - - return coord_array; + /* Note: this function is used in convertblender only atm, so + * suppose nonzero curve's render resolution should always be used */ + Curve *cu = ob->data; + Nurb *nu; + int a, b, tot = 0; + int sizeu, sizev; + int resolu, resolv; + float *fp, *coord_array; + + /* first calculate the size of the datablock */ + nu = cu->nurb.first; + while (nu) { + /* as we want to avoid the seam in a cyclic nurbs + * texture wrapping, reserve extra orco data space to save these extra needed + * vertex based UV coordinates for the meridian vertices. + * Vertices on the 0/2pi boundary are not duplicated inside the displist but later in + * the renderface/vert construction. + * + * See also convertblender.c: init_render_surf() + */ + + resolu = cu->resolu_ren ? cu->resolu_ren : nu->resolu; + resolv = cu->resolv_ren ? cu->resolv_ren : nu->resolv; + + sizeu = nu->pntsu * resolu; + sizev = nu->pntsv * resolv; + if (nu->flagu & CU_NURB_CYCLIC) + sizeu++; + if (nu->flagv & CU_NURB_CYCLIC) + sizev++; + if (nu->pntsv > 1) + tot += sizeu * sizev; + + nu = nu->next; + } + /* makeNurbfaces wants zeros */ + fp = coord_array = MEM_calloc_arrayN(tot, 3 * sizeof(float), "make_orco"); + + nu = cu->nurb.first; + while (nu) { + resolu = cu->resolu_ren ? cu->resolu_ren : nu->resolu; + resolv = cu->resolv_ren ? cu->resolv_ren : nu->resolv; + + if (nu->pntsv > 1) { + sizeu = nu->pntsu * resolu; + sizev = nu->pntsv * resolv; + + if (nu->flagu & CU_NURB_CYCLIC) + sizeu++; + if (nu->flagv & CU_NURB_CYCLIC) + sizev++; + + if (cu->flag & CU_UV_ORCO) { + for (b = 0; b < sizeu; b++) { + for (a = 0; a < sizev; a++) { + + if (sizev < 2) + fp[0] = 0.0f; + else + fp[0] = -1.0f + 2.0f * ((float)a) / (sizev - 1); + + if (sizeu < 2) + fp[1] = 0.0f; + else + fp[1] = -1.0f + 2.0f * ((float)b) / (sizeu - 1); + + fp[2] = 0.0; + + fp += 3; + } + } + } + else { + int size = (nu->pntsu * resolu) * (nu->pntsv * resolv) * 3 * sizeof(float); + float *_tdata = MEM_mallocN(size, "temp data"); + float *tdata = _tdata; + + BKE_nurb_makeFaces(nu, tdata, 0, resolu, resolv); + + for (b = 0; b < sizeu; b++) { + int use_b = b; + if (b == sizeu - 1 && (nu->flagu & CU_NURB_CYCLIC)) + use_b = false; + + for (a = 0; a < sizev; a++) { + int use_a = a; + if (a == sizev - 1 && (nu->flagv & CU_NURB_CYCLIC)) + use_a = false; + + tdata = _tdata + 3 * (use_b * (nu->pntsv * resolv) + use_a); + + fp[0] = (tdata[0] - cu->loc[0]) / cu->size[0]; + fp[1] = (tdata[1] - cu->loc[1]) / cu->size[1]; + fp[2] = (tdata[2] - cu->loc[2]) / cu->size[2]; + fp += 3; + } + } + + MEM_freeN(_tdata); + } + } + nu = nu->next; + } + + return coord_array; } - /* NOTE: This routine is tied to the order of vertex * built by displist and as passed to the renderer. */ float *BKE_curve_make_orco(Depsgraph *depsgraph, Scene *scene, Object *ob, int *r_numVerts) { - Curve *cu = ob->data; - DispList *dl; - int u, v, numVerts; - float *fp, *coord_array; - ListBase disp = {NULL, NULL}; - - BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp, NULL); - - numVerts = 0; - for (dl = disp.first; dl; dl = dl->next) { - if (dl->type == DL_INDEX3) { - numVerts += dl->nr; - } - else if (dl->type == DL_SURF) { - /* convertblender.c uses the Surface code for creating renderfaces when cyclic U only - * (closed circle beveling) - */ - if (dl->flag & DL_CYCL_U) { - if (dl->flag & DL_CYCL_V) - numVerts += (dl->parts + 1) * (dl->nr + 1); - else - numVerts += dl->parts * (dl->nr + 1); - } - else if (dl->flag & DL_CYCL_V) { - numVerts += (dl->parts + 1) * dl->nr; - } - else - numVerts += dl->parts * dl->nr; - } - } - - if (r_numVerts) - *r_numVerts = numVerts; - - fp = coord_array = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "cu_orco"); - for (dl = disp.first; dl; dl = dl->next) { - if (dl->type == DL_INDEX3) { - for (u = 0; u < dl->nr; u++, fp += 3) { - if (cu->flag & CU_UV_ORCO) { - fp[0] = 2.0f * u / (dl->nr - 1) - 1.0f; - fp[1] = 0.0; - fp[2] = 0.0; - } - else { - copy_v3_v3(fp, &dl->verts[u * 3]); - - fp[0] = (fp[0] - cu->loc[0]) / cu->size[0]; - fp[1] = (fp[1] - cu->loc[1]) / cu->size[1]; - fp[2] = (fp[2] - cu->loc[2]) / cu->size[2]; - } - } - } - else if (dl->type == DL_SURF) { - int sizeu = dl->nr, sizev = dl->parts; - - /* exception as handled in convertblender.c too */ - if (dl->flag & DL_CYCL_U) { - sizeu++; - if (dl->flag & DL_CYCL_V) - sizev++; - } - else if (dl->flag & DL_CYCL_V) { - sizev++; - } - - for (u = 0; u < sizev; u++) { - for (v = 0; v < sizeu; v++, fp += 3) { - if (cu->flag & CU_UV_ORCO) { - fp[0] = 2.0f * u / (sizev - 1) - 1.0f; - fp[1] = 2.0f * v / (sizeu - 1) - 1.0f; - fp[2] = 0.0; - } - else { - const float *vert; - int realv = v % dl->nr; - int realu = u % dl->parts; - - vert = dl->verts + 3 * (dl->nr * realu + realv); - copy_v3_v3(fp, vert); - - fp[0] = (fp[0] - cu->loc[0]) / cu->size[0]; - fp[1] = (fp[1] - cu->loc[1]) / cu->size[1]; - fp[2] = (fp[2] - cu->loc[2]) / cu->size[2]; - } - } - } - } - } - - BKE_displist_free(&disp); - - return coord_array; + Curve *cu = ob->data; + DispList *dl; + int u, v, numVerts; + float *fp, *coord_array; + ListBase disp = {NULL, NULL}; + + BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp, NULL); + + numVerts = 0; + for (dl = disp.first; dl; dl = dl->next) { + if (dl->type == DL_INDEX3) { + numVerts += dl->nr; + } + else if (dl->type == DL_SURF) { + /* convertblender.c uses the Surface code for creating renderfaces when cyclic U only + * (closed circle beveling) + */ + if (dl->flag & DL_CYCL_U) { + if (dl->flag & DL_CYCL_V) + numVerts += (dl->parts + 1) * (dl->nr + 1); + else + numVerts += dl->parts * (dl->nr + 1); + } + else if (dl->flag & DL_CYCL_V) { + numVerts += (dl->parts + 1) * dl->nr; + } + else + numVerts += dl->parts * dl->nr; + } + } + + if (r_numVerts) + *r_numVerts = numVerts; + + fp = coord_array = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "cu_orco"); + for (dl = disp.first; dl; dl = dl->next) { + if (dl->type == DL_INDEX3) { + for (u = 0; u < dl->nr; u++, fp += 3) { + if (cu->flag & CU_UV_ORCO) { + fp[0] = 2.0f * u / (dl->nr - 1) - 1.0f; + fp[1] = 0.0; + fp[2] = 0.0; + } + else { + copy_v3_v3(fp, &dl->verts[u * 3]); + + fp[0] = (fp[0] - cu->loc[0]) / cu->size[0]; + fp[1] = (fp[1] - cu->loc[1]) / cu->size[1]; + fp[2] = (fp[2] - cu->loc[2]) / cu->size[2]; + } + } + } + else if (dl->type == DL_SURF) { + int sizeu = dl->nr, sizev = dl->parts; + + /* exception as handled in convertblender.c too */ + if (dl->flag & DL_CYCL_U) { + sizeu++; + if (dl->flag & DL_CYCL_V) + sizev++; + } + else if (dl->flag & DL_CYCL_V) { + sizev++; + } + + for (u = 0; u < sizev; u++) { + for (v = 0; v < sizeu; v++, fp += 3) { + if (cu->flag & CU_UV_ORCO) { + fp[0] = 2.0f * u / (sizev - 1) - 1.0f; + fp[1] = 2.0f * v / (sizeu - 1) - 1.0f; + fp[2] = 0.0; + } + else { + const float *vert; + int realv = v % dl->nr; + int realu = u % dl->parts; + + vert = dl->verts + 3 * (dl->nr * realu + realv); + copy_v3_v3(fp, vert); + + fp[0] = (fp[0] - cu->loc[0]) / cu->size[0]; + fp[1] = (fp[1] - cu->loc[1]) / cu->size[1]; + fp[2] = (fp[2] - cu->loc[2]) / cu->size[2]; + } + } + } + } + } + + BKE_displist_free(&disp); + + return coord_array; } - /* ***************** BEVEL ****************** */ -void BKE_curve_bevel_make( - Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *disp, - const bool for_render, const bool use_render_resolution, - LinkNode *ob_cyclic_list) -{ - DispList *dl, *dlnew; - Curve *bevcu, *cu; - float *fp, facx, facy, angle, dangle; - int nr, a; - - cu = ob->data; - BLI_listbase_clear(disp); - - /* if a font object is being edited, then do nothing */ -// XXX if ( ob == obedit && ob->type == OB_FONT ) return; - - if (cu->bevobj) { - if (cu->bevobj->type != OB_CURVE) - return; - - bevcu = cu->bevobj->data; - if (bevcu->ext1 == 0.0f && bevcu->ext2 == 0.0f) { - ListBase bevdisp = {NULL, NULL}; - facx = cu->bevobj->scale[0]; - facy = cu->bevobj->scale[1]; - - if (for_render) { - if (BLI_linklist_index(ob_cyclic_list, cu->bevobj) == -1) { - BKE_displist_make_curveTypes_forRender( - depsgraph, scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution, - &(LinkNode){ .link = ob, .next = ob_cyclic_list, }); - dl = bevdisp.first; - } - else { - dl = NULL; - } - } - else if (cu->bevobj->runtime.curve_cache) { - dl = cu->bevobj->runtime.curve_cache->disp.first; - } - else { - BLI_assert(cu->bevobj->runtime.curve_cache != NULL); - dl = NULL; - } - - while (dl) { - if (ELEM(dl->type, DL_POLY, DL_SEGM)) { - dlnew = MEM_mallocN(sizeof(DispList), "makebevelcurve1"); - *dlnew = *dl; - dlnew->verts = MEM_malloc_arrayN(dl->parts * dl->nr, 3 * sizeof(float), "makebevelcurve1"); - memcpy(dlnew->verts, dl->verts, 3 * sizeof(float) * dl->parts * dl->nr); - - if (dlnew->type == DL_SEGM) - dlnew->flag |= (DL_FRONT_CURVE | DL_BACK_CURVE); - - BLI_addtail(disp, dlnew); - fp = dlnew->verts; - nr = dlnew->parts * dlnew->nr; - while (nr--) { - fp[2] = fp[1] * facy; - fp[1] = -fp[0] * facx; - fp[0] = 0.0; - fp += 3; - } - } - dl = dl->next; - } - - BKE_displist_free(&bevdisp); - } - } - else if (cu->ext1 == 0.0f && cu->ext2 == 0.0f) { - /* pass */ - } - else if (cu->ext2 == 0.0f) { - dl = MEM_callocN(sizeof(DispList), "makebevelcurve2"); - dl->verts = MEM_malloc_arrayN(2, sizeof(float[3]), "makebevelcurve2"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->parts = 1; - dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE; - dl->nr = 2; - - fp = dl->verts; - fp[0] = fp[1] = 0.0; - fp[2] = -cu->ext1; - fp[3] = fp[4] = 0.0; - fp[5] = cu->ext1; - } - else if ((cu->flag & (CU_FRONT | CU_BACK)) == 0 && cu->ext1 == 0.0f) { /* we make a full round bevel in that case */ - nr = 4 + 2 * cu->bevresol; - - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1"); - BLI_addtail(disp, dl); - dl->type = DL_POLY; - dl->parts = 1; - dl->flag = DL_BACK_CURVE; - dl->nr = nr; - - /* a circle */ - fp = dl->verts; - dangle = (2.0f * (float)M_PI / (nr)); - angle = -(nr - 1) * dangle; - - for (a = 0; a < nr; a++) { - fp[0] = 0.0; - fp[1] = (cosf(angle) * (cu->ext2)); - fp[2] = (sinf(angle) * (cu->ext2)) - cu->ext1; - angle += dangle; - fp += 3; - } - } - else { - short dnr; - - /* bevel now in three parts, for proper vertex normals */ - /* part 1, back */ - - if ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT)) { - dnr = nr = 2 + cu->bevresol; - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - nr = 3 + 2 * cu->bevresol; - } - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->parts = 1; - dl->flag = DL_BACK_CURVE; - dl->nr = nr; - - /* half a circle */ - fp = dl->verts; - dangle = ((float)M_PI_2 / (dnr - 1)); - angle = -(nr - 1) * dangle; - - for (a = 0; a < nr; a++) { - fp[0] = 0.0; - fp[1] = (float)(cosf(angle) * (cu->ext2)); - fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1; - angle += dangle; - fp += 3; - } - } - - /* part 2, sidefaces */ - if (cu->ext1 != 0.0f) { - nr = 2; - - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->parts = 1; - dl->nr = nr; - - fp = dl->verts; - fp[1] = cu->ext2; - fp[2] = -cu->ext1; - fp[4] = cu->ext2; - fp[5] = cu->ext1; - - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - dl = MEM_dupallocN(dl); - dl->verts = MEM_dupallocN(dl->verts); - BLI_addtail(disp, dl); - - fp = dl->verts; - fp[1] = -fp[1]; - fp[2] = -fp[2]; - fp[4] = -fp[4]; - fp[5] = -fp[5]; - } - } - - /* part 3, front */ - if ((cu->flag & CU_FRONT) || !(cu->flag & CU_BACK)) { - dnr = nr = 2 + cu->bevresol; - if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { - nr = 3 + 2 * cu->bevresol; - } - dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3"); - dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3"); - BLI_addtail(disp, dl); - dl->type = DL_SEGM; - dl->flag = DL_FRONT_CURVE; - dl->parts = 1; - dl->nr = nr; - - /* half a circle */ - fp = dl->verts; - angle = 0.0; - dangle = ((float)M_PI_2 / (dnr - 1)); - - for (a = 0; a < nr; a++) { - fp[0] = 0.0; - fp[1] = (float)(cosf(angle) * (cu->ext2)); - fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; - angle += dangle; - fp += 3; - } - } - } -} - -static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], const float v4[3], - short cox, short coy, - float *lambda, float *mu, float vec[3]) -{ - /* return: - * -1: collinear - * 0: no intersection of segments - * 1: exact intersection of segments - * 2: cross-intersection of segments - */ - float deler; - - deler = (v1[cox] - v2[cox]) * (v3[coy] - v4[coy]) - (v3[cox] - v4[cox]) * (v1[coy] - v2[coy]); - if (deler == 0.0f) - return -1; - - *lambda = (v1[coy] - v3[coy]) * (v3[cox] - v4[cox]) - (v1[cox] - v3[cox]) * (v3[coy] - v4[coy]); - *lambda = -(*lambda / deler); - - deler = v3[coy] - v4[coy]; - if (deler == 0) { - deler = v3[cox] - v4[cox]; - *mu = -(*lambda * (v2[cox] - v1[cox]) + v1[cox] - v3[cox]) / deler; - } - else { - *mu = -(*lambda * (v2[coy] - v1[coy]) + v1[coy] - v3[coy]) / deler; - } - vec[cox] = *lambda * (v2[cox] - v1[cox]) + v1[cox]; - vec[coy] = *lambda * (v2[coy] - v1[coy]) + v1[coy]; - - if (*lambda >= 0.0f && *lambda <= 1.0f && *mu >= 0.0f && *mu <= 1.0f) { - if (*lambda == 0.0f || *lambda == 1.0f || *mu == 0.0f || *mu == 1.0f) - return 1; - return 2; - } - return 0; +void BKE_curve_bevel_make(Depsgraph *depsgraph, + Scene *scene, + Object *ob, + ListBase *disp, + const bool for_render, + const bool use_render_resolution, + LinkNode *ob_cyclic_list) +{ + DispList *dl, *dlnew; + Curve *bevcu, *cu; + float *fp, facx, facy, angle, dangle; + int nr, a; + + cu = ob->data; + BLI_listbase_clear(disp); + + /* if a font object is being edited, then do nothing */ + // XXX if ( ob == obedit && ob->type == OB_FONT ) return; + + if (cu->bevobj) { + if (cu->bevobj->type != OB_CURVE) + return; + + bevcu = cu->bevobj->data; + if (bevcu->ext1 == 0.0f && bevcu->ext2 == 0.0f) { + ListBase bevdisp = {NULL, NULL}; + facx = cu->bevobj->scale[0]; + facy = cu->bevobj->scale[1]; + + if (for_render) { + if (BLI_linklist_index(ob_cyclic_list, cu->bevobj) == -1) { + BKE_displist_make_curveTypes_forRender(depsgraph, + scene, + cu->bevobj, + &bevdisp, + NULL, + false, + use_render_resolution, + &(LinkNode){ + .link = ob, + .next = ob_cyclic_list, + }); + dl = bevdisp.first; + } + else { + dl = NULL; + } + } + else if (cu->bevobj->runtime.curve_cache) { + dl = cu->bevobj->runtime.curve_cache->disp.first; + } + else { + BLI_assert(cu->bevobj->runtime.curve_cache != NULL); + dl = NULL; + } + + while (dl) { + if (ELEM(dl->type, DL_POLY, DL_SEGM)) { + dlnew = MEM_mallocN(sizeof(DispList), "makebevelcurve1"); + *dlnew = *dl; + dlnew->verts = MEM_malloc_arrayN( + dl->parts * dl->nr, 3 * sizeof(float), "makebevelcurve1"); + memcpy(dlnew->verts, dl->verts, 3 * sizeof(float) * dl->parts * dl->nr); + + if (dlnew->type == DL_SEGM) + dlnew->flag |= (DL_FRONT_CURVE | DL_BACK_CURVE); + + BLI_addtail(disp, dlnew); + fp = dlnew->verts; + nr = dlnew->parts * dlnew->nr; + while (nr--) { + fp[2] = fp[1] * facy; + fp[1] = -fp[0] * facx; + fp[0] = 0.0; + fp += 3; + } + } + dl = dl->next; + } + + BKE_displist_free(&bevdisp); + } + } + else if (cu->ext1 == 0.0f && cu->ext2 == 0.0f) { + /* pass */ + } + else if (cu->ext2 == 0.0f) { + dl = MEM_callocN(sizeof(DispList), "makebevelcurve2"); + dl->verts = MEM_malloc_arrayN(2, sizeof(float[3]), "makebevelcurve2"); + BLI_addtail(disp, dl); + dl->type = DL_SEGM; + dl->parts = 1; + dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE; + dl->nr = 2; + + fp = dl->verts; + fp[0] = fp[1] = 0.0; + fp[2] = -cu->ext1; + fp[3] = fp[4] = 0.0; + fp[5] = cu->ext1; + } + else if ((cu->flag & (CU_FRONT | CU_BACK)) == 0 && + cu->ext1 == 0.0f) { /* we make a full round bevel in that case */ + nr = 4 + 2 * cu->bevresol; + + dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1"); + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1"); + BLI_addtail(disp, dl); + dl->type = DL_POLY; + dl->parts = 1; + dl->flag = DL_BACK_CURVE; + dl->nr = nr; + + /* a circle */ + fp = dl->verts; + dangle = (2.0f * (float)M_PI / (nr)); + angle = -(nr - 1) * dangle; + + for (a = 0; a < nr; a++) { + fp[0] = 0.0; + fp[1] = (cosf(angle) * (cu->ext2)); + fp[2] = (sinf(angle) * (cu->ext2)) - cu->ext1; + angle += dangle; + fp += 3; + } + } + else { + short dnr; + + /* bevel now in three parts, for proper vertex normals */ + /* part 1, back */ + + if ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT)) { + dnr = nr = 2 + cu->bevresol; + if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { + nr = 3 + 2 * cu->bevresol; + } + dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1"); + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1"); + BLI_addtail(disp, dl); + dl->type = DL_SEGM; + dl->parts = 1; + dl->flag = DL_BACK_CURVE; + dl->nr = nr; + + /* half a circle */ + fp = dl->verts; + dangle = ((float)M_PI_2 / (dnr - 1)); + angle = -(nr - 1) * dangle; + + for (a = 0; a < nr; a++) { + fp[0] = 0.0; + fp[1] = (float)(cosf(angle) * (cu->ext2)); + fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1; + angle += dangle; + fp += 3; + } + } + + /* part 2, sidefaces */ + if (cu->ext1 != 0.0f) { + nr = 2; + + dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2"); + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2"); + BLI_addtail(disp, dl); + dl->type = DL_SEGM; + dl->parts = 1; + dl->nr = nr; + + fp = dl->verts; + fp[1] = cu->ext2; + fp[2] = -cu->ext1; + fp[4] = cu->ext2; + fp[5] = cu->ext1; + + if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { + dl = MEM_dupallocN(dl); + dl->verts = MEM_dupallocN(dl->verts); + BLI_addtail(disp, dl); + + fp = dl->verts; + fp[1] = -fp[1]; + fp[2] = -fp[2]; + fp[4] = -fp[4]; + fp[5] = -fp[5]; + } + } + + /* part 3, front */ + if ((cu->flag & CU_FRONT) || !(cu->flag & CU_BACK)) { + dnr = nr = 2 + cu->bevresol; + if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) { + nr = 3 + 2 * cu->bevresol; + } + dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3"); + dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3"); + BLI_addtail(disp, dl); + dl->type = DL_SEGM; + dl->flag = DL_FRONT_CURVE; + dl->parts = 1; + dl->nr = nr; + + /* half a circle */ + fp = dl->verts; + angle = 0.0; + dangle = ((float)M_PI_2 / (dnr - 1)); + + for (a = 0; a < nr; a++) { + fp[0] = 0.0; + fp[1] = (float)(cosf(angle) * (cu->ext2)); + fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1; + angle += dangle; + fp += 3; + } + } + } +} + +static int cu_isectLL(const float v1[3], + const float v2[3], + const float v3[3], + const float v4[3], + short cox, + short coy, + float *lambda, + float *mu, + float vec[3]) +{ + /* return: + * -1: collinear + * 0: no intersection of segments + * 1: exact intersection of segments + * 2: cross-intersection of segments + */ + float deler; + + deler = (v1[cox] - v2[cox]) * (v3[coy] - v4[coy]) - (v3[cox] - v4[cox]) * (v1[coy] - v2[coy]); + if (deler == 0.0f) + return -1; + + *lambda = (v1[coy] - v3[coy]) * (v3[cox] - v4[cox]) - (v1[cox] - v3[cox]) * (v3[coy] - v4[coy]); + *lambda = -(*lambda / deler); + + deler = v3[coy] - v4[coy]; + if (deler == 0) { + deler = v3[cox] - v4[cox]; + *mu = -(*lambda * (v2[cox] - v1[cox]) + v1[cox] - v3[cox]) / deler; + } + else { + *mu = -(*lambda * (v2[coy] - v1[coy]) + v1[coy] - v3[coy]) / deler; + } + vec[cox] = *lambda * (v2[cox] - v1[cox]) + v1[cox]; + vec[coy] = *lambda * (v2[coy] - v1[coy]) + v1[coy]; + + if (*lambda >= 0.0f && *lambda <= 1.0f && *mu >= 0.0f && *mu <= 1.0f) { + if (*lambda == 0.0f || *lambda == 1.0f || *mu == 0.0f || *mu == 1.0f) + return 1; + return 2; + } + return 0; } - static bool bevelinside(BevList *bl1, BevList *bl2) { - /* is bl2 INSIDE bl1 ? with left-right method and "lambda's" */ - /* returns '1' if correct hole */ - BevPoint *bevp, *prevbevp; - float min, max, vec[3], hvec1[3], hvec2[3], lab, mu; - int nr, links = 0, rechts = 0, mode; - - /* take first vertex of possible hole */ - - bevp = bl2->bevpoints; - hvec1[0] = bevp->vec[0]; - hvec1[1] = bevp->vec[1]; - hvec1[2] = 0.0; - copy_v3_v3(hvec2, hvec1); - hvec2[0] += 1000; - - /* test it with all edges of potential surrounding poly */ - /* count number of transitions left-right */ - - bevp = bl1->bevpoints; - nr = bl1->nr; - prevbevp = bevp + (nr - 1); - - while (nr--) { - min = prevbevp->vec[1]; - max = bevp->vec[1]; - if (max < min) { - min = max; - max = prevbevp->vec[1]; - } - if (min != max) { - if (min <= hvec1[1] && max >= hvec1[1]) { - /* there's a transition, calc intersection point */ - mode = cu_isectLL(prevbevp->vec, bevp->vec, hvec1, hvec2, 0, 1, &lab, &mu, vec); - /* if lab==0.0 or lab==1.0 then the edge intersects exactly a transition - * only allow for one situation: we choose lab= 1.0 - */ - if (mode >= 0 && lab != 0.0f) { - if (vec[0] < hvec1[0]) links++; - else rechts++; - } - } - } - prevbevp = bevp; - bevp++; - } - - return (links & 1) && (rechts & 1); + /* is bl2 INSIDE bl1 ? with left-right method and "lambda's" */ + /* returns '1' if correct hole */ + BevPoint *bevp, *prevbevp; + float min, max, vec[3], hvec1[3], hvec2[3], lab, mu; + int nr, links = 0, rechts = 0, mode; + + /* take first vertex of possible hole */ + + bevp = bl2->bevpoints; + hvec1[0] = bevp->vec[0]; + hvec1[1] = bevp->vec[1]; + hvec1[2] = 0.0; + copy_v3_v3(hvec2, hvec1); + hvec2[0] += 1000; + + /* test it with all edges of potential surrounding poly */ + /* count number of transitions left-right */ + + bevp = bl1->bevpoints; + nr = bl1->nr; + prevbevp = bevp + (nr - 1); + + while (nr--) { + min = prevbevp->vec[1]; + max = bevp->vec[1]; + if (max < min) { + min = max; + max = prevbevp->vec[1]; + } + if (min != max) { + if (min <= hvec1[1] && max >= hvec1[1]) { + /* there's a transition, calc intersection point */ + mode = cu_isectLL(prevbevp->vec, bevp->vec, hvec1, hvec2, 0, 1, &lab, &mu, vec); + /* if lab==0.0 or lab==1.0 then the edge intersects exactly a transition + * only allow for one situation: we choose lab= 1.0 + */ + if (mode >= 0 && lab != 0.0f) { + if (vec[0] < hvec1[0]) + links++; + else + rechts++; + } + } + } + prevbevp = bevp; + bevp++; + } + + return (links & 1) && (rechts & 1); } - struct BevelSort { - BevList *bl; - float left; - int dir; + BevList *bl; + float left; + int dir; }; static int vergxcobev(const void *a1, const void *a2) { - const struct BevelSort *x1 = a1, *x2 = a2; + const struct BevelSort *x1 = a1, *x2 = a2; - if (x1->left > x2->left) - return 1; - else if (x1->left < x2->left) - return -1; - return 0; + if (x1->left > x2->left) + return 1; + else if (x1->left < x2->left) + return -1; + return 0; } /* this function cannot be replaced with atan2, but why? */ -static void calc_bevel_sin_cos(float x1, float y1, float x2, float y2, - float *r_sina, float *r_cosa) -{ - float t01, t02, x3, y3; - - t01 = sqrtf(x1 * x1 + y1 * y1); - t02 = sqrtf(x2 * x2 + y2 * y2); - if (t01 == 0.0f) - t01 = 1.0f; - if (t02 == 0.0f) - t02 = 1.0f; - - x1 /= t01; - y1 /= t01; - x2 /= t02; - y2 /= t02; - - t02 = x1 * x2 + y1 * y2; - if (fabsf(t02) >= 1.0f) - t02 = M_PI_2; - else - t02 = (saacos(t02)) / 2.0f; - - t02 = sinf(t02); - if (t02 == 0.0f) - t02 = 1.0f; - - x3 = x1 - x2; - y3 = y1 - y2; - if (x3 == 0 && y3 == 0) { - x3 = y1; - y3 = -x1; - } - else { - t01 = sqrtf(x3 * x3 + y3 * y3); - x3 /= t01; - y3 /= t01; - } - - *r_sina = -y3 / t02; - *r_cosa = x3 / t02; - -} - -static void tilt_bezpart( - BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *tilt_array, float *radius_array, - float *weight_array, int resolu, int stride) -{ - BezTriple *pprev, *next, *last; - float fac, dfac, t[4]; - int a; - - if (tilt_array == NULL && radius_array == NULL) - return; - - last = nu->bezt + (nu->pntsu - 1); - - /* returns a point */ - if (prevbezt == nu->bezt) { - if (nu->flagu & CU_NURB_CYCLIC) - pprev = last; - else - pprev = prevbezt; - } - else - pprev = prevbezt - 1; - - /* next point */ - if (bezt == last) { - if (nu->flagu & CU_NURB_CYCLIC) - next = nu->bezt; - else - next = bezt; - } - else - next = bezt + 1; - - fac = 0.0; - dfac = 1.0f / (float)resolu; - - for (a = 0; a < resolu; a++, fac += dfac) { - if (tilt_array) { - if (nu->tilt_interp == KEY_CU_EASE) { /* May as well support for tilt also 2.47 ease interp */ - *tilt_array = prevbezt->tilt + - (bezt->tilt - prevbezt->tilt) * (3.0f * fac * fac - 2.0f * fac * fac * fac); - } - else { - key_curve_position_weights(fac, t, nu->tilt_interp); - *tilt_array = t[0] * pprev->tilt + t[1] * prevbezt->tilt + t[2] * bezt->tilt + t[3] * next->tilt; - } - - tilt_array = POINTER_OFFSET(tilt_array, stride); - } - - if (radius_array) { - if (nu->radius_interp == KEY_CU_EASE) { - /* Support 2.47 ease interp - * Note! - this only takes the 2 points into account, - * giving much more localized results to changes in radius, sometimes you want that */ - *radius_array = prevbezt->radius + - (bezt->radius - prevbezt->radius) * (3.0f * fac * fac - 2.0f * fac * fac * fac); - } - else { - - /* reuse interpolation from tilt if we can */ - if (tilt_array == NULL || nu->tilt_interp != nu->radius_interp) { - key_curve_position_weights(fac, t, nu->radius_interp); - } - *radius_array = - t[0] * pprev->radius + t[1] * prevbezt->radius + - t[2] * bezt->radius + t[3] * next->radius; - } - - radius_array = POINTER_OFFSET(radius_array, stride); - } - - if (weight_array) { - /* basic interpolation for now, could copy tilt interp too */ - *weight_array = - prevbezt->weight + - (bezt->weight - prevbezt->weight) * (3.0f * fac * fac - 2.0f * fac * fac * fac); - - weight_array = POINTER_OFFSET(weight_array, stride); - } - } +static void calc_bevel_sin_cos( + float x1, float y1, float x2, float y2, float *r_sina, float *r_cosa) +{ + float t01, t02, x3, y3; + + t01 = sqrtf(x1 * x1 + y1 * y1); + t02 = sqrtf(x2 * x2 + y2 * y2); + if (t01 == 0.0f) + t01 = 1.0f; + if (t02 == 0.0f) + t02 = 1.0f; + + x1 /= t01; + y1 /= t01; + x2 /= t02; + y2 /= t02; + + t02 = x1 * x2 + y1 * y2; + if (fabsf(t02) >= 1.0f) + t02 = M_PI_2; + else + t02 = (saacos(t02)) / 2.0f; + + t02 = sinf(t02); + if (t02 == 0.0f) + t02 = 1.0f; + + x3 = x1 - x2; + y3 = y1 - y2; + if (x3 == 0 && y3 == 0) { + x3 = y1; + y3 = -x1; + } + else { + t01 = sqrtf(x3 * x3 + y3 * y3); + x3 /= t01; + y3 /= t01; + } + + *r_sina = -y3 / t02; + *r_cosa = x3 / t02; +} + +static void tilt_bezpart(BezTriple *prevbezt, + BezTriple *bezt, + Nurb *nu, + float *tilt_array, + float *radius_array, + float *weight_array, + int resolu, + int stride) +{ + BezTriple *pprev, *next, *last; + float fac, dfac, t[4]; + int a; + + if (tilt_array == NULL && radius_array == NULL) + return; + + last = nu->bezt + (nu->pntsu - 1); + + /* returns a point */ + if (prevbezt == nu->bezt) { + if (nu->flagu & CU_NURB_CYCLIC) + pprev = last; + else + pprev = prevbezt; + } + else + pprev = prevbezt - 1; + + /* next point */ + if (bezt == last) { + if (nu->flagu & CU_NURB_CYCLIC) + next = nu->bezt; + else + next = bezt; + } + else + next = bezt + 1; + + fac = 0.0; + dfac = 1.0f / (float)resolu; + + for (a = 0; a < resolu; a++, fac += dfac) { + if (tilt_array) { + if (nu->tilt_interp == + KEY_CU_EASE) { /* May as well support for tilt also 2.47 ease interp */ + *tilt_array = prevbezt->tilt + + (bezt->tilt - prevbezt->tilt) * (3.0f * fac * fac - 2.0f * fac * fac * fac); + } + else { + key_curve_position_weights(fac, t, nu->tilt_interp); + *tilt_array = t[0] * pprev->tilt + t[1] * prevbezt->tilt + t[2] * bezt->tilt + + t[3] * next->tilt; + } + + tilt_array = POINTER_OFFSET(tilt_array, stride); + } + + if (radius_array) { + if (nu->radius_interp == KEY_CU_EASE) { + /* Support 2.47 ease interp + * Note! - this only takes the 2 points into account, + * giving much more localized results to changes in radius, sometimes you want that */ + *radius_array = prevbezt->radius + (bezt->radius - prevbezt->radius) * + (3.0f * fac * fac - 2.0f * fac * fac * fac); + } + else { + + /* reuse interpolation from tilt if we can */ + if (tilt_array == NULL || nu->tilt_interp != nu->radius_interp) { + key_curve_position_weights(fac, t, nu->radius_interp); + } + *radius_array = t[0] * pprev->radius + t[1] * prevbezt->radius + t[2] * bezt->radius + + t[3] * next->radius; + } + + radius_array = POINTER_OFFSET(radius_array, stride); + } + + if (weight_array) { + /* basic interpolation for now, could copy tilt interp too */ + *weight_array = prevbezt->weight + (bezt->weight - prevbezt->weight) * + (3.0f * fac * fac - 2.0f * fac * fac * fac); + + weight_array = POINTER_OFFSET(weight_array, stride); + } + } } /* make_bevel_list_3D_* funcs, at a minimum these must @@ -2279,1228 +2335,1248 @@ static void tilt_bezpart( /* utility for make_bevel_list_3D_* funcs */ static void bevel_list_calc_bisect(BevList *bl) { - BevPoint *bevp2, *bevp1, *bevp0; - int nr; - bool is_cyclic = bl->poly != -1; - - if (is_cyclic) { - bevp2 = bl->bevpoints; - bevp1 = bevp2 + (bl->nr - 1); - bevp0 = bevp1 - 1; - nr = bl->nr; - } - else { - /* If spline is not cyclic, direction of first and - * last bevel points matches direction of CV handle. - * - * This is getting calculated earlier when we know - * CV's handles and here we might simply skip evaluation - * of direction for this guys. - */ - - bevp0 = bl->bevpoints; - bevp1 = bevp0 + 1; - bevp2 = bevp1 + 1; - - nr = bl->nr - 2; - } - - while (nr--) { - /* totally simple */ - bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec); - - bevp0 = bevp1; - bevp1 = bevp2; - bevp2++; - } + BevPoint *bevp2, *bevp1, *bevp0; + int nr; + bool is_cyclic = bl->poly != -1; + + if (is_cyclic) { + bevp2 = bl->bevpoints; + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; + nr = bl->nr; + } + else { + /* If spline is not cyclic, direction of first and + * last bevel points matches direction of CV handle. + * + * This is getting calculated earlier when we know + * CV's handles and here we might simply skip evaluation + * of direction for this guys. + */ + + bevp0 = bl->bevpoints; + bevp1 = bevp0 + 1; + bevp2 = bevp1 + 1; + + nr = bl->nr - 2; + } + + while (nr--) { + /* totally simple */ + bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec); + + bevp0 = bevp1; + bevp1 = bevp2; + bevp2++; + } } static void bevel_list_flip_tangents(BevList *bl) { - BevPoint *bevp2, *bevp1, *bevp0; - int nr; + BevPoint *bevp2, *bevp1, *bevp0; + int nr; - bevp2 = bl->bevpoints; - bevp1 = bevp2 + (bl->nr - 1); - bevp0 = bevp1 - 1; + bevp2 = bl->bevpoints; + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; - nr = bl->nr; - while (nr--) { - if (angle_normalized_v3v3(bevp0->tan, bevp1->tan) > DEG2RADF(90.0f)) - negate_v3(bevp1->tan); + nr = bl->nr; + while (nr--) { + if (angle_normalized_v3v3(bevp0->tan, bevp1->tan) > DEG2RADF(90.0f)) + negate_v3(bevp1->tan); - bevp0 = bevp1; - bevp1 = bevp2; - bevp2++; - } + bevp0 = bevp1; + bevp1 = bevp2; + bevp2++; + } } /* apply user tilt */ static void bevel_list_apply_tilt(BevList *bl) { - BevPoint *bevp2, *bevp1; - int nr; - float q[4]; + BevPoint *bevp2, *bevp1; + int nr; + float q[4]; - bevp2 = bl->bevpoints; - bevp1 = bevp2 + (bl->nr - 1); + bevp2 = bl->bevpoints; + bevp1 = bevp2 + (bl->nr - 1); - nr = bl->nr; - while (nr--) { - axis_angle_to_quat(q, bevp1->dir, bevp1->tilt); - mul_qt_qtqt(bevp1->quat, q, bevp1->quat); - normalize_qt(bevp1->quat); + nr = bl->nr; + while (nr--) { + axis_angle_to_quat(q, bevp1->dir, bevp1->tilt); + mul_qt_qtqt(bevp1->quat, q, bevp1->quat); + normalize_qt(bevp1->quat); - bevp1 = bevp2; - bevp2++; - } + bevp1 = bevp2; + bevp2++; + } } /* smooth quats, this function should be optimized, it can get slow with many iterations. */ static void bevel_list_smooth(BevList *bl, int smooth_iter) { - BevPoint *bevp2, *bevp1, *bevp0; - int nr; + BevPoint *bevp2, *bevp1, *bevp0; + int nr; - float q[4]; - float bevp0_quat[4]; - int a; + float q[4]; + float bevp0_quat[4]; + int a; - for (a = 0; a < smooth_iter; a++) { - bevp2 = bl->bevpoints; - bevp1 = bevp2 + (bl->nr - 1); - bevp0 = bevp1 - 1; + for (a = 0; a < smooth_iter; a++) { + bevp2 = bl->bevpoints; + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; - nr = bl->nr; + nr = bl->nr; - if (bl->poly == -1) { /* check its not cyclic */ - /* skip the first point */ - /* bevp0 = bevp1; */ - bevp1 = bevp2; - bevp2++; - nr--; + if (bl->poly == -1) { /* check its not cyclic */ + /* skip the first point */ + /* bevp0 = bevp1; */ + bevp1 = bevp2; + bevp2++; + nr--; - bevp0 = bevp1; - bevp1 = bevp2; - bevp2++; - nr--; - } + bevp0 = bevp1; + bevp1 = bevp2; + bevp2++; + nr--; + } - copy_qt_qt(bevp0_quat, bevp0->quat); + copy_qt_qt(bevp0_quat, bevp0->quat); - while (nr--) { - /* interpolate quats */ - float zaxis[3] = {0, 0, 1}, cross[3], q2[4]; - interp_qt_qtqt(q, bevp0_quat, bevp2->quat, 0.5); - normalize_qt(q); + while (nr--) { + /* interpolate quats */ + float zaxis[3] = {0, 0, 1}, cross[3], q2[4]; + interp_qt_qtqt(q, bevp0_quat, bevp2->quat, 0.5); + normalize_qt(q); - mul_qt_v3(q, zaxis); - cross_v3_v3v3(cross, zaxis, bevp1->dir); - axis_angle_to_quat(q2, cross, angle_normalized_v3v3(zaxis, bevp1->dir)); - normalize_qt(q2); + mul_qt_v3(q, zaxis); + cross_v3_v3v3(cross, zaxis, bevp1->dir); + axis_angle_to_quat(q2, cross, angle_normalized_v3v3(zaxis, bevp1->dir)); + normalize_qt(q2); - copy_qt_qt(bevp0_quat, bevp1->quat); - mul_qt_qtqt(q, q2, q); - interp_qt_qtqt(bevp1->quat, bevp1->quat, q, 0.5); - normalize_qt(bevp1->quat); + copy_qt_qt(bevp0_quat, bevp1->quat); + mul_qt_qtqt(q, q2, q); + interp_qt_qtqt(bevp1->quat, bevp1->quat, q, 0.5); + normalize_qt(bevp1->quat); - /* bevp0 = bevp1; */ /* UNUSED */ - bevp1 = bevp2; - bevp2++; - } - } + /* bevp0 = bevp1; */ /* UNUSED */ + bevp1 = bevp2; + bevp2++; + } + } } static void make_bevel_list_3D_zup(BevList *bl) { - BevPoint *bevp = bl->bevpoints; - int nr = bl->nr; + BevPoint *bevp = bl->bevpoints; + int nr = bl->nr; - bevel_list_calc_bisect(bl); + bevel_list_calc_bisect(bl); - while (nr--) { - vec_to_quat(bevp->quat, bevp->dir, 5, 1); - bevp++; - } + while (nr--) { + vec_to_quat(bevp->quat, bevp->dir, 5, 1); + bevp++; + } } static void minimum_twist_between_two_points(BevPoint *current_point, BevPoint *previous_point) { - float angle = angle_normalized_v3v3(previous_point->dir, current_point->dir); - float q[4]; + float angle = angle_normalized_v3v3(previous_point->dir, current_point->dir); + float q[4]; - if (angle > 0.0f) { /* otherwise we can keep as is */ - float cross_tmp[3]; - cross_v3_v3v3(cross_tmp, previous_point->dir, current_point->dir); - axis_angle_to_quat(q, cross_tmp, angle); - mul_qt_qtqt(current_point->quat, q, previous_point->quat); - } - else { - copy_qt_qt(current_point->quat, previous_point->quat); - } + if (angle > 0.0f) { /* otherwise we can keep as is */ + float cross_tmp[3]; + cross_v3_v3v3(cross_tmp, previous_point->dir, current_point->dir); + axis_angle_to_quat(q, cross_tmp, angle); + mul_qt_qtqt(current_point->quat, q, previous_point->quat); + } + else { + copy_qt_qt(current_point->quat, previous_point->quat); + } } static void make_bevel_list_3D_minimum_twist(BevList *bl) { - BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */ - int nr; - float q[4]; - - bevel_list_calc_bisect(bl); - - bevp2 = bl->bevpoints; - bevp1 = bevp2 + (bl->nr - 1); - bevp0 = bevp1 - 1; - - nr = bl->nr; - while (nr--) { - - if (nr + 4 > bl->nr) { /* first time and second time, otherwise first point adjusts last */ - vec_to_quat(bevp1->quat, bevp1->dir, 5, 1); - } - else { - minimum_twist_between_two_points(bevp1, bevp0); - } - - bevp0 = bevp1; - bevp1 = bevp2; - bevp2++; - } - - if (bl->poly != -1) { /* check for cyclic */ - - /* Need to correct for the start/end points not matching - * do this by calculating the tilt angle difference, then apply - * the rotation gradually over the entire curve - * - * note that the split is between last and second last, rather than first/last as youd expect. - * - * real order is like this - * 0,1,2,3,4 --> 1,2,3,4,0 - * - * this is why we compare last with second last - * */ - float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3]; - - BevPoint *bevp_first; - BevPoint *bevp_last; - - - bevp_first = bl->bevpoints; - bevp_first += bl->nr - 1; - bevp_last = bevp_first; - bevp_last--; - - /* quats and vec's are normalized, should not need to re-normalize */ - mul_qt_v3(bevp_first->quat, vec_1); - mul_qt_v3(bevp_last->quat, vec_2); - normalize_v3(vec_1); - normalize_v3(vec_2); - - /* align the vector, can avoid this and it looks 98% OK but - * better to align the angle quat roll's before comparing */ - { - cross_v3_v3v3(cross_tmp, bevp_last->dir, bevp_first->dir); - angle = angle_normalized_v3v3(bevp_first->dir, bevp_last->dir); - axis_angle_to_quat(q, cross_tmp, angle); - mul_qt_v3(q, vec_2); - } - - angle = angle_normalized_v3v3(vec_1, vec_2); - - /* flip rotation if needs be */ - cross_v3_v3v3(cross_tmp, vec_1, vec_2); - normalize_v3(cross_tmp); - if (angle_normalized_v3v3(bevp_first->dir, cross_tmp) < DEG2RADF(90.0f)) - angle = -angle; - - bevp2 = bl->bevpoints; - bevp1 = bevp2 + (bl->nr - 1); - bevp0 = bevp1 - 1; - - nr = bl->nr; - while (nr--) { - ang_fac = angle * (1.0f - ((float)nr / bl->nr)); /* also works */ - - axis_angle_to_quat(q, bevp1->dir, ang_fac); - mul_qt_qtqt(bevp1->quat, q, bevp1->quat); - - bevp0 = bevp1; - bevp1 = bevp2; - bevp2++; - } - } - else { - /* Need to correct quat for the first/last point, - * this is so because previously it was only calculated - * using it's own direction, which might not correspond - * the twist of neighbor point. - */ - bevp1 = bl->bevpoints; - bevp0 = bevp1 + 1; - minimum_twist_between_two_points(bevp1, bevp0); - - bevp2 = bl->bevpoints; - bevp1 = bevp2 + (bl->nr - 1); - bevp0 = bevp1 - 1; - minimum_twist_between_two_points(bevp1, bevp0); - } + BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */ + int nr; + float q[4]; + + bevel_list_calc_bisect(bl); + + bevp2 = bl->bevpoints; + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; + + nr = bl->nr; + while (nr--) { + + if (nr + 4 > bl->nr) { /* first time and second time, otherwise first point adjusts last */ + vec_to_quat(bevp1->quat, bevp1->dir, 5, 1); + } + else { + minimum_twist_between_two_points(bevp1, bevp0); + } + + bevp0 = bevp1; + bevp1 = bevp2; + bevp2++; + } + + if (bl->poly != -1) { /* check for cyclic */ + + /* Need to correct for the start/end points not matching + * do this by calculating the tilt angle difference, then apply + * the rotation gradually over the entire curve + * + * note that the split is between last and second last, rather than first/last as youd expect. + * + * real order is like this + * 0,1,2,3,4 --> 1,2,3,4,0 + * + * this is why we compare last with second last + * */ + float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3]; + + BevPoint *bevp_first; + BevPoint *bevp_last; + + bevp_first = bl->bevpoints; + bevp_first += bl->nr - 1; + bevp_last = bevp_first; + bevp_last--; + + /* quats and vec's are normalized, should not need to re-normalize */ + mul_qt_v3(bevp_first->quat, vec_1); + mul_qt_v3(bevp_last->quat, vec_2); + normalize_v3(vec_1); + normalize_v3(vec_2); + + /* align the vector, can avoid this and it looks 98% OK but + * better to align the angle quat roll's before comparing */ + { + cross_v3_v3v3(cross_tmp, bevp_last->dir, bevp_first->dir); + angle = angle_normalized_v3v3(bevp_first->dir, bevp_last->dir); + axis_angle_to_quat(q, cross_tmp, angle); + mul_qt_v3(q, vec_2); + } + + angle = angle_normalized_v3v3(vec_1, vec_2); + + /* flip rotation if needs be */ + cross_v3_v3v3(cross_tmp, vec_1, vec_2); + normalize_v3(cross_tmp); + if (angle_normalized_v3v3(bevp_first->dir, cross_tmp) < DEG2RADF(90.0f)) + angle = -angle; + + bevp2 = bl->bevpoints; + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; + + nr = bl->nr; + while (nr--) { + ang_fac = angle * (1.0f - ((float)nr / bl->nr)); /* also works */ + + axis_angle_to_quat(q, bevp1->dir, ang_fac); + mul_qt_qtqt(bevp1->quat, q, bevp1->quat); + + bevp0 = bevp1; + bevp1 = bevp2; + bevp2++; + } + } + else { + /* Need to correct quat for the first/last point, + * this is so because previously it was only calculated + * using it's own direction, which might not correspond + * the twist of neighbor point. + */ + bevp1 = bl->bevpoints; + bevp0 = bevp1 + 1; + minimum_twist_between_two_points(bevp1, bevp0); + + bevp2 = bl->bevpoints; + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; + minimum_twist_between_two_points(bevp1, bevp0); + } } static void make_bevel_list_3D_tangent(BevList *bl) { - BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */ - int nr; + BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */ + int nr; - float bevp0_tan[3]; + float bevp0_tan[3]; - bevel_list_calc_bisect(bl); - bevel_list_flip_tangents(bl); + bevel_list_calc_bisect(bl); + bevel_list_flip_tangents(bl); - /* correct the tangents */ - bevp2 = bl->bevpoints; - bevp1 = bevp2 + (bl->nr - 1); - bevp0 = bevp1 - 1; + /* correct the tangents */ + bevp2 = bl->bevpoints; + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; - nr = bl->nr; - while (nr--) { - float cross_tmp[3]; - cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir); - cross_v3_v3v3(bevp1->tan, cross_tmp, bevp1->dir); - normalize_v3(bevp1->tan); + nr = bl->nr; + while (nr--) { + float cross_tmp[3]; + cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir); + cross_v3_v3v3(bevp1->tan, cross_tmp, bevp1->dir); + normalize_v3(bevp1->tan); - bevp0 = bevp1; - bevp1 = bevp2; - bevp2++; - } + bevp0 = bevp1; + bevp1 = bevp2; + bevp2++; + } + /* now for the real twist calc */ + bevp2 = bl->bevpoints; + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; - /* now for the real twist calc */ - bevp2 = bl->bevpoints; - bevp1 = bevp2 + (bl->nr - 1); - bevp0 = bevp1 - 1; + copy_v3_v3(bevp0_tan, bevp0->tan); - copy_v3_v3(bevp0_tan, bevp0->tan); + nr = bl->nr; + while (nr--) { + /* make perpendicular, modify tan in place, is ok */ + float cross_tmp[3]; + float zero[3] = {0, 0, 0}; - nr = bl->nr; - while (nr--) { - /* make perpendicular, modify tan in place, is ok */ - float cross_tmp[3]; - float zero[3] = {0, 0, 0}; + cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir); + normalize_v3(cross_tmp); + tri_to_quat(bevp1->quat, zero, cross_tmp, bevp1->tan); /* XXX - could be faster */ - cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir); - normalize_v3(cross_tmp); - tri_to_quat(bevp1->quat, zero, cross_tmp, bevp1->tan); /* XXX - could be faster */ - - /* bevp0 = bevp1; */ /* UNUSED */ - bevp1 = bevp2; - bevp2++; - } + /* bevp0 = bevp1; */ /* UNUSED */ + bevp1 = bevp2; + bevp2++; + } } static void make_bevel_list_3D(BevList *bl, int smooth_iter, int twist_mode) { - switch (twist_mode) { - case CU_TWIST_TANGENT: - make_bevel_list_3D_tangent(bl); - break; - case CU_TWIST_MINIMUM: - make_bevel_list_3D_minimum_twist(bl); - break; - default: /* CU_TWIST_Z_UP default, pre 2.49c */ - make_bevel_list_3D_zup(bl); - break; - } + switch (twist_mode) { + case CU_TWIST_TANGENT: + make_bevel_list_3D_tangent(bl); + break; + case CU_TWIST_MINIMUM: + make_bevel_list_3D_minimum_twist(bl); + break; + default: /* CU_TWIST_Z_UP default, pre 2.49c */ + make_bevel_list_3D_zup(bl); + break; + } - if (smooth_iter) - bevel_list_smooth(bl, smooth_iter); + if (smooth_iter) + bevel_list_smooth(bl, smooth_iter); - bevel_list_apply_tilt(bl); + bevel_list_apply_tilt(bl); } /* only for 2 points */ static void make_bevel_list_segment_3D(BevList *bl) { - float q[4]; + float q[4]; - BevPoint *bevp2 = bl->bevpoints; - BevPoint *bevp1 = bevp2 + 1; + BevPoint *bevp2 = bl->bevpoints; + BevPoint *bevp1 = bevp2 + 1; - /* simple quat/dir */ - sub_v3_v3v3(bevp1->dir, bevp1->vec, bevp2->vec); - normalize_v3(bevp1->dir); + /* simple quat/dir */ + sub_v3_v3v3(bevp1->dir, bevp1->vec, bevp2->vec); + normalize_v3(bevp1->dir); - vec_to_quat(bevp1->quat, bevp1->dir, 5, 1); + vec_to_quat(bevp1->quat, bevp1->dir, 5, 1); - axis_angle_to_quat(q, bevp1->dir, bevp1->tilt); - mul_qt_qtqt(bevp1->quat, q, bevp1->quat); - normalize_qt(bevp1->quat); - copy_v3_v3(bevp2->dir, bevp1->dir); - copy_qt_qt(bevp2->quat, bevp1->quat); + axis_angle_to_quat(q, bevp1->dir, bevp1->tilt); + mul_qt_qtqt(bevp1->quat, q, bevp1->quat); + normalize_qt(bevp1->quat); + copy_v3_v3(bevp2->dir, bevp1->dir); + copy_qt_qt(bevp2->quat, bevp1->quat); } /* only for 2 points */ static void make_bevel_list_segment_2D(BevList *bl) { - BevPoint *bevp2 = bl->bevpoints; - BevPoint *bevp1 = bevp2 + 1; + BevPoint *bevp2 = bl->bevpoints; + BevPoint *bevp1 = bevp2 + 1; - const float x1 = bevp1->vec[0] - bevp2->vec[0]; - const float y1 = bevp1->vec[1] - bevp2->vec[1]; + const float x1 = bevp1->vec[0] - bevp2->vec[0]; + const float y1 = bevp1->vec[1] - bevp2->vec[1]; - calc_bevel_sin_cos(x1, y1, -x1, -y1, &(bevp1->sina), &(bevp1->cosa)); - bevp2->sina = bevp1->sina; - bevp2->cosa = bevp1->cosa; + calc_bevel_sin_cos(x1, y1, -x1, -y1, &(bevp1->sina), &(bevp1->cosa)); + bevp2->sina = bevp1->sina; + bevp2->cosa = bevp1->cosa; - /* fill in dir & quat */ - make_bevel_list_segment_3D(bl); + /* fill in dir & quat */ + make_bevel_list_segment_3D(bl); } static void make_bevel_list_2D(BevList *bl) { - /* note: bevp->dir and bevp->quat are not needed for beveling but are - * used when making a path from a 2D curve, therefore they need to be set - Campbell */ - - BevPoint *bevp0, *bevp1, *bevp2; - int nr; - - if (bl->poly != -1) { - bevp2 = bl->bevpoints; - bevp1 = bevp2 + (bl->nr - 1); - bevp0 = bevp1 - 1; - nr = bl->nr; - } - else { - bevp0 = bl->bevpoints; - bevp1 = bevp0 + 1; - bevp2 = bevp1 + 1; - - nr = bl->nr - 2; - } - - while (nr--) { - const float x1 = bevp1->vec[0] - bevp0->vec[0]; - const float x2 = bevp1->vec[0] - bevp2->vec[0]; - const float y1 = bevp1->vec[1] - bevp0->vec[1]; - const float y2 = bevp1->vec[1] - bevp2->vec[1]; - - calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa)); - - /* from: make_bevel_list_3D_zup, could call but avoid a second loop. - * no need for tricky tilt calculation as with 3D curves */ - bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec); - vec_to_quat(bevp1->quat, bevp1->dir, 5, 1); - /* done with inline make_bevel_list_3D_zup */ - - bevp0 = bevp1; - bevp1 = bevp2; - bevp2++; - } - - /* correct non-cyclic cases */ - if (bl->poly == -1) { - BevPoint *bevp; - float angle; - - /* first */ - bevp = bl->bevpoints; - angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2; - bevp->sina = sinf(angle); - bevp->cosa = cosf(angle); - vec_to_quat(bevp->quat, bevp->dir, 5, 1); - - /* last */ - bevp = bl->bevpoints; - bevp += (bl->nr - 1); - angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2; - bevp->sina = sinf(angle); - bevp->cosa = cosf(angle); - vec_to_quat(bevp->quat, bevp->dir, 5, 1); - } + /* note: bevp->dir and bevp->quat are not needed for beveling but are + * used when making a path from a 2D curve, therefore they need to be set - Campbell */ + + BevPoint *bevp0, *bevp1, *bevp2; + int nr; + + if (bl->poly != -1) { + bevp2 = bl->bevpoints; + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; + nr = bl->nr; + } + else { + bevp0 = bl->bevpoints; + bevp1 = bevp0 + 1; + bevp2 = bevp1 + 1; + + nr = bl->nr - 2; + } + + while (nr--) { + const float x1 = bevp1->vec[0] - bevp0->vec[0]; + const float x2 = bevp1->vec[0] - bevp2->vec[0]; + const float y1 = bevp1->vec[1] - bevp0->vec[1]; + const float y2 = bevp1->vec[1] - bevp2->vec[1]; + + calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa)); + + /* from: make_bevel_list_3D_zup, could call but avoid a second loop. + * no need for tricky tilt calculation as with 3D curves */ + bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec); + vec_to_quat(bevp1->quat, bevp1->dir, 5, 1); + /* done with inline make_bevel_list_3D_zup */ + + bevp0 = bevp1; + bevp1 = bevp2; + bevp2++; + } + + /* correct non-cyclic cases */ + if (bl->poly == -1) { + BevPoint *bevp; + float angle; + + /* first */ + bevp = bl->bevpoints; + angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2; + bevp->sina = sinf(angle); + bevp->cosa = cosf(angle); + vec_to_quat(bevp->quat, bevp->dir, 5, 1); + + /* last */ + bevp = bl->bevpoints; + bevp += (bl->nr - 1); + angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2; + bevp->sina = sinf(angle); + bevp->cosa = cosf(angle); + vec_to_quat(bevp->quat, bevp->dir, 5, 1); + } } static void bevlist_firstlast_direction_calc_from_bpoint(Nurb *nu, BevList *bl) { - if (nu->pntsu > 1) { - BPoint *first_bp = nu->bp, *last_bp = nu->bp + (nu->pntsu - 1); - BevPoint *first_bevp, *last_bevp; + if (nu->pntsu > 1) { + BPoint *first_bp = nu->bp, *last_bp = nu->bp + (nu->pntsu - 1); + BevPoint *first_bevp, *last_bevp; - first_bevp = bl->bevpoints; - last_bevp = first_bevp + (bl->nr - 1); + first_bevp = bl->bevpoints; + last_bevp = first_bevp + (bl->nr - 1); - sub_v3_v3v3(first_bevp->dir, (first_bp + 1)->vec, first_bp->vec); - normalize_v3(first_bevp->dir); + sub_v3_v3v3(first_bevp->dir, (first_bp + 1)->vec, first_bp->vec); + normalize_v3(first_bevp->dir); - sub_v3_v3v3(last_bevp->dir, last_bp->vec, (last_bp - 1)->vec); - normalize_v3(last_bevp->dir); - } + sub_v3_v3v3(last_bevp->dir, last_bp->vec, (last_bp - 1)->vec); + normalize_v3(last_bevp->dir); + } } 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); - } - if (bl->bevpoints != NULL) { - MEM_freeN(bl->bevpoints); - } - MEM_freeN(bl); - } + 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); + } + if (bl->bevpoints != NULL) { + MEM_freeN(bl->bevpoints); + } + MEM_freeN(bl); + } - BLI_listbase_clear(bev); + BLI_listbase_clear(bev); } void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) { - /* - * - convert all curves to polys, with indication of resol and flags for double-vertices - * - possibly; do a smart vertice removal (in case Nurb) - * - separate in individual blocks with BoundBox - * - AutoHole detection - */ - - /* 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 *bevp2, *bevp1 = NULL, *bevp0; - const float treshold = 0.00001f; - float min, inp; - float *seglen = NULL; - struct BevelSort *sortdata, *sd, *sd1; - 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; - - /* 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->runtime.curve_cache->bev; - - /* do we need to calculate the radius for each point? */ - /* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */ - - /* STEP 1: MAKE POLYS */ - - BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); - nu = nurbs->first; - if (cu->editnurb && ob->type != OB_FONT) { - is_editmode = 1; - } - - for (; nu; nu = nu->next) { - - if (nu->hide && is_editmode) - continue; - - /* check if we will calculate tilt data */ - do_tilt = CU_DO_TILT(cu, nu); - do_radius = CU_DO_RADIUS(cu, nu); /* normal display uses the radius, better just to calculate them */ - do_weight = true; - - /* check we are a single point? also check we are not a surface and that the orderu is sane, - * enforced in the UI but can go wrong possibly */ - if (!BKE_nurb_check_valid_u(nu)) { - bl = MEM_callocN(sizeof(BevList), "makeBevelList1"); - bl->bevpoints = MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1"); - BLI_addtail(bev, bl); - bl->nr = 0; - bl->charidx = nu->charidx; - } - else { - BevPoint *bevp; - - if (for_render && cu->resolu_ren != 0) - resolu = cu->resolu_ren; - else - resolu = nu->resolu; - - segcount = SEGMENTSU(nu); - - if (nu->type == CU_POLY) { - len = nu->pntsu; - bl = MEM_callocN(sizeof(BevList), "makeBevelList2"); - bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints2"); - if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { - bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList2_seglen"); - bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList2_segbevcount"); - } - BLI_addtail(bev, bl); - - bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; - bl->nr = len; - bl->dupe_nr = 0; - bl->charidx = nu->charidx; - bevp = bl->bevpoints; - bevp->offset = 0; - bp = nu->bp; - seglen = bl->seglen; - segbevcount = bl->segbevcount; - - while (len--) { - copy_v3_v3(bevp->vec, bp->vec); - bevp->tilt = bp->tilt; - bevp->radius = bp->radius; - bevp->weight = bp->weight; - bevp->split_tag = true; - bp++; - if (seglen != NULL && len != 0) { - *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); - } - } - else if (nu->type == CU_BEZIER) { - /* in case last point is not cyclic */ - len = segcount * resolu + 1; - - bl = MEM_callocN(sizeof(BevList), "makeBevelBPoints"); - bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelBPointsPoints"); - if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { - bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelBPoints_seglen"); - bl->segbevcount = MEM_malloc_arrayN(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; - if (nu->flagu & CU_NURB_CYCLIC) { - a++; - prevbezt = nu->bezt + (nu->pntsu - 1); - } - else { - prevbezt = bezt; - bezt++; - } - - 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) { - - copy_v3_v3(bevp->vec, prevbezt->vec[1]); - bevp->tilt = prevbezt->tilt; - bevp->radius = prevbezt->radius; - bevp->weight = prevbezt->weight; - bevp->split_tag = true; - bevp->dupe_tag = false; - 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 */ - int j; - - /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */ - for (j = 0; j < 3; j++) { - BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], prevbezt->vec[2][j], - bezt->vec[0][j], bezt->vec[1][j], - &(bevp->vec[j]), resolu, sizeof(BevPoint)); - } - - /* if both arrays are NULL do nothiong */ - tilt_bezpart(prevbezt, bezt, nu, - do_tilt ? &bevp->tilt : NULL, - do_radius ? &bevp->radius : NULL, - do_weight ? &bevp->weight : NULL, - resolu, sizeof(BevPoint)); - - - if (cu->twist_mode == CU_TWIST_TANGENT) { - forward_diff_bezier_cotangent(prevbezt->vec[1], prevbezt->vec[2], - bezt->vec[0], bezt->vec[1], - bevp->tan, resolu, sizeof(BevPoint)); - } - - /* indicate with handlecodes double points */ - if (prevbezt->h1 == prevbezt->h2) { - if (prevbezt->h1 == 0 || prevbezt->h1 == HD_VECT) - bevp->split_tag = true; - } - else { - if (prevbezt->h1 == 0 || prevbezt->h1 == HD_VECT) - bevp->split_tag = true; - 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; - } - prevbezt = bezt; - bezt++; - } - - if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic: endpoint */ - copy_v3_v3(bevp->vec, prevbezt->vec[1]); - bevp->tilt = prevbezt->tilt; - bevp->radius = prevbezt->radius; - bevp->weight = prevbezt->weight; - - sub_v3_v3v3(bevp->dir, prevbezt->vec[1], prevbezt->vec[0]); - normalize_v3(bevp->dir); - - bl->nr++; - } - } - else if (nu->type == CU_NURBS) { - if (nu->pntsv == 1) { - len = (resolu * segcount); - - bl = MEM_callocN(sizeof(BevList), "makeBevelList3"); - bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints3"); - if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { - bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList3_seglen"); - bl->segbevcount = MEM_malloc_arrayN(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->tilt : NULL, - do_radius ? &bevp->radius : NULL, - 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); - } - } - } - } - } - - /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */ - bl = bev->first; - while (bl) { - if (bl->nr) { /* null bevel items come from single points */ - bool is_cyclic = bl->poly != -1; - nr = bl->nr; - if (is_cyclic) { - bevp1 = bl->bevpoints; - bevp0 = bevp1 + (nr - 1); - } - else { - bevp0 = bl->bevpoints; - bevp0->offset = 0; - bevp1 = bevp0 + 1; - } - nr--; - while (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++; - } - } - } - } - bevp0 = bevp1; - bevp1++; - } - } - bl = bl->next; - } - bl = bev->first; - while (bl) { - blnext = bl->next; - if (bl->nr && bl->dupe_nr) { - nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */ - blnew = MEM_callocN(sizeof(BevList), "makeBevelList4"); - memcpy(blnew, bl, sizeof(BevList)); - blnew->bevpoints = MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4"); - if (!blnew->bevpoints) { - MEM_freeN(blnew); - break; - } - 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 */ - bevp0 = bl->bevpoints; - bevp1 = blnew->bevpoints; - nr = bl->nr; - while (nr--) { - if (bevp0->dupe_tag == 0) { - memcpy(bevp1, bevp0, sizeof(BevPoint)); - bevp1++; - blnew->nr++; - } - bevp0++; - } - if (bl->bevpoints != NULL) { - MEM_freeN(bl->bevpoints); - } - MEM_freeN(bl); - blnew->dupe_nr = 0; - } - bl = blnext; - } - - /* STEP 3: POLYS COUNT AND AUTOHOLE */ - bl = bev->first; - poly = 0; - while (bl) { - if (bl->nr && bl->poly >= 0) { - poly++; - bl->poly = poly; - bl->hole = 0; - } - bl = bl->next; - } - - /* find extreme left points, also test (turning) direction */ - if (poly > 0) { - sd = sortdata = MEM_malloc_arrayN(poly, sizeof(struct BevelSort), "makeBevelList5"); - bl = bev->first; - while (bl) { - if (bl->poly > 0) { - BevPoint *bevp; - - min = 300000.0; - bevp = bl->bevpoints; - nr = bl->nr; - while (nr--) { - if (min > bevp->vec[0]) { - min = bevp->vec[0]; - bevp1 = bevp; - } - bevp++; - } - sd->bl = bl; - sd->left = min; - - bevp = bl->bevpoints; - if (bevp1 == bevp) - bevp0 = bevp + (bl->nr - 1); - else - bevp0 = bevp1 - 1; - bevp = bevp + (bl->nr - 1); - if (bevp1 == bevp) - bevp2 = bl->bevpoints; - else - bevp2 = bevp1 + 1; - - inp = ((bevp1->vec[0] - bevp0->vec[0]) * (bevp0->vec[1] - bevp2->vec[1]) + - (bevp0->vec[1] - bevp1->vec[1]) * (bevp0->vec[0] - bevp2->vec[0])); - - if (inp > 0.0f) - sd->dir = 1; - else - sd->dir = 0; - - sd++; - } - - bl = bl->next; - } - qsort(sortdata, poly, sizeof(struct BevelSort), vergxcobev); - - sd = sortdata + 1; - for (a = 1; a < poly; a++, sd++) { - bl = sd->bl; /* is bl a hole? */ - sd1 = sortdata + (a - 1); - for (b = a - 1; b >= 0; b--, sd1--) { /* all polys to the left */ - if (sd1->bl->charidx == bl->charidx) { /* for text, only check matching char */ - if (bevelinside(sd1->bl, bl)) { - bl->hole = 1 - sd1->bl->hole; - break; - } - } - } - } - - /* turning direction */ - if ((cu->flag & CU_3D) == 0) { - sd = sortdata; - for (a = 0; a < poly; a++, sd++) { - if (sd->bl->hole == sd->dir) { - bl = sd->bl; - bevp1 = bl->bevpoints; - bevp2 = bevp1 + (bl->nr - 1); - nr = bl->nr / 2; - while (nr--) { - SWAP(BevPoint, *bevp1, *bevp2); - bevp1++; - bevp2--; - } - } - } - } - MEM_freeN(sortdata); - } - - /* STEP 4: 2D-COSINES or 3D ORIENTATION */ - if ((cu->flag & CU_3D) == 0) { - /* 2D Curves */ - for (bl = bev->first; bl; bl = bl->next) { - if (bl->nr < 2) { - BevPoint *bevp = bl->bevpoints; - unit_qt(bevp->quat); - } - else if (bl->nr == 2) { /* 2 pnt, treat separate */ - make_bevel_list_segment_2D(bl); - } - else { - make_bevel_list_2D(bl); - } - } - } - else { - /* 3D Curves */ - for (bl = bev->first; bl; bl = bl->next) { - if (bl->nr < 2) { - BevPoint *bevp = bl->bevpoints; - unit_qt(bevp->quat); - } - else if (bl->nr == 2) { /* 2 pnt, treat separate */ - make_bevel_list_segment_3D(bl); - } - else { - make_bevel_list_3D(bl, (int)(resolu * cu->twist_smooth), cu->twist_mode); - } - } - } + /* + * - convert all curves to polys, with indication of resol and flags for double-vertices + * - possibly; do a smart vertice removal (in case Nurb) + * - separate in individual blocks with BoundBox + * - AutoHole detection + */ + + /* 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 *bevp2, *bevp1 = NULL, *bevp0; + const float treshold = 0.00001f; + float min, inp; + float *seglen = NULL; + struct BevelSort *sortdata, *sd, *sd1; + 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; + + /* 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->runtime.curve_cache->bev; + + /* do we need to calculate the radius for each point? */ + /* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */ + + /* STEP 1: MAKE POLYS */ + + BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); + nu = nurbs->first; + if (cu->editnurb && ob->type != OB_FONT) { + is_editmode = 1; + } + + for (; nu; nu = nu->next) { + + if (nu->hide && is_editmode) + continue; + + /* check if we will calculate tilt data */ + do_tilt = CU_DO_TILT(cu, nu); + do_radius = CU_DO_RADIUS( + cu, nu); /* normal display uses the radius, better just to calculate them */ + do_weight = true; + + /* check we are a single point? also check we are not a surface and that the orderu is sane, + * enforced in the UI but can go wrong possibly */ + if (!BKE_nurb_check_valid_u(nu)) { + bl = MEM_callocN(sizeof(BevList), "makeBevelList1"); + bl->bevpoints = MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1"); + BLI_addtail(bev, bl); + bl->nr = 0; + bl->charidx = nu->charidx; + } + else { + BevPoint *bevp; + + if (for_render && cu->resolu_ren != 0) + resolu = cu->resolu_ren; + else + resolu = nu->resolu; + + segcount = SEGMENTSU(nu); + + if (nu->type == CU_POLY) { + len = nu->pntsu; + bl = MEM_callocN(sizeof(BevList), "makeBevelList2"); + bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints2"); + if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { + bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList2_seglen"); + bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList2_segbevcount"); + } + BLI_addtail(bev, bl); + + bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; + bl->nr = len; + bl->dupe_nr = 0; + bl->charidx = nu->charidx; + bevp = bl->bevpoints; + bevp->offset = 0; + bp = nu->bp; + seglen = bl->seglen; + segbevcount = bl->segbevcount; + + while (len--) { + copy_v3_v3(bevp->vec, bp->vec); + bevp->tilt = bp->tilt; + bevp->radius = bp->radius; + bevp->weight = bp->weight; + bevp->split_tag = true; + bp++; + if (seglen != NULL && len != 0) { + *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); + } + } + else if (nu->type == CU_BEZIER) { + /* in case last point is not cyclic */ + len = segcount * resolu + 1; + + bl = MEM_callocN(sizeof(BevList), "makeBevelBPoints"); + bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelBPointsPoints"); + if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { + bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelBPoints_seglen"); + bl->segbevcount = MEM_malloc_arrayN( + 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; + if (nu->flagu & CU_NURB_CYCLIC) { + a++; + prevbezt = nu->bezt + (nu->pntsu - 1); + } + else { + prevbezt = bezt; + bezt++; + } + + 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) { + + copy_v3_v3(bevp->vec, prevbezt->vec[1]); + bevp->tilt = prevbezt->tilt; + bevp->radius = prevbezt->radius; + bevp->weight = prevbezt->weight; + bevp->split_tag = true; + bevp->dupe_tag = false; + 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 */ + int j; + + /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */ + for (j = 0; j < 3; j++) { + BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], + prevbezt->vec[2][j], + bezt->vec[0][j], + bezt->vec[1][j], + &(bevp->vec[j]), + resolu, + sizeof(BevPoint)); + } + + /* if both arrays are NULL do nothiong */ + tilt_bezpart(prevbezt, + bezt, + nu, + do_tilt ? &bevp->tilt : NULL, + do_radius ? &bevp->radius : NULL, + do_weight ? &bevp->weight : NULL, + resolu, + sizeof(BevPoint)); + + if (cu->twist_mode == CU_TWIST_TANGENT) { + forward_diff_bezier_cotangent(prevbezt->vec[1], + prevbezt->vec[2], + bezt->vec[0], + bezt->vec[1], + bevp->tan, + resolu, + sizeof(BevPoint)); + } + + /* indicate with handlecodes double points */ + if (prevbezt->h1 == prevbezt->h2) { + if (prevbezt->h1 == 0 || prevbezt->h1 == HD_VECT) + bevp->split_tag = true; + } + else { + if (prevbezt->h1 == 0 || prevbezt->h1 == HD_VECT) + bevp->split_tag = true; + 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; + } + prevbezt = bezt; + bezt++; + } + + if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic: endpoint */ + copy_v3_v3(bevp->vec, prevbezt->vec[1]); + bevp->tilt = prevbezt->tilt; + bevp->radius = prevbezt->radius; + bevp->weight = prevbezt->weight; + + sub_v3_v3v3(bevp->dir, prevbezt->vec[1], prevbezt->vec[0]); + normalize_v3(bevp->dir); + + bl->nr++; + } + } + else if (nu->type == CU_NURBS) { + if (nu->pntsv == 1) { + len = (resolu * segcount); + + bl = MEM_callocN(sizeof(BevList), "makeBevelList3"); + bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints3"); + if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { + bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList3_seglen"); + bl->segbevcount = MEM_malloc_arrayN( + 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->tilt : NULL, + do_radius ? &bevp->radius : NULL, + 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); + } + } + } + } + } + + /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */ + bl = bev->first; + while (bl) { + if (bl->nr) { /* null bevel items come from single points */ + bool is_cyclic = bl->poly != -1; + nr = bl->nr; + if (is_cyclic) { + bevp1 = bl->bevpoints; + bevp0 = bevp1 + (nr - 1); + } + else { + bevp0 = bl->bevpoints; + bevp0->offset = 0; + bevp1 = bevp0 + 1; + } + nr--; + while (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++; + } + } + } + } + bevp0 = bevp1; + bevp1++; + } + } + bl = bl->next; + } + bl = bev->first; + while (bl) { + blnext = bl->next; + if (bl->nr && bl->dupe_nr) { + nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */ + blnew = MEM_callocN(sizeof(BevList), "makeBevelList4"); + memcpy(blnew, bl, sizeof(BevList)); + blnew->bevpoints = MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4"); + if (!blnew->bevpoints) { + MEM_freeN(blnew); + break; + } + 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 */ + bevp0 = bl->bevpoints; + bevp1 = blnew->bevpoints; + nr = bl->nr; + while (nr--) { + if (bevp0->dupe_tag == 0) { + memcpy(bevp1, bevp0, sizeof(BevPoint)); + bevp1++; + blnew->nr++; + } + bevp0++; + } + if (bl->bevpoints != NULL) { + MEM_freeN(bl->bevpoints); + } + MEM_freeN(bl); + blnew->dupe_nr = 0; + } + bl = blnext; + } + + /* STEP 3: POLYS COUNT AND AUTOHOLE */ + bl = bev->first; + poly = 0; + while (bl) { + if (bl->nr && bl->poly >= 0) { + poly++; + bl->poly = poly; + bl->hole = 0; + } + bl = bl->next; + } + + /* find extreme left points, also test (turning) direction */ + if (poly > 0) { + sd = sortdata = MEM_malloc_arrayN(poly, sizeof(struct BevelSort), "makeBevelList5"); + bl = bev->first; + while (bl) { + if (bl->poly > 0) { + BevPoint *bevp; + + min = 300000.0; + bevp = bl->bevpoints; + nr = bl->nr; + while (nr--) { + if (min > bevp->vec[0]) { + min = bevp->vec[0]; + bevp1 = bevp; + } + bevp++; + } + sd->bl = bl; + sd->left = min; + + bevp = bl->bevpoints; + if (bevp1 == bevp) + bevp0 = bevp + (bl->nr - 1); + else + bevp0 = bevp1 - 1; + bevp = bevp + (bl->nr - 1); + if (bevp1 == bevp) + bevp2 = bl->bevpoints; + else + bevp2 = bevp1 + 1; + + inp = ((bevp1->vec[0] - bevp0->vec[0]) * (bevp0->vec[1] - bevp2->vec[1]) + + (bevp0->vec[1] - bevp1->vec[1]) * (bevp0->vec[0] - bevp2->vec[0])); + + if (inp > 0.0f) + sd->dir = 1; + else + sd->dir = 0; + + sd++; + } + + bl = bl->next; + } + qsort(sortdata, poly, sizeof(struct BevelSort), vergxcobev); + + sd = sortdata + 1; + for (a = 1; a < poly; a++, sd++) { + bl = sd->bl; /* is bl a hole? */ + sd1 = sortdata + (a - 1); + for (b = a - 1; b >= 0; b--, sd1--) { /* all polys to the left */ + if (sd1->bl->charidx == bl->charidx) { /* for text, only check matching char */ + if (bevelinside(sd1->bl, bl)) { + bl->hole = 1 - sd1->bl->hole; + break; + } + } + } + } + + /* turning direction */ + if ((cu->flag & CU_3D) == 0) { + sd = sortdata; + for (a = 0; a < poly; a++, sd++) { + if (sd->bl->hole == sd->dir) { + bl = sd->bl; + bevp1 = bl->bevpoints; + bevp2 = bevp1 + (bl->nr - 1); + nr = bl->nr / 2; + while (nr--) { + SWAP(BevPoint, *bevp1, *bevp2); + bevp1++; + bevp2--; + } + } + } + } + MEM_freeN(sortdata); + } + + /* STEP 4: 2D-COSINES or 3D ORIENTATION */ + if ((cu->flag & CU_3D) == 0) { + /* 2D Curves */ + for (bl = bev->first; bl; bl = bl->next) { + if (bl->nr < 2) { + BevPoint *bevp = bl->bevpoints; + unit_qt(bevp->quat); + } + else if (bl->nr == 2) { /* 2 pnt, treat separate */ + make_bevel_list_segment_2D(bl); + } + else { + make_bevel_list_2D(bl); + } + } + } + else { + /* 3D Curves */ + for (bl = bev->first; bl; bl = bl->next) { + if (bl->nr < 2) { + BevPoint *bevp = bl->bevpoints; + unit_qt(bevp->quat); + } + else if (bl->nr == 2) { /* 2 pnt, treat separate */ + make_bevel_list_segment_3D(bl); + } + else { + make_bevel_list_3D(bl, (int)(resolu * cu->twist_smooth), cu->twist_mode); + } + } + } } /* ****************** HANDLES ************** */ -static void calchandleNurb_intern( - BezTriple *bezt, const BezTriple *prev, const BezTriple *next, - bool is_fcurve, bool skip_align, char fcurve_smoothing) +static void calchandleNurb_intern(BezTriple *bezt, + const BezTriple *prev, + const BezTriple *next, + bool is_fcurve, + bool skip_align, + char fcurve_smoothing) { - /* defines to avoid confusion */ -#define p2_h1 ((p2) - 3) + /* defines to avoid confusion */ +#define p2_h1 ((p2)-3) #define p2_h2 ((p2) + 3) - const float *p1, *p3; - float *p2; - float pt[3]; - float dvec_a[3], dvec_b[3]; - float len, len_a, len_b; - float len_ratio; - const float eps = 1e-5; - - /* assume normal handle until we check */ - bezt->f5 = HD_AUTOTYPE_NORMAL; - - if (bezt->h1 == 0 && bezt->h2 == 0) { - return; - } - - p2 = bezt->vec[1]; - - if (prev == NULL) { - p3 = next->vec[1]; - pt[0] = 2.0f * p2[0] - p3[0]; - pt[1] = 2.0f * p2[1] - p3[1]; - pt[2] = 2.0f * p2[2] - p3[2]; - p1 = pt; - } - else { - p1 = prev->vec[1]; - } - - if (next == NULL) { - pt[0] = 2.0f * p2[0] - p1[0]; - pt[1] = 2.0f * p2[1] - p1[1]; - pt[2] = 2.0f * p2[2] - p1[2]; - p3 = pt; - } - else { - p3 = next->vec[1]; - } - - sub_v3_v3v3(dvec_a, p2, p1); - sub_v3_v3v3(dvec_b, p3, p2); - - if (is_fcurve) { - len_a = dvec_a[0]; - len_b = dvec_b[0]; - } - else { - len_a = len_v3(dvec_a); - len_b = len_v3(dvec_b); - } - - if (len_a == 0.0f) len_a = 1.0f; - if (len_b == 0.0f) len_b = 1.0f; - - len_ratio = len_a / len_b; - - if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */ - float tvec[3]; - tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a; - tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a; - tvec[2] = dvec_b[2] / len_b + dvec_a[2] / len_a; - - if (is_fcurve) { - if (fcurve_smoothing != FCURVE_SMOOTH_NONE) { - /* force the horizontal handle size to be 1/3 of the key interval so that - * the X component of the parametric bezier curve is a linear spline */ - len = 6.0f / 2.5614f; - } - else { - len = tvec[0]; - } - } - else { - len = len_v3(tvec); - } - len *= 2.5614f; - - if (len != 0.0f) { - /* only for fcurves */ - bool leftviolate = false, rightviolate = false; - - if (!is_fcurve || fcurve_smoothing == FCURVE_SMOOTH_NONE) { - if (len_a > 5.0f * len_b) - len_a = 5.0f * len_b; - if (len_b > 5.0f * len_a) - len_b = 5.0f * len_a; - } - - if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) { - len_a /= len; - madd_v3_v3v3fl(p2_h1, p2, tvec, -len_a); - - if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */ - float ydiff1 = prev->vec[1][1] - bezt->vec[1][1]; - float ydiff2 = next->vec[1][1] - bezt->vec[1][1]; - if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) { - bezt->vec[0][1] = bezt->vec[1][1]; - bezt->f5 = HD_AUTOTYPE_SPECIAL; - } - else { /* handles should not be beyond y coord of two others */ - if (ydiff1 <= 0.0f) { - if (prev->vec[1][1] > bezt->vec[0][1]) { - bezt->vec[0][1] = prev->vec[1][1]; - leftviolate = 1; - } - } - else { - if (prev->vec[1][1] < bezt->vec[0][1]) { - bezt->vec[0][1] = prev->vec[1][1]; - leftviolate = 1; - } - } - } - } - } - if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { - len_b /= len; - madd_v3_v3v3fl(p2_h2, p2, tvec, len_b); - - if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */ - float ydiff1 = prev->vec[1][1] - bezt->vec[1][1]; - float ydiff2 = next->vec[1][1] - bezt->vec[1][1]; - if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) { - bezt->vec[2][1] = bezt->vec[1][1]; - bezt->f5 = HD_AUTOTYPE_SPECIAL; - } - else { /* handles should not be beyond y coord of two others */ - if (ydiff1 <= 0.0f) { - if (next->vec[1][1] < bezt->vec[2][1]) { - bezt->vec[2][1] = next->vec[1][1]; - rightviolate = 1; - } - } - else { - if (next->vec[1][1] > bezt->vec[2][1]) { - bezt->vec[2][1] = next->vec[1][1]; - rightviolate = 1; - } - } - } - } - } - if (leftviolate || rightviolate) { /* align left handle */ - BLI_assert(is_fcurve); - /* simple 2d calculation */ - float h1_x = p2_h1[0] - p2[0]; - float h2_x = p2[0] - p2_h2[0]; - - if (leftviolate) { - p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x; - } - else { - p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x; - } - } - } - } - - if (bezt->h1 == HD_VECT) { /* vector */ - madd_v3_v3v3fl(p2_h1, p2, dvec_a, -1.0f / 3.0f); - } - if (bezt->h2 == HD_VECT) { - madd_v3_v3v3fl(p2_h2, p2, dvec_b, 1.0f / 3.0f); - } - - 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 */ - return; - } - - len_a = len_v3v3(p2, p2_h1); - len_b = len_v3v3(p2, p2_h2); - - if (len_a == 0.0f) len_a = 1.0f; - if (len_b == 0.0f) len_b = 1.0f; - - len_ratio = len_a / len_b; - - if (bezt->f1 & SELECT) { /* order of calculation */ - if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */ - if (len_a > eps) { - len = 1.0f / len_ratio; - p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]); - p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]); - p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]); - } - } - if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { - if (len_b > eps) { - len = len_ratio; - p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]); - p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]); - p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]); - } - } - } - else { - if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { - if (len_b > eps) { - len = len_ratio; - p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]); - p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]); - p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]); - } - } - if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */ - if (len_a > eps) { - len = 1.0f / len_ratio; - p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]); - p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]); - p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]); - } - } - } + const float *p1, *p3; + float *p2; + float pt[3]; + float dvec_a[3], dvec_b[3]; + float len, len_a, len_b; + float len_ratio; + const float eps = 1e-5; + + /* assume normal handle until we check */ + bezt->f5 = HD_AUTOTYPE_NORMAL; + + if (bezt->h1 == 0 && bezt->h2 == 0) { + return; + } + + p2 = bezt->vec[1]; + + if (prev == NULL) { + p3 = next->vec[1]; + pt[0] = 2.0f * p2[0] - p3[0]; + pt[1] = 2.0f * p2[1] - p3[1]; + pt[2] = 2.0f * p2[2] - p3[2]; + p1 = pt; + } + else { + p1 = prev->vec[1]; + } + + if (next == NULL) { + pt[0] = 2.0f * p2[0] - p1[0]; + pt[1] = 2.0f * p2[1] - p1[1]; + pt[2] = 2.0f * p2[2] - p1[2]; + p3 = pt; + } + else { + p3 = next->vec[1]; + } + + sub_v3_v3v3(dvec_a, p2, p1); + sub_v3_v3v3(dvec_b, p3, p2); + + if (is_fcurve) { + len_a = dvec_a[0]; + len_b = dvec_b[0]; + } + else { + len_a = len_v3(dvec_a); + len_b = len_v3(dvec_b); + } + + if (len_a == 0.0f) + len_a = 1.0f; + if (len_b == 0.0f) + len_b = 1.0f; + + len_ratio = len_a / len_b; + + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */ + float tvec[3]; + tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a; + tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a; + tvec[2] = dvec_b[2] / len_b + dvec_a[2] / len_a; + + if (is_fcurve) { + if (fcurve_smoothing != FCURVE_SMOOTH_NONE) { + /* force the horizontal handle size to be 1/3 of the key interval so that + * the X component of the parametric bezier curve is a linear spline */ + len = 6.0f / 2.5614f; + } + else { + len = tvec[0]; + } + } + else { + len = len_v3(tvec); + } + len *= 2.5614f; + + if (len != 0.0f) { + /* only for fcurves */ + bool leftviolate = false, rightviolate = false; + + if (!is_fcurve || fcurve_smoothing == FCURVE_SMOOTH_NONE) { + if (len_a > 5.0f * len_b) + len_a = 5.0f * len_b; + if (len_b > 5.0f * len_a) + len_b = 5.0f * len_a; + } + + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) { + len_a /= len; + madd_v3_v3v3fl(p2_h1, p2, tvec, -len_a); + + if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */ + float ydiff1 = prev->vec[1][1] - bezt->vec[1][1]; + float ydiff2 = next->vec[1][1] - bezt->vec[1][1]; + if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) { + bezt->vec[0][1] = bezt->vec[1][1]; + bezt->f5 = HD_AUTOTYPE_SPECIAL; + } + else { /* handles should not be beyond y coord of two others */ + if (ydiff1 <= 0.0f) { + if (prev->vec[1][1] > bezt->vec[0][1]) { + bezt->vec[0][1] = prev->vec[1][1]; + leftviolate = 1; + } + } + else { + if (prev->vec[1][1] < bezt->vec[0][1]) { + bezt->vec[0][1] = prev->vec[1][1]; + leftviolate = 1; + } + } + } + } + } + if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { + len_b /= len; + madd_v3_v3v3fl(p2_h2, p2, tvec, len_b); + + if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */ + float ydiff1 = prev->vec[1][1] - bezt->vec[1][1]; + float ydiff2 = next->vec[1][1] - bezt->vec[1][1]; + if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) { + bezt->vec[2][1] = bezt->vec[1][1]; + bezt->f5 = HD_AUTOTYPE_SPECIAL; + } + else { /* handles should not be beyond y coord of two others */ + if (ydiff1 <= 0.0f) { + if (next->vec[1][1] < bezt->vec[2][1]) { + bezt->vec[2][1] = next->vec[1][1]; + rightviolate = 1; + } + } + else { + if (next->vec[1][1] > bezt->vec[2][1]) { + bezt->vec[2][1] = next->vec[1][1]; + rightviolate = 1; + } + } + } + } + } + if (leftviolate || rightviolate) { /* align left handle */ + BLI_assert(is_fcurve); + /* simple 2d calculation */ + float h1_x = p2_h1[0] - p2[0]; + float h2_x = p2[0] - p2_h2[0]; + + if (leftviolate) { + p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x; + } + else { + p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x; + } + } + } + } + + if (bezt->h1 == HD_VECT) { /* vector */ + madd_v3_v3v3fl(p2_h1, p2, dvec_a, -1.0f / 3.0f); + } + if (bezt->h2 == HD_VECT) { + madd_v3_v3v3fl(p2_h2, p2, dvec_b, 1.0f / 3.0f); + } + + 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 */ + return; + } + + len_a = len_v3v3(p2, p2_h1); + len_b = len_v3v3(p2, p2_h2); + + if (len_a == 0.0f) + len_a = 1.0f; + if (len_b == 0.0f) + len_b = 1.0f; + + len_ratio = len_a / len_b; + + if (bezt->f1 & SELECT) { /* order of calculation */ + if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */ + if (len_a > eps) { + len = 1.0f / len_ratio; + p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]); + p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]); + p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]); + } + } + if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { + if (len_b > eps) { + len = len_ratio; + p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]); + p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]); + p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]); + } + } + } + else { + if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { + if (len_b > eps) { + len = len_ratio; + p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]); + p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]); + p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]); + } + } + if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */ + if (len_a > eps) { + len = 1.0f / len_ratio; + p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]); + p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]); + p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]); + } + } + } #undef p2_h1 #undef p2_h2 @@ -3508,34 +3584,36 @@ static void calchandleNurb_intern( static void calchandlesNurb_intern(Nurb *nu, bool skip_align) { - BezTriple *bezt, *prev, *next; - int a; - - if (nu->type != CU_BEZIER) - return; - if (nu->pntsu < 2) - return; - - a = nu->pntsu; - bezt = nu->bezt; - if (nu->flagu & CU_NURB_CYCLIC) prev = bezt + (a - 1); - else prev = NULL; - next = bezt + 1; - - while (a--) { - calchandleNurb_intern(bezt, prev, next, 0, skip_align, 0); - prev = bezt; - if (a == 1) { - if (nu->flagu & CU_NURB_CYCLIC) - next = nu->bezt; - else - next = NULL; - } - else - next++; - - bezt++; - } + BezTriple *bezt, *prev, *next; + int a; + + if (nu->type != CU_BEZIER) + return; + if (nu->pntsu < 2) + return; + + a = nu->pntsu; + bezt = nu->bezt; + if (nu->flagu & CU_NURB_CYCLIC) + prev = bezt + (a - 1); + else + prev = NULL; + next = bezt + 1; + + while (a--) { + calchandleNurb_intern(bezt, prev, next, 0, skip_align, 0); + prev = bezt; + if (a == 1) { + if (nu->flagu & CU_NURB_CYCLIC) + next = nu->bezt; + else + next = NULL; + } + else + next++; + + bezt++; + } } /* A utility function for allocating a number of arrays of the same length @@ -3548,146 +3626,146 @@ static void calchandlesNurb_intern(Nurb *nu, bool skip_align) */ static void *allocate_arrays(int count, float ***floats, char ***chars, const char *name) { - size_t num_floats = 0, num_chars = 0; + size_t num_floats = 0, num_chars = 0; - while (floats && floats[num_floats]) { - num_floats++; - } + while (floats && floats[num_floats]) { + num_floats++; + } - while (chars && chars[num_chars]) { - num_chars++; - } + while (chars && chars[num_chars]) { + num_chars++; + } - void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name); + void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name); - if (!buffer) - return NULL; + if (!buffer) + return NULL; - float *fptr = buffer; + float *fptr = buffer; - for (int i = 0; i < num_floats; i++, fptr += count) { - *floats[i] = fptr; - } + for (int i = 0; i < num_floats; i++, fptr += count) { + *floats[i] = fptr; + } - char *cptr = (char *)fptr; + char *cptr = (char *)fptr; - for (int i = 0; i < num_chars; i++, cptr += count) { - *chars[i] = cptr; - } + for (int i = 0; i < num_chars; i++, cptr += count) { + *chars[i] = cptr; + } - return buffer; + return buffer; } static void free_arrays(void *buffer) { - MEM_freeN(buffer); + MEM_freeN(buffer); } /* computes in which direction to change h[i] to satisfy conditions better */ -static float bezier_relax_direction(float *a, float *b, float *c, float *d, float *h, int i, int count) +static float bezier_relax_direction( + float *a, float *b, float *c, float *d, float *h, int i, int count) { - /* current deviation between sides of the equation */ - float state = a[i] * h[(i + count - 1) % count] + - b[i] * h[i] + - c[i] * h[(i + 1) % count] - - d[i]; + /* current deviation between sides of the equation */ + float state = a[i] * h[(i + count - 1) % count] + b[i] * h[i] + c[i] * h[(i + 1) % count] - d[i]; - /* only the sign is meaningful */ - return -state * b[i]; + /* only the sign is meaningful */ + return -state * b[i]; } static void bezier_lock_unknown(float *a, float *b, float *c, float *d, int i, float value) { - a[i] = c[i] = 0.0f; - b[i] = 1.0f; - d[i] = value; + a[i] = c[i] = 0.0f; + b[i] = 1.0f; + d[i] = value; } -static void bezier_restore_equation(float *a, float *b, float *c, float *d, float *a0, float *b0, float *c0, float *d0, int i) +static void bezier_restore_equation( + float *a, float *b, float *c, float *d, float *a0, float *b0, float *c0, float *d0, int i) { - a[i] = a0[i]; - b[i] = b0[i]; - c[i] = c0[i]; - d[i] = d0[i]; + a[i] = a0[i]; + b[i] = b0[i]; + c[i] = c0[i]; + d[i] = d0[i]; } -static bool tridiagonal_solve_with_limits(float *a, float *b, float *c, float *d, float *h, float *hmin, float *hmax, int solve_count) +static bool tridiagonal_solve_with_limits( + float *a, float *b, float *c, float *d, float *h, float *hmin, float *hmax, int solve_count) { - float *a0, *b0, *c0, *d0; - float **arrays[] = { &a0, &b0, &c0, &d0, NULL }; - char *is_locked, *num_unlocks; - char **flagarrays[] = { &is_locked, &num_unlocks, NULL }; + float *a0, *b0, *c0, *d0; + float **arrays[] = {&a0, &b0, &c0, &d0, NULL}; + char *is_locked, *num_unlocks; + char **flagarrays[] = {&is_locked, &num_unlocks, NULL}; - void *tmps = allocate_arrays(solve_count, arrays, flagarrays, "tridiagonal_solve_with_limits"); - if (!tmps) - return false; + void *tmps = allocate_arrays(solve_count, arrays, flagarrays, "tridiagonal_solve_with_limits"); + if (!tmps) + return false; - memcpy(a0, a, sizeof(float) * solve_count); - memcpy(b0, b, sizeof(float) * solve_count); - memcpy(c0, c, sizeof(float) * solve_count); - memcpy(d0, d, sizeof(float) * solve_count); + memcpy(a0, a, sizeof(float) * solve_count); + memcpy(b0, b, sizeof(float) * solve_count); + memcpy(c0, c, sizeof(float) * solve_count); + memcpy(d0, d, sizeof(float) * solve_count); - memset(is_locked, 0, solve_count); - memset(num_unlocks, 0, solve_count); + memset(is_locked, 0, solve_count); + memset(num_unlocks, 0, solve_count); - bool overshoot, unlocked; + bool overshoot, unlocked; - do { - if (!BLI_tridiagonal_solve_cyclic(a, b, c, d, h, solve_count)) { - free_arrays(tmps); - return false; - } + do { + if (!BLI_tridiagonal_solve_cyclic(a, b, c, d, h, solve_count)) { + free_arrays(tmps); + return false; + } - /* first check if any handles overshoot the limits, and lock them */ - bool all = false, locked = false; + /* first check if any handles overshoot the limits, and lock them */ + bool all = false, locked = false; - overshoot = unlocked = false; + overshoot = unlocked = false; - do { - for (int i = 0; i < solve_count; i++) { - if (h[i] >= hmin[i] && h[i] <= hmax[i]) - continue; + do { + for (int i = 0; i < solve_count; i++) { + if (h[i] >= hmin[i] && h[i] <= hmax[i]) + continue; - overshoot = true; + overshoot = true; - float target = h[i] > hmax[i] ? hmax[i] : hmin[i]; + float target = h[i] > hmax[i] ? hmax[i] : hmin[i]; - /* heuristically only lock handles that go in the right direction if there are such ones */ - if (target != 0.0f || all) { - /* mark item locked */ - is_locked[i] = 1; + /* heuristically only lock handles that go in the right direction if there are such ones */ + if (target != 0.0f || all) { + /* mark item locked */ + is_locked[i] = 1; - bezier_lock_unknown(a, b, c, d, i, target); - locked = true; - } - } + bezier_lock_unknown(a, b, c, d, i, target); + locked = true; + } + } - all = true; - } while (overshoot && !locked); + all = true; + } while (overshoot && !locked); - /* if no handles overshot and were locked, see if it may be a good idea to unlock some handles */ - if (!locked) { - for (int i = 0; i < solve_count; i++) { - // to definitely avoid infinite loops limit this to 2 times - if (!is_locked[i] || num_unlocks[i] >= 2) - continue; + /* if no handles overshot and were locked, see if it may be a good idea to unlock some handles */ + if (!locked) { + for (int i = 0; i < solve_count; i++) { + // to definitely avoid infinite loops limit this to 2 times + if (!is_locked[i] || num_unlocks[i] >= 2) + continue; - /* if the handle wants to move in allowable direction, release it */ - float relax = bezier_relax_direction(a0, b0, c0, d0, h, i, solve_count); + /* if the handle wants to move in allowable direction, release it */ + float relax = bezier_relax_direction(a0, b0, c0, d0, h, i, solve_count); - if ((relax > 0 && h[i] < hmax[i]) || (relax < 0 && h[i] > hmin[i])) { - bezier_restore_equation(a, b, c, d, a0, b0, c0, d0, i); + if ((relax > 0 && h[i] < hmax[i]) || (relax < 0 && h[i] > hmin[i])) { + bezier_restore_equation(a, b, c, d, a0, b0, c0, d0, i); - is_locked[i] = 0; - num_unlocks[i]++; - unlocked = true; - } - } - } - } while (overshoot || unlocked); + is_locked[i] = 0; + num_unlocks[i]++; + unlocked = true; + } + } + } + } while (overshoot || unlocked); - free_arrays(tmps); - return true; + free_arrays(tmps); + return true; } /* @@ -3742,339 +3820,347 @@ static bool tridiagonal_solve_with_limits(float *a, float *b, float *c, float *d * equation with parts omitted, so the handle size correction also applies. */ - -static void bezier_eq_continuous(float *a, float *b, float *c, float *d, float *dy, float *l, int i) +static void bezier_eq_continuous( + float *a, float *b, float *c, float *d, float *dy, float *l, int i) { - a[i] = l[i] * l[i]; - b[i] = 2.0f * (l[i] + 1); - c[i] = 1.0f / l[i + 1]; - d[i] = dy[i] * l[i] * l[i] + dy[i + 1]; + a[i] = l[i] * l[i]; + b[i] = 2.0f * (l[i] + 1); + c[i] = 1.0f / l[i + 1]; + d[i] = dy[i] * l[i] * l[i] + dy[i + 1]; } -static void bezier_eq_noaccel_right(float *a, float *b, float *c, float *d, float *dy, float *l, int i) +static void bezier_eq_noaccel_right( + float *a, float *b, float *c, float *d, float *dy, float *l, int i) { - a[i] = 0.0f; - b[i] = 2.0f; - c[i] = 1.0f / l[i + 1]; - d[i] = dy[i + 1]; + a[i] = 0.0f; + b[i] = 2.0f; + c[i] = 1.0f / l[i + 1]; + d[i] = dy[i + 1]; } -static void bezier_eq_noaccel_left(float *a, float *b, float *c, float *d, float *dy, float *l, int i) +static void bezier_eq_noaccel_left( + float *a, float *b, float *c, float *d, float *dy, float *l, int i) { - a[i] = l[i] * l[i]; - b[i] = 2.0f * l[i]; - c[i] = 0.0f; - d[i] = dy[i] * l[i] * l[i]; + a[i] = l[i] * l[i]; + b[i] = 2.0f * l[i]; + c[i] = 0.0f; + d[i] = dy[i] * l[i] * l[i]; } /* auto clamp prevents its own point going the wrong way, and adjacent handles overshooting */ -static void bezier_clamp(float *hmax, float *hmin, int i, float dy, bool no_reverse, bool no_overshoot) -{ - if (dy > 0) { - if (no_overshoot) - hmax[i] = min_ff(hmax[i], dy); - if (no_reverse) - hmin[i] = 0.0f; - } - else if (dy < 0) { - if (no_reverse) - hmax[i] = 0.0f; - if (no_overshoot) - hmin[i] = max_ff(hmin[i], dy); - } - else if (no_reverse || no_overshoot) { - hmax[i] = hmin[i] = 0.0f; - } +static void bezier_clamp( + float *hmax, float *hmin, int i, float dy, bool no_reverse, bool no_overshoot) +{ + if (dy > 0) { + if (no_overshoot) + hmax[i] = min_ff(hmax[i], dy); + if (no_reverse) + hmin[i] = 0.0f; + } + else if (dy < 0) { + if (no_reverse) + hmax[i] = 0.0f; + if (no_overshoot) + hmin[i] = max_ff(hmin[i], dy); + } + else if (no_reverse || no_overshoot) { + hmax[i] = hmin[i] = 0.0f; + } } /* write changes to a bezier handle */ static void bezier_output_handle_inner(BezTriple *bezt, bool right, float newval[3], bool endpoint) { - float tmp[3]; + float tmp[3]; - int idx = right ? 2 : 0; - char hr = right ? bezt->h2 : bezt->h1; - char hm = right ? bezt->h1 : bezt->h2; + int idx = right ? 2 : 0; + char hr = right ? bezt->h2 : bezt->h1; + char hm = right ? bezt->h1 : bezt->h2; - /* only assign Auto/Vector handles */ - if (!ELEM(hr, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) - return; + /* only assign Auto/Vector handles */ + if (!ELEM(hr, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) + return; - copy_v3_v3(bezt->vec[idx], newval); + copy_v3_v3(bezt->vec[idx], newval); - /* fix up the Align handle if any */ - if (ELEM(hm, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { - float hlen = len_v3v3(bezt->vec[1], bezt->vec[2 - idx]); - float h2len = len_v3v3(bezt->vec[1], bezt->vec[idx]); + /* fix up the Align handle if any */ + if (ELEM(hm, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { + float hlen = len_v3v3(bezt->vec[1], bezt->vec[2 - idx]); + float h2len = len_v3v3(bezt->vec[1], bezt->vec[idx]); - sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]); - madd_v3_v3v3fl(bezt->vec[2 - idx], bezt->vec[1], tmp, hlen / h2len); - } - /* at end points of the curve, mirror handle to the other side */ - else if (endpoint && ELEM(hm, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) { - sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]); - add_v3_v3v3(bezt->vec[2 - idx], bezt->vec[1], tmp); - } + sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]); + madd_v3_v3v3fl(bezt->vec[2 - idx], bezt->vec[1], tmp, hlen / h2len); + } + /* at end points of the curve, mirror handle to the other side */ + else if (endpoint && ELEM(hm, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) { + sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]); + add_v3_v3v3(bezt->vec[2 - idx], bezt->vec[1], tmp); + } } static void bezier_output_handle(BezTriple *bezt, bool right, float dy, bool endpoint) { - float tmp[3]; + float tmp[3]; - copy_v3_v3(tmp, bezt->vec[right ? 2 : 0]); + copy_v3_v3(tmp, bezt->vec[right ? 2 : 0]); - tmp[1] = bezt->vec[1][1] + dy; + tmp[1] = bezt->vec[1][1] + dy; - bezier_output_handle_inner(bezt, right, tmp, endpoint); + bezier_output_handle_inner(bezt, right, tmp, endpoint); } static bool bezier_check_solve_end_handle(BezTriple *bezt, char htype, bool end) { - return (htype == HD_VECT) || (end && ELEM(htype, HD_AUTO, HD_AUTO_ANIM) && bezt->f5 == HD_AUTOTYPE_NORMAL); + return (htype == HD_VECT) || + (end && ELEM(htype, HD_AUTO, HD_AUTO_ANIM) && bezt->f5 == HD_AUTOTYPE_NORMAL); } static float bezier_calc_handle_adj(float hsize[2], float dx) { - /* if handles intersect in x direction, they are scaled to fit */ - float fac = dx / (hsize[0] + dx / 3.0f); - if (fac < 1.0f) { - mul_v2_fl(hsize, fac); - } - return 1.0f - 3.0f * hsize[0] / dx; + /* if handles intersect in x direction, they are scaled to fit */ + float fac = dx / (hsize[0] + dx / 3.0f); + if (fac < 1.0f) { + mul_v2_fl(hsize, fac); + } + return 1.0f - 3.0f * hsize[0] / dx; } -static void bezier_handle_calc_smooth_fcurve(BezTriple *bezt, int total, int start, int count, bool cycle) +static void bezier_handle_calc_smooth_fcurve( + BezTriple *bezt, int total, int start, int count, bool cycle) { - float *dx, *dy, *l, *a, *b, *c, *d, *h, *hmax, *hmin; - float **arrays[] = { &dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, NULL }; + float *dx, *dy, *l, *a, *b, *c, *d, *h, *hmax, *hmin; + float **arrays[] = {&dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, NULL}; - int solve_count = count; + int solve_count = count; - /* verify index ranges */ + /* verify index ranges */ - if (count < 2) - return; + if (count < 2) + return; - BLI_assert(start < total - 1 && count <= total); - BLI_assert(start + count <= total || cycle); + BLI_assert(start < total - 1 && count <= total); + BLI_assert(start + count <= total || cycle); - bool full_cycle = (start == 0 && count == total && cycle); + bool full_cycle = (start == 0 && count == total && cycle); - BezTriple *bezt_first = &bezt[start]; - BezTriple *bezt_last = &bezt[(start + count > total) ? start + count - total : start + count - 1]; + BezTriple *bezt_first = &bezt[start]; + BezTriple *bezt_last = + &bezt[(start + count > total) ? start + count - total : start + count - 1]; - bool solve_first = bezier_check_solve_end_handle(bezt_first, bezt_first->h2, start == 0); - bool solve_last = bezier_check_solve_end_handle(bezt_last, bezt_last->h1, start + count == total); + bool solve_first = bezier_check_solve_end_handle(bezt_first, bezt_first->h2, start == 0); + bool solve_last = bezier_check_solve_end_handle( + bezt_last, bezt_last->h1, start + count == total); - if (count == 2 && !full_cycle && solve_first == solve_last) { - return; - } + if (count == 2 && !full_cycle && solve_first == solve_last) { + return; + } - /* allocate all */ + /* allocate all */ - void *tmp_buffer = allocate_arrays(count, arrays, NULL, "bezier_calc_smooth_tmp"); - if (!tmp_buffer) - return; + void *tmp_buffer = allocate_arrays(count, arrays, NULL, "bezier_calc_smooth_tmp"); + if (!tmp_buffer) + return; - /* point locations */ + /* point locations */ - dx[0] = dy[0] = NAN_FLT; + dx[0] = dy[0] = NAN_FLT; - for (int i = 1, j = start + 1; i < count; i++, j++) { - dx[i] = bezt[j].vec[1][0] - bezt[j - 1].vec[1][0]; - dy[i] = bezt[j].vec[1][1] - bezt[j - 1].vec[1][1]; + for (int i = 1, j = start + 1; i < count; i++, j++) { + dx[i] = bezt[j].vec[1][0] - bezt[j - 1].vec[1][0]; + dy[i] = bezt[j].vec[1][1] - bezt[j - 1].vec[1][1]; - /* when cyclic, jump from last point to first */ - if (cycle && j == total - 1) - j = 0; - } + /* when cyclic, jump from last point to first */ + if (cycle && j == total - 1) + j = 0; + } - /* ratio of x intervals */ + /* ratio of x intervals */ - l[0] = l[count - 1] = 1.0f; + l[0] = l[count - 1] = 1.0f; - for (int i = 1; i < count - 1; i++) { - l[i] = dx[i + 1] / dx[i]; - } + for (int i = 1; i < count - 1; i++) { + l[i] = dx[i + 1] / dx[i]; + } - /* compute handle clamp ranges */ + /* compute handle clamp ranges */ - bool clamped_prev = false, clamped_cur = ELEM(HD_AUTO_ANIM, bezt_first->h1, bezt_first->h2); + bool clamped_prev = false, clamped_cur = ELEM(HD_AUTO_ANIM, bezt_first->h1, bezt_first->h2); - for (int i = 0; i < count; i++) { - hmax[i] = FLT_MAX; - hmin[i] = -FLT_MAX; - } + for (int i = 0; i < count; i++) { + hmax[i] = FLT_MAX; + hmin[i] = -FLT_MAX; + } - for (int i = 1, j = start + 1; i < count; i++, j++) { - clamped_prev = clamped_cur; - clamped_cur = ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2); + for (int i = 1, j = start + 1; i < count; i++, j++) { + clamped_prev = clamped_cur; + clamped_cur = ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2); - if (cycle && j == total - 1) { - j = 0; - clamped_cur = clamped_cur || ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2); - } + if (cycle && j == total - 1) { + j = 0; + clamped_cur = clamped_cur || ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2); + } - bezier_clamp(hmax, hmin, i - 1, dy[i], clamped_prev, clamped_prev); - bezier_clamp(hmax, hmin, i, dy[i] * l[i], clamped_cur, clamped_cur); - } + bezier_clamp(hmax, hmin, i - 1, dy[i], clamped_prev, clamped_prev); + bezier_clamp(hmax, hmin, i, dy[i] * l[i], clamped_cur, clamped_cur); + } - /* full cycle merges first and last points into continuous loop */ + /* full cycle merges first and last points into continuous loop */ - float first_handle_adj = 0.0f, last_handle_adj = 0.0f; + float first_handle_adj = 0.0f, last_handle_adj = 0.0f; - if (full_cycle) { - /* reduce the number of unknowns by one */ - int i = solve_count = count - 1; + if (full_cycle) { + /* reduce the number of unknowns by one */ + int i = solve_count = count - 1; - dx[0] = dx[i]; - dy[0] = dy[i]; + dx[0] = dx[i]; + dy[0] = dy[i]; - l[0] = l[i] = dx[1] / dx[0]; + l[0] = l[i] = dx[1] / dx[0]; - hmin[0] = max_ff(hmin[0], hmin[i]); - hmax[0] = min_ff(hmax[0], hmax[i]); + hmin[0] = max_ff(hmin[0], hmin[i]); + hmax[0] = min_ff(hmax[0], hmax[i]); - solve_first = solve_last = true; + solve_first = solve_last = true; - bezier_eq_continuous(a, b, c, d, dy, l, 0); - } - else { - float tmp[2]; + bezier_eq_continuous(a, b, c, d, dy, l, 0); + } + else { + float tmp[2]; - /* boundary condition: fixed handles or zero curvature */ - if (!solve_first) { - sub_v2_v2v2(tmp, bezt_first->vec[2], bezt_first->vec[1]); - first_handle_adj = bezier_calc_handle_adj(tmp, dx[1]); + /* boundary condition: fixed handles or zero curvature */ + if (!solve_first) { + sub_v2_v2v2(tmp, bezt_first->vec[2], bezt_first->vec[1]); + first_handle_adj = bezier_calc_handle_adj(tmp, dx[1]); - bezier_lock_unknown(a, b, c, d, 0, tmp[1]); - } - else { - bezier_eq_noaccel_right(a, b, c, d, dy, l, 0); - } + bezier_lock_unknown(a, b, c, d, 0, tmp[1]); + } + else { + bezier_eq_noaccel_right(a, b, c, d, dy, l, 0); + } - if (!solve_last) { - sub_v2_v2v2(tmp, bezt_last->vec[1], bezt_last->vec[0]); - last_handle_adj = bezier_calc_handle_adj(tmp, dx[count - 1]); + if (!solve_last) { + sub_v2_v2v2(tmp, bezt_last->vec[1], bezt_last->vec[0]); + last_handle_adj = bezier_calc_handle_adj(tmp, dx[count - 1]); - bezier_lock_unknown(a, b, c, d, count - 1, tmp[1]); - } - else { - bezier_eq_noaccel_left(a, b, c, d, dy, l, count - 1); - } - } + bezier_lock_unknown(a, b, c, d, count - 1, tmp[1]); + } + else { + bezier_eq_noaccel_left(a, b, c, d, dy, l, count - 1); + } + } - /* main tridiagonal system of equations */ + /* main tridiagonal system of equations */ - for (int i = 1; i < count - 1; i++) { - bezier_eq_continuous(a, b, c, d, dy, l, i); - } + for (int i = 1; i < count - 1; i++) { + bezier_eq_continuous(a, b, c, d, dy, l, i); + } - /* apply correction for user-defined handles with nonstandard x positions */ + /* apply correction for user-defined handles with nonstandard x positions */ - if (!full_cycle) { - if (count > 2 || solve_last) { - b[1] += l[1] * first_handle_adj; - } + if (!full_cycle) { + if (count > 2 || solve_last) { + b[1] += l[1] * first_handle_adj; + } - if (count > 2 || solve_first) { - b[count - 2] += last_handle_adj; - } - } + if (count > 2 || solve_first) { + b[count - 2] += last_handle_adj; + } + } - /* solve and output results */ + /* solve and output results */ - if (tridiagonal_solve_with_limits(a, b, c, d, h, hmin, hmax, solve_count)) { - if (full_cycle) { - h[count - 1] = h[0]; - } + if (tridiagonal_solve_with_limits(a, b, c, d, h, hmin, hmax, solve_count)) { + if (full_cycle) { + h[count - 1] = h[0]; + } - for (int i = 1, j = start + 1; i < count - 1; i++, j++) { - bool end = (j == total - 1); + for (int i = 1, j = start + 1; i < count - 1; i++, j++) { + bool end = (j == total - 1); - bezier_output_handle(&bezt[j], false, -h[i] / l[i], end); + bezier_output_handle(&bezt[j], false, -h[i] / l[i], end); - if (end) - j = 0; + if (end) + j = 0; - bezier_output_handle(&bezt[j], true, h[i], end); - } + bezier_output_handle(&bezt[j], true, h[i], end); + } - if (solve_first) { - bezier_output_handle(bezt_first, true, h[0], start == 0); - } + if (solve_first) { + bezier_output_handle(bezt_first, true, h[0], start == 0); + } - if (solve_last) { - bezier_output_handle(bezt_last, false, -h[count - 1] / l[count - 1], start + count == total); - } - } + if (solve_last) { + bezier_output_handle(bezt_last, false, -h[count - 1] / l[count - 1], start + count == total); + } + } - /* free all */ + /* free all */ - free_arrays(tmp_buffer); + free_arrays(tmp_buffer); } static bool is_free_auto_point(BezTriple *bezt) { - return BEZT_IS_AUTOH(bezt) && bezt->f5 == HD_AUTOTYPE_NORMAL; + return BEZT_IS_AUTOH(bezt) && bezt->f5 == HD_AUTOTYPE_NORMAL; } void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cycle) { - /* ignore cyclic extrapolation if end points are locked */ - cycle = cycle && is_free_auto_point(&bezt[0]) && is_free_auto_point(&bezt[total - 1]); + /* ignore cyclic extrapolation if end points are locked */ + cycle = cycle && is_free_auto_point(&bezt[0]) && is_free_auto_point(&bezt[total - 1]); - /* if cyclic, try to find a sequence break point */ - int search_base = 0; + /* if cyclic, try to find a sequence break point */ + int search_base = 0; - if (cycle) { - for (int i = 1; i < total - 1; i++) { - if (!is_free_auto_point(&bezt[i])) { - search_base = i; - break; - } - } + if (cycle) { + for (int i = 1; i < total - 1; i++) { + if (!is_free_auto_point(&bezt[i])) { + search_base = i; + break; + } + } - /* all points of the curve are freely changeable auto handles - solve as full cycle */ - if (search_base == 0) { - bezier_handle_calc_smooth_fcurve(bezt, total, 0, total, cycle); - return; - } - } + /* all points of the curve are freely changeable auto handles - solve as full cycle */ + if (search_base == 0) { + bezier_handle_calc_smooth_fcurve(bezt, total, 0, total, cycle); + return; + } + } - /* Find continuous subsequences of free auto handles and smooth them, starting at - * search_base. In cyclic mode these subsequences can span the cycle boundary. */ - int start = search_base, count = 1; + /* Find continuous subsequences of free auto handles and smooth them, starting at + * search_base. In cyclic mode these subsequences can span the cycle boundary. */ + int start = search_base, count = 1; - for (int i = 1, j = start + 1; i < total; i++, j++) { - /* in cyclic mode: jump from last to first point when necessary */ - if (j == total - 1 && cycle) - j = 0; + for (int i = 1, j = start + 1; i < total; i++, j++) { + /* in cyclic mode: jump from last to first point when necessary */ + if (j == total - 1 && cycle) + j = 0; - /* non auto handle closes the list (we come here at least for the last handle, see above) */ - if (!is_free_auto_point(&bezt[j])) { - bezier_handle_calc_smooth_fcurve(bezt, total, start, count + 1, cycle); - start = j; - count = 1; - } - else { - count++; - } - } + /* non auto handle closes the list (we come here at least for the last handle, see above) */ + if (!is_free_auto_point(&bezt[j])) { + bezier_handle_calc_smooth_fcurve(bezt, total, start, count + 1, cycle); + start = j; + count = 1; + } + else { + count++; + } + } - if (count > 1) { - bezier_handle_calc_smooth_fcurve(bezt, total, start, count, cycle); - } + if (count > 1) { + bezier_handle_calc_smooth_fcurve(bezt, total, start, count, cycle); + } } -void BKE_nurb_handle_calc(BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing) +void BKE_nurb_handle_calc( + BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing) { - calchandleNurb_intern(bezt, prev, next, is_fcurve, false, smoothing); + calchandleNurb_intern(bezt, prev, next, is_fcurve, false, smoothing); } void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */ { - calchandlesNurb_intern(nu, false); + calchandlesNurb_intern(nu, false); } /** @@ -4083,49 +4169,49 @@ void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */ */ static void nurbList_handles_swap_select(Nurb *nu) { - BezTriple *bezt; - int i; + 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; - } - } + 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); + 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) { - if (nu->pntsu > 1) { - BezTriple *prev = BKE_nurb_bezt_get_prev(nu, bezt); - BezTriple *next = BKE_nurb_bezt_get_next(nu, bezt); - BKE_nurb_handle_calc(bezt, prev, next, 0, 0); - } + if (nu->pntsu > 1) { + BezTriple *prev = BKE_nurb_bezt_get_prev(nu, bezt); + BezTriple *next = BKE_nurb_bezt_get_next(nu, bezt); + BKE_nurb_handle_calc(bezt, prev, next, 0, 0); + } } void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt) { - if (nu->pntsu > 1) { - const char h1_back = bezt->h1, h2_back = bezt->h2; + if (nu->pntsu > 1) { + const char h1_back = bezt->h1, h2_back = bezt->h2; - bezt->h1 = bezt->h2 = HD_AUTO; + bezt->h1 = bezt->h2 = HD_AUTO; - /* Override handle types to HD_AUTO and recalculate */ - BKE_nurb_handle_calc_simple(nu, bezt); + /* Override handle types to HD_AUTO and recalculate */ + BKE_nurb_handle_calc_simple(nu, bezt); - bezt->h1 = h1_back; - bezt->h2 = h2_back; - } + bezt->h1 = h1_back; + bezt->h2 = h2_back; + } } /** @@ -4135,635 +4221,654 @@ void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt) */ void BKE_nurb_bezt_handle_test(BezTriple *bezt, const bool use_handle) { - short flag = 0; + short flag = 0; #define SEL_F1 (1 << 0) #define SEL_F2 (1 << 1) #define SEL_F3 (1 << 2) - if (use_handle) { - if (bezt->f1 & SELECT) flag |= SEL_F1; - if (bezt->f2 & SELECT) flag |= SEL_F2; - if (bezt->f3 & SELECT) flag |= SEL_F3; - } - else { - flag = (bezt->f2 & SELECT) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0; - } - - /* check for partial selection */ - if (!ELEM(flag, 0, SEL_F1 | SEL_F2 | SEL_F3)) { - if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) { - bezt->h1 = HD_ALIGN; - } - if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { - bezt->h2 = HD_ALIGN; - } - - if (bezt->h1 == HD_VECT) { - if ((!(flag & SEL_F1)) != (!(flag & SEL_F2))) { - bezt->h1 = HD_FREE; - } - } - if (bezt->h2 == HD_VECT) { - if ((!(flag & SEL_F3)) != (!(flag & SEL_F2))) { - bezt->h2 = HD_FREE; - } - } - } + if (use_handle) { + if (bezt->f1 & SELECT) + flag |= SEL_F1; + if (bezt->f2 & SELECT) + flag |= SEL_F2; + if (bezt->f3 & SELECT) + flag |= SEL_F3; + } + else { + flag = (bezt->f2 & SELECT) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0; + } + + /* check for partial selection */ + if (!ELEM(flag, 0, SEL_F1 | SEL_F2 | SEL_F3)) { + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) { + bezt->h1 = HD_ALIGN; + } + if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { + bezt->h2 = HD_ALIGN; + } + + if (bezt->h1 == HD_VECT) { + if ((!(flag & SEL_F1)) != (!(flag & SEL_F2))) { + bezt->h1 = HD_FREE; + } + } + if (bezt->h2 == HD_VECT) { + if ((!(flag & SEL_F3)) != (!(flag & SEL_F2))) { + bezt->h2 = HD_FREE; + } + } + } #undef SEL_F1 #undef SEL_F2 #undef SEL_F3 - } void BKE_nurb_handles_test(Nurb *nu, const bool use_handle) { - BezTriple *bezt; - int a; + BezTriple *bezt; + int a; - if (nu->type != CU_BEZIER) - return; + if (nu->type != CU_BEZIER) + return; - bezt = nu->bezt; - a = nu->pntsu; - while (a--) { - BKE_nurb_bezt_handle_test(bezt, use_handle); - bezt++; - } + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + BKE_nurb_bezt_handle_test(bezt, use_handle); + bezt++; + } - BKE_nurb_handles_calc(nu); + BKE_nurb_handles_calc(nu); } void BKE_nurb_handles_autocalc(Nurb *nu, int flag) { - /* checks handle coordinates and calculates type */ - const float eps = 0.0001f; - const float eps_sq = eps * eps; - - BezTriple *bezt2, *bezt1, *bezt0; - int i; - - if (nu == NULL || nu->bezt == NULL) - return; - - bezt2 = nu->bezt; - bezt1 = bezt2 + (nu->pntsu - 1); - bezt0 = bezt1 - 1; - i = nu->pntsu; - - while (i--) { - bool align = false, leftsmall = false, rightsmall = false; - - /* left handle: */ - if (flag == 0 || (bezt1->f1 & flag)) { - bezt1->h1 = HD_FREE; - /* distance too short: vectorhandle */ - if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) { - bezt1->h1 = HD_VECT; - leftsmall = true; - } - else { - /* aligned handle? */ - if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) { - align = true; - bezt1->h1 = HD_ALIGN; - } - /* or vector handle? */ - if (dist_squared_to_line_v3(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < eps_sq) - bezt1->h1 = HD_VECT; - } - } - /* right handle: */ - if (flag == 0 || (bezt1->f3 & flag)) { - bezt1->h2 = HD_FREE; - /* distance too short: vectorhandle */ - if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) { - bezt1->h2 = HD_VECT; - rightsmall = true; - } - else { - /* aligned handle? */ - if (align) bezt1->h2 = HD_ALIGN; - - /* or vector handle? */ - if (dist_squared_to_line_v3(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < eps_sq) - bezt1->h2 = HD_VECT; - } - } - if (leftsmall && bezt1->h2 == HD_ALIGN) - bezt1->h2 = HD_FREE; - if (rightsmall && bezt1->h1 == HD_ALIGN) - bezt1->h1 = HD_FREE; - - /* undesired combination: */ - if (bezt1->h1 == HD_ALIGN && bezt1->h2 == HD_VECT) - bezt1->h1 = HD_FREE; - if (bezt1->h2 == HD_ALIGN && bezt1->h1 == HD_VECT) - bezt1->h2 = HD_FREE; - - bezt0 = bezt1; - bezt1 = bezt2; - bezt2++; - } - - BKE_nurb_handles_calc(nu); + /* checks handle coordinates and calculates type */ + const float eps = 0.0001f; + const float eps_sq = eps * eps; + + BezTriple *bezt2, *bezt1, *bezt0; + int i; + + if (nu == NULL || nu->bezt == NULL) + return; + + bezt2 = nu->bezt; + bezt1 = bezt2 + (nu->pntsu - 1); + bezt0 = bezt1 - 1; + i = nu->pntsu; + + while (i--) { + bool align = false, leftsmall = false, rightsmall = false; + + /* left handle: */ + if (flag == 0 || (bezt1->f1 & flag)) { + bezt1->h1 = HD_FREE; + /* distance too short: vectorhandle */ + if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) { + bezt1->h1 = HD_VECT; + leftsmall = true; + } + else { + /* aligned handle? */ + if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) { + align = true; + bezt1->h1 = HD_ALIGN; + } + /* or vector handle? */ + if (dist_squared_to_line_v3(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < eps_sq) + bezt1->h1 = HD_VECT; + } + } + /* right handle: */ + if (flag == 0 || (bezt1->f3 & flag)) { + bezt1->h2 = HD_FREE; + /* distance too short: vectorhandle */ + if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) { + bezt1->h2 = HD_VECT; + rightsmall = true; + } + else { + /* aligned handle? */ + if (align) + bezt1->h2 = HD_ALIGN; + + /* or vector handle? */ + if (dist_squared_to_line_v3(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < eps_sq) + bezt1->h2 = HD_VECT; + } + } + if (leftsmall && bezt1->h2 == HD_ALIGN) + bezt1->h2 = HD_FREE; + if (rightsmall && bezt1->h1 == HD_ALIGN) + bezt1->h1 = HD_FREE; + + /* undesired combination: */ + if (bezt1->h1 == HD_ALIGN && bezt1->h2 == HD_VECT) + bezt1->h1 = HD_FREE; + if (bezt1->h2 == HD_ALIGN && bezt1->h1 == HD_VECT) + bezt1->h2 = HD_FREE; + + bezt0 = bezt1; + bezt1 = bezt2; + bezt2++; + } + + BKE_nurb_handles_calc(nu); } void BKE_nurbList_handles_autocalc(ListBase *editnurb, int flag) { - Nurb *nu; + Nurb *nu; - nu = editnurb->first; - while (nu) { - BKE_nurb_handles_autocalc(nu, flag); - nu = nu->next; - } + nu = editnurb->first; + while (nu) { + BKE_nurb_handles_autocalc(nu, flag); + nu = nu->next; + } } void BKE_nurbList_handles_set(ListBase *editnurb, const char code) { - /* code==1: set autohandle */ - /* code==2: set vectorhandle */ - /* code==3 (HD_ALIGN) it toggle, vectorhandles become HD_FREE */ - /* code==4: sets icu flag to become IPO_AUTO_HORIZ, horizontal extremes on auto-handles */ - /* code==5: Set align, like 3 but no toggle */ - /* code==6: Clear align, like 3 but no toggle */ - Nurb *nu; - BezTriple *bezt; - int a; - - if (ELEM(code, HD_AUTO, HD_VECT)) { - nu = editnurb->first; - while (nu) { - if (nu->type == CU_BEZIER) { - bezt = nu->bezt; - a = nu->pntsu; - while (a--) { - if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) { - if (bezt->f1 & SELECT) - bezt->h1 = code; - if (bezt->f3 & SELECT) - bezt->h2 = code; - if (bezt->h1 != bezt->h2) { - if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO)) - bezt->h1 = HD_FREE; - if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO)) - bezt->h2 = HD_FREE; - } - } - bezt++; - } - - /* like BKE_nurb_handles_calc but moves selected */ - nurb_handles_calc__align_selected(nu); - } - nu = nu->next; - } - } - else { - char h_new = HD_FREE; - - /* there is 1 handle not FREE: FREE it all, else make ALIGNED */ - if (code == 5) { - h_new = HD_ALIGN; - } - else if (code == 6) { - h_new = HD_FREE; - } - else { - /* Toggle */ - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - bezt = nu->bezt; - a = nu->pntsu; - while (a--) { - if (((bezt->f1 & SELECT) && bezt->h1 != HD_FREE) || - ((bezt->f3 & SELECT) && bezt->h2 != HD_FREE)) - { - h_new = HD_AUTO; - break; - } - bezt++; - } - } - } - h_new = (h_new == HD_FREE) ? HD_ALIGN : HD_FREE; - } - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - bezt = nu->bezt; - a = nu->pntsu; - while (a--) { - if (bezt->f1 & SELECT) bezt->h1 = h_new; - if (bezt->f3 & SELECT) bezt->h2 = h_new; - - bezt++; - } - - /* like BKE_nurb_handles_calc but moves selected */ - nurb_handles_calc__align_selected(nu); - } - } - } + /* code==1: set autohandle */ + /* code==2: set vectorhandle */ + /* code==3 (HD_ALIGN) it toggle, vectorhandles become HD_FREE */ + /* code==4: sets icu flag to become IPO_AUTO_HORIZ, horizontal extremes on auto-handles */ + /* code==5: Set align, like 3 but no toggle */ + /* code==6: Clear align, like 3 but no toggle */ + Nurb *nu; + BezTriple *bezt; + int a; + + if (ELEM(code, HD_AUTO, HD_VECT)) { + nu = editnurb->first; + while (nu) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) { + if (bezt->f1 & SELECT) + bezt->h1 = code; + if (bezt->f3 & SELECT) + bezt->h2 = code; + if (bezt->h1 != bezt->h2) { + if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO)) + bezt->h1 = HD_FREE; + if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO)) + bezt->h2 = HD_FREE; + } + } + bezt++; + } + + /* like BKE_nurb_handles_calc but moves selected */ + nurb_handles_calc__align_selected(nu); + } + nu = nu->next; + } + } + else { + char h_new = HD_FREE; + + /* there is 1 handle not FREE: FREE it all, else make ALIGNED */ + if (code == 5) { + h_new = HD_ALIGN; + } + else if (code == 6) { + h_new = HD_FREE; + } + else { + /* Toggle */ + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + if (((bezt->f1 & SELECT) && bezt->h1 != HD_FREE) || + ((bezt->f3 & SELECT) && bezt->h2 != HD_FREE)) { + h_new = HD_AUTO; + break; + } + bezt++; + } + } + } + h_new = (h_new == HD_FREE) ? HD_ALIGN : HD_FREE; + } + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + if (bezt->f1 & SELECT) + bezt->h1 = h_new; + if (bezt->f3 & SELECT) + bezt->h2 = h_new; + + bezt++; + } + + /* like BKE_nurb_handles_calc but moves selected */ + nurb_handles_calc__align_selected(nu); + } + } + } } void BKE_nurbList_handles_recalculate(ListBase *editnurb, const bool calc_length, const char flag) { - Nurb *nu; - BezTriple *bezt; - int a; + Nurb *nu; + BezTriple *bezt; + int a; - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - bool changed = false; + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + bool changed = false; - for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) { + for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) { - const bool h1_select = (bezt->f1 & flag) == flag; - const bool h2_select = (bezt->f3 & flag) == flag; + const bool h1_select = (bezt->f1 & flag) == flag; + const bool h2_select = (bezt->f3 & flag) == flag; - if (h1_select || h2_select) { + if (h1_select || h2_select) { - float co1_back[3], co2_back[3]; + float co1_back[3], co2_back[3]; - copy_v3_v3(co1_back, bezt->vec[0]); - copy_v3_v3(co2_back, bezt->vec[2]); + copy_v3_v3(co1_back, bezt->vec[0]); + copy_v3_v3(co2_back, bezt->vec[2]); - BKE_nurb_handle_calc_simple_auto(nu, bezt); + BKE_nurb_handle_calc_simple_auto(nu, bezt); - if (h1_select) { - if (!calc_length) { - dist_ensure_v3_v3fl(bezt->vec[0], bezt->vec[1], len_v3v3(co1_back, bezt->vec[1])); - } - } - else { - copy_v3_v3(bezt->vec[0], co1_back); - } + if (h1_select) { + if (!calc_length) { + dist_ensure_v3_v3fl(bezt->vec[0], bezt->vec[1], len_v3v3(co1_back, bezt->vec[1])); + } + } + else { + copy_v3_v3(bezt->vec[0], co1_back); + } - if (h2_select) { - if (!calc_length) { - dist_ensure_v3_v3fl(bezt->vec[2], bezt->vec[1], len_v3v3(co2_back, bezt->vec[1])); - } - } - else { - copy_v3_v3(bezt->vec[2], co2_back); - } + if (h2_select) { + if (!calc_length) { + dist_ensure_v3_v3fl(bezt->vec[2], bezt->vec[1], len_v3v3(co2_back, bezt->vec[1])); + } + } + else { + copy_v3_v3(bezt->vec[2], co2_back); + } - changed = true; - } - } + changed = true; + } + } - if (changed) { - /* Recalculate the whole curve */ - BKE_nurb_handles_calc(nu); - } - } - } + if (changed) { + /* Recalculate the whole curve */ + BKE_nurb_handles_calc(nu); + } + } + } } void BKE_nurbList_flag_set(ListBase *editnurb, short flag) { - Nurb *nu; - BezTriple *bezt; - BPoint *bp; - int a; - - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - a = nu->pntsu; - bezt = nu->bezt; - while (a--) { - bezt->f1 = bezt->f2 = bezt->f3 = flag; - bezt++; - } - } - else { - a = nu->pntsu * nu->pntsv; - bp = nu->bp; - while (a--) { - bp->f1 = flag; - bp++; - } - } - } + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + a = nu->pntsu; + bezt = nu->bezt; + while (a--) { + bezt->f1 = bezt->f2 = bezt->f3 = flag; + bezt++; + } + } + else { + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a--) { + bp->f1 = flag; + bp++; + } + } + } } void BKE_nurb_direction_switch(Nurb *nu) { - BezTriple *bezt1, *bezt2; - BPoint *bp1, *bp2; - float *fp1, *fp2, *tempf; - int a, b; - - if (nu->pntsu == 1 && nu->pntsv == 1) { - return; - } - - if (nu->type == CU_BEZIER) { - a = nu->pntsu; - bezt1 = nu->bezt; - bezt2 = bezt1 + (a - 1); - if (a & 1) a += 1; /* if odd, also swap middle content */ - a /= 2; - while (a > 0) { - if (bezt1 != bezt2) { - SWAP(BezTriple, *bezt1, *bezt2); - } - - swap_v3_v3(bezt1->vec[0], bezt1->vec[2]); - - if (bezt1 != bezt2) { - swap_v3_v3(bezt2->vec[0], bezt2->vec[2]); - } - - SWAP(char, bezt1->h1, bezt1->h2); - SWAP(char, bezt1->f1, bezt1->f3); - - if (bezt1 != bezt2) { - SWAP(char, bezt2->h1, bezt2->h2); - SWAP(char, bezt2->f1, bezt2->f3); - bezt1->tilt = -bezt1->tilt; - bezt2->tilt = -bezt2->tilt; - } - else { - bezt1->tilt = -bezt1->tilt; - } - a--; - bezt1++; - bezt2--; - } - } - else if (nu->pntsv == 1) { - a = nu->pntsu; - bp1 = nu->bp; - bp2 = bp1 + (a - 1); - a /= 2; - while (bp1 != bp2 && a > 0) { - SWAP(BPoint, *bp1, *bp2); - a--; - bp1->tilt = -bp1->tilt; - bp2->tilt = -bp2->tilt; - bp1++; - bp2--; - } - /* If there're odd number of points no need to touch coord of middle one, - * but still need to change it's tilt. - */ - if (nu->pntsu & 1) { - bp1->tilt = -bp1->tilt; - } - if (nu->type == CU_NURBS) { - /* no knots for too short paths */ - if (nu->knotsu) { - /* inverse knots */ - a = KNOTSU(nu); - fp1 = nu->knotsu; - fp2 = fp1 + (a - 1); - a /= 2; - while (fp1 != fp2 && a > 0) { - SWAP(float, *fp1, *fp2); - a--; - fp1++; - fp2--; - } - /* and make in increasing order again */ - a = KNOTSU(nu); - fp1 = nu->knotsu; - fp2 = tempf = MEM_malloc_arrayN(a, sizeof(float), "switchdirect"); - a--; - fp2[a] = fp1[a]; - while (a--) { - fp2[0] = fabsf(fp1[1] - fp1[0]); - fp1++; - fp2++; - } - - a = KNOTSU(nu) - 1; - fp1 = nu->knotsu; - fp2 = tempf; - fp1[0] = 0.0; - fp1++; - while (a--) { - fp1[0] = fp1[-1] + fp2[0]; - fp1++; - fp2++; - } - MEM_freeN(tempf); - } - } - } - else { - for (b = 0; b < nu->pntsv; b++) { - bp1 = nu->bp + b * nu->pntsu; - a = nu->pntsu; - bp2 = bp1 + (a - 1); - a /= 2; - - while (bp1 != bp2 && a > 0) { - SWAP(BPoint, *bp1, *bp2); - a--; - bp1++; - bp2--; - } - } - } + BezTriple *bezt1, *bezt2; + BPoint *bp1, *bp2; + float *fp1, *fp2, *tempf; + int a, b; + + if (nu->pntsu == 1 && nu->pntsv == 1) { + return; + } + + if (nu->type == CU_BEZIER) { + a = nu->pntsu; + bezt1 = nu->bezt; + bezt2 = bezt1 + (a - 1); + if (a & 1) + a += 1; /* if odd, also swap middle content */ + a /= 2; + while (a > 0) { + if (bezt1 != bezt2) { + SWAP(BezTriple, *bezt1, *bezt2); + } + + swap_v3_v3(bezt1->vec[0], bezt1->vec[2]); + + if (bezt1 != bezt2) { + swap_v3_v3(bezt2->vec[0], bezt2->vec[2]); + } + + SWAP(char, bezt1->h1, bezt1->h2); + SWAP(char, bezt1->f1, bezt1->f3); + + if (bezt1 != bezt2) { + SWAP(char, bezt2->h1, bezt2->h2); + SWAP(char, bezt2->f1, bezt2->f3); + bezt1->tilt = -bezt1->tilt; + bezt2->tilt = -bezt2->tilt; + } + else { + bezt1->tilt = -bezt1->tilt; + } + a--; + bezt1++; + bezt2--; + } + } + else if (nu->pntsv == 1) { + a = nu->pntsu; + bp1 = nu->bp; + bp2 = bp1 + (a - 1); + a /= 2; + while (bp1 != bp2 && a > 0) { + SWAP(BPoint, *bp1, *bp2); + a--; + bp1->tilt = -bp1->tilt; + bp2->tilt = -bp2->tilt; + bp1++; + bp2--; + } + /* If there're odd number of points no need to touch coord of middle one, + * but still need to change it's tilt. + */ + if (nu->pntsu & 1) { + bp1->tilt = -bp1->tilt; + } + if (nu->type == CU_NURBS) { + /* no knots for too short paths */ + if (nu->knotsu) { + /* inverse knots */ + a = KNOTSU(nu); + fp1 = nu->knotsu; + fp2 = fp1 + (a - 1); + a /= 2; + while (fp1 != fp2 && a > 0) { + SWAP(float, *fp1, *fp2); + a--; + fp1++; + fp2--; + } + /* and make in increasing order again */ + a = KNOTSU(nu); + fp1 = nu->knotsu; + fp2 = tempf = MEM_malloc_arrayN(a, sizeof(float), "switchdirect"); + a--; + fp2[a] = fp1[a]; + while (a--) { + fp2[0] = fabsf(fp1[1] - fp1[0]); + fp1++; + fp2++; + } + + a = KNOTSU(nu) - 1; + fp1 = nu->knotsu; + fp2 = tempf; + fp1[0] = 0.0; + fp1++; + while (a--) { + fp1[0] = fp1[-1] + fp2[0]; + fp1++; + fp2++; + } + MEM_freeN(tempf); + } + } + } + else { + for (b = 0; b < nu->pntsv; b++) { + bp1 = nu->bp + b * nu->pntsu; + a = nu->pntsu; + bp2 = bp1 + (a - 1); + a /= 2; + + while (bp1 != bp2 && a > 0) { + SWAP(BPoint, *bp1, *bp2); + a--; + bp1++; + bp2--; + } + } + } } - float (*BKE_curve_nurbs_vertexCos_get(ListBase *lb, int *r_numVerts))[3] { - int i, numVerts = *r_numVerts = BKE_nurbList_verts_count(lb); - float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos"); - Nurb *nu; - - co = cos[0]; - for (nu = lb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - BezTriple *bezt = nu->bezt; - - for (i = 0; i < nu->pntsu; i++, bezt++) { - copy_v3_v3(co, bezt->vec[0]); co += 3; - copy_v3_v3(co, bezt->vec[1]); co += 3; - copy_v3_v3(co, bezt->vec[2]); co += 3; - } - } - else { - BPoint *bp = nu->bp; - - for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) { - copy_v3_v3(co, bp->vec); co += 3; - } - } - } - - return cos; + int i, numVerts = *r_numVerts = BKE_nurbList_verts_count(lb); + float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos"); + Nurb *nu; + + co = cos[0]; + for (nu = lb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + BezTriple *bezt = nu->bezt; + + for (i = 0; i < nu->pntsu; i++, bezt++) { + copy_v3_v3(co, bezt->vec[0]); + co += 3; + copy_v3_v3(co, bezt->vec[1]); + co += 3; + copy_v3_v3(co, bezt->vec[2]); + co += 3; + } + } + else { + BPoint *bp = nu->bp; + + for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) { + copy_v3_v3(co, bp->vec); + co += 3; + } + } + } + + return cos; } void BK_curve_nurbs_vertexCos_apply(ListBase *lb, float (*vertexCos)[3]) { - const float *co = vertexCos[0]; - Nurb *nu; - int i; + const float *co = vertexCos[0]; + Nurb *nu; + int i; - for (nu = lb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - BezTriple *bezt = nu->bezt; + for (nu = lb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + BezTriple *bezt = nu->bezt; - for (i = 0; i < nu->pntsu; i++, bezt++) { - copy_v3_v3(bezt->vec[0], co); co += 3; - copy_v3_v3(bezt->vec[1], co); co += 3; - copy_v3_v3(bezt->vec[2], co); co += 3; - } - } - else { - BPoint *bp = nu->bp; + for (i = 0; i < nu->pntsu; i++, bezt++) { + copy_v3_v3(bezt->vec[0], co); + co += 3; + copy_v3_v3(bezt->vec[1], co); + co += 3; + copy_v3_v3(bezt->vec[2], co); + co += 3; + } + } + else { + BPoint *bp = nu->bp; - for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) { - copy_v3_v3(bp->vec, co); co += 3; - } - } + for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) { + copy_v3_v3(bp->vec, co); + co += 3; + } + } - calchandlesNurb_intern(nu, true); - } + calchandlesNurb_intern(nu, true); + } } float (*BKE_curve_nurbs_keyVertexCos_get(ListBase *lb, float *key))[3] { - int i, numVerts = BKE_nurbList_verts_count(lb); - float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos"); - Nurb *nu; - - co = cos[0]; - for (nu = lb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - BezTriple *bezt = nu->bezt; - - for (i = 0; i < nu->pntsu; i++, bezt++) { - copy_v3_v3(co, &key[0]); co += 3; - copy_v3_v3(co, &key[3]); co += 3; - copy_v3_v3(co, &key[6]); co += 3; - key += KEYELEM_FLOAT_LEN_BEZTRIPLE; - } - } - else { - BPoint *bp = nu->bp; - - for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) { - copy_v3_v3(co, key); co += 3; - key += KEYELEM_FLOAT_LEN_BPOINT; - } - } - } - - return cos; + int i, numVerts = BKE_nurbList_verts_count(lb); + float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos"); + Nurb *nu; + + co = cos[0]; + for (nu = lb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + BezTriple *bezt = nu->bezt; + + for (i = 0; i < nu->pntsu; i++, bezt++) { + copy_v3_v3(co, &key[0]); + co += 3; + copy_v3_v3(co, &key[3]); + co += 3; + copy_v3_v3(co, &key[6]); + co += 3; + key += KEYELEM_FLOAT_LEN_BEZTRIPLE; + } + } + else { + BPoint *bp = nu->bp; + + for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) { + copy_v3_v3(co, key); + co += 3; + key += KEYELEM_FLOAT_LEN_BPOINT; + } + } + } + + return cos; } void BKE_curve_nurbs_keyVertexTilts_apply(ListBase *lb, float *key) { - Nurb *nu; - int i; + Nurb *nu; + int i; - for (nu = lb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - BezTriple *bezt = nu->bezt; + for (nu = lb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + BezTriple *bezt = nu->bezt; - for (i = 0; i < nu->pntsu; i++, bezt++) { - bezt->tilt = key[9]; - bezt->radius = key[10]; - key += KEYELEM_FLOAT_LEN_BEZTRIPLE; - } - } - else { - BPoint *bp = nu->bp; + for (i = 0; i < nu->pntsu; i++, bezt++) { + bezt->tilt = key[9]; + bezt->radius = key[10]; + key += KEYELEM_FLOAT_LEN_BEZTRIPLE; + } + } + else { + BPoint *bp = nu->bp; - for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) { - bp->tilt = key[3]; - bp->radius = key[4]; - key += KEYELEM_FLOAT_LEN_BPOINT; - } - } - } + for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) { + bp->tilt = key[3]; + bp->radius = key[4]; + key += KEYELEM_FLOAT_LEN_BPOINT; + } + } + } } bool BKE_nurb_check_valid_u(struct Nurb *nu) { - if (nu->pntsu <= 1) - return false; - if (nu->type != CU_NURBS) - return true; /* not a nurb, lets assume its valid */ - - if (nu->pntsu < nu->orderu) return false; - if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) { /* Bezier U Endpoints */ - if (nu->orderu == 4) { - if (nu->pntsu < 5) - return false; /* bezier with 4 orderu needs 5 points */ - } - else { - if (nu->orderu != 3) - return false; /* order must be 3 or 4 */ - } - } - return true; + if (nu->pntsu <= 1) + return false; + if (nu->type != CU_NURBS) + return true; /* not a nurb, lets assume its valid */ + + if (nu->pntsu < nu->orderu) + return false; + if (((nu->flagu & CU_NURB_CYCLIC) == 0) && + (nu->flagu & CU_NURB_BEZIER)) { /* Bezier U Endpoints */ + if (nu->orderu == 4) { + if (nu->pntsu < 5) + return false; /* bezier with 4 orderu needs 5 points */ + } + else { + if (nu->orderu != 3) + return false; /* order must be 3 or 4 */ + } + } + return true; } bool BKE_nurb_check_valid_v(struct Nurb *nu) { - if (nu->pntsv <= 1) - return false; - if (nu->type != CU_NURBS) - return true; /* not a nurb, lets assume its valid */ - - if (nu->pntsv < nu->orderv) - return false; - if (((nu->flagv & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) { /* Bezier V Endpoints */ - if (nu->orderv == 4) { - if (nu->pntsv < 5) - return false; /* bezier with 4 orderu needs 5 points */ - } - else { - if (nu->orderv != 3) - return false; /* order must be 3 or 4 */ - } - } - return true; + if (nu->pntsv <= 1) + return false; + if (nu->type != CU_NURBS) + return true; /* not a nurb, lets assume its valid */ + + if (nu->pntsv < nu->orderv) + return false; + if (((nu->flagv & CU_NURB_CYCLIC) == 0) && + (nu->flagv & CU_NURB_BEZIER)) { /* Bezier V Endpoints */ + if (nu->orderv == 4) { + if (nu->pntsv < 5) + return false; /* bezier with 4 orderu needs 5 points */ + } + else { + if (nu->orderv != 3) + return false; /* order must be 3 or 4 */ + } + } + return true; } bool BKE_nurb_check_valid_uv(struct Nurb *nu) { - if (!BKE_nurb_check_valid_u(nu)) - return false; - if ((nu->pntsv > 1) && !BKE_nurb_check_valid_v(nu)) - return false; + if (!BKE_nurb_check_valid_u(nu)) + return false; + if ((nu->pntsv > 1) && !BKE_nurb_check_valid_v(nu)) + return false; - return true; + return true; } bool BKE_nurb_order_clamp_u(struct Nurb *nu) { - bool changed = false; - if (nu->pntsu < nu->orderu) { - nu->orderu = max_ii(2, nu->pntsu); - changed = true; - } - if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) { - CLAMP(nu->orderu, 3, 4); - changed = true; - } - return changed; + bool changed = false; + if (nu->pntsu < nu->orderu) { + nu->orderu = max_ii(2, nu->pntsu); + changed = true; + } + if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) { + CLAMP(nu->orderu, 3, 4); + changed = true; + } + return changed; } bool BKE_nurb_order_clamp_v(struct Nurb *nu) { - bool changed = false; - if (nu->pntsv < nu->orderv) { - nu->orderv = max_ii(2, nu->pntsv); - changed = true; - } - if (((nu->flagv & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) { - CLAMP(nu->orderv, 3, 4); - changed = true; - } - return changed; + bool changed = false; + if (nu->pntsv < nu->orderv) { + nu->orderv = max_ii(2, nu->pntsv); + changed = true; + } + if (((nu->flagv & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) { + CLAMP(nu->orderv, 3, 4); + changed = true; + } + return changed; } /** @@ -4771,608 +4876,608 @@ bool BKE_nurb_order_clamp_v(struct Nurb *nu) */ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles) { - BezTriple *bezt; - BPoint *bp; - int a, c, nr; - - if (nu->type == CU_POLY) { - if (type == CU_BEZIER) { /* to Bezier with vecthandles */ - nr = nu->pntsu; - bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2"); - nu->bezt = bezt; - a = nr; - bp = nu->bp; - while (a--) { - copy_v3_v3(bezt->vec[1], bp->vec); - bezt->f1 = bezt->f2 = bezt->f3 = bp->f1; - bezt->h1 = bezt->h2 = HD_VECT; - bezt->weight = bp->weight; - bezt->radius = bp->radius; - bp++; - bezt++; - } - MEM_freeN(nu->bp); - nu->bp = NULL; - nu->pntsu = nr; - nu->pntsv = 0; - nu->type = CU_BEZIER; - BKE_nurb_handles_calc(nu); - } - else if (type == CU_NURBS) { - nu->type = CU_NURBS; - nu->orderu = 4; - nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */ - BKE_nurb_knot_calc_u(nu); - a = nu->pntsu * nu->pntsv; - bp = nu->bp; - while (a--) { - bp->vec[3] = 1.0; - bp++; - } - } - } - else if (nu->type == CU_BEZIER) { /* Bezier */ - if (type == CU_POLY || type == CU_NURBS) { - nr = use_handles ? (3 * nu->pntsu) : nu->pntsu; - nu->bp = MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype"); - a = nu->pntsu; - bezt = nu->bezt; - bp = nu->bp; - while (a--) { - if ((type == CU_POLY && bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) || (use_handles == false)) { - /* vector handle becomes 1 poly vertice */ - copy_v3_v3(bp->vec, bezt->vec[1]); - bp->vec[3] = 1.0; - bp->f1 = bezt->f2; - if (use_handles) nr -= 2; - bp->radius = bezt->radius; - bp->weight = bezt->weight; - bp++; - } - else { - const char *f = &bezt->f1; - for (c = 0; c < 3; c++, f++) { - copy_v3_v3(bp->vec, bezt->vec[c]); - bp->vec[3] = 1.0; - bp->f1 = *f; - bp->radius = bezt->radius; - bp->weight = bezt->weight; - bp++; - } - } - bezt++; - } - MEM_freeN(nu->bezt); - nu->bezt = NULL; - nu->pntsu = nr; - nu->pntsv = 1; - nu->orderu = 4; - nu->orderv = 1; - nu->type = type; - - if (type == CU_NURBS) { - nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */ - nu->flagu |= CU_NURB_BEZIER; - BKE_nurb_knot_calc_u(nu); - } - } - } - else if (nu->type == CU_NURBS) { - if (type == CU_POLY) { - nu->type = CU_POLY; - if (nu->knotsu) MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */ - nu->knotsu = NULL; - if (nu->knotsv) MEM_freeN(nu->knotsv); - nu->knotsv = NULL; - } - else if (type == CU_BEZIER) { /* to Bezier */ - nr = nu->pntsu / 3; - - if (nr < 2) { - return false; /* conversion impossible */ - } - else { - bezt = MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2"); - nu->bezt = bezt; - a = nr; - bp = nu->bp; - while (a--) { - copy_v3_v3(bezt->vec[0], bp->vec); - bezt->f1 = bp->f1; - bp++; - copy_v3_v3(bezt->vec[1], bp->vec); - bezt->f2 = bp->f1; - bp++; - copy_v3_v3(bezt->vec[2], bp->vec); - bezt->f3 = bp->f1; - bezt->radius = bp->radius; - bezt->weight = bp->weight; - bp++; - bezt++; - } - MEM_freeN(nu->bp); - nu->bp = NULL; - MEM_freeN(nu->knotsu); - nu->knotsu = NULL; - nu->pntsu = nr; - nu->type = CU_BEZIER; - } - } - } - - return true; + BezTriple *bezt; + BPoint *bp; + int a, c, nr; + + if (nu->type == CU_POLY) { + if (type == CU_BEZIER) { /* to Bezier with vecthandles */ + nr = nu->pntsu; + bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2"); + nu->bezt = bezt; + a = nr; + bp = nu->bp; + while (a--) { + copy_v3_v3(bezt->vec[1], bp->vec); + bezt->f1 = bezt->f2 = bezt->f3 = bp->f1; + bezt->h1 = bezt->h2 = HD_VECT; + bezt->weight = bp->weight; + bezt->radius = bp->radius; + bp++; + bezt++; + } + MEM_freeN(nu->bp); + nu->bp = NULL; + nu->pntsu = nr; + nu->pntsv = 0; + nu->type = CU_BEZIER; + BKE_nurb_handles_calc(nu); + } + else if (type == CU_NURBS) { + nu->type = CU_NURBS; + nu->orderu = 4; + nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */ + BKE_nurb_knot_calc_u(nu); + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a--) { + bp->vec[3] = 1.0; + bp++; + } + } + } + else if (nu->type == CU_BEZIER) { /* Bezier */ + if (type == CU_POLY || type == CU_NURBS) { + nr = use_handles ? (3 * nu->pntsu) : nu->pntsu; + nu->bp = MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype"); + a = nu->pntsu; + bezt = nu->bezt; + bp = nu->bp; + while (a--) { + if ((type == CU_POLY && bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) || + (use_handles == false)) { + /* vector handle becomes 1 poly vertice */ + copy_v3_v3(bp->vec, bezt->vec[1]); + bp->vec[3] = 1.0; + bp->f1 = bezt->f2; + if (use_handles) + nr -= 2; + bp->radius = bezt->radius; + bp->weight = bezt->weight; + bp++; + } + else { + const char *f = &bezt->f1; + for (c = 0; c < 3; c++, f++) { + copy_v3_v3(bp->vec, bezt->vec[c]); + bp->vec[3] = 1.0; + bp->f1 = *f; + bp->radius = bezt->radius; + bp->weight = bezt->weight; + bp++; + } + } + bezt++; + } + MEM_freeN(nu->bezt); + nu->bezt = NULL; + nu->pntsu = nr; + nu->pntsv = 1; + nu->orderu = 4; + nu->orderv = 1; + nu->type = type; + + if (type == CU_NURBS) { + nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */ + nu->flagu |= CU_NURB_BEZIER; + BKE_nurb_knot_calc_u(nu); + } + } + } + else if (nu->type == CU_NURBS) { + if (type == CU_POLY) { + nu->type = CU_POLY; + if (nu->knotsu) + MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */ + nu->knotsu = NULL; + if (nu->knotsv) + MEM_freeN(nu->knotsv); + nu->knotsv = NULL; + } + else if (type == CU_BEZIER) { /* to Bezier */ + nr = nu->pntsu / 3; + + if (nr < 2) { + return false; /* conversion impossible */ + } + else { + bezt = MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2"); + nu->bezt = bezt; + a = nr; + bp = nu->bp; + while (a--) { + copy_v3_v3(bezt->vec[0], bp->vec); + bezt->f1 = bp->f1; + bp++; + copy_v3_v3(bezt->vec[1], bp->vec); + bezt->f2 = bp->f1; + bp++; + copy_v3_v3(bezt->vec[2], bp->vec); + bezt->f3 = bp->f1; + bezt->radius = bp->radius; + bezt->weight = bp->weight; + bp++; + bezt++; + } + MEM_freeN(nu->bp); + nu->bp = NULL; + MEM_freeN(nu->knotsu); + nu->knotsu = NULL; + nu->pntsu = nr; + nu->type = CU_BEZIER; + } + } + } + + return true; } /* Get edit nurbs or normal nurbs list */ ListBase *BKE_curve_nurbs_get(Curve *cu) { - if (cu->editnurb) { - return BKE_curve_editNurbs_get(cu); - } + if (cu->editnurb) { + return BKE_curve_editNurbs_get(cu); + } - return &cu->nurb; + return &cu->nurb; } void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu) { - if (nu == NULL) { - cu->actnu = CU_ACT_NONE; - } - else { - BLI_assert(!nu->hide); - ListBase *nurbs = BKE_curve_editNurbs_get(cu); - cu->actnu = BLI_findindex(nurbs, nu); - } + if (nu == NULL) { + cu->actnu = CU_ACT_NONE; + } + else { + BLI_assert(!nu->hide); + ListBase *nurbs = BKE_curve_editNurbs_get(cu); + cu->actnu = BLI_findindex(nurbs, nu); + } } Nurb *BKE_curve_nurb_active_get(Curve *cu) { - ListBase *nurbs = BKE_curve_editNurbs_get(cu); - return BLI_findlink(nurbs, cu->actnu); + ListBase *nurbs = BKE_curve_editNurbs_get(cu); + return BLI_findlink(nurbs, cu->actnu); } /* Get active vert for curve */ void *BKE_curve_vert_active_get(Curve *cu) { - Nurb *nu = NULL; - void *vert = NULL; + Nurb *nu = NULL; + void *vert = NULL; - BKE_curve_nurb_vert_active_get(cu, &nu, &vert); - return vert; + BKE_curve_nurb_vert_active_get(cu, &nu, &vert); + return vert; } int BKE_curve_nurb_vert_index_get(const Nurb *nu, const void *vert) { - if (nu->type == CU_BEZIER) { - BLI_assert(ARRAY_HAS_ITEM((BezTriple *)vert, nu->bezt, nu->pntsu)); - return (BezTriple *)vert - nu->bezt; - } - else { - BLI_assert(ARRAY_HAS_ITEM((BPoint *)vert, nu->bp, nu->pntsu * nu->pntsv)); - return (BPoint *)vert - nu->bp; - } + if (nu->type == CU_BEZIER) { + BLI_assert(ARRAY_HAS_ITEM((BezTriple *)vert, nu->bezt, nu->pntsu)); + return (BezTriple *)vert - nu->bezt; + } + else { + BLI_assert(ARRAY_HAS_ITEM((BPoint *)vert, nu->bp, nu->pntsu * nu->pntsv)); + return (BPoint *)vert - nu->bp; + } } /* Set active nurb and active vert for curve */ void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert) { - if (nu) { - BKE_curve_nurb_active_set(cu, nu); + if (nu) { + BKE_curve_nurb_active_set(cu, nu); - if (vert) { - cu->actvert = BKE_curve_nurb_vert_index_get(nu, vert); - } - else { - cu->actvert = CU_ACT_NONE; - } - } - else { - cu->actnu = cu->actvert = CU_ACT_NONE; - } + if (vert) { + cu->actvert = BKE_curve_nurb_vert_index_get(nu, vert); + } + else { + cu->actvert = CU_ACT_NONE; + } + } + else { + cu->actnu = cu->actvert = CU_ACT_NONE; + } } /* Get points to active active nurb and active vert for curve */ bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert) { - Nurb *nu = NULL; - void *vert = NULL; + Nurb *nu = NULL; + void *vert = NULL; - if (cu->actvert != CU_ACT_NONE) { - ListBase *nurbs = BKE_curve_editNurbs_get(cu); - nu = BLI_findlink(nurbs, cu->actnu); + if (cu->actvert != CU_ACT_NONE) { + ListBase *nurbs = BKE_curve_editNurbs_get(cu); + nu = BLI_findlink(nurbs, cu->actnu); - if (nu) { - if (nu->type == CU_BEZIER) { - BLI_assert(nu->pntsu > cu->actvert); - vert = &nu->bezt[cu->actvert]; - } - else { - BLI_assert((nu->pntsu * nu->pntsv) > cu->actvert); - vert = &nu->bp[cu->actvert]; - } - } - } + if (nu) { + if (nu->type == CU_BEZIER) { + BLI_assert(nu->pntsu > cu->actvert); + vert = &nu->bezt[cu->actvert]; + } + else { + BLI_assert((nu->pntsu * nu->pntsv) > cu->actvert); + vert = &nu->bp[cu->actvert]; + } + } + } - *r_nu = nu; - *r_vert = vert; + *r_nu = nu; + *r_vert = vert; - return (*r_vert != NULL); + return (*r_vert != NULL); } void BKE_curve_nurb_vert_active_validate(Curve *cu) { - Nurb *nu; - void *vert; - - if (BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) { - if (nu->type == CU_BEZIER) { - BezTriple *bezt = vert; - if (BEZT_ISSEL_ANY(bezt) == 0) { - cu->actvert = CU_ACT_NONE; - } - } - else { - BPoint *bp = vert; - if ((bp->f1 & SELECT) == 0) { - cu->actvert = CU_ACT_NONE; - } - } - - if (nu->hide) { - cu->actnu = CU_ACT_NONE; - } - } + Nurb *nu; + void *vert; + + if (BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) { + if (nu->type == CU_BEZIER) { + BezTriple *bezt = vert; + if (BEZT_ISSEL_ANY(bezt) == 0) { + cu->actvert = CU_ACT_NONE; + } + } + else { + BPoint *bp = vert; + if ((bp->f1 & SELECT) == 0) { + cu->actvert = CU_ACT_NONE; + } + } + + if (nu->hide) { + cu->actnu = CU_ACT_NONE; + } + } } /* basic vertex data functions */ bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3]) { - ListBase *nurb_lb = BKE_curve_nurbs_get(cu); - ListBase temp_nurb_lb = {NULL, NULL}; - const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0); - /* For font curves we generate temp list of splines. - * - * This is likely to be fine, this function is not supposed to be called - * often, and it's the only way to get meaningful bounds for fonts. - */ - if (is_font) { - nurb_lb = &temp_nurb_lb; - BKE_vfont_to_curve_ex(NULL, cu, FO_EDIT, nurb_lb, - NULL, NULL, NULL, NULL); - use_radius = false; - } - /* Do bounding box based on splines. */ - for (Nurb *nu = nurb_lb->first; nu; nu = nu->next) { - BKE_nurb_minmax(nu, use_radius, min, max); - } - const bool result = (BLI_listbase_is_empty(nurb_lb) == false); - /* Cleanup if needed. */ - BKE_nurbList_free(&temp_nurb_lb); - return result; + ListBase *nurb_lb = BKE_curve_nurbs_get(cu); + ListBase temp_nurb_lb = {NULL, NULL}; + const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0); + /* For font curves we generate temp list of splines. + * + * This is likely to be fine, this function is not supposed to be called + * often, and it's the only way to get meaningful bounds for fonts. + */ + if (is_font) { + nurb_lb = &temp_nurb_lb; + BKE_vfont_to_curve_ex(NULL, cu, FO_EDIT, nurb_lb, NULL, NULL, NULL, NULL); + use_radius = false; + } + /* Do bounding box based on splines. */ + for (Nurb *nu = nurb_lb->first; nu; nu = nu->next) { + BKE_nurb_minmax(nu, use_radius, min, max); + } + const bool result = (BLI_listbase_is_empty(nurb_lb) == false); + /* Cleanup if needed. */ + BKE_nurbList_free(&temp_nurb_lb); + return result; } bool BKE_curve_center_median(Curve *cu, float cent[3]) { - ListBase *nurb_lb = BKE_curve_nurbs_get(cu); - Nurb *nu; - int total = 0; - - zero_v3(cent); - - for (nu = nurb_lb->first; nu; nu = nu->next) { - int i; - - if (nu->type == CU_BEZIER) { - BezTriple *bezt; - i = nu->pntsu; - total += i * 3; - for (bezt = nu->bezt; i--; bezt++) { - add_v3_v3(cent, bezt->vec[0]); - add_v3_v3(cent, bezt->vec[1]); - add_v3_v3(cent, bezt->vec[2]); - } - } - else { - BPoint *bp; - i = nu->pntsu * nu->pntsv; - total += i; - for (bp = nu->bp; i--; bp++) { - add_v3_v3(cent, bp->vec); - } - } - } - - if (total) { - mul_v3_fl(cent, 1.0f / (float)total); - } - - return (total != 0); + ListBase *nurb_lb = BKE_curve_nurbs_get(cu); + Nurb *nu; + int total = 0; + + zero_v3(cent); + + for (nu = nurb_lb->first; nu; nu = nu->next) { + int i; + + if (nu->type == CU_BEZIER) { + BezTriple *bezt; + i = nu->pntsu; + total += i * 3; + for (bezt = nu->bezt; i--; bezt++) { + add_v3_v3(cent, bezt->vec[0]); + add_v3_v3(cent, bezt->vec[1]); + add_v3_v3(cent, bezt->vec[2]); + } + } + else { + BPoint *bp; + i = nu->pntsu * nu->pntsv; + total += i; + for (bp = nu->bp; i--; bp++) { + add_v3_v3(cent, bp->vec); + } + } + } + + if (total) { + mul_v3_fl(cent, 1.0f / (float)total); + } + + return (total != 0); } bool BKE_curve_center_bounds(Curve *cu, float cent[3]) { - float min[3], max[3]; - INIT_MINMAX(min, max); - if (BKE_curve_minmax(cu, false, min, max)) { - mid_v3_v3v3(cent, min, max); - return true; - } + float min[3], max[3]; + INIT_MINMAX(min, max); + if (BKE_curve_minmax(cu, false, min, max)) { + mid_v3_v3v3(cent, min, max); + return true; + } - return false; + return false; } - void BKE_curve_transform_ex( - Curve *cu, float mat[4][4], - const bool do_keys, const bool do_props, const 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]); - if (do_props) { - 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_props) { - bp->radius *= unit_scale; - } - } - } - } - - if (do_keys && cu->key) { - KeyBlock *kb; - for (kb = cu->key->block.first; kb; kb = kb->next) { - float *fp = kb->data; - int n = kb->totelem; - - for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) { - mul_m4_v3(mat, &fp[0]); - mul_m4_v3(mat, &fp[3]); - mul_m4_v3(mat, &fp[6]); - if (do_props) { - fp[10] *= unit_scale; /* radius */ - } - fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; - } - } - else { - for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) { - mul_m4_v3(mat, fp); - if (do_props) { - fp[4] *= unit_scale; /* radius */ - } - fp += KEYELEM_FLOAT_LEN_BPOINT; - } - } - } - } - } -} - -void BKE_curve_transform( - Curve *cu, float mat[4][4], - const bool do_keys, const bool do_props) -{ - float unit_scale = mat4_to_scale(mat); - BKE_curve_transform_ex(cu, mat, do_keys, do_props, unit_scale); + Curve *cu, float mat[4][4], const bool do_keys, const bool do_props, const 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]); + if (do_props) { + 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_props) { + bp->radius *= unit_scale; + } + } + } + } + + if (do_keys && cu->key) { + KeyBlock *kb; + for (kb = cu->key->block.first; kb; kb = kb->next) { + float *fp = kb->data; + int n = kb->totelem; + + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) { + mul_m4_v3(mat, &fp[0]); + mul_m4_v3(mat, &fp[3]); + mul_m4_v3(mat, &fp[6]); + if (do_props) { + fp[10] *= unit_scale; /* radius */ + } + fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; + } + } + else { + for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) { + mul_m4_v3(mat, fp); + if (do_props) { + fp[4] *= unit_scale; /* radius */ + } + fp += KEYELEM_FLOAT_LEN_BPOINT; + } + } + } + } + } +} + +void BKE_curve_transform(Curve *cu, float mat[4][4], const bool do_keys, const bool do_props) +{ + float unit_scale = mat4_to_scale(mat); + BKE_curve_transform_ex(cu, mat, do_keys, do_props, unit_scale); } void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys) { - ListBase *nurb_lb = BKE_curve_nurbs_get(cu); - Nurb *nu; - int i; - - for (nu = nurb_lb->first; nu; nu = nu->next) { - BezTriple *bezt; - BPoint *bp; - - if (nu->type == CU_BEZIER) { - i = nu->pntsu; - for (bezt = nu->bezt; i--; bezt++) { - add_v3_v3(bezt->vec[0], offset); - add_v3_v3(bezt->vec[1], offset); - add_v3_v3(bezt->vec[2], offset); - } - } - else { - i = nu->pntsu * nu->pntsv; - for (bp = nu->bp; i--; bp++) { - add_v3_v3(bp->vec, offset); - } - } - } - - if (do_keys && cu->key) { - KeyBlock *kb; - for (kb = cu->key->block.first; kb; kb = kb->next) { - float *fp = kb->data; - int n = kb->totelem; - - for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) { - add_v3_v3(&fp[0], offset); - add_v3_v3(&fp[3], offset); - add_v3_v3(&fp[6], offset); - fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; - } - } - else { - for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) { - add_v3_v3(fp, offset); - fp += KEYELEM_FLOAT_LEN_BPOINT; - } - } - } - } - } + ListBase *nurb_lb = BKE_curve_nurbs_get(cu); + Nurb *nu; + int i; + + for (nu = nurb_lb->first; nu; nu = nu->next) { + BezTriple *bezt; + BPoint *bp; + + if (nu->type == CU_BEZIER) { + i = nu->pntsu; + for (bezt = nu->bezt; i--; bezt++) { + add_v3_v3(bezt->vec[0], offset); + add_v3_v3(bezt->vec[1], offset); + add_v3_v3(bezt->vec[2], offset); + } + } + else { + i = nu->pntsu * nu->pntsv; + for (bp = nu->bp; i--; bp++) { + add_v3_v3(bp->vec, offset); + } + } + } + + if (do_keys && cu->key) { + KeyBlock *kb; + for (kb = cu->key->block.first; kb; kb = kb->next) { + float *fp = kb->data; + int n = kb->totelem; + + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) { + add_v3_v3(&fp[0], offset); + add_v3_v3(&fp[3], offset); + add_v3_v3(&fp[6], offset); + fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; + } + } + else { + for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) { + add_v3_v3(fp, offset); + fp += KEYELEM_FLOAT_LEN_BPOINT; + } + } + } + } + } } void BKE_curve_material_index_remove(Curve *cu, int index) { - const int curvetype = BKE_curve_type_get(cu); + const int curvetype = BKE_curve_type_get(cu); - if (curvetype == OB_FONT) { - struct CharInfo *info = cu->strinfo; - int i; - for (i = cu->len_wchar - 1; i >= 0; i--, info++) { - if (info->mat_nr && info->mat_nr >= index) { - info->mat_nr--; - } - } - } - else { - Nurb *nu; + if (curvetype == OB_FONT) { + struct CharInfo *info = cu->strinfo; + int i; + for (i = cu->len_wchar - 1; i >= 0; i--, info++) { + if (info->mat_nr && info->mat_nr >= index) { + info->mat_nr--; + } + } + } + else { + Nurb *nu; - for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu->mat_nr && nu->mat_nr >= index) { - nu->mat_nr--; - } - } - } + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->mat_nr && nu->mat_nr >= index) { + nu->mat_nr--; + } + } + } } void BKE_curve_material_index_clear(Curve *cu) { - const int curvetype = BKE_curve_type_get(cu); + const int curvetype = BKE_curve_type_get(cu); - if (curvetype == OB_FONT) { - struct CharInfo *info = cu->strinfo; - int i; - for (i = cu->len_wchar - 1; i >= 0; i--, info++) { - info->mat_nr = 0; - } - } - else { - Nurb *nu; + if (curvetype == OB_FONT) { + struct CharInfo *info = cu->strinfo; + int i; + for (i = cu->len_wchar - 1; i >= 0; i--, info++) { + info->mat_nr = 0; + } + } + else { + Nurb *nu; - for (nu = cu->nurb.first; nu; nu = nu->next) { - nu->mat_nr = 0; - } - } + for (nu = cu->nurb.first; nu; nu = nu->next) { + nu->mat_nr = 0; + } + } } bool 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; - is_valid = false; - } - } - } - - if (!is_valid) { - DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY); - return true; - } - else { - return false; - } + 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; + is_valid = false; + } + } + } + + if (!is_valid) { + DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY); + return true; + } + else { + return false; + } } void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int remap_len) { - const int curvetype = BKE_curve_type_get(cu); - const short remap_len_short = (short)remap_len; + const int curvetype = BKE_curve_type_get(cu); + const short remap_len_short = (short)remap_len; #define MAT_NR_REMAP(n) \ - if (n < remap_len_short) { \ - BLI_assert(n >= 0 && remap[n] < remap_len_short); \ - n = remap[n]; \ - } ((void)0) - - if (curvetype == OB_FONT) { - struct CharInfo *strinfo; - int charinfo_len, i; - - if (cu->editfont) { - EditFont *ef = cu->editfont; - strinfo = ef->textbufinfo; - charinfo_len = ef->len; - } - else { - strinfo = cu->strinfo; - charinfo_len = cu->len_wchar; - } - - for (i = 0; i <= charinfo_len; i++) { - if (strinfo[i].mat_nr > 0) { - strinfo[i].mat_nr -= 1; - MAT_NR_REMAP(strinfo[i].mat_nr); - strinfo[i].mat_nr += 1; - } - } - } - else { - Nurb *nu; - ListBase *nurbs = BKE_curve_editNurbs_get(cu); - - if (nurbs) { - for (nu = nurbs->first; nu; nu = nu->next) { - MAT_NR_REMAP(nu->mat_nr); - } - } - } + if (n < remap_len_short) { \ + BLI_assert(n >= 0 && remap[n] < remap_len_short); \ + n = remap[n]; \ + } \ + ((void)0) + + if (curvetype == OB_FONT) { + struct CharInfo *strinfo; + int charinfo_len, i; + + if (cu->editfont) { + EditFont *ef = cu->editfont; + strinfo = ef->textbufinfo; + charinfo_len = ef->len; + } + else { + strinfo = cu->strinfo; + charinfo_len = cu->len_wchar; + } + + for (i = 0; i <= charinfo_len; i++) { + if (strinfo[i].mat_nr > 0) { + strinfo[i].mat_nr -= 1; + MAT_NR_REMAP(strinfo[i].mat_nr); + strinfo[i].mat_nr += 1; + } + } + } + else { + Nurb *nu; + ListBase *nurbs = BKE_curve_editNurbs_get(cu); + + if (nurbs) { + for (nu = nurbs->first; nu; nu = nu->next) { + MAT_NR_REMAP(nu->mat_nr); + } + } + } #undef MAT_NR_REMAP - } -void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect) +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; - r_rect->ymax = cu->yof + tb->y + cu->fsize; + r_rect->xmin = cu->xof + tb->x; + r_rect->ymax = cu->yof + tb->y + cu->fsize; - r_rect->xmax = r_rect->xmin + tb->w; - r_rect->ymin = r_rect->ymax - tb->h; + r_rect->xmax = r_rect->xmin + tb->w; + r_rect->ymin = r_rect->ymax - tb->h; } /* **** Depsgraph evaluation **** */ -void BKE_curve_eval_geometry(Depsgraph *depsgraph, - Curve *curve) +void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve) { - DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve); - if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) { - BKE_curve_texspace_calc(curve); - } + DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve); + if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) { + BKE_curve_texspace_calc(curve); + } } /* Draw Engine */ @@ -5381,13 +5486,13 @@ void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL; void BKE_curve_batch_cache_dirty_tag(Curve *cu, int mode) { - if (cu->batch_cache) { - BKE_curve_batch_cache_dirty_tag_cb(cu, mode); - } + if (cu->batch_cache) { + BKE_curve_batch_cache_dirty_tag_cb(cu, mode); + } } void BKE_curve_batch_cache_free(Curve *cu) { - if (cu->batch_cache) { - BKE_curve_batch_cache_free_cb(cu); - } + if (cu->batch_cache) { + BKE_curve_batch_cache_free_cb(cu); + } } |