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/modifiers/intern/MOD_array.c')
-rw-r--r--source/blender/modifiers/intern/MOD_array.c307
1 files changed, 216 insertions, 91 deletions
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 621be8023a2..d552e73bc32 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -162,6 +162,51 @@ static float vertarray_size(MVert *mvert, int numVerts, int axis)
return max_co - min_co;
}
+static int *find_doubles_index_map(BMesh *bm, BMOperator *dupe_op,
+ const ArrayModifierData *amd,
+ int *index_map_length)
+{
+ BMOperator find_op;
+ BMOIter oiter;
+ BMVert *v, *v2;
+ BMElem *ele;
+ int *index_map, i;
+
+ BMO_op_initf(bm, &find_op,
+ "finddoubles verts=%av dist=%f keepverts=%s",
+ amd->merge_dist, dupe_op, "geom");
+
+ BMO_op_exec(bm, &find_op);
+
+ i = 0;
+ BMO_ITER(ele, &oiter, bm, dupe_op, "geom", BM_ALL) {
+ BM_elem_index_set(ele, i); /* set_dirty */
+ i++;
+ }
+
+ BMO_ITER(ele, &oiter, bm, dupe_op, "newout", BM_ALL) {
+ BM_elem_index_set(ele, i); /* set_dirty */
+ i++;
+ }
+ /* above loops over all, so set all to dirty, if this is somehow
+ * setting valid values, this line can be remvoed - campbell */
+ bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
+
+ (*index_map_length) = i;
+ index_map = MEM_callocN(sizeof(int) * (*index_map_length), "index_map");
+
+ /*element type argument doesn't do anything here*/
+ BMO_ITER(v, &oiter, bm, &find_op, "targetmapout", 0) {
+ v2 = BMO_iter_map_value_p(&oiter);
+
+ index_map[BM_elem_index_get(v)] = BM_elem_index_get(v2) + 1;
+ }
+
+ BMO_op_finish(bm, &find_op);
+
+ return index_map;
+}
+
/* Used for start/end cap.
*
* this function expects all existing vertices to be tagged,
@@ -169,29 +214,97 @@ static float vertarray_size(MVert *mvert, int numVerts, int axis)
*
* All verts will be tagged on exit.
*/
-static void bm_merge_dm_transform(BMesh* bm, DerivedMesh *dm, float mat[4][4])
+static void bm_merge_dm_transform(BMesh* bm, DerivedMesh *dm, float mat[4][4],
+ const ArrayModifierData *amd,
+ BMOperator *dupe_op,
+ const char *dupe_slot_name,
+ BMOperator *weld_op)
{
- BMVert *v;
+ BMVert *v, *v2;
BMIter iter;
DM_to_bmesh_ex(dm, bm);
- /* transform all verts */
- BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
- if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
- mul_m4_v3(mat, v->co);
- BM_elem_flag_enable(v, BM_ELEM_TAG);
+ if (amd->flags & MOD_ARR_MERGE) {
+ /* if merging is enabled, find doubles */
+
+ BMOIter oiter;
+ BMOperator find_op;
+
+ BMO_op_initf(bm, &find_op,
+ "finddoubles verts=%Hv dist=%f keepverts=%s",
+ BM_ELEM_TAG, amd->merge_dist,
+ dupe_op, dupe_slot_name);
+
+ /* append the dupe's geom to the findop input verts */
+ BMO_slot_buffer_append(&find_op, "verts", dupe_op, dupe_slot_name);
+
+ /* transform and tag verts */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ mul_m4_v3(mat, v->co);
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
+ }
+
+ BMO_op_exec(bm, &find_op);
+
+ /* add new merge targets to weld operator */
+ BMO_ITER(v, &oiter, bm, &find_op, "targetmapout", 0) {
+ v2 = BMO_iter_map_value_p(&oiter);
+ BMO_slot_map_ptr_insert(bm, weld_op, "targetmap", v, v2);
+ }
+
+ BMO_op_finish(bm, &find_op);
+ }
+ else {
+ /* transform and tag verts */
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ mul_m4_v3(mat, v->co);
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
}
}
}
+static void merge_first_last(BMesh* bm,
+ const ArrayModifierData *amd,
+ BMOperator *dupe_first,
+ BMOperator *dupe_last,
+ BMOperator *weld_op)
+{
+ BMOperator find_op;
+ BMOIter oiter;
+ BMVert *v, *v2;
+
+ BMO_op_initf(bm, &find_op,
+ "finddoubles verts=%s dist=%f keepverts=%s",
+ dupe_first, "geom", amd->merge_dist,
+ dupe_first, "geom");
+
+ /* append the last dupe's geom to the findop input verts */
+ BMO_slot_buffer_append(&find_op, "verts", dupe_last, "newout");
+
+ BMO_op_exec(bm, &find_op);
+
+ /* add new merge targets to weld operator */
+ BMO_ITER(v, &oiter, bm, &find_op, "targetmapout", 0) {
+ v2 = BMO_iter_map_value_p(&oiter);
+ BMO_slot_map_ptr_insert(bm, weld_op, "targetmap", v, v2);
+ }
+
+ BMO_op_finish(bm, &find_op);
+}
+
static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
Scene *scene, Object *ob, DerivedMesh *dm,
int UNUSED(initFlags))
{
DerivedMesh *result;
BMEditMesh *em = DM_to_editbmesh(dm, NULL, FALSE);
- BMOperator op, oldop, weldop;
+ BMOperator first_dupe_op, dupe_op, old_dupe_op, weld_op;
+ BMVert **first_geom = NULL;
int i, j, indexLen;
/* offset matrix */
float offset[4][4];
@@ -237,14 +350,6 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
copy_m4_m4(offset, result_mat);
}
- /* calculate the offset matrix of the final copy (for merging) */
- unit_m4(final_offset);
-
- for (j=0; j < count - 1; j++) {
- mult_m4_m4m4(tmp_mat, offset, final_offset);
- copy_m4_m4(final_offset, tmp_mat);
- }
-
if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
Curve *cu = amd->curve_ob->data;
if (cu) {
@@ -281,6 +386,14 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
if (count < 1)
count = 1;
+ /* calculate the offset matrix of the final copy (for merging) */
+ unit_m4(final_offset);
+
+ for (j=0; j < count - 1; j++) {
+ mult_m4_m4m4(tmp_mat, offset, final_offset);
+ copy_m4_m4(final_offset, tmp_mat);
+ }
+
/* BMESH_TODO: bumping up the stack level avoids computing the normals
* after every top-level operator execution (and this modifier has the
* potential to execute a *lot* of top-level BMOps. There should be a
@@ -290,118 +403,118 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
BMO_push(em->bm, NULL);
bmesh_edit_begin(em->bm, 0);
- BMO_op_init(em->bm, &weldop, "weldverts");
- BMO_op_initf(em->bm, &op, "dupe geom=%avef");
- oldop = op;
- for (j=0; j < count - 1; j++) {
- BMVert *v, *v2;
- BMOpSlot *s1;
- BMOpSlot *s2;
-
- BMO_op_initf(em->bm, &op, "dupe geom=%s", &oldop, j==0 ? "geom" : "newout");
- BMO_op_exec(em->bm, &op);
+ if (amd->flags & MOD_ARR_MERGE)
+ BMO_op_init(em->bm, &weld_op, "weldverts");
- s1 = BMO_slot_get(&op, "geom");
- s2 = BMO_slot_get(&op, "newout");
+ BMO_op_initf(em->bm, &dupe_op, "dupe geom=%avef");
+ first_dupe_op = dupe_op;
- BMO_op_callf(em->bm, "transform mat=%m4 verts=%s", offset, &op, "newout");
+ for (j=0; j < count - 1; j++) {
+ BMVert *v, *v2, *v3;
+ BMOpSlot *geom_slot;
+ BMOpSlot *newout_slot;
+ BMOIter oiter;
- #define _E(s, i) ((BMVert **)(s)->data.buf)[i]
+ if (j != 0)
+ BMO_op_initf(em->bm, &dupe_op, "dupe geom=%s", &old_dupe_op, "newout");
+ BMO_op_exec(em->bm, &dupe_op);
- /*calculate merge mapping*/
- if (j == 0) {
- BMOperator findop;
- BMOIter oiter;
- BMVert *v, *v2;
- BMElem *ele;
+ geom_slot = BMO_slot_get(&dupe_op, "geom");
+ newout_slot = BMO_slot_get(&dupe_op, "newout");
- BMO_op_initf(em->bm, &findop,
- "finddoubles verts=%av dist=%f keepverts=%s",
- amd->merge_dist, &op, "geom");
+ if ((amd->flags & MOD_ARR_MERGEFINAL) && j == 0) {
+ int first_geom_bytes = sizeof(BMVert*) * geom_slot->len;
+
+ /* make a copy of the initial geometry ordering so the
+ last duplicate can be merged into it */
+ first_geom = MEM_mallocN(first_geom_bytes, "first_geom");
+ memcpy(first_geom, geom_slot->data.buf, first_geom_bytes);
+ }
- i = 0;
- BMO_ITER(ele, &oiter, em->bm, &op, "geom", BM_ALL) {
- BM_elem_index_set(ele, i); /* set_dirty */
- i++;
- }
+ /* apply transformation matrix */
+ BMO_ITER(v, &oiter, em->bm, &dupe_op, "newout", BM_VERT) {
+ mul_m4_v3(offset, v->co);
+ }
- BMO_ITER(ele, &oiter, em->bm, &op, "newout", BM_ALL) {
- BM_elem_index_set(ele, i); /* set_dirty */
- i++;
+ if (amd->flags & MOD_ARR_MERGE) {
+ /*calculate merge mapping*/
+ if (j == 0) {
+ indexMap = find_doubles_index_map(em->bm, &dupe_op,
+ amd, &indexLen);
}
- /* above loops over all, so set all to dirty, if this is somehow
- * setting valid values, this line can be remvoed - campbell */
- em->bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
+ #define _E(s, i) ((BMVert **)(s)->data.buf)[i]
- BMO_op_exec(em->bm, &findop);
+ for (i=0; i<indexLen; i++) {
+ if (!indexMap[i]) continue;
- indexLen = i;
- indexMap = MEM_callocN(sizeof(int)*indexLen, "indexMap");
+ /* merge v (from 'newout') into v2 (from old 'geom') */
+ v = _E(newout_slot, i - geom_slot->len);
+ v2 = _E(geom_slot, indexMap[i]-1);
- /*element type argument doesn't do anything here*/
- BMO_ITER(v, &oiter, em->bm, &findop, "targetmapout", 0) {
- v2 = BMO_iter_map_value_p(&oiter);
+ /* check in case the target vertex (v2) is already marked
+ for merging */
+ while((v3 = BMO_slot_map_ptr_get(em->bm, &weld_op, "targetmap", v2)))
+ v2 = v3;
- indexMap[BM_elem_index_get(v)] = BM_elem_index_get(v2)+1;
+ BMO_slot_map_ptr_insert(em->bm, &weld_op, "targetmap", v, v2);
}
- BMO_op_finish(em->bm, &findop);
+ #undef _E
}
- /* generate merge mapping using index map. we do this by using the
- * operator slots as lookup arrays.*/
- #define E(i) (i) < s1->len ? _E(s1, i) : _E(s2, (i)-s1->len)
-
- for (i=0; i<indexLen; i++) {
- if (!indexMap[i]) continue;
-
- v = E(i);
- v2 = E(indexMap[i]-1);
-
- BMO_slot_map_ptr_insert(em->bm, &weldop, "targetmap", v, v2);
- }
-
- #undef E
- #undef _E
-
- BMO_op_finish(em->bm, &oldop);
- oldop = op;
+ /* already copied earlier, but after executation more slot
+ memory may be allocated */
+ if (j == 0)
+ first_dupe_op = dupe_op;
+
+ if (j >= 2)
+ BMO_op_finish(em->bm, &old_dupe_op);
+ old_dupe_op = dupe_op;
}
- if (j > 0) BMO_op_finish(em->bm, &op);
+ if ((amd->flags & MOD_ARR_MERGE) &&
+ (amd->flags & MOD_ARR_MERGEFINAL) &&
+ (count > 1)) {
+ /* Merge first and last copies. Note that we can't use the
+ indexMap for this because (unless the array is forming a
+ loop) the offset between first and last is different from
+ dupe X to dupe X+1. */
- /* BMESH_TODO - cap ends are not welded, even though weld is called after */
+ merge_first_last(em->bm, amd, &first_dupe_op, &dupe_op, &weld_op);
+ }
/* start capping */
- if ((start_cap || end_cap) &&
-
- /* BMESH_TODO - theres a bug in DM_to_bmesh_ex() when in editmode!
- * this needs investigation, but for now at least don't crash */
- ob->mode != OB_MODE_EDIT
-
- )
+ if (start_cap || end_cap)
{
BM_mesh_elem_flag_enable_all(em->bm, BM_VERT, BM_ELEM_TAG);
if (start_cap) {
float startoffset[4][4];
invert_m4_m4(startoffset, offset);
- bm_merge_dm_transform(em->bm, start_cap, startoffset);
+ bm_merge_dm_transform(em->bm, start_cap, startoffset, amd,
+ &first_dupe_op, "geom", &weld_op);
}
if (end_cap) {
float endoffset[4][4];
mult_m4_m4m4(endoffset, offset, final_offset);
- bm_merge_dm_transform(em->bm, end_cap, endoffset);
+ bm_merge_dm_transform(em->bm, end_cap, endoffset, amd,
+ &dupe_op, count == 1 ? "geom" : "newout", &weld_op);
}
}
/* done capping */
- if (amd->flags & MOD_ARR_MERGE)
- BMO_op_exec(em->bm, &weldop);
+ /* free remaining dupe operators */
+ BMO_op_finish(em->bm, &first_dupe_op);
+ if (count > 2)
+ BMO_op_finish(em->bm, &dupe_op);
- BMO_op_finish(em->bm, &weldop);
+ /* run merge operator */
+ if (amd->flags & MOD_ARR_MERGE) {
+ BMO_op_exec(em->bm, &weld_op);
+ BMO_op_finish(em->bm, &weld_op);
+ }
/* Bump the stack level back down to match the adjustment up above */
BMO_pop(em->bm);
@@ -409,9 +522,21 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
BLI_assert(em->looptris == NULL);
result = CDDM_from_BMEditMesh(em, NULL, FALSE, FALSE);
+ if ((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
+ /* Update normals in case offset object has rotation. */
+
+ /* BMESH_TODO: check if normal recalc needed under any other
+ conditions? */
+
+ CDDM_calc_normals(result);
+ }
+
BMEdit_Free(em);
MEM_freeN(em);
- MEM_freeN(indexMap);
+ if (indexMap)
+ MEM_freeN(indexMap);
+ if (first_geom)
+ MEM_freeN(first_geom);
return result;
}