static MFace *get_dface(DerivedMesh *dm, DerivedMesh *split, int cur, int i, MFace *mf) { MFace *df = CDDM_get_face(split, cur); DM_copy_face_data(dm, split, i, cur, 1); *df = *mf; return df; }
static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh) { DerivedMesh *result = CDDM_from_template(mesh->dm, mesh->num_verts, mesh->num_edges, mesh->num_faces); MVert *new_verts = CDDM_get_verts(result); MEdge *new_edges = CDDM_get_edges(result); MFace *new_faces = CDDM_get_faces(result); int i; for(i = 0; i < mesh->num_verts; ++i) { SmoothVert *vert = &mesh->verts[i]; MVert *newMV = &new_verts[vert->newIndex]; DM_copy_vert_data(mesh->dm, result, vert->oldIndex, vert->newIndex, 1); mesh->dm->getVert(mesh->dm, vert->oldIndex, newMV); } for(i = 0; i < mesh->num_edges; ++i) { SmoothEdge *edge = &mesh->edges[i]; MEdge *newME = &new_edges[edge->newIndex]; DM_copy_edge_data(mesh->dm, result, edge->oldIndex, edge->newIndex, 1); mesh->dm->getEdge(mesh->dm, edge->oldIndex, newME); newME->v1 = edge->verts[0]->newIndex; newME->v2 = edge->verts[1]->newIndex; } for(i = 0; i < mesh->num_faces; ++i) { SmoothFace *face = &mesh->faces[i]; MFace *newMF = &new_faces[face->newIndex]; DM_copy_face_data(mesh->dm, result, face->oldIndex, face->newIndex, 1); mesh->dm->getFace(mesh->dm, face->oldIndex, newMF); newMF->v1 = face->edges[0]->verts[face->flip[0]]->newIndex; newMF->v2 = face->edges[1]->verts[face->flip[1]]->newIndex; newMF->v3 = face->edges[2]->verts[face->flip[2]]->newIndex; if(face->edges[3]) { newMF->v4 = face->edges[3]->verts[face->flip[3]]->newIndex; } else { newMF->v4 = 0; } } return result; }
static DerivedMesh * applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, int UNUSED(useRenderParams), int UNUSED(isFinalCalc)) { DerivedMesh *dm = derivedData, *result; ParticleInstanceModifierData *pimd= (ParticleInstanceModifierData*) md; ParticleSimulationData sim; ParticleSystem *psys= NULL; ParticleData *pa= NULL, *pars= NULL; MFace *mface, *orig_mface; MVert *mvert, *orig_mvert; int i,totvert, totpart=0, totface, maxvert, maxface, first_particle=0; short track=ob->trackflag%3, trackneg, axis = pimd->axis; float max_co=0.0, min_co=0.0, temp_co[3], cross[3]; float *size=NULL; trackneg=((ob->trackflag>2)?1:0); if(pimd->ob==ob){ pimd->ob= NULL; return derivedData; } if(pimd->ob){ psys = BLI_findlink(&pimd->ob->particlesystem,pimd->psys-1); if(psys==NULL || psys->totpart==0) return derivedData; } else return derivedData; if(pimd->flag & eParticleInstanceFlag_Parents) totpart+=psys->totpart; if(pimd->flag & eParticleInstanceFlag_Children){ if(totpart==0) first_particle=psys->totpart; totpart+=psys->totchild; } if(totpart==0) return derivedData; sim.scene = md->scene; sim.ob = pimd->ob; sim.psys = psys; sim.psmd = psys_get_modifier(pimd->ob, psys); if(pimd->flag & eParticleInstanceFlag_UseSize) { int p; float *si; si = size = MEM_callocN(totpart * sizeof(float), "particle size array"); if(pimd->flag & eParticleInstanceFlag_Parents) { for(p=0, pa= psys->particles; p<psys->totpart; p++, pa++, si++) *si = pa->size; } if(pimd->flag & eParticleInstanceFlag_Children) { ChildParticle *cpa = psys->child; for(p=0; p<psys->totchild; p++, cpa++, si++) { *si = psys_get_child_size(psys, cpa, 0.0f, NULL); } } } pars=psys->particles; totvert=dm->getNumVerts(dm); totface=dm->getNumFaces(dm); maxvert=totvert*totpart; maxface=totface*totpart; psys->lattice=psys_get_lattice(&sim); if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED){ float min_r[3], max_r[3]; INIT_MINMAX(min_r, max_r); dm->getMinMax(dm, min_r, max_r); min_co=min_r[track]; max_co=max_r[track]; } result = CDDM_from_template(dm, maxvert,dm->getNumEdges(dm)*totpart,maxface); mvert=result->getVertArray(result); orig_mvert=dm->getVertArray(dm); for(i=0; i<maxvert; i++){ MVert *inMV; MVert *mv = mvert + i; ParticleKey state; inMV = orig_mvert + i%totvert; DM_copy_vert_data(dm, result, i%totvert, i, 1); *mv = *inMV; /*change orientation based on object trackflag*/ copy_v3_v3(temp_co, mv->co); mv->co[axis]=temp_co[track]; mv->co[(axis+1)%3]=temp_co[(track+1)%3]; mv->co[(axis+2)%3]=temp_co[(track+2)%3]; if((psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && pimd->flag & eParticleInstanceFlag_Path){ float ran = 0.0f; if(pimd->random_position != 0.0f) { BLI_srandom(psys->seed + (i/totvert)%totpart); ran = pimd->random_position * BLI_frand(); } if(pimd->flag & eParticleInstanceFlag_KeepShape) { state.time = pimd->position * (1.0f - ran); } else { state.time=(mv->co[axis]-min_co)/(max_co-min_co) * pimd->position * (1.0f - ran); if(trackneg) state.time=1.0f-state.time; mv->co[axis] = 0.0; } psys_get_particle_on_path(&sim, first_particle + i/totvert, &state,1); normalize_v3(state.vel); /* TODO: incremental rotations somehow */ if(state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) { state.rot[0] = 1; state.rot[1] = state.rot[2] = state.rot[3] = 0.0f; } else { float temp[3] = {0.0f,0.0f,0.0f}; temp[axis] = 1.0f; cross_v3_v3v3(cross, temp, state.vel); /* state.vel[axis] is the only component surviving from a dot product with the axis */ axis_angle_to_quat(state.rot,cross,saacos(state.vel[axis])); } } else{ state.time=-1.0; psys_get_particle_state(&sim, first_particle + i/totvert, &state,1); } mul_qt_v3(state.rot,mv->co); if(pimd->flag & eParticleInstanceFlag_UseSize) mul_v3_fl(mv->co, size[i/totvert]); VECADD(mv->co,mv->co,state.co); } mface=result->getFaceArray(result); orig_mface=dm->getFaceArray(dm); for(i=0; i<maxface; i++){ MFace *inMF; MFace *mf = mface + i; if(pimd->flag & eParticleInstanceFlag_Parents){ if(i/totface>=psys->totpart){ if(psys->part->childtype==PART_CHILD_PARTICLES) pa=psys->particles+(psys->child+i/totface-psys->totpart)->parent; else pa= NULL; } else pa=pars+i/totface; } else{ if(psys->part->childtype==PART_CHILD_PARTICLES) pa=psys->particles+(psys->child+i/totface)->parent; else pa= NULL; } if(pa){ if(pa->alive==PARS_UNBORN && (pimd->flag&eParticleInstanceFlag_Unborn)==0) continue; if(pa->alive==PARS_ALIVE && (pimd->flag&eParticleInstanceFlag_Alive)==0) continue; if(pa->alive==PARS_DEAD && (pimd->flag&eParticleInstanceFlag_Dead)==0) continue; } inMF = orig_mface + i%totface; DM_copy_face_data(dm, result, i%totface, i, 1); *mf = *inMF; mf->v1+=(i/totface)*totvert; mf->v2+=(i/totface)*totvert; mf->v3+=(i/totface)*totvert; if(mf->v4) mf->v4+=(i/totface)*totvert; } CDDM_calc_edges(result); CDDM_calc_normals(result); if(psys->lattice){ end_latt_deform(psys->lattice); psys->lattice= NULL; } if(size) MEM_freeN(size); return result; }
static DerivedMesh * explodeMesh(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, Scene *scene, Object *ob, DerivedMesh *to_explode) { DerivedMesh *explode, *dm=to_explode; MFace *mf= NULL, *mface; /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */ ParticleSimulationData sim= {NULL}; ParticleData *pa=NULL, *pars=psmd->psys->particles; ParticleKey state, birth; EdgeHash *vertpahash; EdgeHashIterator *ehi; float *vertco= NULL, imat[4][4]; float rot[4]; float cfra; /* float timestep; */ int *facepa=emd->facepa; int totdup=0,totvert=0,totface=0,totpart=0; int i, j, v, mindex=0; MTFace *mtface = NULL, *mtf; totface= dm->getNumFaces(dm); totvert= dm->getNumVerts(dm); mface= dm->getFaceArray(dm); totpart= psmd->psys->totpart; sim.scene= scene; sim.ob= ob; sim.psys= psmd->psys; sim.psmd= psmd; /* timestep= psys_get_timestep(&sim); */ //if(part->flag & PART_GLOB_TIME) cfra= BKE_curframe(scene); //else // cfra=bsystem_time(scene, ob,(float)scene->r.cfra,0.0); /* hash table for vertice <-> particle relations */ vertpahash= BLI_edgehash_new(); for (i=0; i<totface; i++) { /* do mindex + totvert to ensure the vertex index to be the first * with BLI_edgehashIterator_getKey */ if(facepa[i]==totpart || cfra < (pars+facepa[i])->time) mindex = totvert+totpart; else mindex = totvert+facepa[i]; mf= &mface[i]; /* set face vertices to exist in particle group */ BLI_edgehash_insert(vertpahash, mf->v1, mindex, NULL); BLI_edgehash_insert(vertpahash, mf->v2, mindex, NULL); BLI_edgehash_insert(vertpahash, mf->v3, mindex, NULL); if(mf->v4) BLI_edgehash_insert(vertpahash, mf->v4, mindex, NULL); } /* make new vertice indexes & count total vertices after duplication */ ehi= BLI_edgehashIterator_new(vertpahash); for(; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(totdup)); totdup++; } BLI_edgehashIterator_free(ehi); /* the final duplicated vertices */ explode= CDDM_from_template(dm, totdup, 0,totface); mtface = CustomData_get_layer_named(&explode->faceData, CD_MTFACE, emd->uvname); /*dupvert= CDDM_get_verts(explode);*/ /* getting back to object space */ invert_m4_m4(imat,ob->obmat); psmd->psys->lattice = psys_get_lattice(&sim); /* duplicate & displace vertices */ ehi= BLI_edgehashIterator_new(vertpahash); for(; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { MVert source; MVert *dest; /* get particle + vertex from hash */ BLI_edgehashIterator_getKey(ehi, &j, &i); i -= totvert; v= GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi)); dm->getVert(dm, j, &source); dest = CDDM_get_vert(explode,v); DM_copy_vert_data(dm,explode,j,v,1); *dest = source; if(i!=totpart) { /* get particle */ pa= pars+i; psys_get_birth_coordinates(&sim, pa, &birth, 0, 0); state.time=cfra; psys_get_particle_state(&sim, i, &state, 1); vertco=CDDM_get_vert(explode,v)->co; mul_m4_v3(ob->obmat,vertco); sub_v3_v3(vertco, birth.co); /* apply rotation, size & location */ sub_qt_qtqt(rot, state.rot, birth.rot); mul_qt_v3(rot, vertco); if(emd->flag & eExplodeFlag_PaSize) mul_v3_fl(vertco,pa->size); add_v3_v3(vertco, state.co); mul_m4_v3(imat, vertco); } } BLI_edgehashIterator_free(ehi); /*map new vertices to faces*/ for (i=0; i<totface; i++) { MFace source; int orig_v4; if(facepa[i]!=totpart) { pa=pars+facepa[i]; if(pa->alive==PARS_UNBORN && (emd->flag&eExplodeFlag_Unborn)==0) continue; if(pa->alive==PARS_ALIVE && (emd->flag&eExplodeFlag_Alive)==0) continue; if(pa->alive==PARS_DEAD && (emd->flag&eExplodeFlag_Dead)==0) continue; } dm->getFace(dm,i,&source); mf=CDDM_get_face(explode,i); orig_v4 = source.v4; if(facepa[i]!=totpart && cfra < pa->time) mindex = totvert+totpart; else mindex = totvert+facepa[i]; source.v1 = edgecut_get(vertpahash, source.v1, mindex); source.v2 = edgecut_get(vertpahash, source.v2, mindex); source.v3 = edgecut_get(vertpahash, source.v3, mindex); if(source.v4) source.v4 = edgecut_get(vertpahash, source.v4, mindex); DM_copy_face_data(dm,explode,i,i,1); *mf = source; /* override uv channel for particle age */ if(mtface) { float age = (cfra - pa->time)/pa->lifetime; /* Clamp to this range to avoid flipping to the other side of the coordinates. */ CLAMP(age, 0.001f, 0.999f); mtf = mtface + i; mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = age; mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = 0.5f; } test_index_face(mf, &explode->faceData, i, (orig_v4 ? 4 : 3)); } /* cleanup */ BLI_edgehash_free(vertpahash, NULL); /* finalization */ CDDM_calc_edges(explode); CDDM_calc_normals(explode); if(psmd->psys->lattice){ end_latt_deform(psmd->psys->lattice); psmd->psys->lattice= NULL; } return explode; }
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, Object *ob, DerivedMesh *dm, int axis) { int i; float tolerance = mmd->tolerance; DerivedMesh *result; int numVerts, numEdges, numFaces; int maxVerts = dm->getNumVerts(dm); int maxEdges = dm->getNumEdges(dm); int maxFaces = dm->getNumFaces(dm); int *flip_map= NULL, flip_map_len= 0; int do_vgroup_mirr= (mmd->flag & MOD_MIR_VGROUP); unsigned int (*indexMap)[2]; float mtx[4][4], imtx[4][4]; numVerts = numEdges = numFaces = 0; indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap"); result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2); if (do_vgroup_mirr) { flip_map= defgroup_flip_map(ob, &flip_map_len, FALSE); if(flip_map == NULL) do_vgroup_mirr= 0; } if (mmd->mirror_ob) { float obinv[4][4]; invert_m4_m4(obinv, mmd->mirror_ob->obmat); mult_m4_m4m4(mtx, obinv, ob->obmat); invert_m4_m4(imtx, mtx); } for(i = 0; i < maxVerts; i++) { MVert inMV; MVert *mv = CDDM_get_vert(result, numVerts); int isShared; float co[3]; dm->getVert(dm, i, &inMV); copy_v3_v3(co, inMV.co); if (mmd->mirror_ob) { mul_m4_v3(mtx, co); } if(mmd->flag & MOD_MIR_NO_MERGE) isShared = 0; else isShared = ABS(co[axis])<=tolerance; /* Because the topology result (# of vertices) must be the same if * the mesh data is overridden by vertex cos, have to calc sharedness * based on original coordinates. This is why we test before copy. */ DM_copy_vert_data(dm, result, i, numVerts, 1); *mv = inMV; indexMap[i][0] = numVerts; indexMap[i][1] = !isShared; numVerts++; if(isShared ) { co[axis] = 0.0f; if (mmd->mirror_ob) { mul_m4_v3(imtx, co); } copy_v3_v3(mv->co, co); mv->flag |= ME_VERT_MERGED; } else { MVert *mv2 = CDDM_get_vert(result, numVerts); DM_copy_vert_data(dm, result, i, numVerts, 1); *mv2 = *mv; co[axis] = -co[axis]; if (mmd->mirror_ob) { mul_m4_v3(imtx, co); } copy_v3_v3(mv2->co, co); if (do_vgroup_mirr) { MDeformVert *dvert= DM_get_vert_data(result, numVerts, CD_MDEFORMVERT); if(dvert) { defvert_flip(dvert, flip_map, flip_map_len); } } numVerts++; } } for(i = 0; i < maxEdges; i++) { MEdge inMED; MEdge *med = CDDM_get_edge(result, numEdges); dm->getEdge(dm, i, &inMED); DM_copy_edge_data(dm, result, i, numEdges, 1); *med = inMED; numEdges++; med->v1 = indexMap[inMED.v1][0]; med->v2 = indexMap[inMED.v2][0]; if(indexMap[inMED.v1][1] || indexMap[inMED.v2][1]) { MEdge *med2 = CDDM_get_edge(result, numEdges); DM_copy_edge_data(dm, result, i, numEdges, 1); *med2 = *med; numEdges++; med2->v1 += indexMap[inMED.v1][1]; med2->v2 += indexMap[inMED.v2][1]; } } for(i = 0; i < maxFaces; i++) { MFace inMF; MFace *mf = CDDM_get_face(result, numFaces); dm->getFace(dm, i, &inMF); DM_copy_face_data(dm, result, i, numFaces, 1); *mf = inMF; numFaces++; mf->v1 = indexMap[inMF.v1][0]; mf->v2 = indexMap[inMF.v2][0]; mf->v3 = indexMap[inMF.v3][0]; mf->v4 = indexMap[inMF.v4][0]; if ( indexMap[inMF.v1][1] || indexMap[inMF.v2][1] || indexMap[inMF.v3][1] || (mf->v4 && indexMap[inMF.v4][1])) { MFace *mf2 = CDDM_get_face(result, numFaces); static int corner_indices[4] = {2, 1, 0, 3}; DM_copy_face_data(dm, result, i, numFaces, 1); *mf2 = *mf; mf2->v1 += indexMap[inMF.v1][1]; mf2->v2 += indexMap[inMF.v2][1]; mf2->v3 += indexMap[inMF.v3][1]; if(inMF.v4) mf2->v4 += indexMap[inMF.v4][1]; /* mirror UVs if enabled */ if(mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) { MTFace *tf = result->getFaceData(result, numFaces, CD_MTFACE); if(tf) { int j; for(j = 0; j < 4; ++j) { if(mmd->flag & MOD_MIR_MIRROR_U) tf->uv[j][0] = 1.0f - tf->uv[j][0]; if(mmd->flag & MOD_MIR_MIRROR_V) tf->uv[j][1] = 1.0f - tf->uv[j][1]; } } } /* Flip face normal */ SWAP(unsigned int, mf2->v1, mf2->v3); DM_swap_face_data(result, numFaces, corner_indices); test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3); numFaces++; } }
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; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, int UNUSED(useRenderParams), int UNUSED(isFinalCalc)) { MaskModifierData *mmd= (MaskModifierData *)md; DerivedMesh *dm= derivedData, *result= NULL; GHash *vertHash=NULL, *edgeHash, *faceHash; GHashIterator *hashIter; MDeformVert *dvert= NULL, *dv; int numFaces=0, numEdges=0, numVerts=0; int maxVerts, maxEdges, maxFaces; int i; /* 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); maxFaces= dm->getNumFaces(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 --- */ { GHash *vgroupHash; Object *oba= mmd->ob_arm; bPoseChannel *pchan; bDeformGroup *def; char *bone_select_array; int bone_select_tot= 0; /* check that there is armature object with bones to use, otherwise return original mesh */ if (ELEM3(NULL, mmd->ob_arm, mmd->ob_arm->pose, ob->defbase.first)) return derivedData; bone_select_array= MEM_mallocN(BLI_countlist(&ob->defbase) * sizeof(char), "mask array"); for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { if (((pchan= get_pose_channel(oba->pose, def->name)) && pchan->bone && (pchan->bone->flag & BONE_SELECTED))) { bone_select_array[i]= TRUE; bone_select_tot++; } else { bone_select_array[i]= FALSE; } } /* hashes for finding mapping of: * - vgroups to indices -> vgroupHash (string, int) * - bones to vgroup indices -> boneHash (index of vgroup, dummy) */ vgroupHash= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "mask vgroup gh"); /* build mapping of names of vertex groups to indices */ for (i = 0, def = ob->defbase.first; def; def = def->next, i++) BLI_ghash_insert(vgroupHash, def->name, SET_INT_IN_POINTER(i)); /* if no bones selected, free hashes and return original mesh */ if (bone_select_tot == 0) { BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); return derivedData; } /* repeat the previous check, but for dverts */ dvert= dm->getVertDataArray(dm, CD_MDEFORMVERT); if (dvert == NULL) { BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); return derivedData; } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert gh"); /* add vertices which exist in vertexgroups into vertHash for filtering */ for (i= 0, dv= dvert; i < maxVerts; i++, dv++) { MDeformWeight *dw= dv->dw; int j; for (j= dv->totweight; j > 0; j--, dw++) { if (bone_select_array[dw->def_nr]) { if(dw->weight != 0.0f) { 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 (dw) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!dw) 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 */ BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); } else /* --- Using Nominated VertexGroup only --- */ { int defgrp_index = defgroup_name_index(ob, mmd->vgroup); /* get dverts */ if (defgrp_index >= 0) dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); /* if no vgroup (i.e. dverts) found, return the initial mesh */ if ((defgrp_index < 0) || (dvert == NULL)) return dm; /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "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_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask ed2 gh"); faceHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask fa2 gh"); /* 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 < maxFaces; i++) { MFace mf; dm->getFace(dm, i, &mf); /* all verts must be available */ if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v2)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v3)) && (mf.v4==0 || BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v4))) ) { BLI_ghash_insert(faceHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numFaces)); numFaces++; } } /* now we know the number of verts, edges and faces, * we can create the new (reduced) mesh */ result = CDDM_from_template(dm, numVerts, numEdges, numFaces); /* 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 = CDDM_get_vert(result, 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 = CDDM_get_edge(result, 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(faceHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { MFace source; MFace *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); int orig_v4; dm->getFace(dm, oldIndex, &source); dest = CDDM_get_face(result, newIndex); 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, oldIndex, newIndex, 1); *dest = source; test_index_face(dest, &result->faceData, newIndex, (orig_v4 ? 4 : 3)); } BLI_ghashIterator_free(hashIter); /* recalculate normals */ CDDM_calc_normals(result); /* free hashes */ BLI_ghash_free(vertHash, NULL, NULL); BLI_ghash_free(edgeHash, NULL, NULL); BLI_ghash_free(faceHash, NULL, NULL); /* return the new mesh */ return result; }