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; }