static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, int p)
{
	ParticleThreadContext *ctx= thread->ctx;
	int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */

	/* TODO_PARTICLE - use original index */
	pa->num= ctx->index[p];
	pa->fuv[0] = 1.0f;
	pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
	
#if ONLY_WORKING_WITH_PA_VERTS
	if (ctx->tree) {
		KDTreeNearest ptn[3];
		int w, maxw;
		
		psys_particle_on_dm(ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
		BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
		maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
		
		for (w=0; w<maxw; w++) {
			pa->verts[w]=ptn->num;
		}
	}
#endif
	
	if (rng_skip_tot > 0) /* should never be below zero */
		BLI_rng_skip(thread->rng, rng_skip_tot);
}
static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, int p)
{
	ParticleThreadContext *ctx= thread->ctx;
	MFace *mface;

	mface = ctx->dm->getTessFaceDataArray(ctx->dm, CD_MFACE);

	int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */

	/* TODO_PARTICLE - use original index */
	pa->num = ctx->index[p];

	zero_v4(pa->fuv);

	if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->dm->getNumVerts(ctx->dm)) {

		/* This finds the first face to contain the emitting vertex,
		 * this is not ideal, but is mostly fine as UV seams generally
		 * map to equal-colored parts of a texture */
		for (int i = 0; i < ctx->dm->getNumTessFaces(ctx->dm); i++, mface++) {
			if (ELEM(pa->num, mface->v1, mface->v2, mface->v3, mface->v4)) {
				unsigned int *vert = &mface->v1;

				for (int j = 0; j < 4; j++, vert++) {
					if (*vert == pa->num) {
						pa->fuv[j] = 1.0f;
						break;
					}
				}

				break;
			}
		}
	}

#if ONLY_WORKING_WITH_PA_VERTS
	if (ctx->tree) {
		KDTreeNearest ptn[3];
		int w, maxw;

		psys_particle_on_dm(ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
		BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
		maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);

		for (w=0; w<maxw; w++) {
			pa->verts[w]=ptn->num;
		}
	}
