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