static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { MaskModifierData *mmd = (MaskModifierData *)md; DerivedMesh *dm = derivedData, *result = NULL; GHash *vertHash = NULL, *edgeHash, *polyHash; GHashIterator *hashIter; MDeformVert *dvert = NULL, *dv; int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0; int maxVerts, maxEdges, maxPolys; int i; MPoly *mpoly; MLoop *mloop; MPoly *mpoly_new; MLoop *mloop_new; MEdge *medge_new; MVert *mvert_new; int *loop_mapping; /* Overview of Method: * 1. Get the vertices that are in the vertexgroup of interest * 2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices * 3. Make a new mesh containing only the mapping data */ /* get original number of verts, edges, and faces */ maxVerts = dm->getNumVerts(dm); maxEdges = dm->getNumEdges(dm); maxPolys = dm->getNumPolys(dm); /* check if we can just return the original mesh * - must have verts and therefore verts assigned to vgroups to do anything useful */ if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || (maxVerts == 0) || (ob->defbase.first == NULL) ) { return derivedData; } /* if mode is to use selected armature bones, aggregate the bone groups */ if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */ Object *oba = mmd->ob_arm; bPoseChannel *pchan; bDeformGroup *def; char *bone_select_array; int bone_select_tot = 0; const int defbase_tot = BLI_countlist(&ob->defbase); /* check that there is armature object with bones to use, otherwise return original mesh */ if (ELEM3(NULL, oba, oba->pose, ob->defbase.first)) return derivedData; /* determine whether each vertexgroup is associated with a selected bone or not * - each cell is a boolean saying whether bone corresponding to the ith group is selected * - groups that don't match a bone are treated as not existing (along with the corresponding ungrouped verts) */ bone_select_array = MEM_mallocN(defbase_tot * sizeof(char), "mask array"); for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { pchan = BKE_pose_channel_find_name(oba->pose, def->name); if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { bone_select_array[i] = TRUE; bone_select_tot++; } else { bone_select_array[i] = FALSE; } } /* if no dverts (i.e. no data for vertex groups exists), we've got an * inconsistent situation, so free hashes and return oirginal mesh */ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); if (dvert == NULL) { MEM_freeN(bone_select_array); return derivedData; } /* verthash gives mapping from original vertex indices to the new indices (including selected matches only) * key = oldindex, value = newindex */ vertHash = BLI_ghash_int_new("mask vert gh"); /* add vertices which exist in vertexgroups into vertHash for filtering * - dv = for each vertex, what vertexgroups does it belong to * - dw = weight that vertex was assigned to a vertexgroup it belongs to */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { MDeformWeight *dw = dv->dw; short found = 0; int j; /* check the groups that vertex is assigned to, and see if it was any use */ for (j = 0; j < dv->totweight; j++, dw++) { if (dw->def_nr < defbase_tot) { if (bone_select_array[dw->def_nr]) { if (dw->weight != 0.0f) { found = TRUE; break; } } } } /* check if include vert in vertHash */ if (mmd->flag & MOD_MASK_INV) { /* if this vert is in the vgroup, don't include it in vertHash */ if (found) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!found) continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } /* free temp hashes */ MEM_freeN(bone_select_array); } else { /* --- Using Nominated VertexGroup only --- */ int defgrp_index = defgroup_name_index(ob, mmd->vgroup); /* get dverts */ if (defgrp_index != -1) dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); /* if no vgroup (i.e. dverts) found, return the initial mesh */ if ((defgrp_index == -1) || (dvert == NULL)) return dm; /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash = BLI_ghash_int_new("mask vert2 bh"); /* add vertices which exist in vertexgroup into ghash for filtering */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { const int weight_set = defvert_find_weight(dv, defgrp_index) != 0.0f; /* check if include vert in vertHash */ if (mmd->flag & MOD_MASK_INV) { /* if this vert is in the vgroup, don't include it in vertHash */ if (weight_set) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!weight_set) continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ edgeHash = BLI_ghash_int_new("mask ed2 gh"); polyHash = BLI_ghash_int_new("mask fa2 gh"); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); loop_mapping = MEM_callocN(sizeof(int) * maxPolys, "mask loopmap"); /* overalloc, assume all polys are seen */ /* loop over edges and faces, and do the same thing to * ensure that they only reference existing verts */ for (i = 0; i < maxEdges; i++) { MEdge me; dm->getEdge(dm, i, &me); /* only add if both verts will be in new mesh */ if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2))) { BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges)); numEdges++; } } for (i = 0; i < maxPolys; i++) { MPoly *mp = &mpoly[i]; MLoop *ml = mloop + mp->loopstart; int ok = TRUE; int j; for (j = 0; j < mp->totloop; j++, ml++) { if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v))) { ok = FALSE; break; } } /* all verts must be available */ if (ok) { BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys)); loop_mapping[numPolys] = numLoops; numPolys++; numLoops += mp->totloop; } } /* now we know the number of verts, edges and faces, * we can create the new (reduced) mesh */ result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys); mpoly_new = CDDM_get_polys(result); mloop_new = CDDM_get_loops(result); medge_new = CDDM_get_edges(result); mvert_new = CDDM_get_verts(result); /* using ghash-iterators, map data into new mesh */ /* vertices */ for (hashIter = BLI_ghashIterator_new(vertHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { MVert source; MVert *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getVert(dm, oldIndex, &source); dest = &mvert_new[newIndex]; DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* edges */ for (hashIter = BLI_ghashIterator_new(edgeHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter)) { MEdge source; MEdge *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getEdge(dm, oldIndex, &source); dest = &medge_new[newIndex]; source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); DM_copy_edge_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* faces */ for (hashIter = BLI_ghashIterator_new(polyHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); MPoly *source = &mpoly[oldIndex]; MPoly *dest = &mpoly_new[newIndex]; int oldLoopIndex = source->loopstart; int newLoopIndex = loop_mapping[newIndex]; MLoop *source_loop = &mloop[oldLoopIndex]; MLoop *dest_loop = &mloop_new[newLoopIndex]; DM_copy_poly_data(dm, result, oldIndex, newIndex, 1); DM_copy_loop_data(dm, result, oldLoopIndex, newLoopIndex, source->totloop); *dest = *source; dest->loopstart = newLoopIndex; for (i = 0; i < source->totloop; i++) { dest_loop[i].v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source_loop[i].v))); dest_loop[i].e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(source_loop[i].e))); } } BLI_ghashIterator_free(hashIter); MEM_freeN(loop_mapping); /* why is this needed? - campbell */ /* recalculate normals */ CDDM_calc_normals(result); /* free hashes */ BLI_ghash_free(vertHash, NULL, NULL); BLI_ghash_free(edgeHash, NULL, NULL); BLI_ghash_free(polyHash, NULL, NULL); /* return the new mesh */ return result; }
static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob), DerivedMesh *derivedData, int UNUSED(useRenderParams), int UNUSED(isFinalCalc)) { DerivedMesh *dm = derivedData; DerivedMesh *result; BuildModifierData *bmd = (BuildModifierData*) md; int i; int numFaces, numEdges; int *vertMap, *edgeMap, *faceMap; float frac; GHashIterator *hashIter; /* maps vert indices in old mesh to indices in new mesh */ GHash *vertHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "build ve apply gh"); /* maps edge indices in new mesh to indices in old mesh */ GHash *edgeHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "build ed apply gh"); const int maxVerts= dm->getNumVerts(dm); const int maxEdges= dm->getNumEdges(dm); const int maxFaces= dm->getNumFaces(dm); vertMap = MEM_callocN(sizeof(*vertMap) * maxVerts, "build modifier vertMap"); for(i = 0; i < maxVerts; ++i) vertMap[i] = i; edgeMap = MEM_callocN(sizeof(*edgeMap) * maxEdges, "build modifier edgeMap"); for(i = 0; i < maxEdges; ++i) edgeMap[i] = i; faceMap = MEM_callocN(sizeof(*faceMap) * maxFaces, "build modifier faceMap"); for(i = 0; i < maxFaces; ++i) faceMap[i] = i; frac = (BKE_curframe(md->scene) - bmd->start) / bmd->length; CLAMP(frac, 0.0f, 1.0f); numFaces = dm->getNumFaces(dm) * frac; numEdges = dm->getNumEdges(dm) * frac; /* if there's at least one face, build based on faces */ if(numFaces) { if(bmd->randomize) BLI_array_randomize(faceMap, sizeof(*faceMap), maxFaces, bmd->seed); /* get the set of all vert indices that will be in the final mesh, * mapped to the new indices */ for(i = 0; i < numFaces; ++i) { MFace mf; dm->getFace(dm, faceMap[i], &mf); if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1))) BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v1), SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v2))) BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v2), SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v3))) BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v3), SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); if(mf.v4 && !BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v4))) BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v4), SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); } /* get the set of edges that will be in the new mesh (i.e. all edges * that have both verts in the new mesh) */ for(i = 0; i < maxEdges; ++i) { MEdge me; dm->getEdge(dm, i, &me); if(BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2))) BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(BLI_ghash_size(edgeHash)), SET_INT_IN_POINTER(i)); } } else if(numEdges) { if(bmd->randomize) BLI_array_randomize(edgeMap, sizeof(*edgeMap), maxEdges, bmd->seed); /* get the set of all vert indices that will be in the final mesh, * mapped to the new indices */ for(i = 0; i < numEdges; ++i) { MEdge me; dm->getEdge(dm, edgeMap[i], &me); if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1))) BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me.v1), SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2))) BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me.v2), SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); } /* get the set of edges that will be in the new mesh */ for(i = 0; i < numEdges; ++i) { MEdge me; dm->getEdge(dm, edgeMap[i], &me); BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(BLI_ghash_size(edgeHash)), SET_INT_IN_POINTER(edgeMap[i])); } } else { int numVerts = dm->getNumVerts(dm) * frac; if(bmd->randomize) BLI_array_randomize(vertMap, sizeof(*vertMap), maxVerts, bmd->seed); /* get the set of all vert indices that will be in the final mesh, * mapped to the new indices */ for(i = 0; i < numVerts; ++i) BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(vertMap[i]), SET_INT_IN_POINTER(i)); } /* now we know the number of verts, edges and faces, we can create * the mesh */ result = CDDM_from_template(dm, BLI_ghash_size(vertHash), BLI_ghash_size(edgeHash), numFaces); /* copy the vertices across */ for( hashIter = BLI_ghashIterator_new(vertHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { MVert source; MVert *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getVert(dm, oldIndex, &source); dest = CDDM_get_vert(result, newIndex); DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* copy the edges across, remapping indices */ for(i = 0; i < BLI_ghash_size(edgeHash); ++i) { MEdge source; MEdge *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(i))); dm->getEdge(dm, oldIndex, &source); dest = CDDM_get_edge(result, i); source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); DM_copy_edge_data(dm, result, oldIndex, i, 1); *dest = source; } /* copy the faces across, remapping indices */ for(i = 0; i < numFaces; ++i) { MFace source; MFace *dest; int orig_v4; dm->getFace(dm, faceMap[i], &source); dest = CDDM_get_face(result, i); orig_v4 = source.v4; source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); source.v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v3))); if(source.v4) source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4))); DM_copy_face_data(dm, result, faceMap[i], i, 1); *dest = source; test_index_face(dest, &result->faceData, i, (orig_v4 ? 4 : 3)); } CDDM_calc_normals(result); BLI_ghash_free(vertHash, NULL, NULL); BLI_ghash_free(edgeHash, NULL, NULL); MEM_freeN(vertMap); MEM_freeN(edgeMap); MEM_freeN(faceMap); return result; }