Example #1
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
                                  ModifierApplyFlag flag)
{
	MultiresModifierData *mmd = (MultiresModifierData *)md;
	DerivedMesh *result;
	Mesh *me = (Mesh *)ob->data;
	const int useRenderParams = flag & MOD_APPLY_RENDER;

	if (mmd->totlvl) {
		if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
			/* multires always needs a displacement layer */
			CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop);
		}
	}

	result = multires_dm_create_from_derived(mmd, 0, dm, ob, useRenderParams);

	if (result == dm)
		return dm;

	if(useRenderParams || !(flag & MOD_APPLY_USECACHE)) {
		DerivedMesh *cddm;
		
		cddm = CDDM_copy(result);

		/* copy hidden flag to vertices */
		if (!useRenderParams) {
			struct MDisps *mdisps;
			mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
			if (mdisps) {
				subsurf_copy_grid_hidden(result, me->mpoly,
				                         cddm->getVertArray(cddm),
				                         mdisps);

				BKE_mesh_flush_hidden_from_verts(cddm->getVertArray(cddm),
				                                 cddm->getLoopArray(cddm),
				                                 cddm->getEdgeArray(cddm),
				                                 cddm->getNumEdges(cddm),
				                                 cddm->getPolyArray(cddm),
				                                 cddm->getNumPolys(cddm));
			}
		}

		result->release(result);
		result = cddm;
	}

	return result;
}
/* Create new external mesh */
static void exporter_InitGeomArrays(ExportMeshData *export_data,
                                    int num_verts, int num_edges,
                                    int num_loops, int num_polys)
{
	DerivedMesh *dm = CDDM_new(num_verts, num_edges, 0,
	                           num_loops, num_polys);
	DerivedMesh *dm_left = export_data->dm_left,
	            *dm_right = export_data->dm_right;

	/* Mask for custom data layers to be merged from operands. */
	CustomDataMask merge_mask = CD_MASK_DERIVEDMESH & ~CD_MASK_ORIGINDEX;

	export_data->dm = dm;
	export_data->mvert = dm->getVertArray(dm);
	export_data->medge = dm->getEdgeArray(dm);
	export_data->mloop = dm->getLoopArray(dm);
	export_data->mpoly = dm->getPolyArray(dm);

	/* Allocate layers for UV layers and vertex colors.
	 * Without this interpolation of those data will not happen.
	 */
	allocate_custom_layers(&dm->loopData, CD_MLOOPCOL, num_loops,
	                       CustomData_number_of_layers(&dm_left->loopData, CD_MLOOPCOL));
	allocate_custom_layers(&dm->loopData, CD_MLOOPUV, num_loops,
	                       CustomData_number_of_layers(&dm_left->loopData, CD_MLOOPUV));

	allocate_custom_layers(&dm->loopData, CD_MLOOPCOL, num_loops,
	                       CustomData_number_of_layers(&dm_right->loopData, CD_MLOOPCOL));
	allocate_custom_layers(&dm->loopData, CD_MLOOPUV, num_loops,
	                       CustomData_number_of_layers(&dm_right->loopData, CD_MLOOPUV));

	/* Merge custom data layers from operands.
	 *
	 * Will only create custom data layers for all the layers which appears in
	 * the operand. Data for those layers will not be allocated or initialized.
	 */
	CustomData_merge(&dm_left->polyData, &dm->polyData, merge_mask, CD_DEFAULT, num_polys);
	CustomData_merge(&dm_right->polyData, &dm->polyData, merge_mask, CD_DEFAULT, num_polys);

	CustomData_merge(&dm_left->edgeData, &dm->edgeData, merge_mask, CD_DEFAULT, num_edges);
	CustomData_merge(&dm_right->edgeData, &dm->edgeData, merge_mask, CD_DEFAULT, num_edges);

	export_data->vert_origindex = dm->getVertDataArray(dm, CD_ORIGINDEX);
	export_data->edge_origindex = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
	export_data->poly_origindex = dm->getPolyDataArray(dm, CD_ORIGINDEX);
	export_data->loop_origindex = dm->getLoopDataArray(dm, CD_ORIGINDEX);
}
Example #3
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;
}
Example #4
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag flag)
{
	DerivedMesh *dm = derivedData;
	DerivedMesh *result;
	ScrewModifierData *ltmd = (ScrewModifierData *) md;
	const int useRenderParams = flag & MOD_APPLY_RENDER;
	
	int *origindex;
	int mpoly_index = 0;
	unsigned int step;
	unsigned int i, j;
	unsigned int i1, i2;
	unsigned int step_tot = useRenderParams ? ltmd->render_steps : ltmd->steps;
	const bool do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0;

	const int quad_ord[4] = {
	    do_flip ? 3 : 0,
	    do_flip ? 2 : 1,
	    do_flip ? 1 : 2,
	    do_flip ? 0 : 3,
	};
	const int quad_ord_ofs[4] = {
	    do_flip ? 2 : 0,
	    do_flip ? 1 : 1,
	    do_flip ? 0 : 2,
	    do_flip ? 3 : 3,
	};

	unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0;
	const unsigned int totvert = (unsigned int)dm->getNumVerts(dm);
	const unsigned int totedge = (unsigned int)dm->getNumEdges(dm);
	const unsigned int totpoly = (unsigned int)dm->getNumPolys(dm);

	unsigned int *edge_poly_map = NULL;  /* orig edge to orig poly */
	unsigned int *vert_loop_map = NULL;  /* orig vert to orig loop */

	/* UV Coords */
	const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
	MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot);
	float uv_u_scale;
	float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX};
	float uv_v_range_inv;
	float uv_axis_plane[4];

	char axis_char = 'X';
	bool close;
	float angle = ltmd->angle;
	float screw_ofs = ltmd->screw_ofs;
	float axis_vec[3] = {0.0f, 0.0f, 0.0f};
	float tmp_vec1[3], tmp_vec2[3]; 
	float mat3[3][3];
	float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */
	float mtx_tx_inv[4][4]; /* inverted */
	float mtx_tmp_a[4][4];
	
	unsigned int vc_tot_linked = 0;
	short other_axis_1, other_axis_2;
	const float *tmpf1, *tmpf2;

	unsigned int edge_offset;
	
	MPoly *mpoly_orig, *mpoly_new, *mp_new;
	MLoop *mloop_orig, *mloop_new, *ml_new;
	MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new;
	MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base;

	ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL;

	const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0;

	/* don't do anything? */
	if (!totvert)
		return CDDM_from_template(dm, 0, 0, 0, 0, 0);

	switch (ltmd->axis) {
		case 0:
			other_axis_1 = 1;
			other_axis_2 = 2;
			break;
		case 1:
			other_axis_1 = 0;
			other_axis_2 = 2;
			break;
		default: /* 2, use default to quiet warnings */
			other_axis_1 = 0;
			other_axis_2 = 1;
			break;
	}

	axis_vec[ltmd->axis] = 1.0f;

	if (ltmd->ob_axis) {
		/* calc the matrix relative to the axis object */
		invert_m4_m4(mtx_tmp_a, ob->obmat);
		copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat);
		mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv);

		/* calc the axis vec */
		mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */
		normalize_v3(axis_vec);

		/* screw */
		if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) {
			/* find the offset along this axis relative to this objects matrix */
			float totlen = len_v3(mtx_tx[3]);

			if (totlen != 0.0f) {
				float zero[3] = {0.0f, 0.0f, 0.0f};
				float cp[3];
				screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec);
			}
			else {
				screw_ofs = 0.0f;
			}
		}

		/* angle */

