add un-subdivude as an optional method for the decimate modifier, gives more even...
authorCampbell Barton <ideasman42@gmail.com>
Tue, 23 Oct 2012 04:26:39 +0000 (04:26 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 23 Oct 2012 04:26:39 +0000 (04:26 +0000)
release/scripts/startup/bl_ui/properties_data_modifier.py
source/blender/bmesh/CMakeLists.txt
source/blender/bmesh/intern/bmesh_decimate.h
source/blender/bmesh/intern/bmesh_decimate_collapse.c
source/blender/bmesh/intern/bmesh_decimate_unsubdivide.c [new file with mode: 0644]
source/blender/bmesh/operators/bmo_unsubdivide.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/intern/makesdna.c
source/blender/makesrna/intern/rna_modifier.c
source/blender/modifiers/intern/MOD_decimate.c

index 5d8144631b024315effd925f6f46bd3e4ef59c72..1887c4786be5241acd3233d3b4c8ee99b3af3ce4 100644 (file)
@@ -211,10 +211,17 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
         layout.row().prop(md, "deform_axis", expand=True)
 
     def DECIMATE(self, layout, ob, md):
-        layout.prop(md, "ratio")
         row = layout.row()
-        row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
-        row.prop(md, "invert_vertex_group")
+        row.prop(md, "decimate_type", expand=True)
+
+        if md.decimate_type == 'COLLAPSE':
+            layout.prop(md, "ratio")
+            row = layout.row()
+            row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+            row.prop(md, "invert_vertex_group")
+        else:  # assume UNSUBDIV
+            layout.prop(md, "iterations")
+
         layout.label(text="Face Count" + ": %d" % md.face_count)
 
     def DISPLACE(self, layout, ob, md):
index 3e0985471e11fcd55412e864288b0e248756a5f5..a000cb59167da4bf996faf0cdeca108d6715bd48 100644 (file)
@@ -65,6 +65,7 @@ set(SRC
        intern/bmesh_core.c
        intern/bmesh_core.h
        intern/bmesh_decimate_collapse.c
+       intern/bmesh_decimate_unsubdivide.c
        intern/bmesh_decimate.h
        intern/bmesh_inline.h
        intern/bmesh_interp.c
index 7fafb752e1ea5636eae174ca5722ba05181361cf..18d86cfb1a5fedd5b10b4931e67e92c24f1b7522 100644 (file)
@@ -29,4 +29,7 @@
 
 void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights);
 
+void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const int tag_only);
+void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations);
+
 #endif /* __BMESH_DECIMATE_H__ */
index 75fe12a418a8b6959c69a6dae3b5b8cf9d97ee2a..ce10fe2fed14b3c1479d3130ce96424a3f7b6b2e 100644 (file)
  * ***** END GPL LICENSE BLOCK *****
  */
 
-/** \file blender/bmesh/intern/bmesh_decimate.c
+/** \file blender/bmesh/intern/bmesh_decimate_collapse.c
  *  \ingroup bmesh
  *
- * BMesh decimator.
+ * BMesh decimator that uses an edge collapse method.
  */
 
 #include <stddef.h>
