diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_data_modifier.py | 22 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_270.c | 12 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_modifier_types.h | 11 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_modifier.c | 95 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_particleinstance.c | 191 |
5 files changed, 281 insertions, 50 deletions
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 942882a9053..e3cc08ce3d8 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -711,11 +711,15 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): def PARTICLE_INSTANCE(self, layout, ob, md): layout.prop(md, "object") - layout.prop(md, "particle_system_index", text="Particle System") + if md.object: + layout.prop_search(md, "particle_system", md.object, "particle_systems", text="Particle System") + else: + layout.prop(md, "particle_system_index", text="Particle System") split = layout.split() col = split.column() col.label(text="Create From:") + layout.prop(md, "space", text="") col.prop(md, "use_normal") col.prop(md, "use_children") col.prop(md, "use_size") @@ -726,6 +730,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "show_unborn") col.prop(md, "show_dead") + row = layout.row(align=True) + row.prop(md, "particle_amount", text="Amount") + row.prop(md, "particle_offset", text="Offset") + layout.separator() layout.prop(md, "use_path", text="Create Along Paths") @@ -737,8 +745,16 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "use_preserve_shape") col = split.column() - col.prop(md, "position", slider=True) - col.prop(md, "random_position", text="Random", slider=True) + col2 = col.column(align=True) + col2.prop(md, "position", slider=True) + col2.prop(md, "random_position", text="Random", slider=True) + col2 = col.column(align=True) + col2.prop(md, "rotation", slider=True) + col2.prop(md, "random_rotation", text="Random", slider=True) + + col = layout.column() + col.prop_search(md, "index_layer_name", ob.data, "vertex_colors", text="Index Layer") + col.prop_search(md, "value_layer_name", ob.data, "vertex_colors", text="Value Layer") def PARTICLE_SYSTEM(self, layout, ob, md): layout.label(text="Settings can be found inside the Particle context") diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index e9de7919d25..86e6071180e 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1813,6 +1813,18 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } scene->r.ffcodecdata.ffmpeg_preset = preset; } + + if (!DNA_struct_elem_find(fd->filesdna, "ParticleInstanceModifierData", "float", "particle_amount")) { + for (Object *ob = main->object.first; ob; ob = ob->id.next) { + for (ModifierData *md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_ParticleInstance) { + ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; + pimd->space = eParticleInstanceSpace_World; + pimd->particle_amount = 1.0f; + } + } + } + } } } diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 766dd196562..258acbab31a 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -753,12 +753,21 @@ typedef enum { eParticleInstanceFlag_UseSize = (1 << 7), } ParticleInstanceModifierFlag; +typedef enum { + eParticleInstanceSpace_World = 0, + eParticleInstanceSpace_Local = 1, +} ParticleInstanceModifierSpace; + typedef struct ParticleInstanceModifierData { ModifierData modifier; struct Object *ob; - short psys, flag, axis, pad; + short psys, flag, axis, space; float position, random_position; + float rotation, random_rotation; + float particle_amount, particle_offset; + char index_layer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + char value_layer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ } ParticleInstanceModifierData; typedef enum { diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 2f92c47eed9..0ebd29b200c 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1155,6 +1155,43 @@ static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, rna_Modifier_update(bmain, scene, ptr); } +static int rna_ParticleInstanceModifier_particle_system_poll(PointerRNA *ptr, const PointerRNA value) +{ + ParticleInstanceModifierData *psmd = ptr->data; + ParticleSystem *psys = value.data; + + if (!psmd->ob) + return false; + + /* make sure psys is in the object */ + return BLI_findindex(&psmd->ob->particlesystem, psys) >= 0; +} + +static PointerRNA rna_ParticleInstanceModifier_particle_system_get(PointerRNA *ptr) +{ + ParticleInstanceModifierData *psmd = ptr->data; + ParticleSystem *psys; + PointerRNA rptr; + + if (!psmd->ob) + return PointerRNA_NULL; + + psys = BLI_findlink(&psmd->ob->particlesystem, psmd->psys - 1); + RNA_pointer_create((ID *)psmd->ob, &RNA_ParticleSystem, psys, &rptr); + return rptr; +} + +static void rna_ParticleInstanceModifier_particle_system_set(PointerRNA *ptr, const PointerRNA value) +{ + ParticleInstanceModifierData *psmd = ptr->data; + + if (!psmd->ob) + return; + + psmd->psys = BLI_findindex(&psmd->ob->particlesystem, value.data) + 1; + CLAMP_MIN(psmd->psys, 1); +} + #else static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[]) @@ -2655,6 +2692,12 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + static EnumPropertyItem particleinstance_space[] = { + {eParticleInstanceSpace_Local, "LOCAL", 0, "Local", "Use offset from the particle object in the instance object"}, + {eParticleInstanceSpace_World, "WORLD", 0, "World", "Use world space offset in the instance object"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "ParticleInstanceModifier", "Modifier"); RNA_def_struct_ui_text(srna, "ParticleInstance Modifier", "Particle system instancing modifier"); RNA_def_struct_sdna(srna, "ParticleInstanceModifierData"); @@ -2669,16 +2712,30 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna) prop = RNA_def_property(srna, "particle_system_index", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "psys"); - RNA_def_property_range(prop, 1, 10); + RNA_def_property_range(prop, 1, SHRT_MAX); RNA_def_property_ui_text(prop, "Particle System Number", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ParticleSystem"); + RNA_def_property_pointer_funcs(prop, "rna_ParticleInstanceModifier_particle_system_get", "rna_ParticleInstanceModifier_particle_system_set", + NULL, "rna_ParticleInstanceModifier_particle_system_poll"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Particle System", ""); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "axis"); RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items); RNA_def_property_ui_text(prop, "Axis", "Pole axis for rotation"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); - + + prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "space"); + RNA_def_property_enum_items(prop, particleinstance_space); + RNA_def_property_ui_text(prop, "Space", "Space to use for copying mesh data"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "use_normal", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", eParticleInstanceFlag_Parents); RNA_def_property_ui_text(prop, "Normal", "Create instances from normal particles"); @@ -2730,6 +2787,40 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna) RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_ui_text(prop, "Random Position", "Randomize position along path"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "rotation"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text(prop, "Rotation", "Rotation around path"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "random_rotation", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "random_rotation"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text(prop, "Random Rotation", "Randomize rotation around path"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "particle_amount", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text(prop, "Particle Amount", "Amount of particles to use for instancing"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "particle_offset", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text(prop, "Particle Offset", "Relative offset of particles to use for instancing, to avoid overlap of multiple instances"); + RNA_def_property_float_default(prop, 0.0f); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "index_layer_name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "index_layer_name"); + RNA_def_property_ui_text(prop, "Index Layer Name", "Custom data layer name for the index"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "value_layer_name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "value_layer_name"); + RNA_def_property_ui_text(prop, "Value Layer Name", "Custom data layer name for the randomized value"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_explode(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index 106a84d3765..f0b80cda447 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -40,10 +40,12 @@ #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_rand.h" +#include "BLI_string.h" #include "BLI_utildefines.h" #include "BKE_cdderivedmesh.h" #include "BKE_effect.h" +#include "BKE_global.h" #include "BKE_lattice.h" #include "BKE_library_query.h" #include "BKE_modifier.h" @@ -53,8 +55,6 @@ #include "depsgraph_private.h" #include "DEG_depsgraph_build.h" -#include "MOD_modifiertypes.h" - static void initData(ModifierData *md) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; @@ -64,7 +64,12 @@ static void initData(ModifierData *md) pimd->psys = 1; pimd->position = 1.0f; pimd->axis = 2; + pimd->space = eParticleInstanceSpace_World; + pimd->particle_amount = 1.0f; + pimd->particle_offset = 0.0f; + STRNCPY(pimd->index_layer_name, ""); + STRNCPY(pimd->value_layer_name, ""); } static void copyData(ModifierData *md, ModifierData *target) { @@ -75,6 +80,21 @@ static void copyData(ModifierData *md, ModifierData *target) modifier_copyData_generic(md, target); } +static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) +{ + ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; + CustomDataMask dataMask = 0; + + if (pimd->index_layer_name[0] != '\0' || + pimd->value_layer_name[0] != '\0') + { + dataMask |= CD_MASK_MLOOPCOL; + } + + return dataMask; + +} + static bool isDisabled(ModifierData *md, int useRenderParams) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; @@ -142,39 +162,59 @@ static void foreachObjectLink(ModifierData *md, Object *ob, walk(userData, ob, &pimd->ob, IDWALK_CB_NOP); } -static int particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p) +static bool particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p) { + const bool between = (psys->part->childtype == PART_CHILD_FACES); ParticleData *pa; + int totpart, randp, minp, maxp; - if (pimd->flag & eParticleInstanceFlag_Parents) { - if (p >= psys->totpart) { - if (psys->part->childtype == PART_CHILD_PARTICLES) { - pa = psys->particles + (psys->child + p - psys->totpart)->parent; - } - else { - pa = NULL; - } - } - else { - pa = psys->particles + p; - } + if (p >= psys->totpart) { + ChildParticle *cpa = psys->child + (p - psys->totpart); + pa = psys->particles + (between? cpa->pa[0]: cpa->parent); } else { - if (psys->part->childtype == PART_CHILD_PARTICLES) { - pa = psys->particles + (psys->child + p)->parent; - } - else { - pa = NULL; - } + pa = psys->particles + p; } if (pa) { - if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) return 1; - if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) return 1; - if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) return 1; + if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) return true; + if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) return true; + if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) return true; } - return 0; + if (pimd->particle_amount == 1.0f) { + /* Early output, all particles are to be instanced. */ + return false; + } + + /* Randomly skip particles based on desired amount of visible particles. */ + + totpart = psys->totpart + psys->totchild; + + /* TODO make randomization optional? */ + randp = (int)(psys_frand(psys, 3578 + p) * totpart) % totpart; + + minp = (int)(totpart * pimd->particle_offset) % (totpart+1); + maxp = (int)(totpart * (pimd->particle_offset + pimd->particle_amount)) % (totpart+1); + + if (maxp > minp) { + return randp < minp || randp >= maxp; + } + else if (maxp < minp) { + return randp < minp && randp >= maxp; + } + else { + return true; + } + + return false; +} + +static void store_float_in_vcol(MLoopCol *vcol, float float_value) +{ + const uchar value = FTOCHAR(float_value); + vcol->r = vcol->g = vcol->b = value; + vcol->a = 1.0f; } static DerivedMesh *applyModifier(ModifierData *md, Object *ob, @@ -190,11 +230,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, MLoop *mloop, *orig_mloop; MVert *mvert, *orig_mvert; int totvert, totpoly, totloop /* , totedge */; - int maxvert, maxpoly, maxloop, totpart = 0, first_particle = 0; + int maxvert, maxpoly, maxloop, part_end = 0, part_start; int k, p, p_skip; short track = ob->trackflag % 3, trackneg, axis = pimd->axis; float max_co = 0.0, min_co = 0.0, temp_co[3]; float *size = NULL; + float spacemat[4][4]; + const bool use_parents = pimd->flag & eParticleInstanceFlag_Parents; + const bool use_children = pimd->flag & eParticleInstanceFlag_Children; + bool between; trackneg = ((ob->trackflag > 2) ? 1 : 0); @@ -212,25 +256,26 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, 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; - } + part_start = use_parents ? 0 : psys->totpart; + + part_end = 0; + if (use_parents) + part_end += psys->totpart; + if (use_children) + part_end += psys->totchild; - if (totpart == 0) + if (part_end == 0) return derivedData; sim.scene = md->scene; sim.ob = pimd->ob; sim.psys = psys; sim.psmd = psys_get_modifier(pimd->ob, psys); + between = (psys->part->childtype == PART_CHILD_FACES); if (pimd->flag & eParticleInstanceFlag_UseSize) { float *si; - si = size = MEM_calloc_arrayN(totpart, sizeof(float), "particle size array"); + si = size = MEM_calloc_arrayN(part_end, sizeof(float), "particle size array"); if (pimd->flag & eParticleInstanceFlag_Parents) { for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++) @@ -246,6 +291,21 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, } } + switch (pimd->space) { + case eParticleInstanceSpace_World: + /* particle states are in world space already */ + unit_m4(spacemat); + break; + case eParticleInstanceSpace_Local: + /* get particle states in the particle object's local space */ + invert_m4_m4(spacemat, pimd->ob->obmat); + break; + default: + /* should not happen */ + BLI_assert(false); + break; + } + totvert = dm->getNumVerts(dm); totpoly = dm->getNumPolys(dm); totloop = dm->getNumLoops(dm); @@ -256,7 +316,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, maxpoly = 0; maxloop = 0; - for (p = 0; p < totpart; p++) { + for (p = part_start; p < part_end; p++) { if (particle_skip(pimd, psys, p)) continue; @@ -285,9 +345,21 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, mloop = result->getLoopArray(result); orig_mloop = dm->getLoopArray(dm); - for (p = 0, p_skip = 0; p < totpart; p++) { + MLoopCol *mloopcols_index = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, pimd->index_layer_name); + MLoopCol *mloopcols_value = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, pimd->value_layer_name); + int *vert_part_index = NULL; + float *vert_part_value = NULL; + if (mloopcols_index != NULL) { + vert_part_index = MEM_calloc_arrayN(maxvert, sizeof(int), "vertex part index array"); + } + if (mloopcols_value) { + vert_part_value = MEM_calloc_arrayN(maxvert, sizeof(float), "vertex part value array"); + } + + for (p = part_start, p_skip = 0; p < part_end; p++) { float prev_dir[3]; float frame[4]; /* frame orientation quaternion */ + float p_random = psys_frand(psys, 77091 + 283*p); /* skip particle? */ if (particle_skip(pimd, psys, p)) @@ -297,12 +369,20 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, for (k = 0; k < totvert; k++) { ParticleKey state; MVert *inMV; - MVert *mv = mvert + p_skip * totvert + k; + int vindex = p_skip * totvert + k; + MVert *mv = mvert + vindex; inMV = orig_mvert + k; DM_copy_vert_data(dm, result, k, p_skip * totvert + k, 1); *mv = *inMV; + if (vert_part_index != NULL) { + vert_part_index[vindex] = p; + } + if (vert_part_value != NULL) { + vert_part_value[vindex] = p_random; + } + /*change orientation based on object trackflag*/ copy_v3_v3(temp_co, mv->co); mv->co[axis] = temp_co[track]; @@ -330,7 +410,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, mv->co[axis] = 0.0; } - psys_get_particle_on_path(&sim, first_particle + p, &state, 1); + psys_get_particle_on_path(&sim, p, &state, 1); normalize_v3(state.vel); @@ -339,17 +419,26 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, float hairmat[4][4]; float mat[3][3]; - if (first_particle + p < psys->totpart) - pa = psys->particles + first_particle + p; + if (p < psys->totpart) + pa = psys->particles + p; else { ChildParticle *cpa = psys->child + (p - psys->totpart); - pa = psys->particles + cpa->parent; + pa = psys->particles + (between? cpa->pa[0]: cpa->parent); } psys_mat_hair_to_global(sim.ob, sim.psmd->dm_final, sim.psys->part->from, pa, hairmat); copy_m3_m4(mat, hairmat); /* to quaternion */ mat3_to_quat(frame, mat); + if (pimd->rotation > 0.0f || pimd->random_rotation > 0.0f) { + float angle = 2.0f*M_PI * (pimd->rotation + pimd->random_rotation * (psys_frand(psys, 19957323 + p) - 0.5f)); + float eul[3] = { 0.0f, 0.0f, angle }; + float rot[4]; + + eul_to_quat(rot, eul); + mul_qt_qtqt(frame, frame, rot); + } + /* note: direction is same as normal vector currently, * but best to keep this separate so the frame can be * rotated later if necessary @@ -386,13 +475,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, } else { state.time = -1.0; - psys_get_particle_state(&sim, first_particle + p, &state, 1); + psys_get_particle_state(&sim, p, &state, 1); } mul_qt_v3(state.rot, mv->co); if (pimd->flag & eParticleInstanceFlag_UseSize) mul_v3_fl(mv->co, size[p]); add_v3_v3(mv->co, state.co); + + mul_m4_v3(spacemat, mv->co); } /* create polys and loops */ @@ -412,6 +503,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DM_copy_loop_data(dm, result, inMP->loopstart, mp->loopstart, j); for (; j; j--, ml++, inML++) { ml->v = inML->v + (p_skip * totvert); + const int ml_index = (ml - mloop); + if (mloopcols_index != NULL) { + const int part_index = vert_part_index[ml->v]; + store_float_in_vcol(&mloopcols_index[ml_index], (float)part_index / psys->totpart); + } + if (mloopcols_value != NULL) { + const float part_value = vert_part_value[ml->v]; + store_float_in_vcol(&mloopcols_value[ml_index], part_value); + } } } } @@ -429,6 +529,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, if (size) MEM_freeN(size); + MEM_SAFE_FREE(vert_part_index); + MEM_SAFE_FREE(vert_part_value); + result->dirty |= DM_DIRTY_NORMALS; return result; @@ -451,7 +554,7 @@ ModifierTypeInfo modifierType_ParticleInstance = { /* applyModifier */ applyModifier, /* applyModifierEM */ NULL, /* initData */ initData, - /* requiredDataMask */ NULL, + /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, /* updateDepgraph */ updateDepgraph, |