#if 0   /* cant incluide this, not predictable enough, though quite fun. */
		if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) {
			float mtx3_tx[3][3];
			copy_m3_m4(mtx3_tx, mtx_tx);

			float vec[3] = {0, 1, 0};
			float cross1[3];
			float cross2[3];
			cross_v3_v3v3(cross1, vec, axis_vec);

			mul_v3_m3v3(cross2, mtx3_tx, cross1);
			{
				float c1[3];
				float c2[3];
				float axis_tmp[3];

				cross_v3_v3v3(c1, cross2, axis_vec);
				cross_v3_v3v3(c2, axis_vec, c1);


				angle = angle_v3v3(cross1, c2);

				cross_v3_v3v3(axis_tmp, cross1, c2);
				normalize_v3(axis_tmp);

				if (len_v3v3(axis_tmp, axis_vec) > 1.0f)
					angle = -angle;

			}
		}
#endif
	}
	else {
		/* exis char is used by i_rotate*/
		axis_char = (char)(axis_char + ltmd->axis); /* 'X' + axis */

		/* useful to be able to use the axis vec in some cases still */
		zero_v3(axis_vec);
		axis_vec[ltmd->axis] = 1.0f;
	}

	/* apply the multiplier */
	angle *= (float)ltmd->iter;
	screw_ofs *= (float)ltmd->iter;
	uv_u_scale = 1.0f / (float)(step_tot);

	/* multiplying the steps is a bit tricky, this works best */
	step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1);

	/* will the screw be closed?
	 * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */
	if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) &&
	    fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f))
	{
		close = 1;
		step_tot--;
		if (step_tot < 3) step_tot = 3;
	
		maxVerts = totvert  * step_tot;   /* -1 because we're joining back up */
		maxEdges = (totvert * step_tot) + /* these are the edges between new verts */
		           (totedge * step_tot);  /* -1 because vert edges join */
		maxPolys = totedge * step_tot;

		screw_ofs = 0.0f;
	}
	else {
		close = 0;
		if (step_tot < 3) step_tot = 3;

		maxVerts =  totvert  * step_tot; /* -1 because we're joining back up */
		maxEdges =  (totvert * (step_tot - 1)) + /* these are the edges between new verts */
		           (totedge * step_tot);  /* -1 because vert edges join */
		maxPolys =  totedge * (step_tot - 1);
	}

	if ((ltmd->flag & MOD_SCREW_UV_STRETCH_U) == 0) {
		uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f));
	}
	
	result = CDDM_from_template(dm, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys);
	
	/* copy verts from mesh */
	mvert_orig =    dm->getVertArray(dm);
	medge_orig =    dm->getEdgeArray(dm);
	
	mvert_new =     result->getVertArray(result);
	mpoly_new =     result->getPolyArray(result);
	mloop_new =     result->getLoopArray(result);
	medge_new =     result->getEdgeArray(result);

	if (!CustomData_has_layer(&result->polyData, CD_ORIGINDEX)) {
		CustomData_add_layer(&result->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys);
	}

	origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);

	DM_copy_vert_data(dm, result, 0, 0, (int)totvert); /* copy first otherwise this overwrites our own vertex normals */

	if (mloopuv_layers_tot) {
		float zero_co[3] = {0};
		plane_from_point_normal_v3(uv_axis_plane, zero_co, axis_vec);
	}

	if (mloopuv_layers_tot) {
		unsigned int uv_lay;
		for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
			mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, (int)uv_lay);
		}

		if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) {
			for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) {
				const float v = dist_squared_to_plane_v3(mv_orig->co, uv_axis_plane);
				uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]);
				uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]);
			}
			uv_v_minmax[0] = sqrtf_signed(uv_v_minmax[0]);
			uv_v_minmax[1] = sqrtf_signed(uv_v_minmax[1]);
		}

		uv_v_range_inv = uv_v_minmax[1] - uv_v_minmax[0];
		uv_v_range_inv = uv_v_range_inv ? 1.0f / uv_v_range_inv : 0.0f;
	}

	/* Set the locations of the first set of verts */
	
	mv_new = mvert_new;
	mv_orig = mvert_orig;
	
	/* Copy the first set of edges */
	med_orig = medge_orig;
	med_new = medge_new;
	for (i = 0; i < totedge; i++, med_orig++, med_new++) {
		med_new->v1 = med_orig->v1;
		med_new->v2 = med_orig->v2;
		med_new->crease = med_orig->crease;
		med_new->flag = med_orig->flag &  ~ME_LOOSEEDGE;
	}
	
	/* build polygon -> edge map */
	if (totpoly) {
		MPoly *mp_orig;

		mpoly_orig = dm->getPolyArray(dm);
		mloop_orig = dm->getLoopArray(dm);
		edge_poly_map = MEM_mallocN(sizeof(*edge_poly_map) * totedge, __func__);
		memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge);

		vert_loop_map = MEM_mallocN(sizeof(*vert_loop_map) * totvert, __func__);
		memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert);

		for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) {
			unsigned int loopstart = (unsigned int)mp_orig->loopstart;
			unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop;

			MLoop *ml_orig = &mloop_orig[loopstart];
			unsigned int k;
			for (k = loopstart; k < loopend; k++, ml_orig++) {
				edge_poly_map[ml_orig->e] = i;
				vert_loop_map[ml_orig->v] = k;

				/* also order edges based on faces */
				if (medge_new[ml_orig->e].v1 != ml_orig->v) {
					SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2);
				}
			}
		}
	}
