Example #1
0
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
	ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
	return psys_emitter_customdata_mask(psmd->psys);
}
/* single_psys_from is optional, if NULL all psys of ob_from are copied */
static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, ParticleSystem *single_psys_from, Object *ob_to, int space)
{
	ModifierData *md;
	ParticleSystem *psys_start = NULL, *psys, *psys_from;
	ParticleSystem **tmp_psys;
	DerivedMesh *final_dm;
	CustomDataMask cdmask;
	int i, totpsys;
	
	if (ob_to->type != OB_MESH)
		return false;
	if (!ob_to->data || ((ID *)ob_to->data)->lib)
		return false;
	
	/* For remapping we need a valid DM.
	 * Because the modifiers are appended at the end it's safe to use
	 * the final DM of the object without particles.
	 * However, when evaluating the DM all the particle modifiers must be valid,
	 * i.e. have the psys assigned already.
	 * To break this hen/egg problem we create all psys separately first (to collect required customdata masks),
	 * then create the DM, then add them to the object and make the psys modifiers ...
	 */
	#define PSYS_FROM_FIRST (single_psys_from ? single_psys_from : ob_from->particlesystem.first)
	#define PSYS_FROM_NEXT(cur) (single_psys_from ? NULL : (cur)->next)
	totpsys = single_psys_from ? 1 : BLI_listbase_count(&ob_from->particlesystem);
	
	tmp_psys = MEM_mallocN(sizeof(ParticleSystem*) * totpsys, "temporary particle system array");
	
	cdmask = 0;
	for (psys_from = PSYS_FROM_FIRST, i = 0;
	     psys_from;
	     psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
		
		psys = BKE_object_copy_particlesystem(psys_from);
		tmp_psys[i] = psys;
		
		if (psys_start == NULL)
			psys_start = psys;
		
		cdmask |= psys_emitter_customdata_mask(psys);
	}
	/* to iterate source and target psys in sync,
	 * we need to know where the newly added psys start
	 */
	psys_start = totpsys > 0 ? tmp_psys[0] : NULL;
	
	/* get the DM (psys and their modifiers have not been appended yet) */
	final_dm = mesh_get_derived_final(scene, ob_to, cdmask);
	
	/* now append psys to the object and make modifiers */
	for (i = 0, psys_from = PSYS_FROM_FIRST;
	     i < totpsys;
	     ++i, psys_from = PSYS_FROM_NEXT(psys_from)) {
		
		ParticleSystemModifierData *psmd;
		
		psys = tmp_psys[i];
		
		/* append to the object */
		BLI_addtail(&ob_to->particlesystem, psys);
		
		/* add a particle system modifier for each system */
		md = modifier_new(eModifierType_ParticleSystem);
		psmd = (ParticleSystemModifierData *)md;
		/* push on top of the stack, no use trying to reproduce old stack order */
		BLI_addtail(&ob_to->modifiers, md);
		
		BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i);
		modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd);
		
		psmd->psys = psys;
		psmd->dm = CDDM_copy(final_dm);
		CDDM_calc_normals(psmd->dm);
		DM_ensure_tessface(psmd->dm);
		
		if (psys_from->edit)
			copy_particle_edit(scene, ob_to, psys, psys_from);
	}
	MEM_freeN(tmp_psys);
	
	/* note: do this after creating DM copies for all the particle system modifiers,
	 * the remapping otherwise makes final_dm invalid!
	 */
	for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0;
	     psys;
	     psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
		
		float (*from_mat)[4], (*to_mat)[4];
		
		switch (space) {
			case PAR_COPY_SPACE_OBJECT:
				from_mat = I;
				to_mat = I;
				break;
			case PAR_COPY_SPACE_WORLD:
				from_mat = ob_from->obmat;
				to_mat = ob_to->obmat;
				break;
			default:
				/* should not happen */
				from_mat = to_mat = NULL;
				BLI_assert(false);
				break;
		}
		
		remap_hair_emitter(scene, ob_from, psys_from, ob_to, psys, psys->edit, from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR);
		
		/* tag for recalc */
//		psys->recalc |= PSYS_RECALC_RESET;
	}
	
	#undef PSYS_FROM_FIRST
	#undef PSYS_FROM_NEXT
	
	DAG_id_tag_update(&ob_to->id, OB_RECALC_DATA);
	WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to);
	return true;
}