Extract common modifier parameters into ModifierEvalContext struct
[blender.git] / source / blender / modifiers / intern / MOD_mask.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_mask.c
32  *  \ingroup modifiers
33  */
34
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_utildefines.h"
39 #include "BLI_listbase.h"
40 #include "BLI_ghash.h"
41
42 #include "DNA_armature_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_modifier_types.h"
45 #include "DNA_object_types.h"
46
47 #include "BKE_action.h" /* BKE_pose_channel_find_name */
48 #include "BKE_cdderivedmesh.h"
49 #include "BKE_library_query.h"
50 #include "BKE_modifier.h"
51 #include "BKE_deform.h"
52
53 #include "DEG_depsgraph_build.h"
54
55 #include "MOD_modifiertypes.h"
56
57 #include "BLI_strict_flags.h"
58
59 static void copyData(ModifierData *md, ModifierData *target)
60 {
61 #if 0
62         MaskModifierData *mmd = (MaskModifierData *) md;
63         MaskModifierData *tmmd = (MaskModifierData *) target;
64 #endif
65         modifier_copyData_generic(md, target);
66 }
67
68 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md))
69 {
70         return CD_MASK_MDEFORMVERT;
71 }
72
73 static void foreachObjectLink(
74         ModifierData *md, Object *ob,
75         ObjectWalkFunc walk, void *userData)
76 {
77         MaskModifierData *mmd = (MaskModifierData *)md;
78         walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP);
79 }
80
81 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
82 {
83         MaskModifierData *mmd = (MaskModifierData *)md;
84         if (mmd->ob_arm) {
85                 bArmature *arm = (bArmature *)mmd->ob_arm->data;
86                 /* Tag relationship in depsgraph, but also on the armature. */
87                 /* TODO(sergey): Is it a proper relation here? */
88                 DEG_add_object_relation(ctx->node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
89                 arm->flag |= ARM_HAS_VIZ_DEPS;
90         }
91 }
92
93 static DerivedMesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx,
94                                   DerivedMesh *dm)
95 {
96         MaskModifierData *mmd = (MaskModifierData *)md;
97         Object *ob = ctx->object;
98         const bool found_test = (mmd->flag & MOD_MASK_INV) == 0;
99         DerivedMesh *result = NULL;
100         GHash *vertHash = NULL, *edgeHash, *polyHash;
101         GHashIterator gh_iter;
102         MDeformVert *dvert, *dv;
103         int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0;
104         int maxVerts, maxEdges, maxPolys;
105         int i;
106
107         const MVert *mvert_src;
108         const MEdge *medge_src;
109         const MPoly *mpoly_src;
110         const MLoop *mloop_src;
111
112         MPoly *mpoly_dst;
113         MLoop *mloop_dst;
114         MEdge *medge_dst;
115         MVert *mvert_dst;
116
117         int *loop_mapping;
118
119         dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
120         if (dvert == NULL) {
121                 return found_test ? CDDM_from_template(dm, 0, 0, 0, 0, 0) : dm;
122         }
123
124         /* Overview of Method:
125          *      1. Get the vertices that are in the vertexgroup of interest 
126          *      2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices
127          *      3. Make a new mesh containing only the mapping data
128          */
129         
130         /* get original number of verts, edges, and faces */
131         maxVerts = dm->getNumVerts(dm);
132         maxEdges = dm->getNumEdges(dm);
133         maxPolys = dm->getNumPolys(dm);
134         
135         /* check if we can just return the original mesh 
136          *      - must have verts and therefore verts assigned to vgroups to do anything useful
137          */
138         if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) ||
139             (maxVerts == 0) || BLI_listbase_is_empty(&ob->defbase))
140         {
141                 return dm;
142         }
143         
144         /* if mode is to use selected armature bones, aggregate the bone groups */
145         if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */
146                 Object *oba = mmd->ob_arm;
147                 bPoseChannel *pchan;
148                 bDeformGroup *def;
149                 bool *bone_select_array;
150                 int bone_select_tot = 0;
151                 const int defbase_tot = BLI_listbase_count(&ob->defbase);
152                 
153                 /* check that there is armature object with bones to use, otherwise return original mesh */
154                 if (ELEM(NULL, oba, oba->pose, ob->defbase.first))
155                         return dm;
156                 
157                 /* determine whether each vertexgroup is associated with a selected bone or not 
158                  * - each cell is a boolean saying whether bone corresponding to the ith group is selected
159                  * - groups that don't match a bone are treated as not existing (along with the corresponding ungrouped verts)
160                  */
161                 bone_select_array = MEM_malloc_arrayN((size_t)defbase_tot, sizeof(char), "mask array");
162                 
163                 for (i = 0, def = ob->defbase.first; def; def = def->next, i++) {
164                         pchan = BKE_pose_channel_find_name(oba->pose, def->name);
165                         if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
166                                 bone_select_array[i] = true;
167                                 bone_select_tot++;
168                         }
169                         else {
170                                 bone_select_array[i] = false;
171                         }
172                 }
173
174                 /* verthash gives mapping from original vertex indices to the new indices (including selected matches only)
175                  * key = oldindex, value = newindex
176                  */
177                 vertHash = BLI_ghash_int_new_ex("mask vert gh", (unsigned int)maxVerts);
178                 
179                 /* add vertices which exist in vertexgroups into vertHash for filtering 
180                  * - dv = for each vertex, what vertexgroups does it belong to
181                  * - dw = weight that vertex was assigned to a vertexgroup it belongs to
182                  */
183                 for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
184                         MDeformWeight *dw = dv->dw;
185                         bool found = false;
186                         int j;
187                         
188                         /* check the groups that vertex is assigned to, and see if it was any use */
189                         for (j = 0; j < dv->totweight; j++, dw++) {
190                                 if (dw->def_nr < defbase_tot) {
191                                         if (bone_select_array[dw->def_nr]) {
192                                                 if (dw->weight != 0.0f) {
193                                                         found = true;
194                                                         break;
195                                                 }
196                                         }
197                                 }
198                         }
199                         
200                         if (found_test != found) {
201                                 continue;
202                         }
203                         
204                         /* add to ghash for verts (numVerts acts as counter for mapping) */
205                         BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
206                         numVerts++;
207                 }
208                 
209                 /* free temp hashes */
210                 MEM_freeN(bone_select_array);
211         }
212         else {  /* --- Using Nominated VertexGroup only --- */
213                 int defgrp_index = defgroup_name_index(ob, mmd->vgroup);
214
215                 /* if no vgroup (i.e. dverts) found, return the initial mesh */
216                 if (defgrp_index == -1)
217                         return dm;
218                         
219                 /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
220                 vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (unsigned int)maxVerts);
221                 
222                 /* add vertices which exist in vertexgroup into ghash for filtering */
223                 for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
224                         const bool found = defvert_find_weight(dv, defgrp_index) != 0.0f;
225                         if (found_test != found) {
226                                 continue;
227                         }
228
229                         /* add to ghash for verts (numVerts acts as counter for mapping) */
230                         BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
231                         numVerts++;
232                 }
233         }
234
235         /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
236         edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (unsigned int)maxEdges);
237         polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (unsigned int)maxPolys);
238
239         mvert_src = dm->getVertArray(dm);
240         medge_src = dm->getEdgeArray(dm);
241         mpoly_src = dm->getPolyArray(dm);
242         mloop_src = dm->getLoopArray(dm);
243
244         /* overalloc, assume all polys are seen */
245         loop_mapping = MEM_malloc_arrayN((size_t)maxPolys, sizeof(int), "mask loopmap");
246
247         /* loop over edges and faces, and do the same thing to 
248          * ensure that they only reference existing verts 
249          */
250         for (i = 0; i < maxEdges; i++) {
251                 const MEdge *me = &medge_src[i];
252                 
253                 /* only add if both verts will be in new mesh */
254                 if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1)) &&
255                     BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2)))
256                 {
257                         BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges));
258                         numEdges++;
259                 }
260         }
261         for (i = 0; i < maxPolys; i++) {
262                 const MPoly *mp_src = &mpoly_src[i];
263                 const MLoop *ml_src = &mloop_src[mp_src->loopstart];
264                 bool ok = true;
265                 int j;
266                 
267                 for (j = 0; j < mp_src->totloop; j++, ml_src++) {
268                         if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml_src->v))) {
269                                 ok = false;
270                                 break;
271                         }
272                 }
273                 
274                 /* all verts must be available */
275                 if (ok) {
276                         BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys));
277                         loop_mapping[numPolys] = numLoops;
278                         numPolys++;
279                         numLoops += mp_src->totloop;
280                 }
281         }
282         
283         
284         /* now we know the number of verts, edges and faces, 
285          * we can create the new (reduced) mesh
286          */
287         result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys);
288         
289         mpoly_dst = CDDM_get_polys(result);
290         mloop_dst = CDDM_get_loops(result);
291         medge_dst = CDDM_get_edges(result);
292         mvert_dst = CDDM_get_verts(result);
293
294         /* using ghash-iterators, map data into new mesh */
295         /* vertices */
296         GHASH_ITER (gh_iter, vertHash) {
297                 const MVert *v_src;
298                 MVert *v_dst;
299                 const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
300                 const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
301                 
302                 v_src = &mvert_src[i_src];
303                 v_dst = &mvert_dst[i_dst];
304
305                 *v_dst = *v_src;
306                 DM_copy_vert_data(dm, result, i_src, i_dst, 1);
307         }
308                 
309         /* edges */
310         GHASH_ITER (gh_iter, edgeHash) {
311                 const MEdge *e_src;
312                 MEdge *e_dst;
313                 const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
314                 const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
315                 
316                 e_src = &medge_src[i_src];
317                 e_dst = &medge_dst[i_dst];
318
319                 DM_copy_edge_data(dm, result, i_src, i_dst, 1);
320                 *e_dst = *e_src;
321                 e_dst->v1 = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(e_src->v1)));
322                 e_dst->v2 = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(e_src->v2)));
323         }
324         
325         /* faces */
326         GHASH_ITER (gh_iter, polyHash) {
327                 const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
328                 const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
329                 const MPoly *mp_src = &mpoly_src[i_src];
330                 MPoly *mp_dst = &mpoly_dst[i_dst];
331                 const int i_ml_src = mp_src->loopstart;
332                 const int i_ml_dst = loop_mapping[i_dst];
333                 const MLoop *ml_src = &mloop_src[i_ml_src];
334                 MLoop *ml_dst = &mloop_dst[i_ml_dst];
335                 
336                 DM_copy_poly_data(dm, result, i_src, i_dst, 1);
337                 DM_copy_loop_data(dm, result, i_ml_src, i_ml_dst, mp_src->totloop);
338
339                 *mp_dst = *mp_src;
340                 mp_dst->loopstart = i_ml_dst;
341                 for (i = 0; i < mp_src->totloop; i++) {
342                         ml_dst[i].v = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(ml_src[i].v)));
343                         ml_dst[i].e = GET_UINT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_UINT_IN_POINTER(ml_src[i].e)));
344                 }
345         }
346
347         MEM_freeN(loop_mapping);
348
349         /* why is this needed? - campbell */
350         /* recalculate normals */
351         result->dirty |= DM_DIRTY_NORMALS;
352         
353         /* free hashes */
354         BLI_ghash_free(vertHash, NULL, NULL);
355         BLI_ghash_free(edgeHash, NULL, NULL);
356         BLI_ghash_free(polyHash, NULL, NULL);
357
358         /* return the new mesh */
359         return result;
360 }
361
362
363 ModifierTypeInfo modifierType_Mask = {
364         /* name */              "Mask",
365         /* structName */        "MaskModifierData",
366         /* structSize */        sizeof(MaskModifierData),
367         /* type */              eModifierTypeType_Nonconstructive,
368         /* flags */             eModifierTypeFlag_AcceptsMesh |
369                                 eModifierTypeFlag_SupportsMapping |
370                                 eModifierTypeFlag_SupportsEditmode,
371
372         /* copyData */          copyData,
373
374         /* deformVerts_DM */    NULL,
375         /* deformMatrices_DM */ NULL,
376         /* deformVertsEM_DM */  NULL,
377         /* deformMatricesEM_DM*/NULL,
378         /* applyModifier_DM */  applyModifier,
379         /* applyModifierEM_DM */NULL,
380
381         /* deformVerts */       NULL,
382         /* deformMatrices */    NULL,
383         /* deformVertsEM */     NULL,
384         /* deformMatricesEM */  NULL,
385         /* applyModifier */     NULL,
386         /* applyModifierEM */   NULL,
387
388         /* initData */          NULL,
389         /* requiredDataMask */  requiredDataMask,
390         /* freeData */          NULL,
391         /* isDisabled */        NULL,
392         /* updateDepsgraph */   updateDepsgraph,
393         /* dependsOnTime */     NULL,
394         /* dependsOnNormals */  NULL,
395         /* foreachObjectLink */ foreachObjectLink,
396         /* foreachIDLink */     NULL,
397         /* foreachTexLink */    NULL,
398 };