Example #5
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
                                  ModifierApplyFlag flag)
{
	MultiresModifierData *mmd = (MultiresModifierData *)md;
	DerivedMesh *result;
	Mesh *me = (Mesh *)ob->data;
	const bool useRenderParams = (flag & MOD_APPLY_RENDER) != 0;
	const bool ignore_simplify = (flag & MOD_APPLY_IGNORE_SIMPLIFY) != 0;
	MultiresFlags flags = 0;
	const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);

	if (mmd->totlvl) {
		if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
			/* multires always needs a displacement layer */
			CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop);
		}
	}

	if (has_mask)
		flags |= MULTIRES_ALLOC_PAINT_MASK;

	if (useRenderParams)
		flags |= MULTIRES_USE_RENDER_PARAMS;

	if (ignore_simplify)
		flags |= MULTIRES_IGNORE_SIMPLIFY;

	result = multires_make_derived_from_derived(dm, mmd, ob, flags);

	if (result == dm)
		return dm;

	if (useRenderParams || !(flag & MOD_APPLY_USECACHE)) {
		DerivedMesh *cddm;
		
		cddm = CDDM_copy(result);

		/* copy hidden/masks to vertices */
		if (!useRenderParams) {
			struct MDisps *mdisps;
			struct GridPaintMask *grid_paint_mask;
			
			mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
			grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
			
			if (mdisps) {
				subsurf_copy_grid_hidden(result, me->mpoly,
				                         cddm->getVertArray(cddm),
				                         mdisps);

				BKE_mesh_flush_hidden_from_verts_ex(cddm->getVertArray(cddm),
				                                    cddm->getLoopArray(cddm),
				                                    cddm->getEdgeArray(cddm),
				                                    cddm->getNumEdges(cddm),
				                                    cddm->getPolyArray(cddm),
				                                    cddm->getNumPolys(cddm));
			}
			if (grid_paint_mask) {
				float *paint_mask = CustomData_add_layer(&cddm->vertData,
				                                         CD_PAINT_MASK,
				                                         CD_CALLOC, NULL,
				                                         cddm->getNumVerts(cddm));

				subsurf_copy_grid_paint_mask(result, me->mpoly,
				                             paint_mask, grid_paint_mask);
			}
		}

		result->release(result);
		result = cddm;
	}

	return result;
}
Example #6
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  int useRenderParams,
                                  int UNUSED(isFinalCalc))
{
    DerivedMesh *dm= derivedData;
    DerivedMesh *result;
    ScrewModifierData *ltmd= (ScrewModifierData*) md;

    int *origindex;
    int mface_index=0;
    int step;
    int i, j;
    int i1,i2;
    int step_tot= useRenderParams ? ltmd->render_steps : ltmd->steps;
    const int do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0;
    int maxVerts=0, maxEdges=0, maxFaces=0;
    int totvert= dm->getNumVerts(dm);
    int totedge= dm->getNumEdges(dm);

    char axis_char= 'X', close;
    float angle= ltmd->angle;
    float screw_ofs= ltmd->screw_ofs;
    float axis_vec[3]= {0.0f, 0.0f, 0.0f};
    float tmp_vec1[3], tmp_vec2[3];
    float mat3[3][3];
    float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */
    float mtx_tx_inv[4][4]; /* inverted */
    float mtx_tmp_a[4][4];

    int vc_tot_linked= 0;
    short other_axis_1, other_axis_2;
    float *tmpf1, *tmpf2;

    MFace *mface_new, *mf_new;
    MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new;
    MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base;

    ScrewVertConnect *vc, *vc_tmp, *vert_connect= NULL;

    /* dont do anything? */
    if (!totvert)
        return CDDM_from_template(dm, 0, 0, 0);

    switch(ltmd->axis) {
    case 0:
        other_axis_1=1;
        other_axis_2=2;
        break;
    case 1:
        other_axis_1=0;
        other_axis_2=2;
        break;
    default: /* 2, use default to quiet warnings */
        other_axis_1=0;
        other_axis_2=1;
        break;
    }

    axis_vec[ltmd->axis]= 1.0f;

    if (ltmd->ob_axis) {
        /* calc the matrix relative to the axis object */
        invert_m4_m4(mtx_tmp_a, ob->obmat);
        copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat);
        mul_m4_m4m4(mtx_tx, mtx_tx_inv, mtx_tmp_a);

        /* calc the axis vec */
        mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */
        normalize_v3(axis_vec);

        /* screw */
        if(ltmd->flag & MOD_SCREW_OBJECT_OFFSET) {
            /* find the offset along this axis relative to this objects matrix */
            float totlen = len_v3(mtx_tx[3]);

            if(totlen != 0.0f) {
                float zero[3]= {0.0f, 0.0f, 0.0f};
                float cp[3];
                screw_ofs= closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec);
            }
            else {
                screw_ofs= 0.0f;
            }
        }

        /* angle */

