/* optimized tree execute test for compositing */
static void ntreeCompositExecTreeOld(bNodeTree *ntree, RenderData *rd, int do_preview)
{
	bNodeExec *nodeexec;
	bNode *node;
	ListBase threads;
	ThreadData thdata;
	int totnode, curnode, rendering = TRUE, n;
	bNodeTreeExec *exec = ntree->execdata;

	if (do_preview)
		ntreeInitPreview(ntree, 0, 0);
	
	if (!ntree->execdata) {
		/* XXX this is the top-level tree, so we use the ntree->execdata pointer. */
		exec = ntreeCompositBeginExecTree(ntree, 1);
	}
	ntree_composite_texnode(ntree, 1);
	
	/* prevent unlucky accidents */
	if (G.background)
		rd->scemode &= ~R_COMP_CROP;
	
	/* setup callerdata for thread callback */
	thdata.rd= rd;
	thdata.stack= exec->stack;
	
	/* fixed seed, for example noise texture */
	BLI_srandom(rd->cfra);

	/* sets need_exec tags in nodes */
	curnode = totnode= setExecutableNodes(exec, &thdata);

	BLI_init_threads(&threads, exec_composite_node, rd->threads);
	
	while (rendering) {
		
		if (BLI_available_threads(&threads)) {
			nodeexec= getExecutableNode(exec);
			if (nodeexec) {
				node = nodeexec->node;
				if (ntree->progress && totnode)
					ntree->progress(ntree->prh, (1.0f - curnode/(float)totnode));
				if (ntree->stats_draw) {
					char str[128];
					BLI_snprintf(str, sizeof(str), "Compositing %d %s", curnode, node->name);
					ntree->stats_draw(ntree->sdh, str);
				}
				curnode--;
				
				node->threaddata = &thdata;
				node->exec= NODE_PROCESSING;
				BLI_insert_thread(&threads, nodeexec);
			}
			else
				PIL_sleep_ms(50);
		}
		else
			PIL_sleep_ms(50);
		
		rendering= 0;
		/* test for ESC */
		if (ntree->test_break && ntree->test_break(ntree->tbh)) {
			for (node= ntree->nodes.first; node; node= node->next)
				node->exec |= NODE_READY;
		}
		
		/* check for ready ones, and if we need to continue */
		for (n=0, nodeexec=exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
			node = nodeexec->node;
			if (node->exec & NODE_READY) {
				if ((node->exec & NODE_FINISHED)==0) {
					BLI_remove_thread(&threads, nodeexec); /* this waits for running thread to finish btw */
					node->exec |= NODE_FINISHED;
					
					/* freeing unused buffers */
					if (rd->scemode & R_COMP_FREE)
						freeExecutableNode(exec);
				}
			}
			else rendering= 1;
		}
	}
	
	BLI_end_threads(&threads);
	
	/* XXX top-level tree uses the ntree->execdata pointer */
	ntreeCompositEndExecTree(exec, 1);
}
static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
						DerivedMesh *derivedData,
						int UNUSED(useRenderParams),
						int UNUSED(isFinalCalc))
{
	DerivedMesh *dm = derivedData, *result;
	ParticleInstanceModifierData *pimd= (ParticleInstanceModifierData*) md;
	ParticleSimulationData sim;
	ParticleSystem *psys= NULL;
	ParticleData *pa= NULL, *pars= NULL;
	MFace *mface, *orig_mface;
	MVert *mvert, *orig_mvert;
	int i,totvert, totpart=0, totface, maxvert, maxface, first_particle=0;
	short track=ob->trackflag%3, trackneg, axis = pimd->axis;
	float max_co=0.0, min_co=0.0, temp_co[3], cross[3];
	float *size=NULL;

	trackneg=((ob->trackflag>2)?1:0);

	if(pimd->ob==ob){
		pimd->ob= NULL;
		return derivedData;
	}

	if(pimd->ob){
		psys = BLI_findlink(&pimd->ob->particlesystem,pimd->psys-1);
		if(psys==NULL || psys->totpart==0)
			return derivedData;
	}
	else return derivedData;

	if(pimd->flag & eParticleInstanceFlag_Parents)
		totpart+=psys->totpart;
	if(pimd->flag & eParticleInstanceFlag_Children){
		if(totpart==0)
			first_particle=psys->totpart;
		totpart+=psys->totchild;
	}

	if(totpart==0)
		return derivedData;

	sim.scene = md->scene;
	sim.ob = pimd->ob;
	sim.psys = psys;
	sim.psmd = psys_get_modifier(pimd->ob, psys);

	if(pimd->flag & eParticleInstanceFlag_UseSize) {
		int p;
		float *si;
		si = size = MEM_callocN(totpart * sizeof(float), "particle size array");

		if(pimd->flag & eParticleInstanceFlag_Parents) {
			for(p=0, pa= psys->particles; p<psys->totpart; p++, pa++, si++)
				*si = pa->size;
		}

		if(pimd->flag & eParticleInstanceFlag_Children) {
			ChildParticle *cpa = psys->child;

			for(p=0; p<psys->totchild; p++, cpa++, si++) {
				*si = psys_get_child_size(psys, cpa, 0.0f, NULL);
			}
		}
	}

	pars=psys->particles;

	totvert=dm->getNumVerts(dm);
	totface=dm->getNumFaces(dm);

	maxvert=totvert*totpart;
	maxface=totface*totpart;

	psys->lattice=psys_get_lattice(&sim);

	if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED){

		float min_r[3], max_r[3];
		INIT_MINMAX(min_r, max_r);
		dm->getMinMax(dm, min_r, max_r);
		min_co=min_r[track];
		max_co=max_r[track];
	}

	result = CDDM_from_template(dm, maxvert,dm->getNumEdges(dm)*totpart,maxface);

	mvert=result->getVertArray(result);
	orig_mvert=dm->getVertArray(dm);

	for(i=0; i<maxvert; i++){
		MVert *inMV;
		MVert *mv = mvert + i;
		ParticleKey state;

		inMV = orig_mvert + i%totvert;
		DM_copy_vert_data(dm, result, i%totvert, i, 1);
		*mv = *inMV;

		/*change orientation based on object trackflag*/
		copy_v3_v3(temp_co, mv->co);
		mv->co[axis]=temp_co[track];
		mv->co[(axis+1)%3]=temp_co[(track+1)%3];
		mv->co[(axis+2)%3]=temp_co[(track+2)%3];

		if((psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && pimd->flag & eParticleInstanceFlag_Path){
			float ran = 0.0f;
			if(pimd->random_position != 0.0f) {
				BLI_srandom(psys->seed + (i/totvert)%totpart);
				ran = pimd->random_position * BLI_frand();
			}

			if(pimd->flag & eParticleInstanceFlag_KeepShape) {
				state.time = pimd->position * (1.0f - ran);
			}
			else {
				state.time=(mv->co[axis]-min_co)/(max_co-min_co) * pimd->position * (1.0f - ran);

				if(trackneg)
					state.time=1.0f-state.time;

				mv->co[axis] = 0.0;
			}

			psys_get_particle_on_path(&sim, first_particle + i/totvert, &state,1);

			normalize_v3(state.vel);

			/* TODO: incremental rotations somehow */
			if(state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) {
				state.rot[0] = 1;
				state.rot[1] = state.rot[2] = state.rot[3] = 0.0f;
			}
			else {
				float temp[3] = {0.0f,0.0f,0.0f};
				temp[axis] = 1.0f;

				cross_v3_v3v3(cross, temp, state.vel);

				/* state.vel[axis] is the only component surviving from a dot product with the axis */
				axis_angle_to_quat(state.rot,cross,saacos(state.vel[axis]));
			}

		}
		else{
			state.time=-1.0;
			psys_get_particle_state(&sim, first_particle + i/totvert, &state,1);
		}

		mul_qt_v3(state.rot,mv->co);
		if(pimd->flag & eParticleInstanceFlag_UseSize)
			mul_v3_fl(mv->co, size[i/totvert]);
		VECADD(mv->co,mv->co,state.co);
	}

	mface=result->getFaceArray(result);
	orig_mface=dm->getFaceArray(dm);

	for(i=0; i<maxface; i++){
		MFace *inMF;
		MFace *mf = mface + i;

		if(pimd->flag & eParticleInstanceFlag_Parents){
			if(i/totface>=psys->totpart){
				if(psys->part->childtype==PART_CHILD_PARTICLES)
					pa=psys->particles+(psys->child+i/totface-psys->totpart)->parent;
				else
					pa= NULL;
			}
			else
				pa=pars+i/totface;
		}
		else{
			if(psys->part->childtype==PART_CHILD_PARTICLES)
				pa=psys->particles+(psys->child+i/totface)->parent;
			else
				pa= NULL;
		}

		if(pa){
			if(pa->alive==PARS_UNBORN && (pimd->flag&eParticleInstanceFlag_Unborn)==0) continue;
			if(pa->alive==PARS_ALIVE && (pimd->flag&eParticleInstanceFlag_Alive)==0) continue;
			if(pa->alive==PARS_DEAD && (pimd->flag&eParticleInstanceFlag_Dead)==0) continue;
		}

		inMF = orig_mface + i%totface;
		DM_copy_face_data(dm, result, i%totface, i, 1);
		*mf = *inMF;

		mf->v1+=(i/totface)*totvert;
		mf->v2+=(i/totface)*totvert;
		mf->v3+=(i/totface)*totvert;
		if(mf->v4)
			mf->v4+=(i/totface)*totvert;
	}

	CDDM_calc_edges(result);
	CDDM_calc_normals(result);

	if(psys->lattice){
		end_latt_deform(psys->lattice);
		psys->lattice= NULL;
	}

	if(size)
		MEM_freeN(size);

	return result;
}
Exemple #3
0
/* OB_DUPLIPARTS */
static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem *psys)
{
	Scene *scene = ctx->scene;
	Object *par = ctx->object;
	bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER;
	bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);

	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];
	int a, b, hair = 0;
	int totpart, totchild, totgroup = 0 /*, pa_num */;
	const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene);

	int no_draw_flag = PARS_UNEXIST;

	if (psys == NULL) return;

	part = psys->part;

	if (part == NULL)
		return;

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

	if (!for_render)
		no_draw_flag |= PARS_NO_DISP;

	ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */

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

	BLI_srandom((unsigned int)(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 || BLI_listbase_is_empty(&part->dup_group->gobject))
				return;

			if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) {
				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_deform_data = psys_create_lattice_deform_data(&sim);

		/* gather list of objects or single object */
		if (part->ren_as == PART_DRAW_GR) {
			if (ctx->do_update) {
				BKE_group_handle_recalc_and_update(ctx->eval_ctx, 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
			 * BKE_object_where_is_calc_time will change the object which breaks transform */
			oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list");
			obcopylist = MEM_callocN((size_t)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; a < totpart + totchild; a++, pa++) {
			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 && psys->pathcache &&
			    ((a < totpart && psys->pathcache[a]->segments < 0) ||
			     (a >= totpart && psys->childcache[a - totpart]->segments < 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;
			}
			else {
				obmat = ob->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_v3(tmat[3], part->dup_group->dupli_ofs);
					/* individual particle transform */
					mul_m4_m4m4(mat, pamat, tmat);

					dob = make_dupli(ctx, go->ob, mat, a, false, false);
					dob->particle_system = psys;
					if (use_texcoords)
						psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
				}
			}
			else {
				/* to give ipos in object correct offset */
				BKE_object_where_is_calc_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], size_mat[4][4], original_size[3];

					mat4_to_size(original_size, obmat);
					size_to_mat4(size_mat, original_size);

					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;

					/* add scaling if requested */
					if ((part->draw & PART_DRAW_NO_SCALE_OB) == 0)
						mul_m4_m4m4(obmat, obmat, size_mat);
				}
				else if (part->draw & PART_DRAW_NO_SCALE_OB) {
					/* remove scaling */
					float size_mat[4][4], original_size[3];

					mat4_to_size(original_size, obmat);
					size_to_mat4(size_mat, original_size);
					invert_m4(size_mat);

					mul_m4_m4m4(obmat, obmat, size_mat);
				}

				mul_m4_m4m4(tmat, pamat, obmat);
				mul_mat3_m4_fl(tmat, size * scale);

				copy_m4_m4(mat, tmat);

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

				dob = make_dupli(ctx, ob, mat, a, false, false);
				dob->particle_system = psys;
				if (use_texcoords)
					psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
				/* XXX blender internal needs this to be set to dupligroup to render
				 * groups correctly, but we don't want this hack for cycles */
				if (dupli_type_hack && ctx->group)
					dob->type = OB_DUPLIGROUP;
			}
		}

		/* restore objects since they were changed in BKE_object_where_is_calc_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_deform_data) {
		end_latt_deform(psys->lattice_deform_data);
		psys->lattice_deform_data = NULL;
	}
}
Exemple #4
0
static void createFacepa(ExplodeModifierData *emd,
						ParticleSystemModifierData *psmd,
						DerivedMesh *dm)
{
	ParticleSystem *psys=psmd->psys;
	MFace *fa=NULL, *mface=NULL;
	MVert *mvert = NULL;
	ParticleData *pa;
	KDTree *tree;
	float center[3], co[3];
	int *facepa=NULL,*vertpa=NULL,totvert=0,totface=0,totpart=0;
	int i,p,v1,v2,v3,v4=0;

	mvert = dm->getVertArray(dm);
	mface = dm->getFaceArray(dm);
	totface= dm->getNumFaces(dm);
	totvert= dm->getNumVerts(dm);
	totpart= psmd->psys->totpart;

	BLI_srandom(psys->seed);

	if(emd->facepa)
		MEM_freeN(emd->facepa);

	facepa = emd->facepa = MEM_callocN(sizeof(int)*totface, "explode_facepa");

	vertpa = MEM_callocN(sizeof(int)*totvert, "explode_vertpa");

	/* initialize all faces & verts to no particle */
	for(i=0; i<totface; i++)
		facepa[i]=totpart;

	for (i=0; i<totvert; i++)
		vertpa[i]=totpart;

	/* set protected verts */
	if(emd->vgroup){
		MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
		if(dvert){
			const int defgrp_index= emd->vgroup-1;
			for(i=0; i<totvert; i++, dvert++){
				float val = BLI_frand();
				val = (1.0f-emd->protect)*val + emd->protect*0.5f;
				if(val < defvert_find_weight(dvert, defgrp_index))
					vertpa[i] = -1;
			}
		}
	}

	/* make tree of emitter locations */
	tree=BLI_kdtree_new(totpart);
	for(p=0,pa=psys->particles; p<totpart; p++,pa++){
		psys_particle_on_emitter(psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,NULL,NULL,NULL,NULL,NULL);
		BLI_kdtree_insert(tree, p, co, NULL);
	}
	BLI_kdtree_balance(tree);

	/* set face-particle-indexes to nearest particle to face center */
	for(i=0,fa=mface; i<totface; i++,fa++){
		add_v3_v3v3(center,mvert[fa->v1].co,mvert[fa->v2].co);
		add_v3_v3(center, mvert[fa->v3].co);
		if(fa->v4){
			add_v3_v3(center, mvert[fa->v4].co);
			mul_v3_fl(center,0.25);
		}
		else
			mul_v3_fl(center,0.3333f);

		p= BLI_kdtree_find_nearest(tree,center,NULL,NULL);

		v1=vertpa[fa->v1];
		v2=vertpa[fa->v2];
		v3=vertpa[fa->v3];
		if(fa->v4)
			v4=vertpa[fa->v4];

		if(v1>=0 && v2>=0 && v3>=0 && (fa->v4==0 || v4>=0))
			facepa[i]=p;

		if(v1>=0) vertpa[fa->v1]=p;
		if(v2>=0) vertpa[fa->v2]=p;
		if(v3>=0) vertpa[fa->v3]=p;
		if(fa->v4 && v4>=0) vertpa[fa->v4]=p;
	}

	if(vertpa) MEM_freeN(vertpa);
	BLI_kdtree_free(tree);
}
Exemple #5
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;
	}
}
Exemple #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=0, **oblist=0, obcopy, *obcopylist=0;
	DupliObject *dob;
	ParticleDupliWeight *dw;
	ParticleSimulationData sim = {scene, par, psys, psys_get_modifier(par, psys)};
	ParticleSettings *part;
	ParticleData *pa;
	ChildParticle *cpa=0;
	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 lay, a, b, counter, hair = 0;
	int totpart, totchild, totgroup=0, pa_num;

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

	if(part==0)
		return;

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

	ctime = bsystem_time(scene, par, (float)scene->r.cfra, 0.0);

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

	BLI_srandom(31415926 + psys->seed);
	
	lay= scene->lay;
	if((psys->renderdata || part->draw_as==PART_DRAW_REND) &&
		((part->ren_as == PART_DRAW_OB && part->dup_ob) ||
		(part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first))) {

		psys_check_group_weights(part);

		/* 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->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 & (PARS_UNEXIST+PARS_NO_DISP))
					continue;

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

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

			if(part->ren_as==PART_DRAW_GR) {
				/* for groups, pick the object based on settings */
				if(part->draw&PART_DRAW_RAND_GR)
					b= BLI_rand() % totgroup;
				else if(part->from==PART_FROM_PARTICLE)
					b= pa_num % 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, 0, cache, pamat, &scale);
				}
				else {
					cache = psys->childcache[a-totpart];
					psys_get_dupli_path_transform(&sim, 0, cpa, cache, pamat, &scale);
				}

				VECCOPY(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;

				QuatToMat4(state.rot, pamat);
				VECCOPY(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++) {
					Mat4MulMat4(tmat, oblist[b]->obmat, pamat);
					Mat4MulFloat3((float *)tmat, size*scale);
					if(par_space_mat)
						Mat4MulMat4(mat, tmat, par_space_mat);
					else
						Mat4CpyMat4(mat, tmat);

					dob= new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated);
					Mat4CpyMat4(dob->omat, obcopylist[b].obmat);
					if(G.rendering)
						psys_get_dupli_texture(par, 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);

				VECCOPY(vec, obmat[3]);
				obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;
				
				Mat4CpyMat4(mat, pamat);

				Mat4MulMat4(tmat, obmat, mat);
				Mat4MulFloat3((float *)tmat, size*scale);

				if(part->draw & PART_DRAW_GLOBAL_OB)
					VECADD(tmat[3], tmat[3], vec);

				if(par_space_mat)
					Mat4MulMat4(mat, tmat, par_space_mat);
				else
					Mat4CpyMat4(mat, tmat);

				dob= new_dupli_object(lb, ob, mat, ob->lay, counter, OB_DUPLIPARTS, animated);
				Mat4CpyMat4(dob->omat, oldobmat);
				if(G.rendering)
					psys_get_dupli_texture(par, 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;
	}
}