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:
authorNicholas Bishop <nicholasbishop@gmail.com>2012-03-30 21:30:56 +0400
committerNicholas Bishop <nicholasbishop@gmail.com>2012-03-30 21:30:56 +0400
commitebb229110e4af5d2df5613b6345da2f602b90092 (patch)
treeb9df208897dbc4d05a383421a4443c5f367be049 /source/blender/modifiers/intern
parentc7aed8b2af38f7b99f9df9d8e18006421ccb900e (diff)
Fix bug 30195, Array modifier fails to merge vertices.
All cases should work now -- that's adjacent duplicate merging, first-last duplicate merging, and start/end cap merging. A lot of complexity really, wonder if it might not be better to just do a full "remove doubles" rather than try to match pre-BMesh behavior exactly.
Diffstat (limited to 'source/blender/modifiers/intern')
-rw-r--r--source/blender/modifiers/intern/MOD_array.c180
1 files changed, 121 insertions, 59 deletions
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index ceae07f1f43..84b5d7deb6f 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -162,30 +162,6 @@ static float vertarray_size(MVert *mvert, int numVerts, int axis)
return max_co - min_co;
}
-/* Used for start/end cap.
- *
- * this function expects all existing vertices to be tagged,
- * so we can know new verts are not tagged.
- *
- * All verts will be tagged on exit.
- */
-static void bm_merge_dm_transform(BMesh* bm, DerivedMesh *dm, float mat[4][4])
-{
- BMVert *v;
- 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);
- }
- }
-}
-
-
static int *find_doubles_index_map(BMesh *bm, BMOperator *dupe_op,
const ArrayModifierData *amd,
int *index_map_length)
@@ -231,6 +207,95 @@ static int *find_doubles_index_map(BMesh *bm, BMOperator *dupe_op,
return index_map;
}
+/* Used for start/end cap.
+ *
+ * this function expects all existing vertices to be tagged,
+ * so we can know new verts are not tagged.
+ *
+ * All verts will be tagged on exit.
+ */
+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, *v2;
+ BMIter iter;
+
+ DM_to_bmesh_ex(dm, bm);
+
+ 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,
@@ -238,7 +303,7 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
{
DerivedMesh *result;
BMEditMesh *em = DM_to_editbmesh(dm, NULL, FALSE);
- BMOperator dupe_op, old_dupe_op, weld_op;
+ BMOperator first_dupe_op, dupe_op, old_dupe_op, weld_op;
BMVert **first_geom = NULL;
int i, j, indexLen;
/* offset matrix */
@@ -340,15 +405,16 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
if (amd->flags & MOD_ARR_MERGE)
BMO_op_init(em->bm, &weld_op, "weldverts");
-
+
+ BMO_op_initf(em->bm, &dupe_op, "dupe geom=%avef");
+ first_dupe_op = dupe_op;
+
for (j=0; j < count - 1; j++) {
BMVert *v, *v2, *v3;
BMOpSlot *geom_slot;
BMOpSlot *newout_slot;
- if (j == 0)
- BMO_op_initf(em->bm, &dupe_op, "dupe geom=%avef");
- else
+ if (j != 0)
BMO_op_initf(em->bm, &dupe_op, "dupe geom=%s", &old_dupe_op, "newout");
BMO_op_exec(em->bm, &dupe_op);
@@ -390,61 +456,57 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
BMO_slot_map_ptr_insert(em->bm, &weld_op, "targetmap", v, v2);
}
- if ((amd->flags & MOD_ARR_MERGEFINAL) && j == count - 2) {
- /* special case for merging first and last */
- for (i=0; i < indexLen; i++) {
- if (!indexMap[i]) continue;
-
- /* merge v (from 'newout') into v2 (from XXX) */
- v = _E(newout_slot, indexMap[i]-1);
- v2 = first_geom[i - geom_slot->len];
-
- /* 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;
-
- BMO_slot_map_ptr_insert(em->bm, &weld_op, "targetmap", v, v2);
- }
- }
-
#undef _E
}
- if (j != 0)
+ /* 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, &dupe_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 */
+ /* free remaining dupe operators */
+ BMO_op_finish(em->bm, &first_dupe_op);
+ if (count > 2)
+ BMO_op_finish(em->bm, &dupe_op);
+
+ /* run merge operator */
if (amd->flags & MOD_ARR_MERGE) {
BMO_op_exec(em->bm, &weld_op);
BMO_op_finish(em->bm, &weld_op);