#endif

	if (rng_skip_tot > 0) /* should never be below zero */
		BLI_rng_skip(thread->rng, rng_skip_tot);
}
static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, int p) {
	ParticleThreadContext *ctx= thread->ctx;
	Object *ob= ctx->sim.ob;
	DerivedMesh *dm= ctx->dm;
	float orco1[3], co1[3], nor1[3];
	float randu, randv;
	int cfrom= ctx->cfrom;
	int i;
	int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */

	MFace *mf;

	if (ctx->index[p] < 0) {
		cpa->num=0;
		cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3]=0.0f;
		cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
		return;
	}

	mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE);

	randu= BLI_rng_get_float(thread->rng);
	randv= BLI_rng_get_float(thread->rng);
	rng_skip_tot -= 2;

	psys_uv_to_w(randu, randv, mf->v4, cpa->fuv);

	cpa->num = ctx->index[p];

	if (ctx->tree) {
		KDTreeNearest ptn[10];
		int w,maxw;//, do_seams;
		float maxd /*, mind,dd */, totw= 0.0f;
		int parent[10];
		float pweight[10];

		psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1,NULL);
		BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
		maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);

		maxd=ptn[maxw-1].dist;
		/* mind=ptn[0].dist; */ /* UNUSED */

		/* the weights here could be done better */
		for (w=0; w<maxw; w++) {
			parent[w]=ptn[w].index;
			pweight[w]=(float)pow(2.0,(double)(-6.0f*ptn[w].dist/maxd));
		}
		for (;w<10; w++) {
			parent[w]=-1;
			pweight[w]=0.0f;
		}

		for (w=0,i=0; w<maxw && i<4; w++) {
			if (parent[w]>=0) {
				cpa->pa[i]=parent[w];
				cpa->w[i]=pweight[w];
				totw+=pweight[w];
				i++;
			}
		}
		for (;i<4; i++) {
			cpa->pa[i]=-1;
			cpa->w[i]=0.0f;
		}

		if (totw > 0.0f) {
			for (w = 0; w < 4; w++) {
				cpa->w[w] /= totw;
			}
		}

		cpa->parent=cpa->pa[0];
	}

	if (rng_skip_tot > 0) /* should never be below zero */
		BLI_rng_skip(thread->rng, rng_skip_tot);
}
Beispiel #4
0
static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated)
{
	Object *ob, *ob_iter;
	Mesh *me = par->data;
	Base *base = NULL;
	DerivedMesh *dm;
	vertexDupliData vdd;
	Scene *sce = NULL;
	Group *group = NULL;
	GroupObject *go = NULL;
	BMEditMesh *em;
	float vec[3], no[3], pmat[4][4];
	int totvert, a, oblay;
	unsigned int lay;
	
	copy_m4_m4(pmat, par->obmat);
	
	/* simple preventing of too deep nested groups */
	if (level > MAX_DUPLI_RECUR) return;
	
	em = me->edit_btmesh;
	
	if (em) {
		dm = editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
	}
	else
		dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
	
	if (G.rendering) {
		vdd.orco = (float(*)[3])BKE_mesh_orco_verts_get(par);
		BKE_mesh_orco_verts_transform(me, vdd.orco, me->totvert, 0);
	}
	else
		vdd.orco = NULL;
	
	totvert = dm->getNumVerts(dm);

	/* having to loop on scene OR group objects is NOT FUN */
	if (GS(id->name) == ID_SCE) {
		sce = (Scene *)id;
		lay = sce->lay;
		base = sce->base.first;
	}
	else {
		group = (Group *)id;
		lay = group->layer;
		go = group->gobject.first;
	}
	
	/* Start looping on Scene OR Group objects */
	while (base || go) { 
		if (sce) {
			ob_iter = base->object;
			oblay = base->lay;
		}
		else {
			ob_iter = go->ob;
			oblay = ob_iter->lay;
		}
		
		if (lay & oblay && scene->obedit != ob_iter) {
			ob = ob_iter->parent;
			while (ob) {
				if (ob == par) {
					ob = ob_iter;
					/* End Scene/Group object loop, below is generic */
					
					
					/* par_space_mat - only used for groups so we can modify the space dupli's are in
					 * when par_space_mat is NULL ob->obmat can be used instead of ob__obmat
					 */
					if (par_space_mat)
						mult_m4_m4m4(vdd.obmat, par_space_mat, ob->obmat);
					else
						copy_m4_m4(vdd.obmat, ob->obmat);

					vdd.id = id;
					vdd.level = level;
					vdd.animated = animated;
					vdd.lb = lb;
					vdd.ob = ob;
					vdd.scene = scene;
					vdd.par = par;
					copy_m4_m4(vdd.pmat, pmat);
					
					/* mballs have a different dupli handling */
					if (ob->type != OB_MBALL) ob->flag |= OB_DONE;  /* doesnt render */

					if (me->edit_btmesh) {
						dm->foreachMappedVert(dm, vertex_dupli__mapFunc, (void *) &vdd);
					}
					else {
						for (a = 0; a < totvert; a++) {
							dm->getVertCo(dm, a, vec);
							dm->getVertNo(dm, a, no);
							
							vertex_dupli__mapFunc(&vdd, a, vec, no, NULL);
						}
					}
					if (sce) {
						/* Set proper layer in case of scene looping,
						 * in case of groups the object layer will be
						 * changed when it's duplicated due to the
						 * group duplication.
						 */
						ob->lay = vdd.par->lay;
					}
					
					break;
				}
				ob = ob->parent;
			}
		}
		if (sce) base = base->next;     /* scene loop */
		else go = go->next;             /* group loop */
	}

	if (vdd.orco)
		MEM_freeN(vdd.orco);
	dm->release(dm);
}
Beispiel #5
0
static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated)
{
	Object *ob, *ob_iter;
	Base *base = NULL;
	DupliObject *dob;
	DerivedMesh *dm;
	Mesh *me = par->data;
	MLoopUV *mloopuv;
	MPoly *mpoly, *mp;
	MLoop *mloop;
	MVert *mvert;
	float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w;
	int lay, oblay, totface, a;
	Scene *sce = NULL;
	Group *group = NULL;
	GroupObject *go = NULL;
	BMEditMesh *em;
	float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
	
	/* simple preventing of too deep nested groups */
	if (level > MAX_DUPLI_RECUR) return;
	
	copy_m4_m4(pmat, par->obmat);
	em = me->edit_btmesh;

	if (em) {
		dm = editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
	}
	else {
		dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
	}

	totface = dm->getNumPolys(dm);
	mpoly = dm->getPolyArray(dm);
	mloop = dm->getLoopArray(dm);
	mvert = dm->getVertArray(dm);

	if (G.rendering) {

		orco = (float(*)[3])BKE_mesh_orco_verts_get(par);
		BKE_mesh_orco_verts_transform(me, orco, me->totvert, 0);
		mloopuv = me->mloopuv;
	}
	else {
		orco = NULL;
		mloopuv = NULL;
	}
	
	/* having to loop on scene OR group objects is NOT FUN */
	if (GS(id->name) == ID_SCE) {
		sce = (Scene *)id;
		lay = sce->lay;
		base = sce->base.first;
	}
	else {
		group = (Group *)id;
		lay = group->layer;
		go = group->gobject.first;
	}
	
	/* Start looping on Scene OR Group objects */
	while (base || go) { 
		if (sce) {
			ob_iter = base->object;
			oblay = base->lay;
		}
		else {
			ob_iter = go->ob;
			oblay = ob_iter->lay;
		}
		
		if (lay & oblay && scene->obedit != ob_iter) {
			ob = ob_iter->parent;
			while (ob) {
				if (ob == par) {
					ob = ob_iter;
					/* End Scene/Group object loop, below is generic */
					
					/* par_space_mat - only used for groups so we can modify the space dupli's are in
					 * when par_space_mat is NULL ob->obmat can be used instead of ob__obmat
					 */
					if (par_space_mat)
						mult_m4_m4m4(ob__obmat, par_space_mat, ob->obmat);
					else
						copy_m4_m4(ob__obmat, ob->obmat);
					
					copy_m3_m4(imat, ob->parentinv);
						
					/* mballs have a different dupli handling */
					if (ob->type != OB_MBALL) ob->flag |= OB_DONE;  /* doesnt render */

					for (a = 0, mp = mpoly; a < totface; a++, mp++) {
						int mv1;
						int mv2;
						int mv3;
						/* int mv4; */ /* UNUSED */
						float *v1;
						float *v2;
						float *v3;
						/* float *v4; */ /* UNUSED */
						float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4];
						MLoop *loopstart = mloop + mp->loopstart;

						if (mp->totloop < 3) {
							/* highly unlikely but to be safe */
							continue;
						}
						else {
							v1 = mvert[(mv1 = loopstart[0].v)].co;
							v2 = mvert[(mv2 = loopstart[1].v)].co;
							v3 = mvert[(mv3 = loopstart[2].v)].co;
#if 0
							if (mp->totloop > 3) {
								v4 = mvert[(mv4 = loopstart[3].v)].co;
							}
#endif
						}

						/* translation */
						BKE_mesh_calc_poly_center(mp, loopstart, mvert, cent);

						mul_m4_v3(pmat, cent);
						
						sub_v3_v3v3(cent, cent, pmat[3]);
						add_v3_v3(cent, ob__obmat[3]);
						
						copy_m4_m4(obmat, ob__obmat);
						
						copy_v3_v3(obmat[3], cent);
						
						/* rotation */
						tri_to_quat(quat, v1, v2, v3);
						quat_to_mat3(mat, quat);
						
						/* scale */
						if (par->transflag & OB_DUPLIFACES_SCALE) {
							float size = BKE_mesh_calc_poly_area(mp, loopstart, mvert, NULL);
							size = sqrtf(size) * par->dupfacesca;
							mul_m3_fl(mat, size);
						}
						
						copy_m3_m3(mat3, mat);
						mul_m3_m3m3(mat, imat, mat3);
						
						copy_m4_m4(tmat, obmat);
						mul_m4_m4m3(obmat, tmat, mat);
						
						dob = new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIFACES, animated);
						if (G.rendering) {
							w = 1.0f / (float)mp->totloop;

							if (orco) {
								int j;
								for (j = 0; j < mpoly->totloop; j++) {
									madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w);
								}
							}

							if (mloopuv) {
								int j;
								for (j = 0; j < mpoly->totloop; j++) {
									madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w);
								}
							}
						}
						
						if (ob->transflag & OB_DUPLI) {
							float tmpmat[4][4];
							copy_m4_m4(tmpmat, ob->obmat);
							copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */
							object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level + 1, animated);
							copy_m4_m4(ob->obmat, tmpmat);
						}
					}
					
					break;
				}
				ob = ob->parent;
			}
		}
		if (sce) base = base->next;     /* scene loop */
		else go = go->next;             /* group loop */
	}

	if (orco)
		MEM_freeN(orco);
	
	dm->release(dm);
}