9546bf1300b95fd36887220f435a676d9c503012
[blender.git] / source / blender / modifiers / intern / MOD_mirror.c
1 /*
2 * $Id$
3 *
4 * ***** BEGIN GPL LICENSE BLOCK *****
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software  Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
21 * All rights reserved.
22 *
23 * Contributor(s): Daniel Dunbar
24 *                 Ton Roosendaal,
25 *                 Ben Batt,
26 *                 Brecht Van Lommel,
27 *                 Campbell Barton
28 *
29 * ***** END GPL LICENSE BLOCK *****
30 *
31 */
32
33 #include "DNA_meshdata_types.h"
34 #include "DNA_object_types.h"
35
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38
39 #include "BKE_cdderivedmesh.h"
40 #include "BKE_mesh.h"
41 #include "BKE_modifier.h"
42 #include "BKE_deform.h"
43
44
45 #include "MEM_guardedalloc.h"
46 #include "depsgraph_private.h"
47
48 static void initData(ModifierData *md)
49 {
50         MirrorModifierData *mmd = (MirrorModifierData*) md;
51
52         mmd->flag |= (MOD_MIR_AXIS_X | MOD_MIR_VGROUP);
53         mmd->tolerance = 0.001;
54         mmd->mirror_ob = NULL;
55 }
56
57 static void copyData(ModifierData *md, ModifierData *target)
58 {
59         MirrorModifierData *mmd = (MirrorModifierData*) md;
60         MirrorModifierData *tmmd = (MirrorModifierData*) target;
61
62         tmmd->axis = mmd->axis;
63         tmmd->flag = mmd->flag;
64         tmmd->tolerance = mmd->tolerance;
65         tmmd->mirror_ob = mmd->mirror_ob;
66 }
67
68 static void foreachObjectLink(
69                                                  ModifierData *md, Object *ob,
70           void (*walk)(void *userData, Object *ob, Object **obpoin),
71                  void *userData)
72 {
73         MirrorModifierData *mmd = (MirrorModifierData*) md;
74
75         walk(userData, ob, &mmd->mirror_ob);
76 }
77
78 static void updateDepgraph(ModifierData *md, DagForest *forest,
79                                                 struct Scene *UNUSED(scene),
80                                                 Object *UNUSED(ob),
81                                                 DagNode *obNode)
82 {
83         MirrorModifierData *mmd = (MirrorModifierData*) md;
84
85         if(mmd->mirror_ob) {
86                 DagNode *latNode = dag_get_node(forest, mmd->mirror_ob);
87
88                 dag_add_relation(forest, latNode, obNode,
89                                  DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Mirror Modifier");
90         }
91 }
92
93 static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
94                 Object *ob,
95                 DerivedMesh *dm,
96                 int initFlags,
97                 int axis)
98 {
99         int i;
100         float tolerance = mmd->tolerance;
101         DerivedMesh *result;
102         int numVerts, numEdges, numFaces;
103         int maxVerts = dm->getNumVerts(dm);
104         int maxEdges = dm->getNumEdges(dm);
105         int maxFaces = dm->getNumFaces(dm);
106         int *flip_map= NULL;
107         int do_vgroup_mirr= (mmd->flag & MOD_MIR_VGROUP);
108         int (*indexMap)[2];
109         float mtx[4][4], imtx[4][4];
110
111         numVerts = numEdges = numFaces = 0;
112
113         indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap");
114
115         result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2);
116
117
118         if (do_vgroup_mirr) {
119                 flip_map= defgroup_flip_map(ob, 0);
120                 if(flip_map == NULL)
121                         do_vgroup_mirr= 0;
122         }
123
124         if (mmd->mirror_ob) {
125                 float obinv[4][4];
126                 
127                 invert_m4_m4(obinv, mmd->mirror_ob->obmat);
128                 mul_m4_m4m4(mtx, ob->obmat, obinv);
129                 invert_m4_m4(imtx, mtx);
130         }
131
132         for(i = 0; i < maxVerts; i++) {
133                 MVert inMV;
134                 MVert *mv = CDDM_get_vert(result, numVerts);
135                 int isShared;
136                 float co[3];
137                 
138                 dm->getVert(dm, i, &inMV);
139                 
140                 copy_v3_v3(co, inMV.co);
141                 
142                 if (mmd->mirror_ob) {
143                         mul_m4_v3(mtx, co);
144                 }
145                 isShared = ABS(co[axis])<=tolerance;
146                 
147                 /* Because the topology result (# of vertices) must be the same if
148                 * the mesh data is overridden by vertex cos, have to calc sharedness
149                 * based on original coordinates. This is why we test before copy.
150                 */
151                 DM_copy_vert_data(dm, result, i, numVerts, 1);
152                 *mv = inMV;
153                 numVerts++;
154                 
155                 indexMap[i][0] = numVerts - 1;
156                 indexMap[i][1] = !isShared;
157                 
158                 if(isShared) {
159                         co[axis] = 0;
160                         if (mmd->mirror_ob) {
161                                 mul_m4_v3(imtx, co);
162                         }
163                         copy_v3_v3(mv->co, co);
164                         
165                         mv->flag |= ME_VERT_MERGED;
166                 } else {
167                         MVert *mv2 = CDDM_get_vert(result, numVerts);
168                         
169                         DM_copy_vert_data(dm, result, i, numVerts, 1);
170                         *mv2 = *mv;
171                         
172                         co[axis] = -co[axis];
173                         if (mmd->mirror_ob) {
174                                 mul_m4_v3(imtx, co);
175                         }
176                         copy_v3_v3(mv2->co, co);
177                         
178                         if (do_vgroup_mirr) {
179                                 MDeformVert *dvert= DM_get_vert_data(result, numVerts, CD_MDEFORMVERT);
180                                 if(dvert) {
181                                         defvert_flip(dvert, flip_map);
182                                 }
183                         }
184
185                         numVerts++;
186                 }
187         }
188
189         for(i = 0; i < maxEdges; i++) {
190                 MEdge inMED;
191                 MEdge *med = CDDM_get_edge(result, numEdges);
192                 
193                 dm->getEdge(dm, i, &inMED);
194                 
195                 DM_copy_edge_data(dm, result, i, numEdges, 1);
196                 *med = inMED;
197                 numEdges++;
198                 
199                 med->v1 = indexMap[inMED.v1][0];
200                 med->v2 = indexMap[inMED.v2][0];
201                 if(initFlags)
202                         med->flag |= ME_EDGEDRAW | ME_EDGERENDER;
203                 
204                 if(indexMap[inMED.v1][1] || indexMap[inMED.v2][1]) {
205                         MEdge *med2 = CDDM_get_edge(result, numEdges);
206                         
207                         DM_copy_edge_data(dm, result, i, numEdges, 1);
208                         *med2 = *med;
209                         numEdges++;
210                         
211                         med2->v1 += indexMap[inMED.v1][1];
212                         med2->v2 += indexMap[inMED.v2][1];
213                 }
214         }
215
216         for(i = 0; i < maxFaces; i++) {
217                 MFace inMF;
218                 MFace *mf = CDDM_get_face(result, numFaces);
219                 
220                 dm->getFace(dm, i, &inMF);
221                 
222                 DM_copy_face_data(dm, result, i, numFaces, 1);
223                 *mf = inMF;
224                 numFaces++;
225                 
226                 mf->v1 = indexMap[inMF.v1][0];
227                 mf->v2 = indexMap[inMF.v2][0];
228                 mf->v3 = indexMap[inMF.v3][0];
229                 mf->v4 = indexMap[inMF.v4][0];
230                 
231                 if(indexMap[inMF.v1][1]
232                                  || indexMap[inMF.v2][1]
233                                  || indexMap[inMF.v3][1]
234                                  || (mf->v4 && indexMap[inMF.v4][1])) {
235                         MFace *mf2 = CDDM_get_face(result, numFaces);
236                         static int corner_indices[4] = {2, 1, 0, 3};
237                         
238                         DM_copy_face_data(dm, result, i, numFaces, 1);
239                         *mf2 = *mf;
240                         
241                         mf2->v1 += indexMap[inMF.v1][1];
242                         mf2->v2 += indexMap[inMF.v2][1];
243                         mf2->v3 += indexMap[inMF.v3][1];
244                         if(inMF.v4) mf2->v4 += indexMap[inMF.v4][1];
245                         
246                         /* mirror UVs if enabled */
247                         if(mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) {
248                                 MTFace *tf = result->getFaceData(result, numFaces, CD_MTFACE);
249                                 if(tf) {
250                                         int j;
251                                         for(j = 0; j < 4; ++j) {
252                                                 if(mmd->flag & MOD_MIR_MIRROR_U)
253                                                         tf->uv[j][0] = 1.0f - tf->uv[j][0];
254                                                 if(mmd->flag & MOD_MIR_MIRROR_V)
255                                                         tf->uv[j][1] = 1.0f - tf->uv[j][1];
256                                         }
257                                 }
258                         }
259                         
260                         /* Flip face normal */
261                         SWAP(int, mf2->v1, mf2->v3);
262                         DM_swap_face_data(result, numFaces, corner_indices);
263                         
264                         test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3);
265                         numFaces++;
266                 }
267         }
268
269         if (flip_map) MEM_freeN(flip_map);
270
271         MEM_freeN(indexMap);
272
273         CDDM_lower_num_verts(result, numVerts);
274         CDDM_lower_num_edges(result, numEdges);
275         CDDM_lower_num_faces(result, numFaces);
276
277         return result;
278 }
279
280 static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
281                                                 Object *ob, DerivedMesh *dm,
282                                                 int initFlags)
283 {
284         DerivedMesh *result = dm;
285
286         /* check which axes have been toggled and mirror accordingly */
287         if(mmd->flag & MOD_MIR_AXIS_X) {
288                 result = doMirrorOnAxis(mmd, ob, result, initFlags, 0);
289         }
290         if(mmd->flag & MOD_MIR_AXIS_Y) {
291                 DerivedMesh *tmp = result;
292                 result = doMirrorOnAxis(mmd, ob, result, initFlags, 1);
293                 if(tmp != dm) tmp->release(tmp); /* free intermediate results */
294         }
295         if(mmd->flag & MOD_MIR_AXIS_Z) {
296                 DerivedMesh *tmp = result;
297                 result = doMirrorOnAxis(mmd, ob, result, initFlags, 2);
298                 if(tmp != dm) tmp->release(tmp); /* free intermediate results */
299         }
300
301         return result;
302 }
303
304 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
305                                                 DerivedMesh *derivedData,
306                                                 int UNUSED(useRenderParams),
307                                                 int UNUSED(isFinalCalc))
308 {
309         DerivedMesh *result;
310         MirrorModifierData *mmd = (MirrorModifierData*) md;
311
312         result = mirrorModifier__doMirror(mmd, ob, derivedData, 0);
313
314         if(result != derivedData)
315                 CDDM_calc_normals(result);
316         
317         return result;
318 }
319
320 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
321                                                 struct EditMesh *UNUSED(editData),
322                                                 DerivedMesh *derivedData)
323 {
324         return applyModifier(md, ob, derivedData, 0, 1);
325 }
326
327
328 ModifierTypeInfo modifierType_Mirror = {
329         /* name */              "Mirror",
330         /* structName */        "MirrorModifierData",
331         /* structSize */        sizeof(MirrorModifierData),
332         /* type */              eModifierTypeType_Constructive,
333         /* flags */             eModifierTypeFlag_AcceptsMesh
334                                                         | eModifierTypeFlag_SupportsMapping
335                                                         | eModifierTypeFlag_SupportsEditmode
336                                                         | eModifierTypeFlag_EnableInEditmode
337                                                         | eModifierTypeFlag_AcceptsCVs,
338
339         /* copyData */          copyData,
340         /* deformVerts */       0,
341         /* deformMatrices */    0,
342         /* deformVertsEM */     0,
343         /* deformMatricesEM */  0,
344         /* applyModifier */     applyModifier,
345         /* applyModifierEM */   applyModifierEM,
346         /* initData */          initData,
347         /* requiredDataMask */  0,
348         /* freeData */          0,
349         /* isDisabled */        0,
350         /* updateDepgraph */    updateDepgraph,
351         /* dependsOnTime */     0,
352         /* dependsOnNormals */  0,
353         /* foreachObjectLink */ foreachObjectLink,
354         /* foreachIDLink */     0,
355 };