diff --git a/source/blender/bmesh/intern/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/intern/bmesh_decimate_unsubdivide.c
new file mode 100644 (file)
index 0000000..18bfa51
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_decimate_unsubdivide.c
+ *  \ingroup bmesh
+ *
+ * BMesh decimator that uses a grid un-subdivide method.
+ */
+
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "bmesh.h"
+
+#include "intern/bmesh_operators_private.h" /* own include */
+
+
+static int bm_vert_dissolve_fan_test(BMVert *v)
+{
+       /* check if we should walk over these verts */
+       BMIter iter;
+       BMEdge *e;
+
+       unsigned int tot_edge = 0;
+       unsigned int tot_edge_boundary = 0;
+       unsigned int tot_edge_manifold = 0;
+       unsigned int tot_edge_wire     = 0;
+
+       BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+               if (BM_edge_is_boundary(e)) {
+                       tot_edge_boundary++;
+               }
+               else if (BM_edge_is_manifold(e)) {
+                       tot_edge_manifold++;
+               }
+               else if (BM_edge_is_wire(e)) {
+                       tot_edge_wire++;
+               }
+               tot_edge++;
+       }
+
+       if ((tot_edge == 4) && (tot_edge_boundary == 0) && (tot_edge_manifold == 4)) {
+               return TRUE;
+       }
+       else if ((tot_edge == 3) && (tot_edge_boundary == 0) && (tot_edge_manifold == 3)) {
+               return TRUE;
+       }
+       else if ((tot_edge == 3) && (tot_edge_boundary == 2) && (tot_edge_manifold == 1)) {
+               return TRUE;
+       }
+       else if ((tot_edge == 2) && (tot_edge_wire == 2)) {
+               return TRUE;
+       }
+       return FALSE;
+}
+
+static int bm_vert_dissolve_fan(BMesh *bm, BMVert *v)
+{
+       /* collapse under 2 conditions.
+        * - vert connects to 4 manifold edges (and 4 faces).
+        * - vert connecrs to 1 manifold edge, 2 boundary edges (and 2 faces).
+        *
+        * This covers boundary verts of a quad grid and center verts.
+        * note that surrounding faces dont have to be quads.
+        */
+
+       BMIter iter;
+       BMEdge *e;
+
+       unsigned int tot_loop = 0;
+       unsigned int tot_edge = 0;
+       unsigned int tot_edge_boundary = 0;
+       unsigned int tot_edge_manifold = 0;
+       unsigned int tot_edge_wire     = 0;
+
+       BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+               if (BM_edge_is_boundary(e)) {
+                       tot_edge_boundary++;
+               }
+               else if (BM_edge_is_manifold(e)) {
+                       tot_edge_manifold++;
+               }
+               else if (BM_edge_is_wire(e)) {
+                       tot_edge_wire++;
+               }
+               tot_edge++;
+       }
+
+       if (tot_edge == 2) {
+               /* check for 2 wire verts only */
+               if (tot_edge_wire == 2) {
+                       return (BM_vert_collapse_edge(bm, v->e, v, TRUE) != NULL);
+               }
+       }
+       else if (tot_edge == 4) {
+               /* check for 4 faces surrounding */
+               if (tot_edge_boundary == 0 && tot_edge_manifold == 4) {
+                       /* good to go! */
+                       tot_loop = 4;
+               }
+       }
+       else if (tot_edge == 3) {
+               /* check for 2 faces surrounding at a boundary */
+               if (tot_edge_boundary == 2 && tot_edge_manifold == 1) {
+                       /* good to go! */
+                       tot_loop = 2;
+               }
+               else if (tot_edge_boundary == 0 && tot_edge_manifold == 3) {
+                       /* good to go! */
+                       tot_loop = 3;
+               }
+       }
+
+       if (tot_loop) {
+               BMLoop *f_loop[4];
+               unsigned int i;
+
+               /* ensure there are exactly tot_loop loops */
+               BLI_assert(BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v, tot_loop) == NULL);
+               BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)f_loop, tot_loop);
+
+               for (i = 0; i < tot_loop; i++) {
+                       BMLoop *l = f_loop[i];
+                       if (l->f->len > 3) {
+                               BLI_assert(l->prev->v != l->next->v);
+                               BM_face_split(bm, l->f, l->prev->v, l->next->v, NULL, NULL, TRUE);
+                       }
+               }
+
+               return BM_vert_dissolve(bm, v);
+       }
+
+       return FALSE;
+}
+
+enum {
+       VERT_INDEX_DO_COLLAPSE  = -1,
+       VERT_INDEX_INIT         =  0,
+       VERT_INDEX_IGNORE       =  1
+};
+
+// #define USE_WALKER  /* gives uneven results, disable for now */
+
+/* - BMVert.flag & BM_ELEM_TAG:  shows we touched this vert
+ * - BMVert.index == -1:         shows we will remove this vert
+ */
+
+/**
+ * \param tag_only so we can call this from an operator */
+void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const int tag_only)
+{
+#ifdef USE_WALKER
+#  define ELE_VERT_TAG 1
+#else
+       BMVert **vert_seek_a = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__);
+       BMVert **vert_seek_b = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__);
+       unsigned vert_seek_a_tot = 0;
+       unsigned vert_seek_b_tot = 0;
+#endif
+
+       BMVert *v;
+       BMIter iter;
+
+       const unsigned int offset = 0;
+       const unsigned int nth = 2;
+
+       int iter_step;
+
+       /* if tag_only is set, we assyme the caller knows what verts to tag
+        * needed for the operator */
+       if (tag_only == FALSE) {
+               BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+                       BM_elem_flag_enable(v, BM_ELEM_TAG);
+               }
+       }
+
+       for (iter_step = 0; iter_step < iterations; iter_step++) {
+               int iter_done;
+
+               BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+                       if (BM_elem_flag_test(v, BM_ELEM_TAG) && bm_vert_dissolve_fan_test(v)) {
+#ifdef USE_WALKER
+                               BMO_elem_flag_enable(bm, v, ELE_VERT_TAG);
+#endif
+                               BM_elem_index_set(v, VERT_INDEX_INIT);  /* set_dirty! */
+                       }
+                       else {
+                               BM_elem_index_set(v, VERT_INDEX_IGNORE);  /* set_dirty! */
+                       }
+               }
+               /* done with selecting tagged verts */
+
+
+               /* main loop, keep tagging until we can't tag any more islands */
+               while (TRUE) {
+#ifdef USE_WALKER
+                       BMWalker walker;
+#else
+                       unsigned int depth = 1;
+                       unsigned int i;
+#endif
+                       BMVert *v_first = NULL;
+                       BMVert *v;
+
+                       /* we could avoid iterating from the start each time */
+                       BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+                               if (v->e && (BM_elem_index_get(v) == VERT_INDEX_INIT)) {
+#ifdef USE_WALKER
+                                       if (BMO_elem_flag_test(bm, v, ELE_VERT_TAG))
+#endif
+                                       {
+                                               /* check again incase the topology changed */
+                                               if (bm_vert_dissolve_fan_test(v)) {
+                                                       v_first = v;
+                                               }
+                                               break;
+                                       }
+                               }
+                       }
+                       if (v_first == NULL) {
+                               break;
+                       }
+
+#ifdef USE_WALKER
+                       /* Walk over selected elements starting at active */
+                       BMW_init(&walker, bm, BMW_CONNECTED_VERTEX,
+                                        ELE_VERT_TAG, BMW_MASK_NOP, BMW_MASK_NOP,
+                                        BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */
+                                        BMW_NIL_LAY);
+
+                       BLI_assert(walker.order == BMW_BREADTH_FIRST);
+                       for (v = BMW_begin(&walker, v_first); v != NULL; v = BMW_step(&walker)) {
+                               /* Deselect elements that aren't at "nth" depth from active */
+                               if (BM_elem_index_get(v) == VERT_INDEX_INIT) {
+                                       if ((offset + BMW_current_depth(&walker)) % nth) {
+                                               /* tag for removal */
+                                               BM_elem_index_set(v, VERT_INDEX_DO_COLLAPSE);  /* set_dirty! */
+                                       }
+                                       else {
+                                               /* works better to allow these verts to be checked again */
+                                               //BM_elem_index_set(v, VERT_INDEX_IGNORE);  /* set_dirty! */
+                                       }
+                               }
+                       }
+                       BMW_end(&walker);
+#else
+
+                       BM_elem_index_set(v_first, (offset + depth) % nth ? VERT_INDEX_IGNORE : VERT_INDEX_DO_COLLAPSE);  /* set_dirty! */
+
+                       vert_seek_b_tot = 0;
+                       vert_seek_b[vert_seek_b_tot++] = v_first;
+
+                       while (TRUE) {
+                               BMEdge *e;
+
+                               if ((offset + depth) % nth) {
+                                       vert_seek_a_tot = 0;
+                                       for (i = 0; i < vert_seek_b_tot; i++) {
+                                               v = vert_seek_b[i];
+                                               BLI_assert(BM_elem_index_get(v) == VERT_INDEX_IGNORE);
+                                               BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+                                                       BMVert *v_other = BM_edge_other_vert(e, v);
+                                                       if (BM_elem_index_get(v_other) == VERT_INDEX_INIT) {
+                                                               BM_elem_index_set(v_other, VERT_INDEX_DO_COLLAPSE);  /* set_dirty! */
+                                                               vert_seek_a[vert_seek_a_tot++] = v_other;
+                                                       }
+                                               }
+                                       }
+                                       if (vert_seek_a_tot == 0) {
+                                               break;
+                                       }
+                               }
+                               else {
+                                       vert_seek_b_tot = 0;
+                                       for (i = 0; i < vert_seek_a_tot; i++) {
+                                               v = vert_seek_a[i];
+                                               BLI_assert(BM_elem_index_get(v) == VERT_INDEX_DO_COLLAPSE);
+                                               BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+                                                       BMVert *v_other = BM_edge_other_vert(e, v);
+                                                       if (BM_elem_index_get(v_other) == VERT_INDEX_INIT) {
+                                                               BM_elem_index_set(v_other, VERT_INDEX_IGNORE);  /* set_dirty! */
+                                                               vert_seek_b[vert_seek_b_tot++] = v_other;
+                                                       }
+                                               }
+                                       }
+                                       if (vert_seek_b_tot == 0) {
+                                               break;
+                                       }
+                               }
+
+                               depth++;
+                       }
+#endif  /* USE_WALKER */
+
+               }
+
+               /* now we tagged all verts -1 for removal, lets loop over and rebuild faces */
+               iter_done = FALSE;
+               BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+                       if (BM_elem_index_get(v) == VERT_INDEX_DO_COLLAPSE) {
+                               iter_done |= bm_vert_dissolve_fan(bm, v);
+                       }
+               }
+
+               if (iter_done == FALSE) {
+                       break;
+               }
+       }
+
+       bm->elem_index_dirty |= BM_VERT;
+
+#ifndef USE_WALKER
+       MEM_freeN(vert_seek_a);
+       MEM_freeN(vert_seek_b);
+#endif
+}
+
+void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations)
+{
+       BM_mesh_decimate_unsubdivide_ex(bm, iterations, FALSE);
+}
index 64b7151aee568370891dc1fbf15fe30a0788fe22..75f886856dc97be0411255259bfcb5fb90d249b7 100644 (file)
  *  \ingroup bmesh
  */
 
