Extract common modifier parameters into ModifierEvalContext struct
[blender.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, const ModifierEvalContext *ctx,
90                                   DerivedMesh *derivedData)
91 {
92         DecimateModifierData *dmd = (DecimateModifierData *) md;
93         DerivedMesh *dm = derivedData, *result = NULL;
94         BMesh *bm;
95         bool calc_face_normal;
96         float *vweights = NULL;
97
98 #ifdef USE_TIMEIT
99         TIMEIT_START(decim);
100 #endif
101
102         /* set up front so we dont show invalid info in the UI */
103         dmd->face_count = dm->getNumPolys(dm);
104
105         switch (dmd->mode) {
106                 case MOD_DECIM_MODE_COLLAPSE:
107                         if (dmd->percent == 1.0f) {
108                                 return dm;
109                         }
110                         calc_face_normal = true;
111                         break;
112                 case MOD_DECIM_MODE_UNSUBDIV:
113                         if (dmd->iter == 0) {
114                                 return dm;
115                         }
116                         calc_face_normal = false;
117                         break;
118                 case MOD_DECIM_MODE_DISSOLVE:
119                         if (dmd->angle == 0.0f) {
120                                 return dm;
121                         }
122                         calc_face_normal = true;
123                         break;
124                 default:
125                         return dm;
126         }
127
128         if (dmd->face_count <= 3) {
129                 modifier_setError(md, "Modifier requires more than 3 input faces");
130                 return dm;
131         }
132
133         if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) {
134                 if (dmd->defgrp_name[0] && (dmd->defgrp_factor > 0.0f)) {
135                         MDeformVert *dvert;
136                         int defgrp_index;
137
138                         modifier_get_vgroup(ctx->object, dm, dmd->defgrp_name, &dvert, &defgrp_index);
139
140                         if (dvert) {
141                                 const unsigned int vert_tot = dm->getNumVerts(dm);
142                                 unsigned int i;
143
144                                 vweights = MEM_malloc_arrayN(vert_tot, sizeof(float), __func__);
145
146                                 if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) {
147                                         for (i = 0; i < vert_tot; i++) {
148                                                 vweights[i] = 1.0f - defvert_find_weight(&dvert[i], defgrp_index);
149                                         }
150                                 }
151                                 else {
152                                         for (i = 0; i < vert_tot; i++) {
153                                                 vweights[i] = defvert_find_weight(&dvert[i], defgrp_index);
154                                         }
155                                 }
156                         }
157                 }
158         }
159
160         bm = DM_to_bmesh(dm, calc_face_normal);
161
162         switch (dmd->mode) {
163                 case MOD_DECIM_MODE_COLLAPSE:
164                 {
165                         const bool do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0;
166                         const int symmetry_axis = (dmd->flag & MOD_DECIM_FLAG_SYMMETRY) ? dmd->symmetry_axis : -1;
167                         const float symmetry_eps = 0.00002f;
168                         BM_mesh_decimate_collapse(
169                                 bm, dmd->percent, vweights, dmd->defgrp_factor, do_triangulate,
170                                 symmetry_axis, symmetry_eps);
171                         break;
172                 }
173                 case MOD_DECIM_MODE_UNSUBDIV:
174                 {
175                         BM_mesh_decimate_unsubdivide(bm, dmd->iter);
176                         break;
177                 }
178                 case MOD_DECIM_MODE_DISSOLVE:
179                 {
180                         const bool do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0;
181                         BM_mesh_decimate_dissolve(bm, dmd->angle, do_dissolve_boundaries, (BMO_Delimit)dmd->delimit);
182                         break;
183                 }
184         }
185
186         if (vweights) {
187                 MEM_freeN(vweights);
188         }
189
190         /* update for display only */
191         dmd->face_count = bm->totface;
192         result = CDDM_from_bmesh(bm, false);
193         BLI_assert(bm->vtoolflagpool == NULL &&
194                    bm->etoolflagpool == NULL &&
195                    bm->ftoolflagpool == NULL);  /* make sure we never alloc'd these */
196         BLI_assert(bm->vtable == NULL &&
197                    bm->etable == NULL &&
198                    bm->ftable == NULL);
199
200         BM_mesh_free(bm);
201
202 #ifdef USE_TIMEIT
203         TIMEIT_END(decim);
204 #endif
205
206         result->dirty = DM_DIRTY_NORMALS;
207
208         return result;
209 }
210
211 ModifierTypeInfo modifierType_Decimate = {
212         /* name */              "Decimate",
213         /* structName */        "DecimateModifierData",
214         /* structSize */        sizeof(DecimateModifierData),
215         /* type */              eModifierTypeType_Nonconstructive,
216         /* flags */             eModifierTypeFlag_AcceptsMesh |
217                                 eModifierTypeFlag_AcceptsCVs,
218         /* copyData */          copyData,
219
220         /* deformVerts_DM */    NULL,
221         /* deformMatrices_DM */ NULL,
222         /* deformVertsEM_DM */  NULL,
223         /* deformMatricesEM_DM*/NULL,
224         /* applyModifier_DM */  applyModifier,
225         /* applyModifierEM_DM */NULL,
226
227         /* deformVerts */       NULL,
228         /* deformMatrices */    NULL,
229         /* deformVertsEM */     NULL,
230         /* deformMatricesEM */  NULL,
231         /* applyModifier */     NULL,
232         /* applyModifierEM */   NULL,
233
234         /* initData */          initData,
235         /* requiredDataMask */  requiredDataMask,
236         /* freeData */          NULL,
237         /* isDisabled */        NULL,
238         /* updateDepsgraph */   NULL,
239         /* dependsOnTime */     NULL,
240         /* dependsOnNormals */  NULL,
241         /* foreachObjectLink */ NULL,
242         /* foreachIDLink */     NULL,
243         /* foreachTexLink */    NULL,
244 };