Exemplo n.º 1
0
void BKE_icons_init(int first_dyn_id)
{
	gNextIconId = first_dyn_id;
	gFirstIconId = first_dyn_id;

	if (!gIcons)
		gIcons = BLI_ghash_int_new("icons_init gh");
}
Exemplo n.º 2
0
void BKE_icons_init(int first_dyn_id)
{
	gNextIconId = first_dyn_id;
	gFirstIconId = first_dyn_id;

	if (!gIcons)
		gIcons = BLI_ghash_int_new(__func__);

	if (!gCachedPreviews) {
		gCachedPreviews = BLI_ghash_str_new(__func__);
	}
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	DerivedMesh *dm = derivedData;
	DerivedMesh *result;
	BuildModifierData *bmd = (BuildModifierData *) md;
	int i, j, k;
	int numFaces_dst, numEdges_dst, numLoops_dst = 0;
	int *vertMap, *edgeMap, *faceMap;
	float frac;
	MPoly *mpoly_dst;
	MLoop *ml_dst, *ml_src /*, *mloop_dst */;
	GHashIterator *hashIter;
	/* maps vert indices in old mesh to indices in new mesh */
	GHash *vertHash = BLI_ghash_int_new("build ve apply gh");
	/* maps edge indices in new mesh to indices in old mesh */
	GHash *edgeHash = BLI_ghash_int_new("build ed apply gh");
	GHash *edgeHash2 = BLI_ghash_int_new("build ed apply gh");

	const int numVert_src = dm->getNumVerts(dm);
	const int numEdge_src = dm->getNumEdges(dm);
	const int numPoly_src = dm->getNumPolys(dm);
	MPoly *mpoly_src = dm->getPolyArray(dm);
	MLoop *mloop_src = dm->getLoopArray(dm);
	MEdge *medge_src = dm->getEdgeArray(dm);
	MVert *mvert_src = dm->getVertArray(dm);


	vertMap = MEM_mallocN(sizeof(*vertMap) * numVert_src, "build modifier vertMap");
	edgeMap = MEM_mallocN(sizeof(*edgeMap) * numEdge_src, "build modifier edgeMap");
	faceMap = MEM_mallocN(sizeof(*faceMap) * numPoly_src, "build modifier faceMap");

#pragma omp parallel sections if (numVert_src + numEdge_src + numPoly_src >= DM_OMP_LIMIT)
	{
#pragma omp section
		{ range_vn_i(vertMap, numVert_src, 0); }
#pragma omp section
		{ range_vn_i(edgeMap, numEdge_src, 0); }
#pragma omp section
		{ range_vn_i(faceMap, numPoly_src, 0); }
	}

	frac = (BKE_scene_frame_get(md->scene) - bmd->start) / bmd->length;
	CLAMP(frac, 0.0f, 1.0f);

	numFaces_dst = numPoly_src * frac;
	numEdges_dst = numEdge_src * frac;

	/* if there's at least one face, build based on faces */
	if (numFaces_dst) {
		MPoly *mpoly, *mp;
		MLoop *ml, *mloop;
		MEdge *medge;
		
		if (bmd->randomize) {
			BLI_array_randomize(faceMap, sizeof(*faceMap),
			                    numPoly_src, bmd->seed);
		}

		/* get the set of all vert indices that will be in the final mesh,
		 * mapped to the new indices
		 */
		mpoly = mpoly_src;
		mloop = mloop_src;
		for (i = 0; i < numFaces_dst; i++) {
			mp = mpoly + faceMap[i];
			ml = mloop + mp->loopstart;

			for (j = 0; j < mp->totloop; j++, ml++) {
				if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v)))
					BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(ml->v),
					                 SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
			}
			
			numLoops_dst += mp->totloop;
		}

		/* get the set of edges that will be in the new mesh (i.e. all edges
		 * that have both verts in the new mesh)
		 */
		medge = medge_src;
		for (i = 0; i < numEdge_src; i++) {
			MEdge *me = medge + i;

			if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1)) &&
			    BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2)))
			{
				j = BLI_ghash_size(edgeHash);
				
				BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j),
				                 SET_INT_IN_POINTER(i));
				BLI_ghash_insert(edgeHash2, SET_INT_IN_POINTER(i),
				                 SET_INT_IN_POINTER(j));
			}
		}
	}
	else if (numEdges_dst) {
		MEdge *medge, *me;

		if (bmd->randomize)
			BLI_array_randomize(edgeMap, sizeof(*edgeMap),
			                    numEdge_src, bmd->seed);

		/* get the set of all vert indices that will be in the final mesh,
		 * mapped to the new indices
		 */
		medge = medge_src;
		for (i = 0; i < numEdges_dst; i++) {
			me = medge + edgeMap[i];

			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_dst; i++) {
			j = BLI_ghash_size(edgeHash);
			
			BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j),
			                 SET_INT_IN_POINTER(edgeMap[i]));
			BLI_ghash_insert(edgeHash2,  SET_INT_IN_POINTER(edgeMap[i]),
			                 SET_INT_IN_POINTER(j));
		}
	}
	else {
		int numVerts = numVert_src * frac;

		if (bmd->randomize) {
			BLI_array_randomize(vertMap, sizeof(*vertMap),
			                    numVert_src, 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), 0, numLoops_dst, numFaces_dst);

	/* copy the vertices across */
	for (hashIter = BLI_ghashIterator_new(vertHash);
	     BLI_ghashIterator_done(hashIter) == false;
	     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));

		source = mvert_src[oldIndex];
		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)));
		
		source = medge_src[oldIndex];
		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;
	}

	mpoly_dst = CDDM_get_polys(result);
	/* mloop_dst = */ ml_dst = CDDM_get_loops(result);
	
	/* copy the faces across, remapping indices */
	k = 0;
	for (i = 0; i < numFaces_dst; i++) {
		MPoly *source;
		MPoly *dest;
		
		source = mpoly_src + faceMap[i];
		dest = mpoly_dst + i;
		DM_copy_poly_data(dm, result, faceMap[i], i, 1);
		
		*dest = *source;
		dest->loopstart = k;
		
		DM_copy_loop_data(dm, result, source->loopstart, dest->loopstart, dest->totloop);

		ml_src = mloop_src + source->loopstart;
		for (j = 0; j < source->totloop; j++, k++, ml_src++, ml_dst++) {
			ml_dst->v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(ml_src->v)));
			ml_dst->e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash2, SET_INT_IN_POINTER(ml_src->e)));
		}
	}

	BLI_ghash_free(vertHash, NULL, NULL);
	BLI_ghash_free(edgeHash, NULL, NULL);
	BLI_ghash_free(edgeHash2, NULL, NULL);
	
	MEM_freeN(vertMap);
	MEM_freeN(edgeMap);
	MEM_freeN(faceMap);

	if (dm->dirty & DM_DIRTY_NORMALS) {
		result->dirty |= DM_DIRTY_NORMALS;
	}

	return result;
}
Exemplo n.º 5
0
static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	DerivedMesh *dm = derivedData;
	DerivedMesh *result;
	BuildModifierData *bmd = (BuildModifierData *) md;
	int i, j, k;
	int numFaces_dst, numEdges_dst, numLoops_dst = 0;
	int *vertMap, *edgeMap, *faceMap;
	float frac;
	MPoly *mpoly_dst;
	MLoop *ml_dst, *ml_src /*, *mloop_dst */;
	GHashIterator gh_iter;
	/* maps vert indices in old mesh to indices in new mesh */
	GHash *vertHash = BLI_ghash_int_new("build ve apply gh");
	/* maps edge indices in new mesh to indices in old mesh */
	GHash *edgeHash = BLI_ghash_int_new("build ed apply gh");
	GHash *edgeHash2 = BLI_ghash_int_new("build ed apply gh");

	const int numVert_src = dm->getNumVerts(dm);
	const int numEdge_src = dm->getNumEdges(dm);
	const int numPoly_src = dm->getNumPolys(dm);
	MPoly *mpoly_src = dm->getPolyArray(dm);
	MLoop *mloop_src = dm->getLoopArray(dm);
	MEdge *medge_src = dm->getEdgeArray(dm);
	MVert *mvert_src = dm->getVertArray(dm);


	vertMap = MEM_malloc_arrayN(numVert_src, sizeof(*vertMap), "build modifier vertMap");
	edgeMap = MEM_malloc_arrayN(numEdge_src, sizeof(*edgeMap), "build modifier edgeMap");
	faceMap = MEM_malloc_arrayN(numPoly_src, sizeof(*faceMap), "build modifier faceMap");

	range_vn_i(vertMap, numVert_src, 0);
	range_vn_i(edgeMap, numEdge_src, 0);
	range_vn_i(faceMap, numPoly_src, 0);

	frac = (BKE_scene_frame_get(md->scene) - bmd->start) / bmd->length;
	CLAMP(frac, 0.0f, 1.0f);
	
	if (bmd->flag & MOD_BUILD_FLAG_REVERSE) {
		frac = 1.0f - frac;
	}
	
	numFaces_dst = numPoly_src * frac;
	numEdges_dst = numEdge_src * frac;

	/* if there's at least one face, build based on faces */
	if (numFaces_dst) {
		MPoly *mpoly, *mp;
		MLoop *ml, *mloop;
		MEdge *medge;
		uintptr_t hash_num, hash_num_alt;
		
		if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) {
			BLI_array_randomize(faceMap, sizeof(*faceMap),
			                    numPoly_src, bmd->seed);
		}

		/* get the set of all vert indices that will be in the final mesh,
		 * mapped to the new indices
		 */
		mpoly = mpoly_src;
		mloop = mloop_src;
		hash_num = 0;
		for (i = 0; i < numFaces_dst; i++) {
			mp = mpoly + faceMap[i];
			ml = mloop + mp->loopstart;

			for (j = 0; j < mp->totloop; j++, ml++) {
				void **val_p;
				if (!BLI_ghash_ensure_p(vertHash, SET_INT_IN_POINTER(ml->v), &val_p)) {
					*val_p = (void *)hash_num;
					hash_num++;
				}
			}

			numLoops_dst += mp->totloop;
		}
		BLI_assert(hash_num == BLI_ghash_len(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)
		 */
		medge = medge_src;
		hash_num = 0;
		hash_num_alt = 0;
		for (i = 0; i < numEdge_src; i++, hash_num_alt++) {
			MEdge *me = medge + i;

			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, (void *)hash_num, (void *)hash_num_alt);
				BLI_ghash_insert(edgeHash2, (void *)hash_num_alt, (void *)hash_num);
				hash_num++;
			}
		}
	}
	else if (numEdges_dst) {
		MEdge *medge, *me;
		uintptr_t hash_num;

		if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE)
			BLI_array_randomize(edgeMap, sizeof(*edgeMap),
			                    numEdge_src, bmd->seed);

		/* get the set of all vert indices that will be in the final mesh,
		 * mapped to the new indices
		 */
		medge = medge_src;
		hash_num = 0;
		BLI_assert(hash_num == BLI_ghash_len(vertHash));
		for (i = 0; i < numEdges_dst; i++) {
			void **val_p;
			me = medge + edgeMap[i];

			if (!BLI_ghash_ensure_p(vertHash, SET_INT_IN_POINTER(me->v1), &val_p)) {
				*val_p = (void *)hash_num;
				hash_num++;
			}
			if (!BLI_ghash_ensure_p(vertHash, SET_INT_IN_POINTER(me->v2), &val_p)) {
				*val_p = (void *)hash_num;
				hash_num++;
			}
		}
		BLI_assert(hash_num == BLI_ghash_len(vertHash));

		/* get the set of edges that will be in the new mesh */
		for (i = 0; i < numEdges_dst; i++) {
			j = BLI_ghash_len(edgeHash);
			
			BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j),
			                 SET_INT_IN_POINTER(edgeMap[i]));
			BLI_ghash_insert(edgeHash2,  SET_INT_IN_POINTER(edgeMap[i]),
			                 SET_INT_IN_POINTER(j));
		}
	}
	else {
		int numVerts = numVert_src * frac;

		if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) {
			BLI_array_randomize(vertMap, sizeof(*vertMap),
			                    numVert_src, 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_len(vertHash),
	                            BLI_ghash_len(edgeHash), 0, numLoops_dst, numFaces_dst);

	/* copy the vertices across */
	GHASH_ITER (gh_iter, vertHash) {
		MVert source;
		MVert *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));

		source = mvert_src[oldIndex];
		dest = CDDM_get_vert(result, newIndex);

		DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
	}