-#include "MEM_guardedalloc.h"
-
 #include "BLI_math.h"
+#include "BLI_utildefines.h"
 
 #include "bmesh.h"
 
 #include "intern/bmesh_operators_private.h" /* own include */
 
-
-static int bm_vert_dissolve_fan_test(BMVert *v)
-{
-       /* check if we should walk over these verts */
-       BMIter iter;
-       BMEdge *e;
-
-       unsigned int tot_edge = 0;
-       unsigned int tot_edge_boundary = 0;
-       unsigned int tot_edge_manifold = 0;
-       unsigned int tot_edge_wire     = 0;
-
-       BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
-               if (BM_edge_is_boundary(e)) {
-                       tot_edge_boundary++;
-               }
-               else if (BM_edge_is_manifold(e)) {
-                       tot_edge_manifold++;
-               }
-               else if (BM_edge_is_wire(e)) {
-                       tot_edge_wire++;
-               }
-               tot_edge++;
-       }
-
-       if ((tot_edge == 4) && (tot_edge_boundary == 0) && (tot_edge_manifold == 4)) {
-               return TRUE;
-       }
-       else if ((tot_edge == 3) && (tot_edge_boundary == 0) && (tot_edge_manifold == 3)) {
-               return TRUE;
-       }
-       else if ((tot_edge == 3) && (tot_edge_boundary == 2) && (tot_edge_manifold == 1)) {
-               return TRUE;
-       }
-       else if ((tot_edge == 2) && (tot_edge_wire == 2)) {
-               return TRUE;
-       }
-       return FALSE;
-}
-
-static int bm_vert_dissolve_fan(BMesh *bm, BMVert *v)
-{
-       /* collapse under 2 conditions.
-        * - vert connects to 4 manifold edges (and 4 faces).
-        * - vert connecrs to 1 manifold edge, 2 boundary edges (and 2 faces).
-        *
-        * This covers boundary verts of a quad grid and center verts.
-        * note that surrounding faces dont have to be quads.
-        */
-
-       BMIter iter;
-       BMEdge *e;
-
-       unsigned int tot_loop = 0;
-       unsigned int tot_edge = 0;
-       unsigned int tot_edge_boundary = 0;
-       unsigned int tot_edge_manifold = 0;
-       unsigned int tot_edge_wire     = 0;
-
-       BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
-               if (BM_edge_is_boundary(e)) {
-                       tot_edge_boundary++;
-               }
-               else if (BM_edge_is_manifold(e)) {
-                       tot_edge_manifold++;
-               }
-               else if (BM_edge_is_wire(e)) {
-                       tot_edge_wire++;
-               }
-               tot_edge++;
-       }
-
-       if (tot_edge == 2) {
-               /* check for 2 wire verts only */
-               if (tot_edge_wire == 2) {
-                       return (BM_vert_collapse_edge(bm, v->e, v, TRUE) != NULL);
-               }
-       }
-       else if (tot_edge == 4) {
-               /* check for 4 faces surrounding */
-               if (tot_edge_boundary == 0 && tot_edge_manifold == 4) {
-                       /* good to go! */
-                       tot_loop = 4;
-               }
-       }
-       else if (tot_edge == 3) {
-               /* check for 2 faces surrounding at a boundary */
-               if (tot_edge_boundary == 2 && tot_edge_manifold == 1) {
-                       /* good to go! */
-                       tot_loop = 2;
-               }
-               else if (tot_edge_boundary == 0 && tot_edge_manifold == 3) {
-                       /* good to go! */
-                       tot_loop = 3;
-               }
-       }
-
-       if (tot_loop) {
-               BMLoop *f_loop[4];
-               unsigned int i;
-
-               /* ensure there are exactly tot_loop loops */
-               BLI_assert(BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v, tot_loop) == NULL);
-               BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)f_loop, tot_loop);
-
-               for (i = 0; i < tot_loop; i++) {
-                       BMLoop *l = f_loop[i];
-                       if (l->f->len > 3) {
-                               BLI_assert(l->prev->v != l->next->v);
-                               BM_face_split(bm, l->f, l->prev->v, l->next->v, NULL, NULL, TRUE);
-                       }
-               }
-
-               return BM_vert_dissolve(bm, v);
-       }
-
-       return FALSE;
-}
-
-enum {
-       VERT_INDEX_DO_COLLAPSE  = -1,
-       VERT_INDEX_INIT         =  0,
-       VERT_INDEX_IGNORE       =  1
-};
-
-// #define USE_WALKER  /* gives uneven results, disable for now */
-// #define USE_ALL_VERTS
-
 /* - BMVert.flag & BM_ELEM_TAG:  shows we touched this vert
  * - BMVert.index == -1:         shows we will remove this vert
  */
 void bmo_unsubdivide_exec(BMesh *bm, BMOperator *op)
 {
-#ifdef USE_WALKER
-#  define ELE_VERT_TAG 1
-#else
-       BMVert **vert_seek_a = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__);
-       BMVert **vert_seek_b = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__);
-       unsigned vert_seek_a_tot = 0;
-       unsigned vert_seek_b_tot = 0;
-#endif
-
        BMVert *v;
        BMIter iter;
 
