/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2005 by the Blender Foundation. * All rights reserved. * * Contributor(s): Daniel Dunbar * Ton Roosendaal, * Ben Batt, * Brecht Van Lommel, * Campbell Barton * * ***** END GPL LICENSE BLOCK ***** * */ /** \file blender/modifiers/intern/MOD_particleinstance.c * \ingroup modifiers */ #include "DNA_meshdata_types.h" #include "MEM_guardedalloc.h" #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_rand.h" #include "BLI_utildefines.h" #include "BKE_cdderivedmesh.h" #include "BKE_lattice.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_pointcache.h" #include "MOD_util.h" #include "depsgraph_private.h" static void initData(ModifierData *md) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; pimd->flag = eParticleInstanceFlag_Parents | eParticleInstanceFlag_Unborn | eParticleInstanceFlag_Alive | eParticleInstanceFlag_Dead; pimd->psys = 1; pimd->position = 1.0f; pimd->axis = 2; } static void copyData(ModifierData *md, ModifierData *target) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; ParticleInstanceModifierData *tpimd = (ParticleInstanceModifierData *) target; tpimd->ob = pimd->ob; tpimd->psys = pimd->psys; tpimd->flag = pimd->flag; tpimd->axis = pimd->axis; tpimd->position = pimd->position; tpimd->random_position = pimd->random_position; } static int dependsOnTime(ModifierData *UNUSED(md)) { return 0; } static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene), Object *UNUSED(ob), DagNode *obNode) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; if (pimd->ob) { DagNode *curNode = dag_get_node(forest, pimd->ob); dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Instance Modifier"); } } static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; walk(userData, ob, &pimd->ob); } 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; DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */ 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->getNumTessFaces(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, 0, 0); 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]); add_v3_v3(mv->co, state.co); } mface = result->getTessFaceArray(result); orig_mface = dm->getTessFaceArray(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_poly_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_tessface(result); if (psys->lattice) { end_latt_deform(psys->lattice); psys->lattice = NULL; } if (size) MEM_freeN(size); CDDM_tessfaces_to_faces(result); /*builds ngon faces from tess (mface) faces*/ CDDM_calc_normals(result); return result; } static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob, struct BMEditMesh *UNUSED(editData), DerivedMesh *derivedData) { return applyModifier(md, ob, derivedData, 0, 1); } ModifierTypeInfo modifierType_ParticleInstance = { /* name */ "ParticleInstance", /* structName */ "ParticleInstanceModifierData", /* structSize */ sizeof(ParticleInstanceModifierData), /* type */ eModifierTypeType_Constructive, /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode, /* copyData */ copyData, /* deformVerts */ NULL, /* deformMatrices */ NULL, /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* applyModifier */ applyModifier, /* applyModifierEM */ applyModifierEM, /* initData */ initData, /* requiredDataMask */ NULL, /* freeData */ NULL, /* isDisabled */ NULL, /* updateDepgraph */ updateDepgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ NULL, /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, };