|
Blender
V2.59
|
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 };