-       const unsigned int offset = 0;
-       const unsigned int nth = 2;
-
        const int iterations = maxi(1, BMO_slot_int_get(op, "iterations"));
-       int iter_step;
 
-#ifdef USE_ALL_VERTS
-       (void)op;
-       BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
-               BM_elem_flag_enable(v, BM_ELEM_TAG);
-       }
-#else  /* USE_ALL_VERTS */
        BMOpSlot *vinput = BMO_slot_get(op, "verts");
        BMVert **vinput_arr = (BMVert **)vinput->data.p;
        int v_index;
@@ -201,148 +53,7 @@ void bmo_unsubdivide_exec(BMesh *bm, BMOperator *op)
                v = vinput_arr[v_index];
                BM_elem_flag_enable(v, BM_ELEM_TAG);
        }
-#endif  /* USE_ALL_VERTS */
-
-
-       for (iter_step = 0; iter_step < iterations; iter_step++) {
-               int iter_done;
-
-               BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
-                       if (BM_elem_flag_test(v, BM_ELEM_TAG) && bm_vert_dissolve_fan_test(v)) {
-#ifdef USE_WALKER
-                               BMO_elem_flag_enable(bm, v, ELE_VERT_TAG);
-#endif
-                               BM_elem_index_set(v, VERT_INDEX_INIT);  /* set_dirty! */
-                       }
-                       else {
-                               BM_elem_index_set(v, VERT_INDEX_IGNORE);  /* set_dirty! */
-                       }
-               }
-               /* done with selecting tagged verts */
-
-
-               /* main loop, keep tagging until we can't tag any more islands */
-               while (TRUE) {
-#ifdef USE_WALKER
-                       BMWalker walker;
-#else
-                       unsigned int depth = 1;
-                       unsigned int i;
-#endif
-                       BMVert *v_first = NULL;
-                       BMVert *v;
-
-                       /* we could avoid iterating from the start each time */
-                       BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
-                               if (v->e && (BM_elem_index_get(v) == VERT_INDEX_INIT)) {
-#ifdef USE_WALKER
-                                       if (BMO_elem_flag_test(bm, v, ELE_VERT_TAG))
-#endif
-                                       {
-                                               /* check again incase the topology changed */
-                                               if (bm_vert_dissolve_fan_test(v)) {
-                                                       v_first = v;
-                                               }
-                                               break;
-                                       }
-                               }
-                       }
-                       if (v_first == NULL) {
-                               break;
-                       }
-
-#ifdef USE_WALKER
-                       /* Walk over selected elements starting at active */
-                       BMW_init(&walker, bm, BMW_CONNECTED_VERTEX,
-                                        ELE_VERT_TAG, BMW_MASK_NOP, BMW_MASK_NOP,
-                                        BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */
-                                        BMW_NIL_LAY);
-
-                       BLI_assert(walker.order == BMW_BREADTH_FIRST);
-                       for (v = BMW_begin(&walker, v_first); v != NULL; v = BMW_step(&walker)) {
-                               /* Deselect elements that aren't at "nth" depth from active */
-                               if (BM_elem_index_get(v) == VERT_INDEX_INIT) {
-                                       if ((offset + BMW_current_depth(&walker)) % nth) {
-                                               /* tag for removal */
-                                               BM_elem_index_set(v, VERT_INDEX_DO_COLLAPSE);  /* set_dirty! */
-                                       }
-                                       else {
-                                               /* works better to allow these verts to be checked again */
-                                               //BM_elem_index_set(v, VERT_INDEX_IGNORE);  /* set_dirty! */
-                                       }
-                               }
-                       }
-                       BMW_end(&walker);
-#else
-
-                       BM_elem_index_set(v_first, (offset + depth) % nth ? VERT_INDEX_IGNORE : VERT_INDEX_DO_COLLAPSE);  /* set_dirty! */
-
-                       vert_seek_b_tot = 0;
-                       vert_seek_b[vert_seek_b_tot++] = v_first;
-
-                       while (TRUE) {
-                               BMEdge *e;
-
-                               if ((offset + depth) % nth) {
-                                       vert_seek_a_tot = 0;
-                                       for (i = 0; i < vert_seek_b_tot; i++) {
-                                               v = vert_seek_b[i];
-                                               BLI_assert(BM_elem_index_get(v) == VERT_INDEX_IGNORE);
-                                               BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
-                                                       BMVert *v_other = BM_edge_other_vert(e, v);
-                                                       if (BM_elem_index_get(v_other) == VERT_INDEX_INIT) {
-                                                               BM_elem_index_set(v_other, VERT_INDEX_DO_COLLAPSE);  /* set_dirty! */
-                                                               vert_seek_a[vert_seek_a_tot++] = v_other;
-                                                       }
-                                               }
-                                       }
-                                       if (vert_seek_a_tot == 0) {
-                                               break;
-                                       }
-                               }
-                               else {
-                                       vert_seek_b_tot = 0;
-                                       for (i = 0; i < vert_seek_a_tot; i++) {
-                                               v = vert_seek_a[i];
-                                               BLI_assert(BM_elem_index_get(v) == VERT_INDEX_DO_COLLAPSE);
-                                               BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
-                                                       BMVert *v_other = BM_edge_other_vert(e, v);
-                                                       if (BM_elem_index_get(v_other) == VERT_INDEX_INIT) {
-                                                               BM_elem_index_set(v_other, VERT_INDEX_IGNORE);  /* set_dirty! */
-                                                               vert_seek_b[vert_seek_b_tot++] = v_other;
-                                                       }
-                                               }
-                                       }
-                                       if (vert_seek_b_tot == 0) {
-                                               break;
-                                       }
-                               }
-
-                               depth++;
-                       }
-#endif  /* USE_WALKER */
-
-               }
-
-               /* now we tagged all verts -1 for removal, lets loop over and rebuild faces */
-               iter_done = FALSE;
-               BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
-                       if (BM_elem_index_get(v) == VERT_INDEX_DO_COLLAPSE) {
-                               iter_done |= bm_vert_dissolve_fan(bm, v);
-                       }
-               }
-
-               if (iter_done == FALSE) {
-                       break;
-               }
-       }
-
-       bm->elem_index_dirty |= BM_VERT;
-
-#ifndef USE_WALKER
-       MEM_freeN(vert_seek_a);
-       MEM_freeN(vert_seek_b);
-#endif
 
