示例#1
0
static void waveModifier_do(WaveModifierData *md, 
		Scene *scene, Object *ob, DerivedMesh *dm,
	   float (*vertexCos)[3], int numVerts)
{
	WaveModifierData *wmd = (WaveModifierData*) md;
	MVert *mvert = NULL;
	MDeformVert *dvert = NULL;
	int defgrp_index;
	float ctime = BKE_curframe(scene);
	float minfac =
			(float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow));
	float lifefac = wmd->height;
	float (*tex_co)[3] = NULL;

	if(wmd->flag & MOD_WAVE_NORM && ob->type == OB_MESH)
		mvert = dm->getVertArray(dm);

	if(wmd->objectcenter){
		float mat[4][4];
		/* get the control object's location in local coordinates */
		invert_m4_m4(ob->imat, ob->obmat);
		mul_m4_m4m4(mat, wmd->objectcenter->obmat, ob->imat);

		wmd->startx = mat[3][0];
		wmd->starty = mat[3][1];
	}

	/* get the index of the deform group */
	defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);

	if(defgrp_index >= 0){
		dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
	}

	if(wmd->damp == 0) wmd->damp = 10.0f;

	if(wmd->lifetime != 0.0) {
		float x = ctime - wmd->timeoffs;

		if(x > wmd->lifetime) {
			lifefac = x - wmd->lifetime;

			if(lifefac > wmd->damp) lifefac = 0.0;
			else lifefac =
				(float)(wmd->height * (1.0 - sqrt(lifefac / wmd->damp)));
		}
	}

	if(wmd->texture) {
		tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts,
					 "waveModifier_do tex_co");
		wavemod_get_texture_coords(wmd, ob, dm, vertexCos, tex_co, numVerts);
	}

	if(lifefac != 0.0) {		
		/* avoid divide by zero checks within the loop */
		float falloff_inv= wmd->falloff ? 1.0f / wmd->falloff : 1.0;
		int i;

		for(i = 0; i < numVerts; i++) {
			float *co = vertexCos[i];
			float x = co[0] - wmd->startx;
			float y = co[1] - wmd->starty;
			float amplit= 0.0f;
			float dist = 0.0f;
			float falloff_fac = 0.0f;
			TexResult texres;
			MDeformWeight *def_weight = NULL;

			/* get weights */
			if(dvert) {
				int j;
				for(j = 0; j < dvert[i].totweight; ++j) {
					if(dvert[i].dw[j].def_nr == defgrp_index) {
						def_weight = &dvert[i].dw[j];
						break;
					}
				}

				/* if this vert isn't in the vgroup, don't deform it */
				if(!def_weight) continue;
			}

			if(wmd->texture) {
				texres.nor = NULL;
				get_texture_value(wmd->texture, tex_co[i], &texres);
			}

			/*get dist*/
			if(wmd->flag & MOD_WAVE_X) {
				if(wmd->flag & MOD_WAVE_Y){
					dist = (float)sqrt(x*x + y*y);
				}
				else{
					dist = fabs(x);
				}
			}
			else if(wmd->flag & MOD_WAVE_Y) {
				dist = fabs(y);
			}

			falloff_fac = (1.0f - (dist * falloff_inv));

			if(wmd->flag & MOD_WAVE_X) {
				if(wmd->flag & MOD_WAVE_Y) amplit = (float)sqrt(x*x + y*y);
				else amplit = x;
			}
			else if(wmd->flag & MOD_WAVE_Y)
				amplit= y;

			/* this way it makes nice circles */
			amplit -= (ctime - wmd->timeoffs) * wmd->speed;

			if(wmd->flag & MOD_WAVE_CYCL) {
				amplit = (float)fmod(amplit - wmd->width, 2.0 * wmd->width)
						+ wmd->width;
			}

			/* GAUSSIAN */
			if(amplit > -wmd->width && amplit < wmd->width) {
				amplit = amplit * wmd->narrow;
				amplit = (float)(1.0 / exp(amplit * amplit) - minfac);

				/*apply texture*/
				if(wmd->texture)
					amplit = amplit * texres.tin;

				/*apply weight*/
				if(def_weight)
					amplit = amplit * def_weight->weight;

				/*apply falloff*/
				if (wmd->falloff > 0)
					amplit = amplit * falloff_fac;

				if(mvert) {
					/* move along normals */
					if(wmd->flag & MOD_WAVE_NORM_X) {
						co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
					}
					if(wmd->flag & MOD_WAVE_NORM_Y) {
						co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
					}
					if(wmd->flag & MOD_WAVE_NORM_Z) {
						co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
					}
				}
				else {
					/* move along local z axis */
					co[2] += lifefac * amplit;
				}
			}
		}
	}

	if(wmd->texture) MEM_freeN(tex_co);
}
示例#2
0
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;
}
示例#3
0
static void waveModifier_do(WaveModifierData *md, 
		Scene *scene, Object *ob, DerivedMesh *dm,
	   float (*vertexCos)[3], int numVerts)
{
	WaveModifierData *wmd = (WaveModifierData*) md;
	MVert *mvert = NULL;
	MDeformVert *dvert;
	int defgrp_index;
	float ctime = BKE_curframe(scene);
	float minfac =
			(float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow));
	float lifefac = wmd->height;
	float (*tex_co)[3] = NULL;
	const int wmd_axis= wmd->flag & (MOD_WAVE_X|MOD_WAVE_Y);
	const float falloff= wmd->falloff;
	float falloff_fac= 1.0f; /* when falloff == 0.0f this stays at 1.0f */

	if(wmd->flag & MOD_WAVE_NORM && ob->type == OB_MESH)
		mvert = dm->getVertArray(dm);

	if(wmd->objectcenter){
		float mat[4][4];
		/* get the control object's location in local coordinates */
		invert_m4_m4(ob->imat, ob->obmat);
		mul_m4_m4m4(mat, wmd->objectcenter->obmat, ob->imat);

		wmd->startx = mat[3][0];
		wmd->starty = mat[3][1];
	}

	/* get the index of the deform group */
	modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);

	if(wmd->damp == 0) wmd->damp = 10.0f;

	if(wmd->lifetime != 0.0f) {
		float x = ctime - wmd->timeoffs;

		if(x > wmd->lifetime) {
			lifefac = x - wmd->lifetime;

			if(lifefac > wmd->damp) lifefac = 0.0;
			else lifefac =
				(float)(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp)));
		}
	}

	if(wmd->texture) {
		tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts,
					 "waveModifier_do tex_co");
		wavemod_get_texture_coords(wmd, ob, dm, vertexCos, tex_co, numVerts);
	}

	if(lifefac != 0.0f) {
		/* avoid divide by zero checks within the loop */
		float falloff_inv= falloff ? 1.0f / falloff : 1.0f;
		int i;

		for(i = 0; i < numVerts; i++) {
			float *co = vertexCos[i];
			float x = co[0] - wmd->startx;
			float y = co[1] - wmd->starty;
			float amplit= 0.0f;
			float def_weight= 1.0f;

			/* get weights */
			if(dvert) {
				def_weight= defvert_find_weight(&dvert[i], defgrp_index);

				/* if this vert isn't in the vgroup, don't deform it */
				if(def_weight == 0.0f) {
					continue;
				}
			}

			switch(wmd_axis) {
			case MOD_WAVE_X|MOD_WAVE_Y:
				amplit = sqrtf(x*x + y*y);
				break;
			case MOD_WAVE_X:
				amplit = x;
				break;
			case MOD_WAVE_Y:
				amplit = y;
				break;
			}

			/* this way it makes nice circles */
			amplit -= (ctime - wmd->timeoffs) * wmd->speed;

			if(wmd->flag & MOD_WAVE_CYCL) {
				amplit = (float)fmodf(amplit - wmd->width, 2.0f * wmd->width)
						+ wmd->width;
			}

			if(falloff != 0.0f) {
				float dist = 0.0f;

				switch(wmd_axis) {
				case MOD_WAVE_X|MOD_WAVE_Y:
					dist = sqrtf(x*x + y*y);
					break;
				case MOD_WAVE_X:
					dist = fabsf(x);
					break;
				case MOD_WAVE_Y:
					dist = fabsf(y);
					break;
				}

				falloff_fac = (1.0f - (dist * falloff_inv));
				CLAMP(falloff_fac, 0.0f, 1.0f);
			}

			/* GAUSSIAN */
			if((falloff_fac != 0.0f) && (amplit > -wmd->width) && (amplit < wmd->width)) {
				amplit = amplit * wmd->narrow;
				amplit = (float)(1.0f / expf(amplit * amplit) - minfac);

				/*apply texture*/
				if(wmd->texture) {
					TexResult texres;
					texres.nor = NULL;
					get_texture_value(wmd->texture, tex_co[i], &texres);
					amplit *= texres.tin;
				}

				/*apply weight & falloff */
				amplit *= def_weight * falloff_fac;

				if(mvert) {
					/* move along normals */
					if(wmd->flag & MOD_WAVE_NORM_X) {
						co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
					}
					if(wmd->flag & MOD_WAVE_NORM_Y) {
						co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
					}
					if(wmd->flag & MOD_WAVE_NORM_Z) {
						co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
					}
				}
				else {
					/* move along local z axis */
					co[2] += lifefac * amplit;
				}
			}
		}
	}

	if(wmd->texture) MEM_freeN(tex_co);
}
示例#4
0
static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys)
{
	DerivedMesh* dm;
	ParticleKey state;
	ParticleSimulationData sim= {NULL};
	ParticleData *pa=NULL;
	float cfra = BKE_curframe(re->scene);
	int i, childexists;
	int total_particles, offset=0;
	int data_used = point_data_used(pd);
	float partco[3];
	float obview[4][4];
	
	/* init everything */
	if (!psys || !ob || !pd) return;

	mul_m4_m4m4(obview, re->viewinv, ob->obmat);
	
	/* Just to create a valid rendering context for particles */
	psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0);
	
	dm = mesh_create_derived_render(re->scene, ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
	
	if ( !psys_check_enabled(ob, psys)) {
		psys_render_restore(ob, psys);
		return;
	}
	
	sim.scene= re->scene;
	sim.ob= ob;
	sim.psys= psys;

	/* in case ob->imat isn't up-to-date */
	invert_m4_m4(ob->imat, ob->obmat);
	
	total_particles = psys->totpart+psys->totchild;
	psys->lattice=psys_get_lattice(&sim);
	
	pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6);
	alloc_point_data(pd, total_particles, data_used);
	pd->totpoints = total_particles;
	if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3;
	
	if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
		childexists = 1;
	
	for (i=0, pa=psys->particles; i < total_particles; i++, pa++) {

		state.time = cfra;
		if(psys_get_particle_state(&sim, i, &state, 0)) {
			
			VECCOPY(partco, state.co);
			
			if (pd->psys_cache_space == TEX_PD_OBJECTSPACE)
				mul_m4_v3(ob->imat, partco);
			else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) {
				sub_v3_v3(partco, ob->loc);
			} else {
				/* TEX_PD_WORLDSPACE */
			}
			
			BLI_bvhtree_insert(pd->point_tree, i, partco, 1);
			
			if (data_used & POINT_DATA_VEL) {
				pd->point_data[i*3 + 0] = state.vel[0];
				pd->point_data[i*3 + 1] = state.vel[1];
				pd->point_data[i*3 + 2] = state.vel[2];
			} 
			if (data_used & POINT_DATA_LIFE) {
				float pa_time;
				
				if (i < psys->totpart) {
					pa_time = (cfra - pa->time)/pa->lifetime;
				} else {
					ChildParticle *cpa= (psys->child + i) - psys->totpart;
					float pa_birthtime, pa_dietime;
					
					pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
				}
				
				pd->point_data[offset + i] = pa_time;
				
			}
		}
	}
	
	BLI_bvhtree_balance(pd->point_tree);
	dm->release(dm);
	
	if(psys->lattice){
		end_latt_deform(psys->lattice);
		psys->lattice=0;
	}
	
	psys_render_restore(ob, psys);
}
示例#5
0
static void do_nla(Scene *scene, Object *ob, int blocktype)
{
	bPose *tpose= NULL;
	Key *key= NULL;
	ListBase tchanbase={NULL, NULL}, chanbase={NULL, NULL};
	bActionStrip *strip, *striplast=NULL, *stripfirst=NULL;
	float striptime, frametime, length, actlength;
	float blendfac, stripframe;
	float scene_cfra= BKE_curframe(scene);
	int	doit, dostride;
	
	if(blocktype==ID_AR) {
		copy_pose(&tpose, ob->pose, 1);
		rest_pose(ob->pose);		// potentially destroying current not-keyed pose
	}
	else {
		key= ob_get_key(ob);
	}
	
	/* check on extend to left or right, when no strip is hit by 'cfra' */
	for (strip=ob->nlastrips.first; strip; strip=strip->next) {
		/* escape loop on a hit */
		if( scene_cfra >= strip->start && scene_cfra <= strip->end + 0.1f)	/* note 0.1 comes back below */
			break;
		if(scene_cfra < strip->start) {
			if(stripfirst==NULL)
				stripfirst= strip;
			else if(stripfirst->start > strip->start)
				stripfirst= strip;
		}
		else if(scene_cfra > strip->end) {
			if(striplast==NULL)
				striplast= strip;
			else if(striplast->end < strip->end)
				striplast= strip;
		}
	}
	if(strip==NULL) {	/* extend */
		if(striplast)
			scene_cfra= striplast->end;
		else if(stripfirst)
			scene_cfra= stripfirst->start;
	}
	
	/* and now go over all strips */
	for (strip=ob->nlastrips.first; strip; strip=strip->next){
		doit=dostride= 0;
		
		if (strip->act && !(strip->flag & ACTSTRIP_MUTE)) {	/* so theres an action */
			
			/* Determine if the current frame is within the strip's range */
			length = strip->end-strip->start;
			actlength = strip->actend-strip->actstart;
			striptime = (scene_cfra-(strip->start)) / length;
			stripframe = (scene_cfra-(strip->start)) ;

			if (striptime>=0.0){
				
				if(blocktype==ID_AR) 
					rest_pose(tpose);
				
				/* To handle repeat, we add 0.1 frame extra to make sure the last frame is included */
				if (striptime < 1.0f + 0.1f/length) {
					
					/* Handle path */
					if ((strip->flag & ACTSTRIP_USESTRIDE) && (blocktype==ID_AR) && (ob->ipoflag & OB_DISABLE_PATH)==0){
						Object *parent= get_parent_path(ob);
						
						if (parent) {
							Curve *cu = parent->data;
							float ctime, pdist;
							
							if (cu->flag & CU_PATH){
								/* Ensure we have a valid path */
								if(cu->path==NULL || cu->path->data==NULL) makeDispListCurveTypes(scene, parent, 0);
								if(cu->path) {
									
									/* Find the position on the path */
									ctime= bsystem_time(scene, ob, scene_cfra, 0.0);
									
									if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) {
										/* correct for actions not starting on zero */
										ctime= (ctime - strip->actstart)/cu->pathlen;
										CLAMP(ctime, 0.0, 1.0);
									}
									pdist = ctime*cu->path->totdist;
									
									if(tpose && strip->stridechannel[0]) {
										striptime= stridechannel_frame(parent, ob->size[0], strip, cu->path, pdist, tpose->stride_offset);
									}									
									else {
										if (strip->stridelen) {
											striptime = pdist / strip->stridelen;
											striptime = (float)fmod (striptime+strip->actoffs, 1.0);
										}
										else
											striptime = 0;
									}
									
									frametime = (striptime * actlength) + strip->actstart;
									frametime= bsystem_time(scene, ob, frametime, 0.0);
									
									if(blocktype==ID_AR) {
										extract_pose_from_action (tpose, strip->act, frametime);
									}
									else if(blocktype==ID_OB) {
										extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime);
										if(key)
											extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime);
									}
									doit=dostride= 1;
								}
							}
						}
					}
					/* To handle repeat, we add 0.1 frame extra to make sure the last frame is included */
					else  {
						
						/* Mod to repeat */
						if(strip->repeat!=1.0f) {
							float cycle= striptime*strip->repeat;
							
							striptime = (float)fmod (cycle, 1.0f + 0.1f/length);
							cycle-= striptime;
							
							if(blocktype==ID_AR)
								cyclic_offs_bone(ob, tpose, strip, cycle);
						}

						frametime = (striptime * actlength) + strip->actstart;
						frametime= nla_time(scene, frametime, (float)strip->repeat);
							
						if(blocktype==ID_AR) {
							extract_pose_from_action (tpose, strip->act, frametime);
						}
						else if(blocktype==ID_OB) {
							extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime);
							if(key)
								extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime);
						}
						
						doit=1;
					}
				}
				/* Handle extend */
				else {
					if (strip->flag & ACTSTRIP_HOLDLASTFRAME){
						/* we want the strip to hold on the exact fraction of the repeat value */
						
						frametime = actlength * (strip->repeat-(int)strip->repeat);
						if(frametime<=0.000001f) frametime= actlength;	/* rounding errors... */
						frametime= bsystem_time(scene, ob, frametime+strip->actstart, 0.0);
						
						if(blocktype==ID_AR)
							extract_pose_from_action (tpose, strip->act, frametime);
						else if(blocktype==ID_OB) {
							extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime);
							if(key)
								extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime);
						}
						
						/* handle cycle hold */
						if(strip->repeat!=1.0f) {
							if(blocktype==ID_AR)
								cyclic_offs_bone(ob, tpose, strip, strip->repeat-1.0f);
						}
						
						doit=1;
					}
				}
				
				/* Handle blendin & blendout */
				if (doit){
					/* Handle blendin */
					
					if (strip->blendin>0.0 && stripframe<=strip->blendin && scene_cfra>=strip->start){
						blendfac = stripframe/strip->blendin;
					}
					else if (strip->blendout>0.0 && stripframe>=(length-strip->blendout) && scene_cfra<=strip->end){
						blendfac = (length-stripframe)/(strip->blendout);
					}
					else
						blendfac = 1;
					
					if(blocktype==ID_AR) {/* Blend this pose with the accumulated pose */
						/* offset bone, for matching cycles */
						blend_pose_offset_bone (strip, ob->pose, tpose, blendfac, strip->mode);
						
						blend_poses (ob->pose, tpose, blendfac, strip->mode);
						if(dostride)
							blend_pose_strides (ob->pose, tpose, blendfac, strip->mode);
					}
					else {
						blend_ipochannels(&chanbase, &tchanbase, blendfac, strip->mode);
						BLI_freelistN(&tchanbase);
					}
				}
			}					
		}
	}
	
	if(blocktype==ID_OB) {
		execute_ipochannels(&chanbase);
	}
	else if(blocktype==ID_AR) {
		/* apply stride offset to object */
		add_v3_v3(ob->obmat[3], ob->pose->stride_offset);
	}
	
	/* free */
	if (tpose)
		free_pose(tpose);
	if(chanbase.first)
		BLI_freelistN(&chanbase);
}
示例#6
0
static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated)
{
	GroupObject *go;
	Object *ob=NULL, **oblist=NULL, obcopy, *obcopylist=NULL;
	DupliObject *dob;
	ParticleDupliWeight *dw;
	ParticleSettings *part;
	ParticleData *pa;
	ChildParticle *cpa=NULL;
	ParticleKey state;
	ParticleCacheKey *cache;
	float ctime, pa_time, scale = 1.0f;
	float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size=0.0;
	float (*obmat)[4], (*oldobmat)[4];
	int a, b, counter, hair = 0;
	int totpart, totchild, totgroup=0 /*, pa_num */;

	int no_draw_flag = PARS_UNEXIST;

	if (psys==NULL) return;
	
	/* simple preventing of too deep nested groups */
	if (level>MAX_DUPLI_RECUR) return;
	
	part=psys->part;

	if (part==NULL)
		return;

	if (!psys_check_enabled(par, psys))
		return;

	if (G.rendering == 0)
		no_draw_flag |= PARS_NO_DISP;
	
	ctime = BKE_curframe(scene); /* NOTE: in old animsys, used parent object's timeoffset... */

	totpart = psys->totpart;
	totchild = psys->totchild;

	BLI_srandom(31415926 + psys->seed);

	if ((psys->renderdata || part->draw_as==PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
		ParticleSimulationData sim= {NULL};
		sim.scene= scene;
		sim.ob= par;
		sim.psys= psys;
		sim.psmd= psys_get_modifier(par, psys);
		/* make sure emitter imat is in global coordinates instead of render view coordinates */
		invert_m4_m4(par->imat, par->obmat);

		/* first check for loops (particle system object used as dupli object) */
		if (part->ren_as == PART_DRAW_OB) {
			if (ELEM(part->dup_ob, NULL, par))
				return;
		}
		else { /*PART_DRAW_GR */
			if (part->dup_group == NULL || part->dup_group->gobject.first == NULL)
				return;

			for (go=part->dup_group->gobject.first; go; go=go->next)
				if (go->ob == par)
					return;
		}

		/* if we have a hair particle system, use the path cache */
		if (part->type == PART_HAIR) {
			if (psys->flag & PSYS_HAIR_DONE)
				hair= (totchild == 0 || psys->childcache) && psys->pathcache;
			if (!hair)
				return;
			
			/* we use cache, update totchild according to cached data */
			totchild = psys->totchildcache;
			totpart = psys->totcached;
		}

		psys_check_group_weights(part);

		psys->lattice = psys_get_lattice(&sim);

		/* gather list of objects or single object */
		if (part->ren_as==PART_DRAW_GR) {
			group_handle_recalc_and_update(scene, par, part->dup_group);

			if (part->draw & PART_DRAW_COUNT_GR) {
				for (dw=part->dupliweights.first; dw; dw=dw->next)
					totgroup += dw->count;
			}
			else {
				for (go=part->dup_group->gobject.first; go; go=go->next)
					totgroup++;
			}

			/* we also copy the actual objects to restore afterwards, since
			 * where_is_object_time will change the object which breaks transform */
			oblist = MEM_callocN(totgroup*sizeof(Object *), "dupgroup object list");
			obcopylist = MEM_callocN(totgroup*sizeof(Object), "dupgroup copy list");

			
			if (part->draw & PART_DRAW_COUNT_GR && totgroup) {
				dw = part->dupliweights.first;

				for (a=0; a<totgroup; dw=dw->next) {
					for (b=0; b<dw->count; b++, a++) {
						oblist[a] = dw->ob;
						obcopylist[a] = *dw->ob;
					}
				}
			}
			else {
				go = part->dup_group->gobject.first;
				for (a=0; a<totgroup; a++, go=go->next) {
					oblist[a] = go->ob;
					obcopylist[a] = *go->ob;
				}
			}
		}
		else {
			ob = part->dup_ob;
			obcopy = *ob;
		}

		if (totchild==0 || part->draw & PART_DRAW_PARENT)
			a = 0;
		else
			a = totpart;

		for (pa=psys->particles,counter=0; a<totpart+totchild; a++,pa++,counter++) {
			if (a<totpart) {
				/* handle parent particle */
				if (pa->flag & no_draw_flag)
					continue;

				/* pa_num = pa->num; */ /* UNUSED */
				pa_time = pa->time;
				size = pa->size;
			}
			else {
				/* handle child particle */
				cpa = &psys->child[a - totpart];

				/* pa_num = a; */ /* UNUSED */
				pa_time = psys->particles[cpa->parent].time;
				size = psys_get_child_size(psys, cpa, ctime, NULL);
			}

			/* some hair paths might be non-existent so they can't be used for duplication */
			if (hair &&
				((a < totpart && psys->pathcache[a]->steps < 0) ||
				(a >= totpart && psys->childcache[a-totpart]->steps < 0)))
				continue;

			if (part->ren_as==PART_DRAW_GR) {
				/* prevent divide by zero below [#28336] */
				if (totgroup == 0)
					continue;

				/* for groups, pick the object based on settings */
				if (part->draw&PART_DRAW_RAND_GR)
					b= BLI_rand() % totgroup;
				else
					b= a % totgroup;

				ob = oblist[b];
				obmat = oblist[b]->obmat;
				oldobmat = obcopylist[b].obmat;
			}
			else {
				obmat= ob->obmat;
				oldobmat= obcopy.obmat;
			}

			if (hair) {
				/* hair we handle separate and compute transform based on hair keys */
				if (a < totpart) {
					cache = psys->pathcache[a];
					psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale);
				}
				else {
					cache = psys->childcache[a-totpart];
					psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale);
				}

				copy_v3_v3(pamat[3], cache->co);
				pamat[3][3]= 1.0f;
				
			}
			else {
				/* first key */
				state.time = ctime;
				if (psys_get_particle_state(&sim, a, &state, 0) == 0) {
					continue;
				}
				else {
					float tquat[4];
					normalize_qt_qt(tquat, state.rot);
					quat_to_mat4(pamat, tquat);
					copy_v3_v3(pamat[3], state.co);
					pamat[3][3]= 1.0f;
				}
			}

			if (part->ren_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
				for (go= part->dup_group->gobject.first, b=0; go; go= go->next, b++) {

					copy_m4_m4(tmat, oblist[b]->obmat);
					/* apply particle scale */
					mul_mat3_m4_fl(tmat, size*scale);
					mul_v3_fl(tmat[3], size*scale);
					/* group dupli offset, should apply after everything else */
					if (!is_zero_v3(part->dup_group->dupli_ofs))
						sub_v3_v3v3(tmat[3], tmat[3], part->dup_group->dupli_ofs);
					/* individual particle transform */
					mult_m4_m4m4(tmat, pamat, tmat);

					if (par_space_mat)
						mult_m4_m4m4(mat, par_space_mat, tmat);
					else
						copy_m4_m4(mat, tmat);

					dob= new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated);
					copy_m4_m4(dob->omat, obcopylist[b].obmat);
					if (G.rendering)
						psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
				}
			}
			else {
				/* to give ipos in object correct offset */
				where_is_object_time(scene, ob, ctime-pa_time);

				copy_v3_v3(vec, obmat[3]);
				obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;

				/* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */
				if ((part->draw & PART_DRAW_ROTATE_OB) == 0) {
					float xvec[3], q[4];
					xvec[0] = -1.f;
					xvec[1] = xvec[2] = 0;
					vec_to_quat(q, xvec, ob->trackflag, ob->upflag);
					quat_to_mat4(obmat, q);
					obmat[3][3]= 1.0f;
				}
				
				/* Normal particles and cached hair live in global space so we need to
				 * remove the real emitter's transformation before 2nd order duplication.
				 */
				if (par_space_mat && GS(id->name) != ID_GR)
					mult_m4_m4m4(mat, psys->imat, pamat);
				else
					copy_m4_m4(mat, pamat);

				mult_m4_m4m4(tmat, mat, obmat);
				mul_mat3_m4_fl(tmat, size*scale);

				if (par_space_mat)
					mult_m4_m4m4(mat, par_space_mat, tmat);
				else
					copy_m4_m4(mat, tmat);

				if (part->draw & PART_DRAW_GLOBAL_OB)
					add_v3_v3v3(mat[3], mat[3], vec);

				dob= new_dupli_object(lb, ob, mat, ob->lay, counter, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated);
				copy_m4_m4(dob->omat, oldobmat);
				if (G.rendering)
					psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
			}
		}

		/* restore objects since they were changed in where_is_object_time */
		if (part->ren_as==PART_DRAW_GR) {
			for (a=0; a<totgroup; a++)
				*(oblist[a])= obcopylist[a];
		}
		else
			*ob= obcopy;
	}

	/* clean up */
	if (oblist)
		MEM_freeN(oblist);
	if (obcopylist)
		MEM_freeN(obcopylist);

	if (psys->lattice) {
		end_latt_deform(psys->lattice);
		psys->lattice = NULL;
	}
}
示例#7
0
static void deformVerts(ModifierData *md, Object *ob,
						DerivedMesh *derivedData,
						float (*vertexCos)[3],
						int UNUSED(numVerts),
						int UNUSED(useRenderParams),
						int UNUSED(isFinalCalc))
{
	CollisionModifierData *collmd = (CollisionModifierData*) md;
	DerivedMesh *dm = NULL;
	MVert *tempVert = NULL;
	
	/* if possible use/create DerivedMesh */
	if(derivedData) dm = CDDM_copy(derivedData);
	else if(ob->type==OB_MESH) dm = CDDM_from_mesh(ob->data, ob);
	
	if(!ob->pd)
	{
		printf("CollisionModifier deformVerts: Should not happen!\n");
		return;
	}
	
	if(dm)
	{
		float current_time = 0;
		unsigned int numverts = 0;

		CDDM_apply_vert_coords(dm, vertexCos);
		CDDM_calc_normals(dm);
		
		current_time = BKE_curframe(md->scene);
		
		if(G.rt > 0)
			printf("current_time %f, collmd->time_xnew %f\n", current_time, collmd->time_xnew);
		
		numverts = dm->getNumVerts ( dm );
		
		if((current_time > collmd->time_xnew)|| (BKE_ptcache_get_continue_physics()))
		{
			unsigned int i;

			// check if mesh has changed
			if(collmd->x && (numverts != collmd->numverts))
				freeData((ModifierData *)collmd);
			
			if(collmd->time_xnew == -1000) // first time
			{
				collmd->x = dm->dupVertArray(dm); // frame start position
				
				for ( i = 0; i < numverts; i++ )
				{
					// we save global positions
					mul_m4_v3( ob->obmat, collmd->x[i].co );
				}
				
				collmd->xnew = MEM_dupallocN(collmd->x); // frame end position
				collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame
				collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
				collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame

				collmd->numverts = numverts;
				
				collmd->mfaces = dm->dupFaceArray(dm);
				collmd->numfaces = dm->getNumFaces(dm);
				
				// create bounding box hierarchy
				collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft);
				
				collmd->time_x = collmd->time_xnew = current_time;
			}
			else if(numverts == collmd->numverts)
			{
				// put positions to old positions
				tempVert = collmd->x;
				collmd->x = collmd->xnew;
				collmd->xnew = tempVert;
				collmd->time_x = collmd->time_xnew;
				
				memcpy(collmd->xnew, dm->getVertArray(dm), numverts*sizeof(MVert));
				
				for ( i = 0; i < numverts; i++ )
				{
					// we save global positions
					mul_m4_v3( ob->obmat, collmd->xnew[i].co );
				}
				
				memcpy(collmd->current_xnew, collmd->x, numverts*sizeof(MVert));
				memcpy(collmd->current_x, collmd->x, numverts*sizeof(MVert));
				
				/* check if GUI setting has changed for bvh */
				if(collmd->bvhtree) 
				{
					if(ob->pd->pdef_sboft != BLI_bvhtree_getepsilon(collmd->bvhtree))
					{
						BLI_bvhtree_free(collmd->bvhtree);
						collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
					}
			
				}
				
				/* happens on file load (ONLY when i decomment changes in readfile.c) */
				if(!collmd->bvhtree)
				{
					collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft);
				}
				else
				{
					// recalc static bounding boxes
					bvhtree_update_from_mvert ( collmd->bvhtree, collmd->mfaces, collmd->numfaces, collmd->current_x, collmd->current_xnew, collmd->numverts, 1 );
				}
				
				collmd->time_xnew = current_time;
			}
			else if(numverts != collmd->numverts)
			{
				freeData((ModifierData *)collmd);
			}
			
		}
		else if(current_time < collmd->time_xnew)
		{	
			freeData((ModifierData *)collmd);
		}
		else
		{
			if(numverts != collmd->numverts)
			{
				freeData((ModifierData *)collmd);
			}
		}
	}
	
	if(dm)
		dm->release(dm);
}
示例#8
0
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;
}