small feature request from zanqdo, merging in the mirror modifier is now optional...
[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                 
146                 if(mmd->flag & MOD_MIR_MERGE)
147                         isShared = ABS(co[axis])<=tolerance;
148                 else
149                         isShared = 0;
150                 
151                 /* Because the topology result (# of vertices) must be the same if
152                 * the mesh data is overridden by vertex cos, have to calc sharedness
153                 * based on original coordinates. This is why we test before copy.
154                 */
155                 DM_copy_vert_data(dm, result, i, numVerts, 1);
156                 *mv = inMV;
157                 numVerts++;
158                 
159                 indexMap[i][0] = numVerts - 1;
160                 indexMap[i][1] = !isShared;
161                 //
162                 if(isShared ) {
163                         co[axis] = 0;
164                         if (mmd->mirror_ob) {
165                                 mul_m4_v3(imtx, co);
166                         }
167                         copy_v3_v3(mv->co, co);
168                         
169                         mv->flag |= ME_VERT_MERGED;
170                 } else {
171                         MVert *mv2 = CDDM_get_vert(result, numVerts);
172                         
173                         DM_copy_vert_data(dm, result, i, numVerts, 1);
174                         *mv2 = *mv;
175                         
176                         co[axis] = -co[axis];
177                         if (mmd->mirror_ob) {
178                                 mul_m4_v3(imtx, co);
179                         }
180                         copy_v3_v3(mv2->co, co);
181                         
182                         if (do_vgroup_mirr) {
183                                 MDeformVert *dvert= DM_get_vert_data(result, numVerts, CD_MDEFORMVERT);
184                                 if(dvert) {
185                                         defvert_flip(dvert, flip_map);
186                                 }
187                         }
188
189                         numVerts++;
190                 }
191         }
192
193         for(i = 0; i < maxEdges; i++) {
194                 MEdge inMED;
195                 MEdge *med = CDDM_get_edge(result, numEdges);
196                 
197                 dm->getEdge(dm, i, &inMED);
198                 
199                 DM_copy_edge_data(dm, result, i, numEdges, 1);
200                 *med = inMED;
201                 numEdges++;
202                 
203                 med->v1 = indexMap[inMED.v1][0];
204                 med->v2 = indexMap[inMED.v2][0];
205                 if(initFlags)
206                         med->flag |= ME_EDGEDRAW | ME_EDGERENDER;
207                 
208                 if(indexMap[inMED.v1][1] || indexMap[inMED.v2][1]) {
209                         MEdge *med2 = CDDM_get_edge(result, numEdges);
210                         
211                         DM_copy_edge_data(dm, result, i, numEdges, 1);
212                         *med2 = *med;
213                         numEdges++;
214                         
215                         med2->v1 += indexMap[inMED.v1][1];
216                         med2->v2 += indexMap[inMED.v2][1];
217                 }
218         }
219
220         for(i = 0; i < maxFaces; i++) {
221                 MFace inMF;
222                 MFace *mf = CDDM_get_face(result, numFaces);
223                 
224                 dm->getFace(dm, i, &inMF);
225                 
226                 DM_copy_face_data(dm, result, i, numFaces, 1);
227                 *mf = inMF;
228                 numFaces++;
229                 
230                 mf->v1 = indexMap[inMF.v1][0];
231                 mf->v2 = indexMap[inMF.v2][0];
232                 mf->v3 = indexMap[inMF.v3][0];
233                 mf->v4 = indexMap[inMF.v4][0];
234                 
235                 if(indexMap[inMF.v1][1]
236                                  || indexMap[inMF.v2][1]
237                                  || indexMap[inMF.v3][1]
238                                  || (mf->v4 && indexMap[inMF.v4][1])) {
239                         MFace *mf2 = CDDM_get_face(result, numFaces);
240                         static int corner_indices[4] = {2, 1, 0, 3};
241                         
242                         DM_copy_face_data(dm, result, i, numFaces, 1);
243                         *mf2 = *mf;
244                         
245                         mf2->v1 += indexMap[inMF.v1][1];
246                         mf2->v2 += indexMap[inMF.v2][1];
247                         mf2->v3 += indexMap[inMF.v3][1];
248                         if(inMF.v4) mf2->v4 += indexMap[inMF.v4][1];
249                         
250                         /* mirror UVs if enabled */
251                         if(mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) {
252                                 MTFace *tf = result->getFaceData(result, numFaces, CD_MTFACE);
253                                 if(tf) {
254                                         int j;
255                                         for(j = 0; j < 4; ++j) {
256                                                 if(mmd->flag & MOD_MIR_MIRROR_U)
257                                                         tf->uv[j][0] = 1.0f - tf->uv[j][0];
258                                                 if(mmd->flag & MOD_MIR_MIRROR_V)
259                                                         tf->uv[j][1] = 1.0f - tf->uv[j][1];
260                                         }
261                                 }
262                         }
263                         
264                         /* Flip face normal */
265                         SWAP(int, mf2->v1, mf2->v3);
266                         DM_swap_face_data(result, numFaces, corner_indices);
267                         
268                         test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3);
269                         numFaces++;
270                 }
271         }
272
273         if (flip_map) MEM_freeN(flip_map);
274
275         MEM_freeN(indexMap);
276
277         CDDM_lower_num_verts(result, numVerts);
278         CDDM_lower_num_edges(result, numEdges);
279         CDDM_lower_num_faces(result, numFaces);
280
281         return result;
282 }
283
284 static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
285                                                 Object *ob, DerivedMesh *dm,
286                                                 int initFlags)
287 {
288         DerivedMesh *result = dm;
289
290         /* check which axes have been toggled and mirror accordingly */
291         if(mmd->flag & MOD_MIR_AXIS_X) {
292                 result = doMirrorOnAxis(mmd, ob, result, initFlags, 0);
293         }
294         if(mmd->flag & MOD_MIR_AXIS_Y) {
295                 DerivedMesh *tmp = result;
296                 result = doMirrorOnAxis(mmd, ob, result, initFlags, 1);
297                 if(tmp != dm) tmp->release(tmp); /* free intermediate results */
298         }
299         if(mmd->flag & MOD_MIR_AXIS_Z) {
300                 DerivedMesh *tmp = result;
301                 result = doMirrorOnAxis(mmd, ob, result, initFlags, 2);
302                 if(tmp != dm) tmp->release(tmp); /* free intermediate results */
303         }
304
305         return result;
306 }
307
308 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
309                                                 DerivedMesh *derivedData,
310                                                 int UNUSED(useRenderParams),
311                                                 int UNUSED(isFinalCalc))
312 {
313         DerivedMesh *result;
314         MirrorModifierData *mmd = (MirrorModifierData*) md;
315
316         result = mirrorModifier__doMirror(mmd, ob, derivedData, 0);
317
318         if(result != derivedData)
319                 CDDM_calc_normals(result);
320         
321         return result;
322 }
323
324 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
325                                                 struct EditMesh *UNUSED(editData),
326                                                 DerivedMesh *derivedData)
327 {
328         return applyModifier(md, ob, derivedData, 0, 1);
329 }
330
331
332 ModifierTypeInfo modifierType_Mirror = {
333         /* name */              "Mirror",
334         /* structName */        "MirrorModifierData",
335         /* structSize */        sizeof(MirrorModifierData),
336         /* type */              eModifierTypeType_Constructive,
337         /* flags */             eModifierTypeFlag_AcceptsMesh
338                                                         | eModifierTypeFlag_SupportsMapping
339                                                         | eModifierTypeFlag_SupportsEditmode
340                                                         | eModifierTypeFlag_EnableInEditmode
341                                                         | eModifierTypeFlag_AcceptsCVs,
342
343         /* copyData */          copyData,
344         /* deformVerts */       0,
345         /* deformMatrices */    0,
346         /* deformVertsEM */     0,
347         /* deformMatricesEM */  0,
348         /* applyModifier */     applyModifier,
349         /* applyModifierEM */   applyModifierEM,
350         /* initData */          initData,
351         /* requiredDataMask */  0,
352         /* freeData */          0,
353         /* isDisabled */        0,
354         /* updateDepgraph */    updateDepgraph,
355         /* dependsOnTime */     0,
356         /* dependsOnNormals */  0,
357         /* foreachObjectLink */ foreachObjectLink,
358         /* foreachIDLink */     0,
359 };