+       /* do all the real work here */
+       BM_mesh_decimate_unsubdivide_ex(bm, iterations, TRUE);
 }
-
index 05c1871ae412f918974805f33b84007e8cd399fb..f53287beb9d5d2b0ae36f4e03169165221510ce6 100644 (file)
@@ -361,15 +361,23 @@ typedef struct UVProjectModifierData {
 typedef struct DecimateModifierData {
        ModifierData modifier;
 
-       float percent;
-       int faceCount;  /* runtime only */
+       float percent;  /* (mode == MOD_DECIM_MODE_COLLAPSE) */
+       int   iter;     /* (mode == MOD_DECIM_MODE_UNSUBDIV) */
 
        char defgrp_name[64];   /* MAX_VGROUP_NAME */
-       int flag, pad;
+       short flag, mode;
+
+       /* runtime only */
+       int face_count;
 } DecimateModifierData;
 
 enum {
-       MOD_DECIM_INVERT_VGROUP = (1 << 0)
+       MOD_DECIM_FLAG_INVERT_VGROUP = (1 << 0)
+};
+
+enum {
+       MOD_DECIM_MODE_COLLAPSE,
+       MOD_DECIM_MODE_UNSUBDIV
 };
 
 /* Smooth modifier flags */
index 77d2b00dfc2b23ec82efdd4a12b527550ecb9828..bef5e5cc16147c18a608228b88a422433db72cbe 100644 (file)
@@ -1195,7 +1195,7 @@ int main(int argc, char **argv)
 }
 
 /* handy but fails on struct bounds which makesdna doesnt care about
- * unless structs are nested */
+ * with quite the same strictness as GCC does */
 #if 0
 /* include files for automatic dependencies */
 
