Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/particle.c')
-rw-r--r--source/blender/blenkernel/intern/particle.c548
1 files changed, 504 insertions, 44 deletions
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 7b8ee7343ee..0b331fb88d2 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -21,6 +21,9 @@
* \ingroup bke
*/
+/* Allow using deprecated functionality for .blend file I/O. */
+#define DNA_DEPRECATED_ALLOW
+
#include <math.h>
#include <stdlib.h>
#include <string.h>
@@ -29,6 +32,7 @@
#include "DNA_defaults.h"
+#include "DNA_cloth_types.h"
#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
#include "DNA_dynamicpaint_types.h"
@@ -52,6 +56,7 @@
#include "BLT_translation.h"
+#include "BKE_anim_data.h"
#include "BKE_anim_path.h"
#include "BKE_boids.h"
#include "BKE_cloth.h"
@@ -78,7 +83,9 @@
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
-#include "RE_render_ext.h"
+#include "RE_texture.h"
+
+#include "BLO_read_write.h"
#include "particle_private.h"
@@ -206,6 +213,279 @@ static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data)
}
}
+static void write_boid_state(BlendWriter *writer, BoidState *state)
+{
+ BLO_write_struct(writer, BoidState, state);
+
+ LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
+ switch (rule->type) {
+ case eBoidRuleType_Goal:
+ case eBoidRuleType_Avoid:
+ BLO_write_struct(writer, BoidRuleGoalAvoid, rule);
+ break;
+ case eBoidRuleType_AvoidCollision:
+ BLO_write_struct(writer, BoidRuleAvoidCollision, rule);
+ break;
+ case eBoidRuleType_FollowLeader:
+ BLO_write_struct(writer, BoidRuleFollowLeader, rule);
+ break;
+ case eBoidRuleType_AverageSpeed:
+ BLO_write_struct(writer, BoidRuleAverageSpeed, rule);
+ break;
+ case eBoidRuleType_Fight:
+ BLO_write_struct(writer, BoidRuleFight, rule);
+ break;
+ default:
+ BLO_write_struct(writer, BoidRule, rule);
+ break;
+ }
+ }
+#if 0
+ BoidCondition *cond = state->conditions.first;
+ for (; cond; cond = cond->next) {
+ BLO_write_struct(writer, BoidCondition, cond);
+ }
+#endif
+}
+
+static void particle_settings_blend_write(BlendWriter *writer, ID *id, const void *id_address)
+{
+ ParticleSettings *part = (ParticleSettings *)id;
+ if (part->id.us > 0 || BLO_write_is_undo(writer)) {
+ /* write LibData */
+ BLO_write_id_struct(writer, ParticleSettings, id_address, &part->id);
+ BKE_id_blend_write(writer, &part->id);
+
+ if (part->adt) {
+ BKE_animdata_blend_write(writer, part->adt);
+ }
+ BLO_write_struct(writer, PartDeflect, part->pd);
+ BLO_write_struct(writer, PartDeflect, part->pd2);
+ BLO_write_struct(writer, EffectorWeights, part->effector_weights);
+
+ if (part->clumpcurve) {
+ BKE_curvemapping_blend_write(writer, part->clumpcurve);
+ }
+ if (part->roughcurve) {
+ BKE_curvemapping_blend_write(writer, part->roughcurve);
+ }
+ if (part->twistcurve) {
+ BKE_curvemapping_blend_write(writer, part->twistcurve);
+ }
+
+ LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) {
+ /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
+ if (dw->ob != NULL) {
+ dw->index = 0;
+ if (part->instance_collection) { /* can be NULL if lining fails or set to None */
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (part->instance_collection, object) {
+ if (object == dw->ob) {
+ break;
+ }
+ dw->index++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+ }
+ BLO_write_struct(writer, ParticleDupliWeight, dw);
+ }
+
+ if (part->boids && part->phystype == PART_PHYS_BOIDS) {
+ BLO_write_struct(writer, BoidSettings, part->boids);
+
+ LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
+ write_boid_state(writer, state);
+ }
+ }
+ if (part->fluid && part->phystype == PART_PHYS_FLUID) {
+ BLO_write_struct(writer, SPHFluidSettings, part->fluid);
+ }
+
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (part->mtex[a]) {
+ BLO_write_struct(writer, MTex, part->mtex[a]);
+ }
+ }
+ }
+}
+
+void BKE_particle_partdeflect_blend_read_data(BlendDataReader *UNUSED(reader), PartDeflect *pd)
+{
+ if (pd) {
+ pd->rng = NULL;
+ }
+}
+
+static void particle_settings_blend_read_data(BlendDataReader *reader, ID *id)
+{
+ ParticleSettings *part = (ParticleSettings *)id;
+ BLO_read_data_address(reader, &part->adt);
+ BLO_read_data_address(reader, &part->pd);
+ BLO_read_data_address(reader, &part->pd2);
+
+ BKE_animdata_blend_read_data(reader, part->adt);
+ BKE_particle_partdeflect_blend_read_data(reader, part->pd);
+ BKE_particle_partdeflect_blend_read_data(reader, part->pd2);
+
+ BLO_read_data_address(reader, &part->clumpcurve);
+ if (part->clumpcurve) {
+ BKE_curvemapping_blend_read(reader, part->clumpcurve);
+ }
+ BLO_read_data_address(reader, &part->roughcurve);
+ if (part->roughcurve) {
+ BKE_curvemapping_blend_read(reader, part->roughcurve);
+ }
+ BLO_read_data_address(reader, &part->twistcurve);
+ if (part->twistcurve) {
+ BKE_curvemapping_blend_read(reader, part->twistcurve);
+ }
+
+ BLO_read_data_address(reader, &part->effector_weights);
+ if (!part->effector_weights) {
+ part->effector_weights = BKE_effector_add_weights(part->force_group);
+ }
+
+ BLO_read_list(reader, &part->instance_weights);
+
+ BLO_read_data_address(reader, &part->boids);
+ BLO_read_data_address(reader, &part->fluid);
+
+ if (part->boids) {
+ BLO_read_list(reader, &part->boids->states);
+
+ LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
+ BLO_read_list(reader, &state->rules);
+ BLO_read_list(reader, &state->conditions);
+ BLO_read_list(reader, &state->actions);
+ }
+ }
+ for (int a = 0; a < MAX_MTEX; a++) {
+ BLO_read_data_address(reader, &part->mtex[a]);
+ }
+
+ /* Protect against integer overflow vulnerability. */
+ CLAMP(part->trail_count, 1, 100000);
+}
+
+void BKE_particle_partdeflect_blend_read_lib(BlendLibReader *reader, ID *id, PartDeflect *pd)
+{
+ if (pd && pd->tex) {
+ BLO_read_id_address(reader, id->lib, &pd->tex);
+ }
+ if (pd && pd->f_source) {
+ BLO_read_id_address(reader, id->lib, &pd->f_source);
+ }
+}
+
+static void particle_settings_blend_read_lib(BlendLibReader *reader, ID *id)
+{
+ ParticleSettings *part = (ParticleSettings *)id;
+ BLO_read_id_address(
+ reader, part->id.lib, &part->ipo); /* XXX deprecated - old animation system */
+
+ BLO_read_id_address(reader, part->id.lib, &part->instance_object);
+ BLO_read_id_address(reader, part->id.lib, &part->instance_collection);
+ BLO_read_id_address(reader, part->id.lib, &part->force_group);
+ BLO_read_id_address(reader, part->id.lib, &part->bb_ob);
+ BLO_read_id_address(reader, part->id.lib, &part->collision_group);
+
+ BKE_particle_partdeflect_blend_read_lib(reader, &part->id, part->pd);
+ BKE_particle_partdeflect_blend_read_lib(reader, &part->id, part->pd2);
+
+ if (part->effector_weights) {
+ BLO_read_id_address(reader, part->id.lib, &part->effector_weights->group);
+ }
+ else {
+ part->effector_weights = BKE_effector_add_weights(part->force_group);
+ }
+
+ if (part->instance_weights.first && part->instance_collection) {
+ LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) {
+ BLO_read_id_address(reader, part->id.lib, &dw->ob);
+ }
+ }
+ else {
+ BLI_listbase_clear(&part->instance_weights);
+ }
+
+ if (part->boids) {
+ LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
+ LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
+ switch (rule->type) {
+ case eBoidRuleType_Goal:
+ case eBoidRuleType_Avoid: {
+ BoidRuleGoalAvoid *brga = (BoidRuleGoalAvoid *)rule;
+ BLO_read_id_address(reader, part->id.lib, &brga->ob);
+ break;
+ }
+ case eBoidRuleType_FollowLeader: {
+ BoidRuleFollowLeader *brfl = (BoidRuleFollowLeader *)rule;
+ BLO_read_id_address(reader, part->id.lib, &brfl->ob);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ for (int a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = part->mtex[a];
+ if (mtex) {
+ BLO_read_id_address(reader, part->id.lib, &mtex->tex);
+ BLO_read_id_address(reader, part->id.lib, &mtex->object);
+ }
+ }
+}
+
+static void particle_settings_blend_read_expand(BlendExpander *expander, ID *id)
+{
+ ParticleSettings *part = (ParticleSettings *)id;
+ BLO_expand(expander, part->instance_object);
+ BLO_expand(expander, part->instance_collection);
+ BLO_expand(expander, part->force_group);
+ BLO_expand(expander, part->bb_ob);
+ BLO_expand(expander, part->collision_group);
+
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (part->mtex[a]) {
+ BLO_expand(expander, part->mtex[a]->tex);
+ BLO_expand(expander, part->mtex[a]->object);
+ }
+ }
+
+ if (part->effector_weights) {
+ BLO_expand(expander, part->effector_weights->group);
+ }
+
+ if (part->pd) {
+ BLO_expand(expander, part->pd->tex);
+ BLO_expand(expander, part->pd->f_source);
+ }
+ if (part->pd2) {
+ BLO_expand(expander, part->pd2->tex);
+ BLO_expand(expander, part->pd2->f_source);
+ }
+
+ if (part->boids) {
+ LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
+ LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
+ if (rule->type == eBoidRuleType_Avoid) {
+ BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
+ BLO_expand(expander, gabr->ob);
+ }
+ else if (rule->type == eBoidRuleType_FollowLeader) {
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
+ BLO_expand(expander, flbr->ob);
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) {
+ BLO_expand(expander, dw->ob);
+ }
+}
+
IDTypeInfo IDType_ID_PA = {
.id_code = ID_PA,
.id_filter = FILTER_ID_PA,
@@ -223,17 +503,19 @@ IDTypeInfo IDType_ID_PA = {
.foreach_id = particle_settings_foreach_id,
.foreach_cache = NULL,
- .blend_write = NULL,
- .blend_read_data = NULL,
- .blend_read_lib = NULL,
- .blend_read_expand = NULL,
+ .blend_write = particle_settings_blend_write,
+ .blend_read_data = particle_settings_blend_read_data,
+ .blend_read_lib = particle_settings_blend_read_lib,
+ .blend_read_expand = particle_settings_blend_read_expand,
+
+ .blend_read_undo_preserve = NULL,
};
unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT];
unsigned int PSYS_FRAND_SEED_MULTIPLIER[PSYS_FRAND_COUNT];
float PSYS_FRAND_BASE[PSYS_FRAND_COUNT];
-void psys_init_rng(void)
+void BKE_particle_init_rng(void)
{
RNG *rng = BLI_rng_new_srandom(5831); /* arbitrary */
for (int i = 0; i < PSYS_FRAND_COUNT; i++) {
@@ -917,7 +1199,7 @@ static float interpolate_particle_value(
value += w[3] * v4;
}
- CLAMP(value, 0.f, 1.f);
+ CLAMP(value, 0.0f, 1.0f);
return value;
}
@@ -1146,7 +1428,7 @@ static void do_particle_interpolation(ParticleSystem *psys,
PTCacheEditPoint *point = pind->epoint;
ParticleKey keys[4];
int point_vel = (point && point->keys->vel);
- float real_t, dfra, keytime, invdt = 1.f;
+ float real_t, dfra, keytime, invdt = 1.0f;
/* billboards wont fill in all of these, so start cleared */
memset(keys, 0, sizeof(keys));
@@ -1316,7 +1598,7 @@ static void do_particle_interpolation(ParticleSystem *psys,
/* Convert velocity to time-step size. */
if (pind->keyed || pind->cache || point_vel) {
- invdt = dfra * 0.04f * (psys ? psys->part->timetweak : 1.f);
+ invdt = dfra * 0.04f * (psys ? psys->part->timetweak : 1.0f);
mul_v3_fl(keys[1].vel, invdt);
mul_v3_fl(keys[2].vel, invdt);
interp_qt_qtqt(result->rot, keys[1].rot, keys[2].rot, keytime);
@@ -1335,7 +1617,7 @@ static void do_particle_interpolation(ParticleSystem *psys,
/* the velocity needs to be converted back from cubic interpolation */
if (pind->keyed || pind->cache || point_vel) {
- mul_v3_fl(result->vel, 1.f / invdt);
+ mul_v3_fl(result->vel, 1.0f / invdt);
}
}
@@ -2200,7 +2482,7 @@ int do_guides(Depsgraph *depsgraph,
pd->kink_freq,
pd->kink_shape,
pd->kink_amp,
- 0.f,
+ 0.0f,
pd->kink,
pd->kink_axis,
0,
@@ -2550,12 +2832,12 @@ static void psys_thread_create_path(ParticleTask *task,
if (ctx->between) {
ParticleData *pa = psys->particles + cpa->pa[0];
int w, needupdate;
- float foffset, wsum = 0.f;
+ float foffset, wsum = 0.0f;
float co[3];
float p_min = part->parting_min;
float p_max = part->parting_max;
/* Virtual parents don't work nicely with parting. */
- float p_fac = part->parents > 0.f ? 0.f : part->parting_fac;
+ float p_fac = part->parents > 0.0f ? 0.0f : part->parting_fac;
if (ctx->editupdate) {
needupdate = 0;
@@ -2583,15 +2865,15 @@ static void psys_thread_create_path(ParticleTask *task,
}
else {
key[w] = pcache[0];
- weight[w] = 0.f;
+ weight[w] = 0.0f;
}
}
/* modify weights to create parting */
- if (p_fac > 0.f) {
+ if (p_fac > 0.0f) {
const ParticleCacheKey *key_0_last = pcache_key_segment_endpoint_safe(key[0]);
for (w = 0; w < 4; w++) {
- if (w && (weight[w] > 0.f)) {
+ if (w && (weight[w] > 0.0f)) {
const ParticleCacheKey *key_w_last = pcache_key_segment_endpoint_safe(key[w]);
float d;
if (part->flag & PART_CHILD_LONG_HAIR) {
@@ -2600,7 +2882,7 @@ static void psys_thread_create_path(ParticleTask *task,
float d1 = len_v3v3(key[0]->co, key[w]->co);
float d2 = len_v3v3(key_0_last->co, key_w_last->co);
- d = d1 > 0.f ? d2 / d1 - 1.f : 10000.f;
+ d = d1 > 0.0f ? d2 / d1 - 1.0f : 10000.0f;
}
else {
float v1[3], v2[3];
@@ -2616,13 +2898,13 @@ static void psys_thread_create_path(ParticleTask *task,
d = (d - p_min) / (p_max - p_min);
}
else {
- d = (d - p_min) <= 0.f ? 0.f : 1.f;
+ d = (d - p_min) <= 0.0f ? 0.0f : 1.0f;
}
- CLAMP(d, 0.f, 1.f);
+ CLAMP(d, 0.0f, 1.0f);
- if (d > 0.f) {
- weight[w] *= (1.f - d);
+ if (d > 0.0f) {
+ weight[w] *= (1.0f - d);
}
}
wsum += weight[w];
@@ -3059,7 +3341,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
LOOP_PARTICLES
{
if (!psys->totchild) {
- psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f);
+ psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.0f);
pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p));
if (vg_length) {
pa_length *= psys_particle_value_from_verts(psmd->mesh_final, part->from, pa, vg_length);
@@ -3716,19 +3998,25 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
if (psys->part->type == PART_FLUID_FLIP) {
fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP;
}
- if (psys->part->type == PART_FLUID_SPRAY || psys->part->type == PART_FLUID_SPRAYFOAM ||
- psys->part->type == PART_FLUID_SPRAYBUBBLE ||
- psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) {
+ if (ELEM(psys->part->type,
+ PART_FLUID_SPRAY,
+ PART_FLUID_SPRAYFOAM,
+ PART_FLUID_SPRAYBUBBLE,
+ PART_FLUID_SPRAYFOAMBUBBLE)) {
fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_SPRAY;
}
- if (psys->part->type == PART_FLUID_FOAM || psys->part->type == PART_FLUID_SPRAYFOAM ||
- psys->part->type == PART_FLUID_FOAMBUBBLE ||
- psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) {
+ if (ELEM(psys->part->type,
+ PART_FLUID_FOAM,
+ PART_FLUID_SPRAYFOAM,
+ PART_FLUID_FOAMBUBBLE,
+ PART_FLUID_SPRAYFOAMBUBBLE)) {
fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FOAM;
}
- if (psys->part->type == PART_FLUID_BUBBLE || psys->part->type == PART_FLUID_FOAMBUBBLE ||
- psys->part->type == PART_FLUID_SPRAYBUBBLE ||
- psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) {
+ if (ELEM(psys->part->type,
+ PART_FLUID_BUBBLE,
+ PART_FLUID_FOAMBUBBLE,
+ PART_FLUID_SPRAYBUBBLE,
+ PART_FLUID_SPRAYFOAMBUBBLE)) {
fmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_BUBBLE;
}
if (psys->part->type == PART_FLUID_TRACER) {
@@ -3736,9 +4024,11 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
}
/* Disable combined export if combined particle system was deleted. */
- if (psys->part->type == PART_FLUID_SPRAYFOAM || psys->part->type == PART_FLUID_SPRAYBUBBLE ||
- psys->part->type == PART_FLUID_FOAMBUBBLE ||
- psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE) {
+ if (ELEM(psys->part->type,
+ PART_FLUID_SPRAYFOAM,
+ PART_FLUID_SPRAYBUBBLE,
+ PART_FLUID_FOAMBUBBLE,
+ PART_FLUID_SPRAYFOAMBUBBLE)) {
fmd->domain->sndparticle_combined_export = SNDPARTICLE_COMBINED_EXPORT_OFF;
}
}
@@ -3992,9 +4282,9 @@ static void get_cpa_texture(Mesh *mesh,
break;
case TEXCO_PARTICLE:
/* texture coordinates in range [-1, 1] */
- texvec[0] = 2.f * (cfra - par->time) / (par->dietime - par->time) - 1.f;
- texvec[1] = 0.f;
- texvec[2] = 0.f;
+ texvec[0] = 2.0f * (cfra - par->time) / (par->dietime - par->time) - 1.0f;
+ texvec[1] = 0.0f;
+ texvec[2] = 0.0f;
break;
}
@@ -4102,14 +4392,15 @@ void psys_get_texture(
break;
case TEXCO_PARTICLE:
/* texture coordinates in range [-1, 1] */
- texvec[0] = 2.f * (cfra - pa->time) / (pa->dietime - pa->time) - 1.f;
+ texvec[0] = 2.0f * (cfra - pa->time) / (pa->dietime - pa->time) - 1.0f;
if (sim->psys->totpart > 0) {
- texvec[1] = 2.f * (float)(pa - sim->psys->particles) / (float)sim->psys->totpart - 1.f;
+ texvec[1] = 2.0f * (float)(pa - sim->psys->particles) / (float)sim->psys->totpart -
+ 1.0f;
}
else {
texvec[1] = 0.0f;
}
- texvec[2] = 0.f;
+ texvec[2] = 0.0f;
break;
}
@@ -4654,8 +4945,8 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
else {
float dfra, frs_sec = sim->scene->r.frs_sec;
/* let's interpolate to try to be as accurate as possible */
- if (pa->state.time + 2.f >= state->time && pa->prev_state.time - 2.f <= state->time) {
- if (pa->prev_state.time >= pa->state.time || pa->prev_state.time < 0.f) {
+ if (pa->state.time + 2.0f >= state->time && pa->prev_state.time - 2.0f <= state->time) {
+ if (pa->prev_state.time >= pa->state.time || pa->prev_state.time < 0.0f) {
/* prev_state is wrong so let's not use it,
* this can happen at frames 1, 0 or particle birth. */
dfra = state->time - pa->state.time;
@@ -4682,13 +4973,13 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
psys_interpolate_particle(-1, keys, keytime, state, 1);
/* convert back to real velocity */
- mul_v3_fl(state->vel, 1.f / (dfra * timestep));
+ mul_v3_fl(state->vel, 1.0f / (dfra * timestep));
interp_v3_v3v3(state->ave, keys[1].ave, keys[2].ave, keytime);
interp_qt_qtqt(state->rot, keys[1].rot, keys[2].rot, keytime);
}
}
- else if (pa->state.time + 1.f >= state->time && pa->state.time - 1.f <= state->time) {
+ else if (pa->state.time + 1.0f >= state->time && pa->state.time - 1.0f <= state->time) {
/* linear interpolation using only pa->state */
dfra = state->time - pa->state.time;
@@ -4949,3 +5240,172 @@ void BKE_particle_batch_cache_free(ParticleSystem *psys)
BKE_particle_batch_cache_free_cb(psys);
}
}
+
+void BKE_particle_system_blend_write(BlendWriter *writer, ListBase *particles)
+{
+ LISTBASE_FOREACH (ParticleSystem *, psys, particles) {
+ BLO_write_struct(writer, ParticleSystem, psys);
+
+ if (psys->particles) {
+ BLO_write_struct_array(writer, ParticleData, psys->totpart, psys->particles);
+
+ if (psys->particles->hair) {
+ ParticleData *pa = psys->particles;
+
+ for (int a = 0; a < psys->totpart; a++, pa++) {
+ BLO_write_struct_array(writer, HairKey, pa->totkey, pa->hair);
+ }
+ }
+
+ if (psys->particles->boid && (psys->part->phystype == PART_PHYS_BOIDS)) {
+ BLO_write_struct_array(writer, BoidParticle, psys->totpart, psys->particles->boid);
+ }
+
+ if (psys->part->fluid && (psys->part->phystype == PART_PHYS_FLUID) &&
+ (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS)) {
+ BLO_write_struct_array(
+ writer, ParticleSpring, psys->tot_fluidsprings, psys->fluid_springs);
+ }
+ }
+ LISTBASE_FOREACH (ParticleTarget *, pt, &psys->targets) {
+ BLO_write_struct(writer, ParticleTarget, pt);
+ }
+
+ if (psys->child) {
+ BLO_write_struct_array(writer, ChildParticle, psys->totchild, psys->child);
+ }
+
+ if (psys->clmd) {
+ BLO_write_struct(writer, ClothModifierData, psys->clmd);
+ BLO_write_struct(writer, ClothSimSettings, psys->clmd->sim_parms);
+ BLO_write_struct(writer, ClothCollSettings, psys->clmd->coll_parms);
+ }
+
+ BKE_ptcache_blend_write(writer, &psys->ptcaches);
+ }
+}
+
+void BKE_particle_system_blend_read_data(BlendDataReader *reader, ListBase *particles)
+{
+ ParticleData *pa;
+ int a;
+
+ LISTBASE_FOREACH (ParticleSystem *, psys, particles) {
+ BLO_read_data_address(reader, &psys->particles);
+
+ if (psys->particles && psys->particles->hair) {
+ for (a = 0, pa = psys->particles; a < psys->totpart; a++, pa++) {
+ BLO_read_data_address(reader, &pa->hair);
+ }
+ }
+
+ if (psys->particles && psys->particles->keys) {
+ for (a = 0, pa = psys->particles; a < psys->totpart; a++, pa++) {
+ pa->keys = NULL;
+ pa->totkey = 0;
+ }
+
+ psys->flag &= ~PSYS_KEYED;
+ }
+
+ if (psys->particles && psys->particles->boid) {
+ pa = psys->particles;
+ BLO_read_data_address(reader, &pa->boid);
+
+ /* This is purely runtime data, but still can be an issue if left dangling. */
+ pa->boid->ground = NULL;
+
+ for (a = 1, pa++; a < psys->totpart; a++, pa++) {
+ pa->boid = (pa - 1)->boid + 1;
+ pa->boid->ground = NULL;
+ }
+ }
+ else if (psys->particles) {
+ for (a = 0, pa = psys->particles; a < psys->totpart; a++, pa++) {
+ pa->boid = NULL;
+ }
+ }
+
+ BLO_read_data_address(reader, &psys->fluid_springs);
+
+ BLO_read_data_address(reader, &psys->child);
+ psys->effectors = NULL;
+
+ BLO_read_list(reader, &psys->targets);
+
+ psys->edit = NULL;
+ psys->free_edit = NULL;
+ psys->pathcache = NULL;
+ psys->childcache = NULL;
+ BLI_listbase_clear(&psys->pathcachebufs);
+ BLI_listbase_clear(&psys->childcachebufs);
+ psys->pdd = NULL;
+
+ if (psys->clmd) {
+ BLO_read_data_address(reader, &psys->clmd);
+ psys->clmd->clothObject = NULL;
+ psys->clmd->hairdata = NULL;
+
+ BLO_read_data_address(reader, &psys->clmd->sim_parms);
+ BLO_read_data_address(reader, &psys->clmd->coll_parms);
+
+ if (psys->clmd->sim_parms) {
+ psys->clmd->sim_parms->effector_weights = NULL;
+ if (psys->clmd->sim_parms->presets > 10) {
+ psys->clmd->sim_parms->presets = 0;
+ }
+ }
+
+ psys->hair_in_mesh = psys->hair_out_mesh = NULL;
+ psys->clmd->solver_result = NULL;
+ }
+
+ BKE_ptcache_blend_read_data(reader, &psys->ptcaches, &psys->pointcache, 0);
+ if (psys->clmd) {
+ psys->clmd->point_cache = psys->pointcache;
+ }
+
+ psys->tree = NULL;
+ psys->bvhtree = NULL;
+
+ psys->orig_psys = NULL;
+ psys->batch_cache = NULL;
+ }
+}
+
+void BKE_particle_system_blend_read_lib(BlendLibReader *reader,
+ Object *ob,
+ ID *id,
+ ListBase *particles)
+{
+ LISTBASE_FOREACH_MUTABLE (ParticleSystem *, psys, particles) {
+
+ BLO_read_id_address(reader, id->lib, &psys->part);
+ if (psys->part) {
+ LISTBASE_FOREACH (ParticleTarget *, pt, &psys->targets) {
+ BLO_read_id_address(reader, id->lib, &pt->ob);
+ }
+
+ BLO_read_id_address(reader, id->lib, &psys->parent);
+ BLO_read_id_address(reader, id->lib, &psys->target_ob);
+
+ if (psys->clmd) {
+ /* XXX - from reading existing code this seems correct but intended usage of
+ * pointcache /w cloth should be added in 'ParticleSystem' - campbell */
+ psys->clmd->point_cache = psys->pointcache;
+ psys->clmd->ptcaches.first = psys->clmd->ptcaches.last = NULL;
+ BLO_read_id_address(reader, id->lib, &psys->clmd->coll_parms->group);
+ psys->clmd->modifier.error = NULL;
+ }
+ }
+ else {
+ /* particle modifier must be removed before particle system */
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+ BLI_remlink(&ob->modifiers, psmd);
+ BKE_modifier_free((ModifierData *)psmd);
+
+ BLI_remlink(particles, psys);
+ MEM_freeN(psys);
+ }
+ }
+}