#if 0	// cant incluide this, not predictable enough, though quite fun,.
        if(ltmd->flag & MOD_SCREW_OBJECT_ANGLE) {
            float mtx3_tx[3][3];
            copy_m3_m4(mtx3_tx, mtx_tx);

            float vec[3] = {0,1,0};
            float cross1[3];
            float cross2[3];
            cross_v3_v3v3(cross1, vec, axis_vec);

            mul_v3_m3v3(cross2, mtx3_tx, cross1);
            {
                float c1[3];
                float c2[3];
                float axis_tmp[3];

                cross_v3_v3v3(c1, cross2, axis_vec);
                cross_v3_v3v3(c2, axis_vec, c1);


                angle= angle_v3v3(cross1, c2);

                cross_v3_v3v3(axis_tmp, cross1, c2);
                normalize_v3(axis_tmp);

                if(len_v3v3(axis_tmp, axis_vec) > 1.0f)
                    angle= -angle;

            }
        }
#endif
    }
    else {
        /* exis char is used by i_rotate*/
        axis_char += ltmd->axis; /* 'X' + axis */

        /* useful to be able to use the axis vec in some cases still */
        zero_v3(axis_vec);
        axis_vec[ltmd->axis]= 1.0f;
    }

    /* apply the multiplier */
    angle *= ltmd->iter;
    screw_ofs *= ltmd->iter;

    /* multiplying the steps is a bit tricky, this works best */
    step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1);

    /* will the screw be closed?
     * Note! smaller then FLT_EPSILON*100 gives problems with float precision so its never closed. */
    if (fabsf(screw_ofs) <= (FLT_EPSILON*100.0f) && fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON*100.0f)) {
        close= 1;
        step_tot--;
        if(step_tot < 3) step_tot= 3;

        maxVerts =	totvert  * step_tot; /* -1 because we're joining back up */
        maxEdges =	(totvert * step_tot) + /* these are the edges between new verts */
                    (totedge * step_tot); /* -1 because vert edges join */
        maxFaces =	totedge * step_tot;

        screw_ofs= 0.0f;
    }
    else {
        close= 0;
        if(step_tot < 3) step_tot= 3;

        maxVerts =	totvert  * step_tot; /* -1 because we're joining back up */
        maxEdges =	(totvert * (step_tot-1)) + /* these are the edges between new verts */
                    (totedge * step_tot); /* -1 because vert edges join */
        maxFaces =	totedge * (step_tot-1);
    }

    result= CDDM_from_template(dm, maxVerts, maxEdges, maxFaces);

    /* copy verts from mesh */
    mvert_orig =	dm->getVertArray(dm);
    medge_orig =	dm->getEdgeArray(dm);

    mvert_new =		result->getVertArray(result);
    mface_new =		result->getFaceArray(result);
    medge_new =		result->getEdgeArray(result);

    origindex= result->getFaceDataArray(result, CD_ORIGINDEX);

    DM_copy_vert_data(dm, result, 0, 0, totvert); /* copy first otherwise this overwrites our own vertex normals */

    /* Set the locations of the first set of verts */

    mv_new= mvert_new;
    mv_orig= mvert_orig;

    /* Copy the first set of edges */
    med_orig= medge_orig;
    med_new= medge_new;
    for (i=0; i < totedge; i++, med_orig++, med_new++) {
        med_new->v1= med_orig->v1;
        med_new->v2= med_orig->v2;
        med_new->crease= med_orig->crease;
        med_new->flag= med_orig->flag &  ~ME_LOOSEEDGE;
    }

    if(ltmd->flag & MOD_SCREW_NORMAL_CALC) {
        /*
         * Normal Calculation (for face flipping)
         * Sort edge verts for correct face flipping
         * NOT REALLY NEEDED but face flipping is nice.
         *
         * */


        /* Notice!
         *
         * Since we are only ordering the edges here it can avoid mallocing the
         * extra space by abusing the vert array berfore its filled with new verts.
         * The new array for vert_connect must be at least sizeof(ScrewVertConnect) * totvert
         * and the size of our resulting meshes array is sizeof(MVert) * totvert * 3
         * so its safe to use the second 2 thrids of MVert the array for vert_connect,
         * just make sure ScrewVertConnect struct is no more then twice as big as MVert,
         * at the moment there is no chance of that being a problem,
         * unless MVert becomes half its current size.
         *
         * once the edges are ordered, vert_connect is not needed and it can be used for verts
         *
         * This makes the modifier faster with one less alloc.
         */

        vert_connect= MEM_mallocN(sizeof(ScrewVertConnect) * totvert, "ScrewVertConnect");
        //vert_connect= (ScrewVertConnect *) &medge_new[totvert]; /* skip the first slice of verts */
        vc= vert_connect;

        /* Copy Vert Locations */
        /* - We can do this in a later loop - only do here if no normal calc */
        if (!totedge) {
            for (i=0; i < totvert; i++, mv_orig++, mv_new++) {
                copy_v3_v3(mv_new->co, mv_orig->co);
                normalize_v3_v3(vc->no, mv_new->co); /* no edges- this is really a dummy normal */
            }
        }
        else {
            /*printf("\n\n\n\n\nStarting Modifier\n");*/
            /* set edge users */
            med_new= medge_new;
            mv_new= mvert_new;

            if (ltmd->ob_axis) {
                /*mtx_tx is initialized early on */
                for (i=0; i < totvert; i++, mv_new++, mv_orig++, vc++) {
                    vc->co[0]= mv_new->co[0]= mv_orig->co[0];
                    vc->co[1]= mv_new->co[1]= mv_orig->co[1];
                    vc->co[2]= mv_new->co[2]= mv_orig->co[2];

                    vc->flag= 0;
                    vc->e[0]= vc->e[1]= NULL;
                    vc->v[0]= vc->v[1]= -1;

                    mul_m4_v3(mtx_tx, vc->co);
                    /* length in 2d, dont sqrt because this is only for comparison */
                    vc->dist =	vc->co[other_axis_1]*vc->co[other_axis_1] +
                                vc->co[other_axis_2]*vc->co[other_axis_2];

                    /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/
                }
            }
            else {
                for (i=0; i < totvert; i++, mv_new++, mv_orig++, vc++) {
                    vc->co[0]= mv_new->co[0]= mv_orig->co[0];
                    vc->co[1]= mv_new->co[1]= mv_orig->co[1];
                    vc->co[2]= mv_new->co[2]= mv_orig->co[2];

                    vc->flag= 0;
                    vc->e[0]= vc->e[1]= NULL;
                    vc->v[0]= vc->v[1]= -1;

                    /* length in 2d, dont sqrt because this is only for comparison */
                    vc->dist =	vc->co[other_axis_1]*vc->co[other_axis_1] +
                                vc->co[other_axis_2]*vc->co[other_axis_2];

                    /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/
                }
            }

            /* this loop builds connectivity info for verts */
            for (i=0; i<totedge; i++, med_new++) {
                vc= &vert_connect[med_new->v1];

                if (vc->v[0] == -1) { /* unused */
                    vc->v[0]= med_new->v2;
                    vc->e[0]= med_new;
                }
                else if (vc->v[1] == -1) {
                    vc->v[1]= med_new->v2;
                    vc->e[1]= med_new;
                }
                else {
                    vc->v[0]= vc->v[1]= -2; /* erro value  - dont use, 3 edges on vert */
                }

                vc= &vert_connect[med_new->v2];

                /* same as above but swap v1/2 */
                if (vc->v[0] == -1) { /* unused */
                    vc->v[0]= med_new->v1;
                    vc->e[0]= med_new;
                }
                else if (vc->v[1] == -1) {
                    vc->v[1]= med_new->v1;
                    vc->e[1]= med_new;
                }
                else {
                    vc->v[0]= vc->v[1]= -2; /* erro value  - dont use, 3 edges on vert */
                }
            }

            /* find the first vert */
            vc= vert_connect;
            for (i=0; i < totvert; i++, vc++) {
                /* Now do search for connected verts, order all edges and flip them
                 * so resulting faces are flipped the right way */
                vc_tot_linked= 0; /* count the number of linked verts for this loop */
                if (vc->flag == 0) {
                    int v_best=-1, ed_loop_closed=0; /* vert and vert new */
                    ScrewVertIter lt_iter;
                    int ed_loop_flip= 0; /* compiler complains if not initialized, but it should be initialized below */
                    float fl= -1.0f;

                    /*printf("Loop on connected vert: %i\n", i);*/

                    for(j=0; j<2; j++) {
                        /*printf("\tSide: %i\n", j);*/
                        screwvert_iter_init(&lt_iter, vert_connect, i, j);
                        if (j == 1) {
                            screwvert_iter_step(&lt_iter);
                        }
                        while (lt_iter.v_poin) {
                            /*printf("\t\tVERT: %i\n", lt_iter.v);*/
                            if (lt_iter.v_poin->flag) {
                                /*printf("\t\t\tBreaking Found end\n");*/
                                //endpoints[0]= endpoints[1]= -1;
                                ed_loop_closed= 1; /* circle */
                                break;
                            }
                            lt_iter.v_poin->flag= 1;
                            vc_tot_linked++;
                            /*printf("Testing 2 floats %f : %f\n", fl, lt_iter.v_poin->dist);*/
                            if (fl <= lt_iter.v_poin->dist) {
                                fl= lt_iter.v_poin->dist;
                                v_best= lt_iter.v;
                                /*printf("\t\t\tVERT BEST: %i\n", v_best);*/
                            }
                            screwvert_iter_step(&lt_iter);
                            if (!lt_iter.v_poin) {
                                /*printf("\t\t\tFound End Also Num %i\n", j);*/
                                /*endpoints[j]= lt_iter.v_other;*/ /* other is still valid */
                                break;
                            }
                        }
                    }

                    /* now we have a collection of used edges. flip their edges the right way*/
                    /*if (v_best != -1) - */

                    /*printf("Done Looking - vc_tot_linked: %i\n", vc_tot_linked);*/

                    if (vc_tot_linked>1) {
                        float vf_1, vf_2, vf_best;

                        vc_tmp= &vert_connect[v_best];

                        tmpf1= vert_connect[vc_tmp->v[0]].co;
                        tmpf2= vert_connect[vc_tmp->v[1]].co;


                        /* edge connects on each side! */
                        if ((vc_tmp->v[0] > -1) && (vc_tmp->v[1] > -1)) {
                            /*printf("Verts on each side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/
                            /* find out which is higher */

                            vf_1= tmpf1[ltmd->axis];
                            vf_2= tmpf2[ltmd->axis];
                            vf_best= vc_tmp->co[ltmd->axis];

                            if (vf_1 < vf_best && vf_best < vf_2) {
                                ed_loop_flip= 0;
                            }
                            else if (vf_1 > vf_best && vf_best > vf_2) {
                                ed_loop_flip= 1;
                            }
                            else {
                                /* not so simple to work out which edge is higher */
                                sub_v3_v3v3(tmp_vec1, tmpf1, vc_tmp->co);
                                sub_v3_v3v3(tmp_vec2, tmpf2, vc_tmp->co);
                                normalize_v3(tmp_vec1);
                                normalize_v3(tmp_vec2);

                                if (tmp_vec1[ltmd->axis] < tmp_vec2[ltmd->axis]) {
                                    ed_loop_flip= 1;
                                }
                                else {
                                    ed_loop_flip= 0;
                                }
                            }
                        }
                        else if (vc_tmp->v[0] >= 0) { /*vertex only connected on 1 side */
                            /*printf("Verts on ONE side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/
                            if (tmpf1[ltmd->axis] < vc_tmp->co[ltmd->axis]) { /* best is above */
                                ed_loop_flip= 1;
                            }
                            else { /* best is below or even... in even case we cant know whet  to do. */
                                ed_loop_flip= 0;
                            }

                        }/* else {
							printf("No Connected ___\n");
						}*/

                        /*printf("flip direction %i\n", ed_loop_flip);*/


                        /* switch the flip option if set
                         * note: flip is now done at face level so copying vgroup slizes is easier */
                        /*
                        if (do_flip)
                        	ed_loop_flip= !ed_loop_flip;
                        */

                        if (angle < 0.0f)
                            ed_loop_flip= !ed_loop_flip;

                        /* if its closed, we only need 1 loop */
                        for(j=ed_loop_closed; j<2; j++) {
                            /*printf("Ordering Side J %i\n", j);*/

                            screwvert_iter_init(&lt_iter, vert_connect, v_best, j);
                            /*printf("\n\nStarting - Loop\n");*/
                            lt_iter.v_poin->flag= 1; /* so a non loop will traverse the other side */


                            /* If this is the vert off the best vert and
                             * the best vert has 2 edges connected too it
                             * then swap the flip direction */
                            if (j == 1 && (vc_tmp->v[0] > -1) && (vc_tmp->v[1] > -1))
                                ed_loop_flip= !ed_loop_flip;

                            while (lt_iter.v_poin && lt_iter.v_poin->flag != 2) {
                                /*printf("\tOrdering Vert V %i\n", lt_iter.v);*/

                                lt_iter.v_poin->flag= 2;
                                if (lt_iter.e) {
                                    if (lt_iter.v == lt_iter.e->v1) {
                                        if (ed_loop_flip == 0) {
                                            /*printf("\t\t\tFlipping 0\n");*/
                                            SWAP(int, lt_iter.e->v1, lt_iter.e->v2);
                                        }/* else {
											printf("\t\t\tFlipping Not 0\n");
										}*/
                                    }
                                    else if (lt_iter.v == lt_iter.e->v2) {
                                        if (ed_loop_flip == 1) {
                                            /*printf("\t\t\tFlipping 1\n");*/
                                            SWAP(int, lt_iter.e->v1, lt_iter.e->v2);
                                        }/* else {
											printf("\t\t\tFlipping Not 1\n");
										}*/
                                    }/* else {
										printf("\t\tIncorrect edge topology");
									}*/
                                }/* else {
									printf("\t\tNo Edge at this point\n");
								}*/
                                screwvert_iter_step(&lt_iter);
                            }
                        }
Example #7
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;
	}