index 67ab14693180ae96a02ae622f04bbf79dab975bd..36bdb6cc896c0e5a55b0b4bdc8df05f00a7fb545 100644 (file)
@@ -1110,6 +1110,12 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
 
 static void rna_def_modifier_decimate(BlenderRNA *brna)
 {
+       static EnumPropertyItem modifier_decim_mode_items[] = {
+               {MOD_DECIM_MODE_COLLAPSE, "COLLAPSE", 0, "Collapse", "Use edge collapsing"},
+               {MOD_DECIM_MODE_UNSUBDIV, "UNSUBDIV", 0, "Un-Subdivide", "Use un-subdivide face reduction"},
+               {0, NULL, 0, NULL, NULL}
+       };
+
        StructRNA *srna;
        PropertyRNA *prop;
 
@@ -1118,6 +1124,12 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
        RNA_def_struct_sdna(srna, "DecimateModifierData");
        RNA_def_struct_ui_icon(srna, ICON_MOD_DECIM);
 
+       prop = RNA_def_property(srna, "decimate_type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "mode");
+       RNA_def_property_enum_items(prop, modifier_decim_mode_items);
+       RNA_def_property_ui_text(prop, "Mode", "");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
        prop = RNA_def_property(srna, "ratio", PROP_FLOAT, PROP_NONE);
        RNA_def_property_float_sdna(prop, NULL, "percent");
        RNA_def_property_range(prop, 0, 1);
@@ -1125,6 +1137,13 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Ratio", "Ratio of triangles to reduce to");
        RNA_def_property_update(prop, 0, "rna_Modifier_update");
 
+       prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_UNSIGNED);
+       RNA_def_property_int_sdna(prop, NULL, "iter");
+       RNA_def_property_range(prop, 0, SHRT_MAX);
+       RNA_def_property_ui_range(prop, 1, 100, 1, 0);
+       RNA_def_property_ui_text(prop, "Iterations", "Number of times to unsubdivide");
+       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
        prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
        RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
        RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name");
@@ -1132,12 +1151,11 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
        RNA_def_property_update(prop, 0, "rna_Modifier_update");
 
        prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_INVERT_VGROUP);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_FLAG_INVERT_VGROUP);
        RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
        RNA_def_property_update(prop, 0, "rna_Modifier_update");
 
        prop = RNA_def_property(srna, "face_count", PROP_INT, PROP_NONE);
