Blender  V2.59
MOD_mask.c
Go to the documentation of this file.
00001 /*
00002 * $Id: MOD_mask.c 37467 2011-06-14 04:19:00Z campbellbarton $
00003 *
00004 * ***** BEGIN GPL LICENSE BLOCK *****
00005 *
00006 * This program is free software; you can redistribute it and/or
00007 * modify it under the terms of the GNU General Public License
00008 * as published by the Free Software Foundation; either version 2
00009 * of the License, or (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU General Public License
00017 * along with this program; if not, write to the Free Software  Foundation,
00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 *
00020 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
00021 * All rights reserved.
00022 *
00023 * Contributor(s): Daniel Dunbar
00024 *                 Ton Roosendaal,
00025 *                 Ben Batt,
00026 *                 Brecht Van Lommel,
00027 *                 Campbell Barton
00028 *
00029 * ***** END GPL LICENSE BLOCK *****
00030 *
00031 */
00032 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "BLI_utildefines.h"
00041 #include "BLI_ghash.h"
00042 
00043 #include "DNA_armature_types.h"
00044 #include "DNA_meshdata_types.h"
00045 #include "DNA_modifier_types.h"
00046 #include "DNA_object_types.h"
00047 
00048 #include "BKE_action.h" /* get_pose_channel */
00049 #include "BKE_cdderivedmesh.h"
00050 #include "BKE_mesh.h"
00051 #include "BKE_modifier.h"
00052 #include "BKE_deform.h"
00053 
00054 #include "depsgraph_private.h"
00055 
00056 #include "MOD_util.h"
00057 
00058 static void copyData(ModifierData *md, ModifierData *target)
00059 {
00060         MaskModifierData *mmd = (MaskModifierData*) md;
00061         MaskModifierData *tmmd = (MaskModifierData*) target;
00062         
00063         BLI_strncpy(tmmd->vgroup, mmd->vgroup, sizeof(tmmd->vgroup));
00064         tmmd->flag = mmd->flag;
00065 }
00066 
00067 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md))
00068 {
00069         return CD_MASK_MDEFORMVERT;
00070 }
00071 
00072 static void foreachObjectLink(
00073                                                   ModifierData *md, Object *ob,
00074            void (*walk)(void *userData, Object *ob, Object **obpoin),
00075                   void *userData)
00076 {
00077         MaskModifierData *mmd = (MaskModifierData *)md;
00078         walk(userData, ob, &mmd->ob_arm);
00079 }
00080 
00081 static void updateDepgraph(ModifierData *md, DagForest *forest,
00082                                                 struct Scene *UNUSED(scene),
00083                                                 Object *UNUSED(ob),
00084                                                 DagNode *obNode)
00085 {
00086         MaskModifierData *mmd = (MaskModifierData *)md;
00087 
00088         if (mmd->ob_arm) 
00089         {
00090                 DagNode *armNode = dag_get_node(forest, mmd->ob_arm);
00091                 
00092                 dag_add_relation(forest, armNode, obNode,
00093                                 DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Mask Modifier");
00094         }
00095 }
00096 
00097 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
00098                                                 DerivedMesh *derivedData,
00099                                                 int UNUSED(useRenderParams),
00100                                                 int UNUSED(isFinalCalc))
00101 {
00102         MaskModifierData *mmd= (MaskModifierData *)md;
00103         DerivedMesh *dm= derivedData, *result= NULL;
00104         GHash *vertHash=NULL, *edgeHash, *faceHash;
00105         GHashIterator *hashIter;
00106         MDeformVert *dvert= NULL, *dv;
00107         int numFaces=0, numEdges=0, numVerts=0;
00108         int maxVerts, maxEdges, maxFaces;
00109         int i;
00110         
00111         /* Overview of Method:
00112          *      1. Get the vertices that are in the vertexgroup of interest 
00113          *      2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices
00114          *      3. Make a new mesh containing only the mapping data
00115          */
00116         
00117         /* get original number of verts, edges, and faces */
00118         maxVerts= dm->getNumVerts(dm);
00119         maxEdges= dm->getNumEdges(dm);
00120         maxFaces= dm->getNumFaces(dm);
00121         
00122         /* check if we can just return the original mesh 
00123          *      - must have verts and therefore verts assigned to vgroups to do anything useful
00124          */
00125         if ( !(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) ||
00126                  (maxVerts == 0) || (ob->defbase.first == NULL) )
00127         {
00128                 return derivedData;
00129         }
00130         
00131         /* if mode is to use selected armature bones, aggregate the bone groups */
00132         if (mmd->mode == MOD_MASK_MODE_ARM) /* --- using selected bones --- */
00133         {
00134                 GHash *vgroupHash;
00135                 Object *oba= mmd->ob_arm;
00136                 bPoseChannel *pchan;
00137                 bDeformGroup *def;
00138                 char *bone_select_array;
00139                 int bone_select_tot= 0;
00140                 
00141                 /* check that there is armature object with bones to use, otherwise return original mesh */
00142                 if (ELEM3(NULL, mmd->ob_arm, mmd->ob_arm->pose, ob->defbase.first))
00143                         return derivedData;
00144 
00145                 bone_select_array= MEM_mallocN(BLI_countlist(&ob->defbase) * sizeof(char), "mask array");
00146 
00147                 for (i = 0, def = ob->defbase.first; def; def = def->next, i++)
00148                 {
00149                         if (((pchan= get_pose_channel(oba->pose, def->name)) && pchan->bone && (pchan->bone->flag & BONE_SELECTED)))
00150                         {
00151                                 bone_select_array[i]= TRUE;
00152                                 bone_select_tot++;
00153                         }
00154                         else {
00155                                 bone_select_array[i]= FALSE;
00156                         }
00157                 }
00158 
00159                 /* hashes for finding mapping of:
00160                  *      - vgroups to indices -> vgroupHash  (string, int)
00161                  *      - bones to vgroup indices -> boneHash (index of vgroup, dummy)
00162                  */
00163                 vgroupHash= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "mask vgroup gh");
00164                 
00165                 /* build mapping of names of vertex groups to indices */
00166                 for (i = 0, def = ob->defbase.first; def; def = def->next, i++) 
00167                         BLI_ghash_insert(vgroupHash, def->name, SET_INT_IN_POINTER(i));
00168                 
00169                 /* if no bones selected, free hashes and return original mesh */
00170                 if (bone_select_tot == 0)
00171                 {
00172                         BLI_ghash_free(vgroupHash, NULL, NULL);
00173                         MEM_freeN(bone_select_array);
00174                         
00175                         return derivedData;
00176                 }
00177                 
00178                 /* repeat the previous check, but for dverts */
00179                 dvert= dm->getVertDataArray(dm, CD_MDEFORMVERT);
00180                 if (dvert == NULL)
00181                 {
00182                         BLI_ghash_free(vgroupHash, NULL, NULL);
00183                         MEM_freeN(bone_select_array);
00184                         
00185                         return derivedData;
00186                 }
00187                 
00188                 /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
00189                 vertHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert gh");
00190                 
00191                 /* add vertices which exist in vertexgroups into vertHash for filtering */
00192                 for (i= 0, dv= dvert; i < maxVerts; i++, dv++)
00193                 {
00194                         MDeformWeight *dw= dv->dw;
00195                         int j;
00196 
00197                         for (j= dv->totweight; j > 0; j--, dw++)
00198                         {
00199                                 if (bone_select_array[dw->def_nr])
00200                                 {
00201                                         if(dw->weight != 0.0f) {
00202                                                 break;
00203                                         }
00204                                 }
00205                         }
00206                         
00207                         /* check if include vert in vertHash */
00208                         if (mmd->flag & MOD_MASK_INV) {
00209                                 /* if this vert is in the vgroup, don't include it in vertHash */
00210                                 if (dw) continue;
00211                         }
00212                         else {
00213                                 /* if this vert isn't in the vgroup, don't include it in vertHash */
00214                                 if (!dw) continue;
00215                         }
00216                         
00217                         /* add to ghash for verts (numVerts acts as counter for mapping) */
00218                         BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
00219                         numVerts++;
00220                 }
00221                 
00222                 /* free temp hashes */
00223                 BLI_ghash_free(vgroupHash, NULL, NULL);
00224                 MEM_freeN(bone_select_array);
00225         }
00226         else            /* --- Using Nominated VertexGroup only --- */ 
00227         {
00228                 int defgrp_index = defgroup_name_index(ob, mmd->vgroup);
00229                 
00230                 /* get dverts */
00231                 if (defgrp_index >= 0)
00232                         dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
00233                         
00234                 /* if no vgroup (i.e. dverts) found, return the initial mesh */
00235                 if ((defgrp_index < 0) || (dvert == NULL))
00236                         return dm;
00237                         
00238                 /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
00239                 vertHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert2 bh");
00240                 
00241                 /* add vertices which exist in vertexgroup into ghash for filtering */
00242                 for (i= 0, dv= dvert; i < maxVerts; i++, dv++)
00243                 {
00244                         const int weight_set= defvert_find_weight(dv, defgrp_index) != 0.0f;
00245                         
00246                         /* check if include vert in vertHash */
00247                         if (mmd->flag & MOD_MASK_INV) {
00248                                 /* if this vert is in the vgroup, don't include it in vertHash */
00249                                 if (weight_set) continue;
00250                         }
00251                         else {
00252                                 /* if this vert isn't in the vgroup, don't include it in vertHash */
00253                                 if (!weight_set) continue;
00254                         }
00255                         
00256                         /* add to ghash for verts (numVerts acts as counter for mapping) */
00257                         BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
00258                         numVerts++;
00259                 }
00260         }
00261         
00262         /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
00263         edgeHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask ed2 gh");
00264         faceHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask fa2 gh");
00265         
00266         /* loop over edges and faces, and do the same thing to 
00267          * ensure that they only reference existing verts 
00268          */
00269         for (i = 0; i < maxEdges; i++) 
00270         {
00271                 MEdge me;
00272                 dm->getEdge(dm, i, &me);
00273                 
00274                 /* only add if both verts will be in new mesh */
00275                 if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) &&
00276                          BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2)) )
00277                 {
00278                         BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges));
00279                         numEdges++;
00280                 }
00281         }
00282         for (i = 0; i < maxFaces; i++) 
00283         {
00284                 MFace mf;
00285                 dm->getFace(dm, i, &mf);
00286                 
00287                 /* all verts must be available */
00288                 if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)) &&
00289                          BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v2)) &&
00290                          BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v3)) &&
00291                         (mf.v4==0 || BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v4))) )
00292                 {
00293                         BLI_ghash_insert(faceHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numFaces));
00294                         numFaces++;
00295                 }
00296         }
00297         
00298         
00299         /* now we know the number of verts, edges and faces, 
00300          * we can create the new (reduced) mesh
00301          */
00302         result = CDDM_from_template(dm, numVerts, numEdges, numFaces);
00303         
00304         
00305         /* using ghash-iterators, map data into new mesh */
00306                 /* vertices */
00307         for ( hashIter = BLI_ghashIterator_new(vertHash);
00308                   !BLI_ghashIterator_isDone(hashIter);
00309                   BLI_ghashIterator_step(hashIter) ) 
00310         {
00311                 MVert source;
00312                 MVert *dest;
00313                 int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
00314                 int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
00315                 
00316                 dm->getVert(dm, oldIndex, &source);
00317                 dest = CDDM_get_vert(result, newIndex);
00318                 
00319                 DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
00320                 *dest = source;
00321         }
00322         BLI_ghashIterator_free(hashIter);
00323                 
00324                 /* edges */
00325         for ( hashIter = BLI_ghashIterator_new(edgeHash);
00326                   !BLI_ghashIterator_isDone(hashIter);
00327                   BLI_ghashIterator_step(hashIter) ) 
00328         {
00329                 MEdge source;
00330                 MEdge *dest;
00331                 int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
00332                 int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
00333                 
00334                 dm->getEdge(dm, oldIndex, &source);
00335                 dest = CDDM_get_edge(result, newIndex);
00336                 
00337                 source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
00338                 source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
00339                 
00340                 DM_copy_edge_data(dm, result, oldIndex, newIndex, 1);
00341                 *dest = source;
00342         }
00343         BLI_ghashIterator_free(hashIter);
00344         
00345                 /* faces */
00346         for ( hashIter = BLI_ghashIterator_new(faceHash);
00347                   !BLI_ghashIterator_isDone(hashIter);
00348                   BLI_ghashIterator_step(hashIter) ) 
00349         {
00350                 MFace source;
00351                 MFace *dest;
00352                 int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
00353                 int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
00354                 int orig_v4;
00355                 
00356                 dm->getFace(dm, oldIndex, &source);
00357                 dest = CDDM_get_face(result, newIndex);
00358                 
00359                 orig_v4 = source.v4;
00360                 
00361                 source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
00362                 source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
00363                 source.v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v3)));
00364                 if (source.v4)
00365                    source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4)));
00366                 
00367                 DM_copy_face_data(dm, result, oldIndex, newIndex, 1);
00368                 *dest = source;
00369                 
00370                 test_index_face(dest, &result->faceData, newIndex, (orig_v4 ? 4 : 3));
00371         }
00372         BLI_ghashIterator_free(hashIter);
00373         
00374         /* recalculate normals */
00375         CDDM_calc_normals(result);
00376         
00377         /* free hashes */
00378         BLI_ghash_free(vertHash, NULL, NULL);
00379         BLI_ghash_free(edgeHash, NULL, NULL);
00380         BLI_ghash_free(faceHash, NULL, NULL);
00381         
00382         /* return the new mesh */
00383         return result;
00384 }
00385 
00386 
00387 ModifierTypeInfo modifierType_Mask = {
00388         /* name */              "Mask",
00389         /* structName */        "MaskModifierData",
00390         /* structSize */        sizeof(MaskModifierData),
00391         /* type */              eModifierTypeType_Nonconstructive,
00392         /* flags */             eModifierTypeFlag_AcceptsMesh|eModifierTypeFlag_SupportsMapping|eModifierTypeFlag_SupportsEditmode,
00393 
00394         /* copyData */          copyData,
00395         /* deformVerts */       NULL,
00396         /* deformMatrices */    NULL,
00397         /* deformVertsEM */     NULL,
00398         /* deformMatricesEM */  NULL,
00399         /* applyModifier */     applyModifier,
00400         /* applyModifierEM */   NULL,
00401         /* initData */          NULL,
00402         /* requiredDataMask */  requiredDataMask,
00403         /* freeData */          NULL,
00404         /* isDisabled */        NULL,
00405         /* updateDepgraph */    updateDepgraph,
00406         /* dependsOnTime */     NULL,
00407         /* dependsOnNormals */  NULL,
00408         /* foreachObjectLink */ foreachObjectLink,
00409         /* foreachIDLink */     NULL,
00410 };