Merge branch 'master' into blender2.8
[blender.git] / source / blender / modifiers / intern / MOD_remesh.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) 2011 by Nicholas Bishop.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/modifiers/intern/MOD_remesh.c
24  *  \ingroup modifiers
25  */
26
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_math_base.h"
30 #include "BLI_math_vector.h"
31 #include "BLI_utildefines.h"
32
33 #include "BKE_cdderivedmesh.h"
34 #include "BKE_DerivedMesh.h"
35
36 #include "DNA_meshdata_types.h"
37 #include "DNA_modifier_types.h"
38 #include "DNA_object_types.h"
39
40 #include "MOD_modifiertypes.h"
41
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #ifdef WITH_MOD_REMESH
47 #  include "dualcon.h"
48 #endif
49
50 static void initData(ModifierData *md)
51 {
52         RemeshModifierData *rmd = (RemeshModifierData *) md;
53
54         rmd->scale = 0.9;
55         rmd->depth = 4;
56         rmd->hermite_num = 1;
57         rmd->flag = MOD_REMESH_FLOOD_FILL;
58         rmd->mode = MOD_REMESH_SHARP_FEATURES;
59         rmd->threshold = 1;
60 }
61
62 #ifdef WITH_MOD_REMESH
63
64 static void init_dualcon_mesh(DualConInput *mesh, DerivedMesh *dm)
65 {
66         memset(mesh, 0, sizeof(DualConInput));
67
68         mesh->co = (void *)dm->getVertArray(dm);
69         mesh->co_stride = sizeof(MVert);
70         mesh->totco = dm->getNumVerts(dm);
71
72         mesh->mloop = (void *)dm->getLoopArray(dm);
73         mesh->loop_stride = sizeof(MLoop);
74         mesh->looptri = (void *)dm->getLoopTriArray(dm);
75         mesh->tri_stride = sizeof(MLoopTri);
76         mesh->tottri = dm->getNumLoopTri(dm);
77
78         INIT_MINMAX(mesh->min, mesh->max);
79         dm->getMinMax(dm, mesh->min, mesh->max);
80 }
81
82 /* simple structure to hold the output: a CDDM and two counters to
83  * keep track of the current elements */
84 typedef struct {
85         DerivedMesh *dm;
86         int curvert, curface;
87 } DualConOutput;
88
89 /* allocate and initialize a DualConOutput */
90 static void *dualcon_alloc_output(int totvert, int totquad)
91 {
92         DualConOutput *output;
93
94         if (!(output = MEM_callocN(sizeof(DualConOutput),
95                                    "DualConOutput")))
96         {
97                 return NULL;
98         }
99         
100         output->dm = CDDM_new(totvert, 0, 0, 4 * totquad, totquad);
101         return output;
102 }
103
104 static void dualcon_add_vert(void *output_v, const float co[3])
105 {
106         DualConOutput *output = output_v;
107         DerivedMesh *dm = output->dm;
108         
109         assert(output->curvert < dm->getNumVerts(dm));
110         
111         copy_v3_v3(CDDM_get_verts(dm)[output->curvert].co, co);
112         output->curvert++;
113 }
114
115 static void dualcon_add_quad(void *output_v, const int vert_indices[4])
116 {
117         DualConOutput *output = output_v;
118         DerivedMesh *dm = output->dm;
119         MLoop *mloop;
120         MPoly *cur_poly;
121         int i;
122         
123         assert(output->curface < dm->getNumPolys(dm));
124
125         mloop = CDDM_get_loops(dm);
126         cur_poly = CDDM_get_poly(dm, output->curface);
127         
128         cur_poly->loopstart = output->curface * 4;
129         cur_poly->totloop = 4;
130         for (i = 0; i < 4; i++)
131                 mloop[output->curface * 4 + i].v = vert_indices[i];
132         
133         output->curface++;
134 }
135
136 static DerivedMesh *applyModifier(ModifierData *md,
137                                   const ModifierEvalContext *UNUSED(ctx),
138                                   DerivedMesh *dm)
139 {
140         RemeshModifierData *rmd;
141         DualConOutput *output;
142         DualConInput input;
143         DerivedMesh *result;
144         DualConFlags flags = 0;
145         DualConMode mode = 0;
146
147         rmd = (RemeshModifierData *)md;
148
149         init_dualcon_mesh(&input, dm);
150
151         if (rmd->flag & MOD_REMESH_FLOOD_FILL)
152                 flags |= DUALCON_FLOOD_FILL;
153
154         switch (rmd->mode) {
155                 case MOD_REMESH_CENTROID:
156                         mode = DUALCON_CENTROID;
157                         break;
158                 case MOD_REMESH_MASS_POINT:
159                         mode = DUALCON_MASS_POINT;
160                         break;
161                 case MOD_REMESH_SHARP_FEATURES:
162                         mode = DUALCON_SHARP_FEATURES;
163                         break;
164         }
165         
166         output = dualcon(&input,
167                          dualcon_alloc_output,
168                          dualcon_add_vert,
169                          dualcon_add_quad,
170                          flags,
171                          mode,
172                          rmd->threshold,
173                          rmd->hermite_num,
174                          rmd->scale,
175                          rmd->depth);
176         result = output->dm;
177         MEM_freeN(output);
178
179         if (rmd->flag & MOD_REMESH_SMOOTH_SHADING) {
180                 MPoly *mpoly = CDDM_get_polys(result);
181                 int i, totpoly = result->getNumPolys(result);
182                 
183                 /* Apply smooth shading to output faces */
184                 for (i = 0; i < totpoly; i++) {
185                         mpoly[i].flag |= ME_SMOOTH;
186                 }
187         }
188
189         CDDM_calc_edges(result);
190         result->dirty |= DM_DIRTY_NORMALS;
191         return result;
192 }
193
194 #else /* !WITH_MOD_REMESH */
195
196 static DerivedMesh *applyModifier(ModifierData *UNUSED(md),
197                                   const ModifierEvalContext *UNUSED(ctx),
198                                   DerivedMesh *derivedData)
199 {
200         return derivedData;
201 }
202
203 #endif /* !WITH_MOD_REMESH */
204
205 ModifierTypeInfo modifierType_Remesh = {
206         /* name */              "Remesh",
207         /* structName */        "RemeshModifierData",
208         /* structSize */        sizeof(RemeshModifierData),
209         /* type */              eModifierTypeType_Nonconstructive,
210         /* flags */             eModifierTypeFlag_AcceptsMesh |
211                                 eModifierTypeFlag_AcceptsCVs |
212                                 eModifierTypeFlag_SupportsEditmode,
213
214         /* copyData */          modifier_copyData_generic,
215
216         /* deformVerts_DM */    NULL,
217         /* deformMatrices_DM */ NULL,
218         /* deformVertsEM_DM */  NULL,
219         /* deformMatricesEM_DM*/NULL,
220         /* applyModifier_DM */  applyModifier,
221         /* applyModifierEM_DM */NULL,
222
223         /* deformVerts */       NULL,
224         /* deformMatrices */    NULL,
225         /* deformVertsEM */     NULL,
226         /* deformMatricesEM */  NULL,
227         /* applyModifier */     NULL,
228         /* applyModifierEM */   NULL,
229
230         /* initData */          initData,
231         /* requiredDataMask */  NULL,
232         /* freeData */          NULL,
233         /* isDisabled */        NULL,
234         /* updateDepsgraph */   NULL,
235         /* dependsOnTime */     NULL,
236         /* dependsOnNormals */  NULL,
237         /* foreachObjectLink */ NULL,
238         /* foreachIDLink */     NULL,
239 };