-       RNA_def_property_int_sdna(prop, NULL, "faceCount");
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
        RNA_def_property_ui_text(prop, "Face Count", "The current number of faces in the decimated mesh");
 }
index 1cb6853447a3f6a5bbfb3fc49422e977823c9044..6eb2f8d6c79af63390d16e1b6bdca1faa1eaf8eb 100644 (file)
@@ -72,8 +72,10 @@ static void copyData(ModifierData *md, ModifierData *target)
        DecimateModifierData *tdmd = (DecimateModifierData *) target;
 
        tdmd->percent = dmd->percent;
+       tdmd->iter = dmd->iter;
        BLI_strncpy(tdmd->defgrp_name, dmd->defgrp_name, sizeof(tdmd->defgrp_name));
        tdmd->flag = dmd->flag;
+       tdmd->mode = dmd->mode;
 }
 
 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -110,42 +112,52 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                return dm;
        }
 
-       if (dmd->defgrp_name[0]) {
-               MDeformVert *dvert;
-               int defgrp_index;
+       if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) {
+               if (dmd->defgrp_name[0]) {
+                       MDeformVert *dvert;
+                       int defgrp_index;
 
-               modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index);
+                       modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index);
 
-               if (dvert) {
-                       const unsigned int vert_tot = dm->getNumVerts(dm);
-                       unsigned int i;
+                       if (dvert) {
+                               const unsigned int vert_tot = dm->getNumVerts(dm);
+                               unsigned int i;
 
-                       vweights = MEM_mallocN(vert_tot * sizeof(float), __func__);
+                               vweights = MEM_mallocN(vert_tot * sizeof(float), __func__);
 
-                       if (dmd->flag & MOD_DECIM_INVERT_VGROUP) {
-                               for (i = 0; i < vert_tot; i++) {
-                                       vweights[i] = 1.0f - defvert_find_weight(&dvert[i], defgrp_index);
+                               if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) {
+                                       for (i = 0; i < vert_tot; i++) {
+                                               vweights[i] = 1.0f - defvert_find_weight(&dvert[i], defgrp_index);
+                                       }
                                }
-                       }
-                       else {
-                               for (i = 0; i < vert_tot; i++) {
-                                       vweights[i] = defvert_find_weight(&dvert[i], defgrp_index);
+                               else {
+                                       for (i = 0; i < vert_tot; i++) {
+                                               vweights[i] = defvert_find_weight(&dvert[i], defgrp_index);
+                                       }
                                }
                        }
                }
        }
 
-
        em = DM_to_editbmesh(dm, NULL, FALSE);
        bm = em->bm;
 
-       BM_mesh_decimate_collapse(bm, dmd->percent, vweights);
+       switch (dmd->mode) {
+               case MOD_DECIM_MODE_COLLAPSE:
+                       BM_mesh_decimate_collapse(bm, dmd->percent, vweights);
+                       break;
+               case MOD_DECIM_MODE_UNSUBDIV:
+                       BM_mesh_decimate_unsubdivide(bm, dmd->iter);
+                       break;
+       }
+
 
        if (vweights) {
                MEM_freeN(vweights);
        }
 
-       dmd->faceCount = bm->totface;
+       /* update for display only */
+       dmd->face_count = bm->totface;
 
        BLI_assert(em->looptris == NULL);
        result = CDDM_from_BMEditMesh(em, NULL, TRUE, FALSE);