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:
authorCampbell Barton <ideasman42@gmail.com>2012-10-23 08:26:39 +0400
committerCampbell Barton <ideasman42@gmail.com>2012-10-23 08:26:39 +0400
commit0636886715b4c5ac56ed7f903bf37a00cfbdc841 (patch)
tree715a71459a6682f623be69b9b7d7ea52911e3be9 /source/blender
parented4b2d97385eb8ab6d052ea6c83e5d62f62776e6 (diff)
add un-subdivude as an optional method for the decimate modifier, gives more even geometry & nicer results in some cases.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/bmesh/CMakeLists.txt1
-rw-r--r--source/blender/bmesh/intern/bmesh_decimate.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_decimate_collapse.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_decimate_unsubdivide.c342
-rw-r--r--source/blender/bmesh/operators/bmo_unsubdivide.c295
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h16
-rw-r--r--source/blender/makesdna/intern/makesdna.c2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c22
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c48
9 files changed, 414 insertions, 319 deletions
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 3e0985471e1..a000cb59167 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -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
diff --git a/source/blender/bmesh/intern/bmesh_decimate.h b/source/blender/bmesh/intern/bmesh_decimate.h
index 7fafb752e1e..18d86cfb1a5 100644
--- a/source/blender/bmesh/intern/bmesh_decimate.h
+++ b/source/blender/bmesh/intern/bmesh_decimate.h
@@ -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__ */
diff --git a/source/blender/bmesh/intern/bmesh_decimate_collapse.c b/source/blender/bmesh/intern/bmesh_decimate_collapse.c
index 75fe12a418a..ce10fe2fed1 100644
--- a/source/blender/bmesh/intern/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/intern/bmesh_decimate_collapse.c
@@ -20,10 +20,10 @@
* ***** 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
index 00000000000..18bfa5159bf
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_decimate_unsubdivide.c
@@ -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);
+}
diff --git a/source/blender/bmesh/operators/bmo_unsubdivide.c b/source/blender/bmesh/operators/bmo_unsubdivide.c
index 64b7151aee5..75f886856dc 100644
--- a/source/blender/bmesh/operators/bmo_unsubdivide.c
+++ b/source/blender/bmesh/operators/bmo_unsubdivide.c
@@ -24,171 +24,23 @@
* \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);
}
-
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 05c1871ae41..f53287beb9d 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -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 */
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 77d2b00dfc2..bef5e5cc161 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -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 */
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 67ab1469318..36bdb6cc896 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -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");
}
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 1cb6853447a..6eb2f8d6c79 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -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);