BMesh decimate, improve behavior with weights
[blender-staging.git] / source / blender / modifiers / intern / MOD_decimate.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software  Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Daniel Dunbar
22  *                 Ton Roosendaal,
23  *                 Ben Batt,
24  *                 Brecht Van Lommel,
25  *                 Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  *
29  */
30
31 /** \file blender/modifiers/intern/MOD_decimate.c
32  *  \ingroup modifiers
33  */
34
35 #include "DNA_object_types.h"
36
37 #include "BLI_math.h"
38 #include "BLI_utildefines.h"
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BKE_modifier.h"
43 #include "BKE_deform.h"
44 #include "BKE_cdderivedmesh.h"
45
46 #include "bmesh.h"
47 #include "bmesh_tools.h"
48
49 // #define USE_TIMEIT
50
51 #ifdef USE_TIMEIT
52 #  include "PIL_time.h"
53 #  include "PIL_time_utildefines.h"
54 #endif
55
56 #include "MOD_util.h"
57
58 static void initData(ModifierData *md)
59 {
60         DecimateModifierData *dmd = (DecimateModifierData *) md;
61
62         dmd->percent = 1.0;
63         dmd->angle   = DEG2RADF(5.0f);
64         dmd->defgrp_factor = 1.0;
65 }
66
67 static void copyData(ModifierData *md, ModifierData *target)
68 {
69 #if 0
70         DecimateModifierData *dmd = (DecimateModifierData *) md;
71         DecimateModifierData *tdmd = (DecimateModifierData *) target;
72 #endif
73         modifier_copyData_generic(md, target);
74 }
75
76 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
77 {
78         DecimateModifierData *dmd = (DecimateModifierData *) md;
79         CustomDataMask dataMask = 0;
80
81         /* ask for vertexgroups if we need them */
82         if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) {
83                 dataMask |= CD_MASK_MDEFORMVERT;
84         }
85
86         return dataMask;
87 }
88
89 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
90                                   DerivedMesh *derivedData,
91                                   ModifierApplyFlag UNUSED(flag))
92 {
93         DecimateModifierData *dmd = (DecimateModifierData *) md;
94         DerivedMesh *dm = derivedData, *result = NULL;
95         BMesh *bm;
96         bool calc_face_normal;
97
98         float *vweights = NULL;
99
100 #ifdef USE_TIMEIT
101         TIMEIT_START(decim);
102 #endif
103
104         /* set up front so we dont show invalid info in the UI */
105         dmd->face_count = dm->getNumPolys(dm);
106
107         switch (dmd->mode) {
108                 case MOD_DECIM_MODE_COLLAPSE:
109                         if (dmd->percent == 1.0f) {
110                                 return dm;
111                         }
112                         calc_face_normal = true;
113                         break;
114                 case MOD_DECIM_MODE_UNSUBDIV:
115                         if (dmd->iter == 0) {
116                                 return dm;
117                         }
118                         calc_face_normal = false;
119                         break;
120                 case MOD_DECIM_MODE_DISSOLVE:
121                         if (dmd->angle == 0.0f) {
122                                 return dm;
123                         }
124                         calc_face_normal = true;
125                         break;
126                 default:
127                         return dm;
128         }
129
130         if (dmd->face_count <= 3) {
131                 modifier_setError(md, "Modifier requires more than 3 input faces");
132                 return dm;
133         }
134
135         if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) {
136                 if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) {
137                         MDeformVert *dvert;
138                         int defgrp_index;
139
140                         modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index);
141
142                         if (dvert) {
143                                 const unsigned int vert_tot = dm->getNumVerts(dm);
144                                 unsigned int i;
145
146                                 vweights = MEM_mallocN(vert_tot * sizeof(float), __func__);
147
148                                 if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) {
149                                         for (i = 0; i < vert_tot; i++) {
150                                                 vweights[i] = (1.0f - defvert_find_weight(&dvert[i], defgrp_index)) * dmd->defgrp_factor;
151                                         }
152                                 }
153                                 else {
154                                         for (i = 0; i < vert_tot; i++) {
155                                                 vweights[i] = (defvert_find_weight(&dvert[i], defgrp_index)) * dmd->defgrp_factor;
156                                         }
157                                 }
158                         }
159                 }
160         }
161
162         bm = DM_to_bmesh(dm, calc_face_normal);
163
164         switch (dmd->mode) {
165                 case MOD_DECIM_MODE_COLLAPSE:
166                 {
167                         const bool do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0;
168                         BM_mesh_decimate_collapse(bm, dmd->percent, vweights, do_triangulate);
169                         break;
170                 }
171                 case MOD_DECIM_MODE_UNSUBDIV:
172                 {
173                         BM_mesh_decimate_unsubdivide(bm, dmd->iter);
174                         break;
175                 }
176                 case MOD_DECIM_MODE_DISSOLVE:
177                 {
178                         const bool do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0;
179                         BM_mesh_decimate_dissolve(bm, dmd->angle, do_dissolve_boundaries, (BMO_Delimit)dmd->delimit);
180                         break;
181                 }
182         }
183
184         if (vweights) {
185                 MEM_freeN(vweights);
186         }
187
188         /* update for display only */
189         dmd->face_count = bm->totface;
190         result = CDDM_from_bmesh(bm, false);
191         BLI_assert(bm->vtoolflagpool == NULL &&
192                    bm->etoolflagpool == NULL &&
193                    bm->ftoolflagpool == NULL);  /* make sure we never alloc'd these */
194         BLI_assert(bm->vtable == NULL &&
195                    bm->etable == NULL &&
196                    bm->ftable == NULL);
197
198         BM_mesh_free(bm);
199
200 #ifdef USE_TIMEIT
201         TIMEIT_END(decim);
202 #endif
203
204         result->dirty = DM_DIRTY_NORMALS;
205
206         return result;
207 }
208
209 ModifierTypeInfo modifierType_Decimate = {
210         /* name */              "Decimate",
211         /* structName */        "DecimateModifierData",
212         /* structSize */        sizeof(DecimateModifierData),
213         /* type */              eModifierTypeType_Nonconstructive,
214         /* flags */             eModifierTypeFlag_AcceptsMesh |
215                                 eModifierTypeFlag_AcceptsCVs,
216         /* copyData */          copyData,
217         /* deformVerts */       NULL,
218         /* deformMatrices */    NULL,
219         /* deformVertsEM */     NULL,
220         /* deformMatricesEM */  NULL,
221         /* applyModifier */     applyModifier,
222         /* applyModifierEM */   NULL,
223         /* initData */          initData,
224         /* requiredDataMask */  requiredDataMask,
225         /* freeData */          NULL,
226         /* isDisabled */        NULL,
227         /* updateDepgraph */    NULL,
228         /* updateDepsgraph */   NULL,
229         /* dependsOnTime */     NULL,
230         /* dependsOnNormals */  NULL,
231         /* foreachObjectLink */ NULL,
232         /* foreachIDLink */     NULL,
233         /* foreachTexLink */    NULL,
234 };