7c13774ee9981d686b71a6f17466b14aadfe8801
[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 }
65
66 static void copyData(ModifierData *md, ModifierData *target)
67 {
68 #if 0
69         DecimateModifierData *dmd = (DecimateModifierData *) md;
70         DecimateModifierData *tdmd = (DecimateModifierData *) target;
71 #endif
72         modifier_copyData_generic(md, target);
73 }
74
75 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
76 {
77         DecimateModifierData *dmd = (DecimateModifierData *) md;
78         CustomDataMask dataMask = 0;
79
80         /* ask for vertexgroups if we need them */
81         if (dmd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
82
83         return dataMask;
84 }
85
86 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
87                                   DerivedMesh *derivedData,
88                                   ModifierApplyFlag UNUSED(flag))
89 {
90         DecimateModifierData *dmd = (DecimateModifierData *) md;
91         DerivedMesh *dm = derivedData, *result = NULL;
92         BMesh *bm;
93         bool calc_face_normal;
94
95         float *vweights = NULL;
96
97 #ifdef USE_TIMEIT
98         TIMEIT_START(decim);
99 #endif
100
101         /* set up front so we dont show invalid info in the UI */
102         dmd->face_count = dm->getNumPolys(dm);
103
104         switch (dmd->mode) {
105                 case MOD_DECIM_MODE_COLLAPSE:
106                         if (dmd->percent == 1.0f) {
107                                 return dm;
108                         }
109                         calc_face_normal = true;
110                         break;
111                 case MOD_DECIM_MODE_UNSUBDIV:
112                         if (dmd->iter == 0) {
113                                 return dm;
114                         }
115                         calc_face_normal = false;
116                         break;
117                 case MOD_DECIM_MODE_DISSOLVE:
118                         if (dmd->angle == 0.0f) {
119                                 return dm;
120                         }
121                         calc_face_normal = true;
122                         break;
123                 default:
124                         return dm;
125         }
126
127         if (dmd->face_count <= 3) {
128                 modifier_setError(md, "Modifier requires more than 3 input faces");
129                 return dm;
130         }
131
132         if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) {
133                 if (dmd->defgrp_name[0]) {
134                         MDeformVert *dvert;
135                         int defgrp_index;
136
137                         modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index);
138
139                         if (dvert) {
140                                 const unsigned int vert_tot = dm->getNumVerts(dm);
141                                 unsigned int i;
142
143                                 vweights = MEM_mallocN(vert_tot * sizeof(float), __func__);
144
145                                 if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) {
146                                         for (i = 0; i < vert_tot; i++) {
147                                                 const float f = 1.0f - defvert_find_weight(&dvert[i], defgrp_index);
148                                                 vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX;
149                                         }
150                                 }
151                                 else {
152                                         for (i = 0; i < vert_tot; i++) {
153                                                 const float f = defvert_find_weight(&dvert[i], defgrp_index);
154                                                 vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX;
155                                         }
156                                 }
157                         }
158                 }
159         }
160
161         bm = DM_to_bmesh(dm, calc_face_normal);
162
163         switch (dmd->mode) {
164                 case MOD_DECIM_MODE_COLLAPSE:
165                 {
166                         const bool do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0;
167                         BM_mesh_decimate_collapse(bm, dmd->percent, vweights, do_triangulate);
168                         break;
169                 }
170                 case MOD_DECIM_MODE_UNSUBDIV:
171                 {
172                         BM_mesh_decimate_unsubdivide(bm, dmd->iter);
173                         break;
174                 }
175                 case MOD_DECIM_MODE_DISSOLVE:
176                 {
177                         const bool do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0;
178                         BM_mesh_decimate_dissolve(bm, dmd->angle, do_dissolve_boundaries, (BMO_Delimit)dmd->delimit);
179                         break;
180                 }
181         }
182
183         if (vweights) {
184                 MEM_freeN(vweights);
185         }
186
187         /* update for display only */
188         dmd->face_count = bm->totface;
189         result = CDDM_from_bmesh(bm, false);
190         BLI_assert(bm->vtoolflagpool == NULL &&
191                    bm->etoolflagpool == NULL &&
192                    bm->ftoolflagpool == NULL);  /* make sure we never alloc'd these */
193         BLI_assert(bm->vtable == NULL &&
194                    bm->etable == NULL &&
195                    bm->ftable == NULL);
196
197         BM_mesh_free(bm);
198
199 #ifdef USE_TIMEIT
200         TIMEIT_END(decim);
201 #endif
202
203         result->dirty = DM_DIRTY_NORMALS;
204
205         return result;
206 }
207
208 ModifierTypeInfo modifierType_Decimate = {
209         /* name */              "Decimate",
210         /* structName */        "DecimateModifierData",
211         /* structSize */        sizeof(DecimateModifierData),
212         /* type */              eModifierTypeType_Nonconstructive,
213         /* flags */             eModifierTypeFlag_AcceptsMesh |
214                                 eModifierTypeFlag_AcceptsCVs,
215         /* copyData */          copyData,
216         /* deformVerts */       NULL,
217         /* deformMatrices */    NULL,
218         /* deformVertsEM */     NULL,
219         /* deformMatricesEM */  NULL,
220         /* applyModifier */     applyModifier,
221         /* applyModifierEM */   NULL,
222         /* initData */          initData,
223         /* requiredDataMask */  requiredDataMask,
224         /* freeData */          NULL,
225         /* isDisabled */        NULL,
226         /* updateDepgraph */    NULL,
227         /* updateDepsgraph */   NULL,
228         /* dependsOnTime */     NULL,
229         /* dependsOnNormals */  NULL,
230         /* foreachObjectLink */ NULL,
231         /* foreachIDLink */     NULL,
232         /* foreachTexLink */    NULL,
233 };