Welcome to mirror list, hosted at ThFree Co, Russian Federation.

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