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:
-rw-r--r--release/ui/buttons_particle.py62
-rw-r--r--source/blender/blenkernel/BKE_particle.h5
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c15
-rw-r--r--source/blender/blenkernel/intern/object.c26
-rw-r--r--source/blender/blenkernel/intern/particle.c669
-rw-r--r--source/blender/blenkernel/intern/particle_system.c279
-rw-r--r--source/blender/blenkernel/intern/pointcache.c36
-rw-r--r--source/blender/blenloader/intern/readfile.c13
-rw-r--r--source/blender/blenloader/intern/writefile.c5
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h4
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c204
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c4
-rw-r--r--source/blender/editors/space_view3d/drawobject.c32
-rw-r--r--source/blender/makesdna/DNA_particle_types.h38
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_particle.c325
-rw-r--r--source/blender/render/intern/source/convertblender.c20
17 files changed, 1093 insertions, 645 deletions
diff --git a/release/ui/buttons_particle.py b/release/ui/buttons_particle.py
index ef7ede15d6e..2d269967e4b 100644
--- a/release/ui/buttons_particle.py
+++ b/release/ui/buttons_particle.py
@@ -131,6 +131,9 @@ class PARTICLE_PT_cache(ParticleButtonsPanel):
psys = context.particle_system
if psys==None: return False
if psys.settings==None: return False
+ phystype = psys.settings.physics_type
+ if phystype == 'NO' or phystype == 'KEYED':
+ return False
return psys.settings.type in ('EMITTER', 'REACTOR')
def draw(self, context):
@@ -277,16 +280,40 @@ class PARTICLE_PT_physics(ParticleButtonsPanel):
sub.itemR(part, "acceleration")
elif part.physics_type == 'KEYED':
- sub.itemR(psys, "keyed_first")
- if psys.keyed_first==True:
- sub.itemR(psys, "timed_keys", text="Key timing")
- else:
- sub.itemR(part, "keyed_time")
- sub = split.column()
- sub.itemL(text="Next key from object:")
- sub.itemR(psys, "keyed_object", text="")
- sub.itemR(psys, "keyed_particle_system")
-
+ row = layout.row()
+ col = row.column()
+ col.active = not psys.keyed_timing
+ col.itemR(part, "keyed_loops", text="Loops")
+ row.itemR(psys, "keyed_timing", text="Use Timing")
+
+ layout.itemL(text="Keys:")
+ row = layout.row()
+
+ row.template_list(psys, "keyed_targets", psys, "active_keyed_target_index")
+
+ col = row.column()
+ subrow = col.row()
+ subcol = subrow.column(align=True)
+ subcol.itemO("PARTICLE_OT_new_keyed_target", icon="ICON_ZOOMIN", text="")
+ subcol.itemO("PARTICLE_OT_remove_keyed_target", icon="ICON_ZOOMOUT", text="")
+ subrow = col.row()
+ subcol = subrow.column(align=True)
+ subcol.itemO("PARTICLE_OT_keyed_target_move_up", icon="VICON_MOVE_UP", text="")
+ subcol.itemO("PARTICLE_OT_keyed_target_move_down", icon="VICON_MOVE_DOWN", text="")
+
+ key = psys.active_keyed_target
+ if key:
+ row = layout.row()
+ col = row.column()
+ #doesn't work yet
+ #col.red_alert = key.valid
+ col.itemR(key, "object", text="")
+ col.itemR(key, "system", text="System")
+ col = row.column();
+ col.active = psys.keyed_timing
+ col.itemR(key, "time")
+ col.itemR(key, "duration")
+
if part.physics_type=='NEWTON' or part.physics_type=='BOIDS':
sub.itemR(part, "size_deflect")
@@ -308,7 +335,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
psys = context.particle_system
part = psys.settings
-
+
row = layout.row()
row.itemR(part, "material")
row.itemR(psys, "parent");
@@ -336,7 +363,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
sub.itemR(part, "velocity_length")
elif part.ren_as == 'PATH':
- if (part.type!='HAIR' and psys.point_cache.baked==False):
+ if (part.type!='HAIR' and part.physics_type!='KEYED' and psys.point_cache.baked==False):
box = layout.box()
box.itemL(text="Baked or keyed particles needed for correct rendering.")
return
@@ -460,7 +487,7 @@ class PARTICLE_PT_draw(ParticleButtonsPanel):
path = (part.ren_as=='PATH' and part.draw_as=='RENDER') or part.draw_as=='PATH'
- if path and part.type!='HAIR' and psys.point_cache.baked==False:
+ if path and part.type!='HAIR' and part.physics_type!='KEYED' and psys.point_cache.baked==False:
box = layout.box()
box.itemL(text="Baked or keyed particles needed for correct drawing.")
return
@@ -549,6 +576,15 @@ class PARTICLE_PT_children(ParticleButtonsPanel):
col.itemR(part, "rough2_size")
col.itemR(part, "rough2_thres", slider=True)
+ row = layout.row()
+ col = row.column(align=True)
+ col.itemR(part, "child_length", slider=True)
+ col.itemR(part, "child_length_thres", slider=True)
+
+ col = row.column(align=True)
+ col.itemL(text="Space reserved for")
+ col.itemL(text="hair parting controls")
+
layout.row().itemL(text="Kink:")
layout.row().itemR(part, "kink", expand=True)
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index aa24706077d..bb0b905b8e3 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -260,7 +260,6 @@ void psys_flush_particle_settings(struct Scene *scene, struct ParticleSettings *
void make_local_particlesettings(struct ParticleSettings *part);
struct LinkNode *psys_using_settings(struct Scene *scene, struct ParticleSettings *part, int flush_update);
-void psys_changed_type(struct ParticleSystem *psys);
void psys_reset(struct ParticleSystem *psys, int mode);
void psys_find_parents(struct Object *ob, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys);
@@ -289,12 +288,14 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]);
/* particle_system.c */
-int psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys);
+void psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys);
void psys_get_reactor_target(struct Object *ob, struct ParticleSystem *psys, struct Object **target_ob, struct ParticleSystem **target_psys);
void psys_init_effectors(struct Scene *scene, struct Object *obsrc, struct Group *group, struct ParticleSystem *psys);
void psys_end_effectors(struct ParticleSystem *psys);
+void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys);
+void psys_end_temp_pointcache(struct ParticleSystem *psys);
void psys_get_pointcache_start_end(struct Scene *scene, struct ParticleSystem *psys, int *sfra, int *efra);
void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index de036e25d82..f52eec34cc7 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -562,10 +562,17 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
if(!psys_check_enabled(ob, psys))
continue;
- if(part->phystype==PART_PHYS_KEYED && psys->keyed_ob &&
- BLI_findlink(&psys->keyed_ob->particlesystem,psys->keyed_psys-1)) {
- node2 = dag_get_node(dag, psys->keyed_ob);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Keyed Physics");
+ if(part->phystype==PART_PHYS_KEYED) {
+ KeyedParticleTarget *kpt = psys->keyed_targets.first;
+
+ for(; kpt; kpt=kpt->next) {
+ if(kpt->ob && BLI_findlink(&kpt->ob->particlesystem, kpt->psys-1)) {
+ node2 = dag_get_node(dag, kpt->ob);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Keyed Physics");
+ }
+ else
+ break;
+ }
}
if(part->ren_as == PART_DRAW_OB && part->dup_ob) {
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 6490ff3c724..7d6a83d7900 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -427,17 +427,14 @@ void unlink_object(Scene *scene, Object *ob)
if(obt->particlesystem.first) {
ParticleSystem *tpsys= obt->particlesystem.first;
for(; tpsys; tpsys=tpsys->next) {
- if(tpsys->keyed_ob==ob) {
- ParticleSystem *psys= BLI_findlink(&ob->particlesystem,tpsys->keyed_psys-1);
-
- if(psys && psys->keyed_ob) {
- tpsys->keyed_ob= psys->keyed_ob;
- tpsys->keyed_psys= psys->keyed_psys;
+ KeyedParticleTarget *kpt = tpsys->keyed_targets.first;
+ for(; kpt; kpt=kpt->next) {
+ if(kpt->ob==ob) {
+ BLI_remlink(&tpsys->keyed_targets, kpt);
+ MEM_freeN(kpt);
+ obt->recalc |= OB_RECALC_DATA;
+ break;
}
- else
- tpsys->keyed_ob= NULL;
-
- obt->recalc |= OB_RECALC_DATA;
}
if(tpsys->target_ob==ob) {
@@ -1050,18 +1047,23 @@ ParticleSystem *copy_particlesystem(ParticleSystem *psys)
psysn= MEM_dupallocN(psys);
psysn->particles= MEM_dupallocN(psys->particles);
psysn->child= MEM_dupallocN(psys->child);
+ if(psysn->particles->keys)
+ psysn->particles->keys = MEM_dupallocN(psys->particles->keys);
for(a=0, pa=psysn->particles; a<psysn->totpart; a++, pa++) {
if(pa->hair)
pa->hair= MEM_dupallocN(pa->hair);
- if(pa->keys)
- pa->keys= MEM_dupallocN(pa->keys);
+ if(a)
+ pa->keys= (pa-1)->keys + (pa-1)->totkey;
}
if(psys->soft) {
psysn->soft= copy_softbody(psys->soft);
psysn->soft->particles = psysn;
}
+
+ if(psys->keyed_targets.first)
+ BLI_duplicatelist(&psysn->keyed_targets, &psys->keyed_targets);
psysn->pathcache= NULL;
psysn->childcache= NULL;
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 4488f8cdffd..cefeafcdd50 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -84,7 +84,8 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index,
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part,
- ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, ParticleKey *state, float t);
+ ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa,
+ float *orco, float mat[4][4], ParticleKey *state, float t);
/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys){
@@ -478,10 +479,16 @@ void psys_free(Object *ob, ParticleSystem * psys)
if(psys->pointcache)
BKE_ptcache_free(psys->pointcache);
+ if(psys->keyed_targets.first)
+ BLI_freelistN(&psys->keyed_targets);
+
MEM_freeN(psys);
}
}
+/************************************************/
+/* Rendering */
+/************************************************/
/* these functions move away particle data and bring it back after
* rendering, to make different render settings possible without
* removing the previous data. this should be solved properly once */
@@ -889,7 +896,7 @@ int psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float
}
/************************************************/
-/* Interpolated Particles */
+/* Interpolation */
/************************************************/
static float interpolate_particle_value(float v1, float v2, float v3, float v4, float *w, int four)
{
@@ -938,6 +945,214 @@ void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, Partic
+typedef struct ParticleInterpolationData {
+ ParticleKey *kkey[2];
+ HairKey *hkey[2];
+ BodyPoint *bp[2];
+ SoftBody *soft;
+ int keyed, cached;
+ float birthtime, dietime;
+} ParticleInterpolationData;
+/* Assumes pointcache->mem_cache exists, so for disk cached particles call psys_make_temp_pointcache() before use */
+static void get_pointcache_keys_for_time(Object *ob, ParticleSystem *psys, int index, float t, ParticleKey *key1, ParticleKey *key2)
+{
+ PointCache *cache = psys->pointcache;
+ static PTCacheMem *pm = NULL; /* not thread safe */
+
+ if(index < 0) { /* initialize */
+ pm = cache->mem_cache.first;
+
+ if(pm)
+ pm = pm->next;
+ }
+ else {
+ if(pm) {
+ while(pm && pm->next && (float)pm->frame < t)
+ pm = pm->next;
+
+ copy_particle_key(key2, ((ParticleKey *)pm->data) + index, 1);
+ copy_particle_key(key1, ((ParticleKey *)(pm->prev)->data) + index, 1);
+ }
+ else if(cache->mem_cache.first) {
+ PTCacheMem *pm2 = cache->mem_cache.first;
+ copy_particle_key(key2, ((ParticleKey *)pm2->data) + index, 1);
+ copy_particle_key(key1, ((ParticleKey *)pm2->data) + index, 1);
+ }
+ }
+}
+static void init_particle_interpolation(Object *ob, ParticleSystem *psys, ParticleData *pa, ParticleInterpolationData *pind)
+{
+
+ if(pind->keyed) {
+ pind->kkey[0] = pa->keys;
+
+ if(pa->totkey > 1)
+ pind->kkey[1] = pa->keys + 1;
+ else
+ pind->kkey[1] = NULL;
+
+ pind->birthtime = pa->keys->time;
+ pind->dietime = (pa->keys + pa->totkey - 1)->time;
+ }
+ else if(pind->cached) {
+ get_pointcache_keys_for_time(ob, psys, -1, 0.0f, NULL, NULL);
+
+ pind->birthtime = pa->time;
+ pind->dietime = pa->dietime;
+ }
+ else {
+ pind->hkey[0] = pa->hair;
+ pind->hkey[1] = pa->hair + 1;
+
+ pind->birthtime = pa->hair->time;
+ pind->dietime = (pa->hair + pa->totkey - 1)->time;
+ }
+
+ if(pind->soft) {
+ pind->bp[0] = pind->soft->bpoint + pa->bpi;
+ pind->bp[1] = pind->soft->bpoint + pa->bpi + 1;
+ }
+}
+static void hair_to_particle(ParticleKey *key, HairKey *hkey)
+{
+ VECCOPY(key->co, hkey->co);
+ key->time = hkey->time;
+}
+static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey)
+{
+ VECCOPY(key->co, bp->pos);
+ key->time = hkey->time;
+}
+
+static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, float frs_sec, ParticleInterpolationData *pind, ParticleKey *result)
+{
+ ParticleKey keys[4];
+ float real_t, dfra, keytime;
+
+ /* interpret timing and find keys */
+ if(pind->keyed) {
+ /* we have only one key, so let's use that */
+ if(pind->kkey[1]==NULL) {
+ copy_particle_key(result, pind->kkey[0], 1);
+ return;
+ }
+
+ if(result->time < 0.0f)
+ real_t = -result->time;
+ else
+ real_t = pind->kkey[0]->time + t * (pind->kkey[0][pa->totkey-1].time - pind->kkey[0]->time);
+
+ if(psys->part->phystype==PART_PHYS_KEYED && psys->flag & PSYS_KEYED_TIMING) {
+ KeyedParticleTarget *kpt = psys->keyed_targets.first;
+
+ kpt=kpt->next;
+
+ while(kpt && pa->time + kpt->time < real_t)
+ kpt= kpt->next;
+
+ if(kpt) {
+ kpt=kpt->prev;
+
+ if(pa->time + kpt->time + kpt->duration > real_t)
+ real_t = pa->time + kpt->time;
+ }
+ else
+ real_t = pa->time + ((KeyedParticleTarget*)psys->keyed_targets.last)->time;
+ }
+
+ CLAMP(real_t, pa->time, pa->dietime);
+
+ while(pind->kkey[1]->time < real_t)
+ pind->kkey[1]++;
+
+ pind->kkey[0] = pind->kkey[1] - 1;
+ }
+ else if(pind->cached) {
+ if(result->time < 0.0f) /* flag for time in frames */
+ real_t = -result->time;
+ else
+ real_t = pa->time + t * (pa->dietime - pa->time);
+ }
+ else {
+ if(result->time < 0.0f)
+ real_t = -result->time;
+ else
+ real_t = pind->hkey[0]->time + t * (pind->hkey[0][pa->totkey-1].time - pind->hkey[0]->time);
+
+ while(pind->hkey[1]->time < real_t) {
+ pind->hkey[1]++;
+ pind->bp[1]++;
+ }
+
+ pind->hkey[0] = pind->hkey[1] - 1;
+ }
+
+ /* set actual interpolation keys */
+ if(pind->soft) {
+ pind->bp[0] = pind->bp[1] - 1;
+ bp_to_particle(keys + 1, pind->bp[0], pind->hkey[0]);
+ bp_to_particle(keys + 2, pind->bp[1], pind->hkey[1]);
+ }
+ else if(pind->keyed) {
+ memcpy(keys + 1, pind->kkey[0], sizeof(ParticleKey));
+ memcpy(keys + 2, pind->kkey[1], sizeof(ParticleKey));
+ }
+ else if(pind->cached) {
+ get_pointcache_keys_for_time(NULL, psys, p, real_t, keys+1, keys+2);
+ }
+ else {
+ hair_to_particle(keys + 1, pind->hkey[0]);
+ hair_to_particle(keys + 2, pind->hkey[1]);
+ }
+
+ /* set secondary interpolation keys for hair */
+ if(!pind->keyed && !pind->cached) {
+ if(pind->soft) {
+ if(pind->hkey[0] != pa->hair)
+ bp_to_particle(keys, pind->bp[0] - 1, pind->hkey[0] - 1);
+ else
+ bp_to_particle(keys, pind->bp[0], pind->hkey[0]);
+ }
+ else {
+ if(pind->hkey[0] != pa->hair)
+ hair_to_particle(keys, pind->hkey[0] - 1);
+ else
+ hair_to_particle(keys, pind->hkey[0]);
+ }
+
+ if(pind->soft) {
+ if(pind->hkey[1] != pa->hair + pa->totkey - 1)
+ bp_to_particle(keys + 3, pind->bp[1] + 1, pind->hkey[1] + 1);
+ else
+ bp_to_particle(keys + 3, pind->bp[1], pind->hkey[1]);
+ }
+ else {
+ if(pind->hkey[1] != pa->hair + pa->totkey - 1)
+ hair_to_particle(keys + 3, pind->hkey[1] + 1);
+ else
+ hair_to_particle(keys + 3, pind->hkey[1]);
+ }
+ }
+
+ dfra = keys[2].time - keys[1].time;
+ keytime = (real_t - keys[1].time) / dfra;
+
+ /* convert velocity to timestep size */
+ if(pind->keyed || pind->cached){
+ VecMulf(keys[1].vel, dfra / frs_sec);
+ VecMulf(keys[2].vel, dfra / frs_sec);
+ QuatInterpol(result->rot,keys[1].rot,keys[2].rot,keytime);
+ }
+
+ /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/
+ psys_interpolate_particle((pind->keyed || pind->cached) ? -1 /* signal for cubic interpolation */
+ : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
+ ,keys, keytime, result, 1);
+
+ /* the velocity needs to be converted back from cubic interpolation */
+ if(pind->keyed || pind->cached)
+ VecMulf(result->vel, frs_sec / dfra);
+}
/************************************************/
/* Particles on a dm */
/************************************************/
@@ -1438,16 +1653,6 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
/************************************************/
/* Path Cache */
/************************************************/
-static void hair_to_particle(ParticleKey *key, HairKey *hkey)
-{
- VECCOPY(key->co, hkey->co);
- key->time = hkey->time;
-}
-static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey)
-{
- VECCOPY(key->co, bp->pos);
- key->time = hkey->time;
-}
static float vert_weight(MDeformVert *dvert, int group)
{
MDeformWeight *dw;
@@ -1734,7 +1939,7 @@ int do_guide(Scene *scene, ParticleKey *state, int pa_num, float time, ListBase
}
return 0;
}
-static void do_rough(float *loc, float t, float fac, float size, float thres, ParticleKey *state)
+static void do_rough(float *loc, float mat[4][4], float t, float fac, float size, float thres, ParticleKey *state)
{
float rough[3];
float rco[3];
@@ -1747,32 +1952,24 @@ static void do_rough(float *loc, float t, float fac, float size, float thres, Pa
rough[0]=-1.0f+2.0f*BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2,0,2);
rough[1]=-1.0f+2.0f*BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2,0,2);
rough[2]=-1.0f+2.0f*BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2,0,2);
- VECADDFAC(state->co,state->co,rough,fac);
+
+ VECADDFAC(state->co,state->co,mat[0],fac*rough[0]);
+ VECADDFAC(state->co,state->co,mat[1],fac*rough[1]);
+ VECADDFAC(state->co,state->co,mat[2],fac*rough[2]);
}
-static void do_rough_end(float *loc, float t, float fac, float shape, ParticleKey *state, ParticleKey *par)
+static void do_rough_end(float *loc, float mat[4][4], float t, float fac, float shape, ParticleKey *state)
{
- float rough[3], rnor[3];
+ float rough[2];
float roughfac;
roughfac=fac*(float)pow((double)t,shape);
VECCOPY(rough,loc);
rough[0]=-1.0f+2.0f*rough[0];
rough[1]=-1.0f+2.0f*rough[1];
- rough[2]=-1.0f+2.0f*rough[2];
VecMulf(rough,roughfac);
-
- if(par){
- VECCOPY(rnor,par->vel);
- }
- else{
- VECCOPY(rnor,state->vel);
- }
- Normalize(rnor);
- Projf(rnor,rough,rnor);
- VECSUB(rough,rough,rnor);
-
- VECADD(state->co,state->co,rough);
+ VECADDFAC(state->co,state->co,mat[0],rough[0]);
+ VECADDFAC(state->co,state->co,mat[1],rough[1]);
}
static void do_path_effectors(Scene *scene, Object *ob, ParticleSystem *psys, int i, ParticleCacheKey *ca, int k, int steps, float *rootco, float effector, float dfra, float cfra, float *length, float *vec)
{
@@ -2007,7 +2204,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
ParticleData *pa=NULL;
ParticleTexture ptex;
float *cpa_fuv=0, *par_rot=0;
- float co[3], orco[3], ornor[3], t, cpa_1st[3], dvec[3];
+ float co[3], orco[3], ornor[3], hairmat[4][4], t, cpa_1st[3], dvec[3];
float branch_begin, branch_end, branch_prob, rough_rand;
float length, max_length = 1.0f, cur_length = 0.0f;
float eff_length, eff_vec[3];
@@ -2065,8 +2262,6 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
cpa_num = cpa->num;
foffset= cpa->foffset;
- if(part->childtype == PART_CHILD_FACES)
- foffset = -(2.0f + part->childspread);
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
@@ -2078,6 +2273,10 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
Mat4MulVecfl(ob->obmat,cpa_1st);
}
+ pa = psys->particles + cpa->parent;
+
+ psys_mat_hair_to_global(ob, ctx->psmd->dm, psys->part->from, pa, hairmat);
+
pa=0;
}
else{
@@ -2099,6 +2298,8 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
cpa_fuv=pa->fuv;
psys_particle_on_emitter(ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,ornor,0,0,orco,0);
+
+ psys_mat_hair_to_global(ob, ctx->psmd->dm, psys->part->from, pa, hairmat);
}
keys->steps = ctx->steps;
@@ -2190,7 +2391,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
}
/* apply different deformations to the child path */
- do_child_modifiers(ctx->scene, ob, psys, part, &ptex, (ParticleKey *)par, par_rot, cpa, orco, (ParticleKey *)state, t);
+ do_child_modifiers(ctx->scene, ob, psys, part, &ptex, (ParticleKey *)par, par_rot, cpa, orco, hairmat, (ParticleKey *)state, t);
/* TODO: better branching */
//if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING)
@@ -2247,20 +2448,12 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
/* check if path needs to be cut before actual end of data points */
if(k){
VECSUB(dvec,state->co,(state-1)->co);
- if(part->flag&PART_ABS_LENGTH)
- length=VecLength(dvec);
- else
- length=1.0f/(float)ctx->steps;
-
+ length=1.0f/(float)ctx->steps;
k=check_path_length(k,keys,state,max_length,&cur_length,length,dvec);
}
else{
/* initialize length calculation */
- if(part->flag&PART_ABS_LENGTH)
- max_length= part->abslength*ptex.length;
- else
- max_length= ptex.length;
-
+ max_length= ptex.length;
cur_length= 0.0f;
}
@@ -2353,36 +2546,6 @@ void psys_cache_child_paths(Scene *scene, Object *ob, ParticleSystem *psys, floa
psys_threads_free(pthreads);
}
-static void get_pointcache_keys_for_time(ParticleSystem *psys, int index, float t, ParticleKey *key1, ParticleKey *key2)
-{
- PointCache *cache = psys->pointcache;
- static PTCacheMem *pm = NULL;
-
- if(cache->flag & PTCACHE_DISK_CACHE) {
- /* TODO */
- }
- else {
- if(index < 0) { /* initialize */
- pm = cache->mem_cache.first;
- if(pm)
- pm = pm->next;
- }
- else {
- if(pm) {
- while(pm && pm->next && (float)pm->frame < t)
- pm = pm->next;
-
- copy_particle_key(key2, ((ParticleKey *)pm->data) + index, 1);
- copy_particle_key(key1, ((ParticleKey *)(pm->prev)->data) + index, 1);
- }
- else if(cache->mem_cache.first) {
- pm = cache->mem_cache.first;
- copy_particle_key(key2, ((ParticleKey *)pm->data) + index, 1);
- copy_particle_key(key1, ((ParticleKey *)pm->data) + index, 1);
- }
- }
- }
-}
/* Calculates paths ready for drawing/rendering. */
/* -Usefull for making use of opengl vertex arrays for super fast strand drawing. */
/* -Makes child strands possible and creates them too into the cache. */
@@ -2395,7 +2558,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
ParticleSettings *part = psys->part;
ParticleData *pa;
- ParticleKey keys[4], result, *kkey[2] = {NULL, NULL};
+ ParticleKey result, *kkey[2] = {NULL, NULL};
HairKey *hkey[2] = {NULL, NULL};
ParticleEdit *edit = 0;
@@ -2405,11 +2568,14 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
BodyPoint *bp[2] = {NULL, NULL};
Material *ma;
+
+ ParticleInterpolationData pind;
float birthtime = 0.0, dietime = 0.0;
float t, time = 0.0, keytime = 0.0, dfra = 1.0, frs_sec = scene->r.frs_sec;
float col[4] = {0.5f, 0.5f, 0.5f, 1.0f};
float prev_tangent[3], hairmat[4][4];
+ float rotmat[3][3];
int k,i;
int steps = (int)pow(2.0, (double)psys->part->draw_step);
int totpart = psys->totpart;
@@ -2492,7 +2658,6 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
else memset(cache[i], 0, sizeof(*cache[i])*(steps+1));
if(!edit && !psys->totchild) {
- //pa_length = part->length * (1.0f - part->randlength*pa->r_ave[0]);
pa_length = 1.0f - part->randlength * 0.5 * (1.0f + pa->r_ave[0]);
if(vg_length)
pa_length *= psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_length);
@@ -2504,38 +2669,27 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
ekey = edit->keys[i];
/*--get the first data points--*/
- if(keyed) {
- kkey[0] = pa->keys;
- kkey[1] = kkey[0] + 1;
+ pind.keyed = keyed;
+ pind.cached = baked;
+ pind.soft = soft;
+ init_particle_interpolation(ob, psys, pa, &pind);
- birthtime = kkey[0]->time;
- dietime = kkey[0][pa->totkey-1].time;
- }
- else if(baked) {
- get_pointcache_keys_for_time(psys, -1, 0.0f, NULL, NULL);
-
- birthtime = pa->time;
- dietime = pa->dietime;
- }
- else {
- hkey[0] = pa->hair;
- hkey[1] = hkey[0] + 1;
- birthtime = hkey[0]->time;
- dietime = hkey[0][pa->totkey-1].time;
-
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
- }
+ /* hairmat is needed for for non-hair particle too so we get proper rotations */
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+ VECCOPY(rotmat[0], hairmat[2]);
+ VECCOPY(rotmat[1], hairmat[1]);
+ VECCOPY(rotmat[2], hairmat[0]);
if(!edit) {
if(part->draw & PART_ABS_PATH_TIME) {
- birthtime = MAX2(birthtime, part->path_start);
- dietime = MIN2(dietime, part->path_end);
+ birthtime = MAX2(pind.birthtime, part->path_start);
+ dietime = MIN2(pind.dietime, part->path_end);
}
else {
- float tb = birthtime;
- birthtime = tb + part->path_start * (dietime - tb);
- dietime = tb + part->path_end * (dietime - tb);
+ float tb = pind.birthtime;
+ birthtime = tb + part->path_start * (pind.dietime - tb);
+ dietime = tb + part->path_end * (pind.dietime - tb);
}
if(birthtime >= dietime) {
@@ -2546,101 +2700,18 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
dietime = birthtime + pa_length * (dietime - birthtime);
}
- if(soft){
- bp[0] = soft->bpoint + pa->bpi;
- bp[1] = bp[0] + 1;
- }
-
/*--interpolate actual path from data points--*/
for(k=0, ca=cache[i]; k<=steps; k++, ca++){
time = (float)k / (float)steps;
t = birthtime + time * (dietime - birthtime);
- if(keyed) {
- while(kkey[1]->time < t) {
- kkey[1]++;
- }
+ result.time = -t;
- kkey[0] = kkey[1] - 1;
- }
- else if(baked) {
- get_pointcache_keys_for_time(psys, i, t, keys+1, keys+2);
- }
- else {
- while(hkey[1]->time < t) {
- hkey[1]++;
- bp[1]++;
- }
-
- hkey[0] = hkey[1] - 1;
- }
+ do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result);
- if(soft) {
- bp[0] = bp[1] - 1;
- bp_to_particle(keys + 1, bp[0], hkey[0]);
- bp_to_particle(keys + 2, bp[1], hkey[1]);
- }
- else if(keyed) {
- memcpy(keys + 1, kkey[0], sizeof(ParticleKey));
- memcpy(keys + 2, kkey[1], sizeof(ParticleKey));
- }
- else if(baked)
- ; /* keys already set */
- else {
- hair_to_particle(keys + 1, hkey[0]);
- hair_to_particle(keys + 2, hkey[1]);
- }
-
-
- if(!keyed && !baked) {
- if(soft) {
- if(hkey[0] != pa->hair)
- bp_to_particle(keys, bp[0] - 1, hkey[0] - 1);
- else
- bp_to_particle(keys, bp[0], hkey[0]);
- }
- else {
- if(hkey[0] != pa->hair)
- hair_to_particle(keys, hkey[0] - 1);
- else
- hair_to_particle(keys, hkey[0]);
- }
-
- if(soft) {
- if(hkey[1] != pa->hair + pa->totkey - 1)
- bp_to_particle(keys + 3, bp[1] + 1, hkey[1] + 1);
- else
- bp_to_particle(keys + 3, bp[1], hkey[1]);
- }
- else {
- if(hkey[1] != pa->hair + pa->totkey - 1)
- hair_to_particle(keys + 3, hkey[1] + 1);
- else
- hair_to_particle(keys + 3, hkey[1]);
- }
- }
-
- dfra = keys[2].time - keys[1].time;
-
- keytime = (t - keys[1].time) / dfra;
-
- /* convert velocity to timestep size */
- if(keyed || baked){
- VecMulf(keys[1].vel, dfra / frs_sec);
- VecMulf(keys[2].vel, dfra / frs_sec);
- }
-
- /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/
- psys_interpolate_particle((keyed || baked) ? -1 /* signal for cubic interpolation */
- : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
- ,keys, keytime, &result, 0);
-
- /* the velocity needs to be converted back from cubic interpolation */
- if(keyed || baked){
- VecMulf(result.vel, frs_sec / dfra);
- }
- else if(soft==NULL) { /* softbody and keyed are allready in global space */
+ /* keyed, baked and softbody are allready in global space */
+ if(!keyed && !baked && !soft) {
Mat4MulVecfl(hairmat, result.co);
}
@@ -2678,8 +2749,9 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
VECCOPY(ca->col, col);
}
}
+
- /*--modify paths--*/
+ /*--modify paths and calculate rotation & velocity--*/
VecSubf(vec,(cache[i]+1)->co,cache[i]->co);
length = VecLength(vec);
@@ -2708,12 +2780,18 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
float cosangle, angle, tangent[3], normal[3], q[4];
if(k == 1) {
+ /* calculate initial tangent for incremental rotations */
VECSUB(tangent, ca->co, (ca - 1)->co);
-
- vectoquat(tangent, OB_POSX, OB_POSZ, (ca-1)->rot);
-
VECCOPY(prev_tangent, tangent);
Normalize(prev_tangent);
+
+ /* First rotation is based on emitting face orientation. */
+ /* This is way better than having flipping rotations resulting */
+ /* from using a global axis as a rotation pole (vec_to_quat()). */
+ /* It's not an ideal solution though since it disregards the */
+ /* initial tangent, but taking that in to account will allow */
+ /* the possibility of flipping again. -jahka */
+ Mat3ToQuat_is_ok(rotmat, (ca-1)->rot);
}
else {
VECSUB(tangent, ca->co, (ca - 1)->co);
@@ -2780,15 +2858,6 @@ void copy_particle_key(ParticleKey *to, ParticleKey *from, int time){
memcpy(to,from,sizeof(ParticleKey));
to->time=to_time;
}
- /*
- VECCOPY(to->co,from->co);
- VECCOPY(to->vel,from->vel);
- QUATCOPY(to->rot,from->rot);
- if(time)
- to->time=from->time;
- to->flag=from->flag;
- to->sbw=from->sbw;
- */
}
void psys_get_from_key(ParticleKey *key, float *loc, float *vel, float *rot, float *time){
if(loc) VECCOPY(loc,key->co);
@@ -3017,8 +3086,6 @@ static void default_particle_settings(ParticleSettings *part)
part->totpart= 1000;
part->grid_res= 10;
part->timetweak= 1.0;
- part->keyed_time= 0.5;
- //part->userjit;
part->integrator= PART_INT_MIDPOINT;
part->phystype= PART_PHYS_NEWTON;
@@ -3032,7 +3099,6 @@ static void default_particle_settings(ParticleSettings *part)
part->reactevent= PART_EVENT_DEATH;
part->disp=100;
part->from= PART_FROM_FACE;
- part->length= 1.0;
part->nbetween= 4;
part->boidneighbours= 5;
@@ -3059,10 +3125,15 @@ static void default_particle_settings(ParticleSettings *part)
part->rough2_size=1.0;
part->rough_end_shape=1.0;
+ part->clength=1.0f;
+ part->clength_thres=0.0f;
+
part->draw_line[0]=0.5;
part->path_start = 0.0f;
part->path_end = 1.0f;
+ part->keyed_loops = 1;
+
part->banking=1.0;
part->max_bank=1.0;
@@ -3480,7 +3551,7 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra,
}
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex)
{
- ptex->length=part->length*(1.0f - part->randlength*cpa->rand[0]);
+ ptex->length= 1.0f - part->randlength*cpa->rand[0];
ptex->clump=1.0;
ptex->kink=1.0;
ptex->rough1= 1.0;
@@ -3489,6 +3560,8 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
ptex->exist= 1.0;
ptex->effector= 1.0;
+ ptex->length*= part->clength_thres < cpa->rand[1] ? part->clength : 1.0f;
+
get_cpa_texture(ctx->dm,ctx->ma,cpa_num,cpa_fuv,orco,ptex,
MAP_PA_DENS|MAP_PA_LENGTH|MAP_PA_CLUMP|MAP_PA_KINK|MAP_PA_ROUGH);
@@ -3511,7 +3584,7 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
if(ctx->vg_effector)
ptex->effector*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_effector);
}
-static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, ParticleKey *state, float t)
+static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, float mat[4][4], ParticleKey *state, float t)
{
int guided = 0;
@@ -3528,13 +3601,13 @@ static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, P
}
if(part->rough1 != 0.0 && ptex->rough1 != 0.0)
- do_rough(orco, t, ptex->rough1*part->rough1, part->rough1_size, 0.0, state);
+ do_rough(orco, mat, t, ptex->rough1*part->rough1, part->rough1_size, 0.0, state);
if(part->rough2 != 0.0 && ptex->rough2 != 0.0)
- do_rough(cpa->rand, t, ptex->rough2*part->rough2, part->rough2_size, part->rough2_thres, state);
+ do_rough(cpa->rand, mat, t, ptex->rough2*part->rough2, part->rough2_size, part->rough2_thres, state);
if(part->rough_end != 0.0 && ptex->roughe != 0.0)
- do_rough_end(cpa->rand, t, ptex->roughe*part->rough_end, part->rough_end_shape, state, par);
+ do_rough_end(cpa->rand, mat, t, ptex->roughe*part->rough_end, part->rough_end_shape, state);
}
/* get's hair (or keyed) particles state at the "path time" specified in state->time */
void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, int p, ParticleKey *state, int vel)
@@ -3549,8 +3622,9 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
HairKey *hkey[2] = {NULL, NULL};
ParticleKey *par=0, keys[4], tstate;
ParticleThreadContext ctx; /* fake thread context for child modifiers */
+ ParticleInterpolationData pind;
- float t, real_t, dfra, keytime, frs_sec = scene->r.frs_sec;
+ float t, frs_sec = scene->r.frs_sec;
float co[3], orco[3];
float hairmat[4][4];
int totparent = 0;
@@ -3558,7 +3632,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
int totchild = psys->totchild;
short between = 0, edit = 0;
- int keyed = psys->flag & PSYS_KEYED;
+ int keyed = part->phystype & PART_PHYS_KEYED && psys->flag & PSYS_KEYED;
int cached = !keyed && part->type != PART_HAIR;
float *cpa_fuv; int cpa_num; short cpa_from;
@@ -3580,88 +3654,14 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
key_from_object(pa->stick_ob,state);
return;
}
-
- if(keyed) {
- kkey[0] = pa->keys;
- kkey[1] = kkey[0] + 1;
- if(state->time < 0.0f)
- real_t = -state->time;
- else
- real_t = kkey[0]->time + t * (kkey[0][pa->totkey-1].time - kkey[0]->time);
- }
- else if(cached) {
- get_pointcache_keys_for_time(psys, -1, 0.0f, NULL, NULL);
- }
- else {
- hkey[0] = pa->hair;
- hkey[1] = pa->hair + 1;
-
- if(state->time < 0.0f)
- real_t = -state->time;
- else
- real_t = hkey[0]->time + t * (hkey[0][pa->totkey-1].time - hkey[0]->time);
- }
-
- if(keyed) {
- while(kkey[1]->time < real_t) {
- kkey[1]++;
- }
- kkey[0] = kkey[1] - 1;
-
- memcpy(keys + 1, kkey[0], sizeof(ParticleKey));
- memcpy(keys + 2, kkey[1], sizeof(ParticleKey));
- }
- else if(cached) {
- if(state->time < 0.0f) /* flag for time in frames */
- real_t = -state->time;
- else
- real_t = pa->time + t * (pa->dietime - pa->time);
-
- get_pointcache_keys_for_time(psys, p, real_t, keys+1, keys+2);
- }
- else {
- while(hkey[1]->time < real_t)
- hkey[1]++;
-
- hkey[0] = hkey[1] - 1;
-
- hair_to_particle(keys + 1, hkey[0]);
- hair_to_particle(keys + 2, hkey[1]);
- }
+ pind.keyed = keyed;
+ pind.cached = cached;
+ pind.soft = NULL;
+ init_particle_interpolation(ob, psys, pa, &pind);
+ do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, state);
if(!keyed && !cached) {
- if(hkey[0] != pa->hair)
- hair_to_particle(keys, hkey[0] - 1);
- else
- hair_to_particle(keys, hkey[0]);
-
- if(hkey[1] != pa->hair + pa->totkey - 1)
- hair_to_particle(keys + 3, hkey[1] + 1);
- else
- hair_to_particle(keys + 3, hkey[1]);
- }
-
- dfra = keys[2].time - keys[1].time;
-
- keytime = (real_t - keys[1].time) / dfra;
-
- /* convert velocity to timestep size */
- if(keyed || cached){
- VecMulf(keys[1].vel, dfra / frs_sec);
- VecMulf(keys[2].vel, dfra / frs_sec);
- QuatInterpol(state->rot,keys[1].rot,keys[2].rot,keytime);
- }
-
- psys_interpolate_particle((keyed || cached) ? -1 /* signal for cubic interpolation */
- : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
- ,keys, keytime, state, 1);
-
- /* the velocity needs to be converted back from cubic interpolation */
- if(keyed || cached){
- VecMulf(state->vel, frs_sec / dfra);
- }
- else {
if((pa->flag & PARS_REKEY)==0) {
psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat);
Mat4MulVecfl(hairmat, state->co);
@@ -3709,8 +3709,6 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
cpa_num=cpa->num;
foffset= cpa->foffset;
- if(part->childtype == PART_CHILD_FACES)
- foffset = -(2.0f + part->childspread);
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
@@ -3721,11 +3719,14 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
//Mat4MulVecfl(ob->obmat,cpa_1st);
+ pa = psys->particles + cpa->parent;
+
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+
pa=0;
}
else{
/* get the parent state */
-
keys->time = state->time;
psys_get_particle_on_path(scene, ob, psys, cpa->parent, keys,1);
@@ -3737,6 +3738,8 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
cpa_fuv=pa->fuv;
psys_particle_on_emitter(psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,0,0,0,orco,0);
+
+ psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
}
/* correct child ipo timing */
@@ -3785,7 +3788,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
copy_particle_key(&tstate, state, 1);
/* apply different deformations to the child path */
- do_child_modifiers(scene, ob, psys, part, &ptex, par, par->rot, cpa, orco, state, t);
+ do_child_modifiers(scene, ob, psys, part, &ptex, par, par->rot, cpa, orco, hairmat, state, t);
/* try to estimate correct velocity */
if(vel){
@@ -3856,7 +3859,7 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy
state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]);
}
else
- state->time= (cfra-pa->time)/(pa->dietime-pa->time);
+ state->time= -cfra;
psys_get_particle_on_path(scene, ob, psys, p, state,1);
return 1;
@@ -3893,57 +3896,55 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy
calc_latt_deform(psys->lattice, state->co,1.0f);
}
else{
- if (pa) { /* TODO PARTICLE - should this ever be NULL? - Campbell */
- if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED))
- copy_particle_key(state, &pa->state, 1);
- else if(pa->prev_state.time==state->time)
- copy_particle_key(state, &pa->prev_state, 1);
- else {
- /* let's interpolate to try to be as accurate as possible */
- if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) {
- ParticleKey keys[4];
- float dfra, keytime, frs_sec = scene->r.frs_sec;
+ if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED))
+ copy_particle_key(state, &pa->state, 1);
+ else if(pa->prev_state.time==state->time)
+ copy_particle_key(state, &pa->prev_state, 1);
+ else {
+ /* let's interpolate to try to be as accurate as possible */
+ if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) {
+ ParticleKey keys[4];
+ float dfra, keytime, frs_sec = scene->r.frs_sec;
- if(pa->prev_state.time >= pa->state.time) {
- /* prev_state is wrong so let's not use it, this can happen at frame 1 or particle birth */
- copy_particle_key(state, &pa->state, 1);
+ if(pa->prev_state.time >= pa->state.time) {
+ /* prev_state is wrong so let's not use it, this can happen at frame 1 or particle birth */
+ copy_particle_key(state, &pa->state, 1);
- VECADDFAC(state->co, state->co, state->vel, (state->time-pa->state.time)/frs_sec);
- }
- else {
- copy_particle_key(keys+1, &pa->prev_state, 1);
- copy_particle_key(keys+2, &pa->state, 1);
+ VECADDFAC(state->co, state->co, state->vel, (state->time-pa->state.time)/frs_sec);
+ }
+ else {
+ copy_particle_key(keys+1, &pa->prev_state, 1);
+ copy_particle_key(keys+2, &pa->state, 1);
- dfra = keys[2].time - keys[1].time;
+ dfra = keys[2].time - keys[1].time;
- keytime = (state->time - keys[1].time) / dfra;
+ keytime = (state->time - keys[1].time) / dfra;
- /* convert velocity to timestep size */
- VecMulf(keys[1].vel, dfra / frs_sec);
- VecMulf(keys[2].vel, dfra / frs_sec);
-
- psys_interpolate_particle(-1, keys, keytime, state, 1);
-
- /* convert back to real velocity */
- VecMulf(state->vel, frs_sec / dfra);
+ /* convert velocity to timestep size */
+ VecMulf(keys[1].vel, dfra / frs_sec);
+ VecMulf(keys[2].vel, dfra / frs_sec);
+
+ psys_interpolate_particle(-1, keys, keytime, state, 1);
+
+ /* convert back to real velocity */
+ VecMulf(state->vel, frs_sec / dfra);
- VecLerpf(state->ave, keys[1].ave, keys[2].ave, keytime);
- QuatInterpol(state->rot, keys[1].rot, keys[2].rot, keytime);
- }
- }
- else {
- /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */
- copy_particle_key(state, &pa->state, 0);
+ VecLerpf(state->ave, keys[1].ave, keys[2].ave, keytime);
+ QuatInterpol(state->rot, keys[1].rot, keys[2].rot, keytime);
}
}
-
- if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){
- key_from_object(pa->stick_ob,state);
+ else {
+ /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */
+ copy_particle_key(state, &pa->state, 0);
}
+ }
- if(psys->lattice)
- calc_latt_deform(psys->lattice, state->co,1.0f);
+ if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){
+ key_from_object(pa->stick_ob,state);
}
+
+ if(psys->lattice)
+ calc_latt_deform(psys->lattice, state->co,1.0f);
}
return 1;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 07e0e82a86d..56ca3e8e22b 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -111,10 +111,7 @@ static int get_current_display_percentage(ParticleSystem *psys)
return 100;
if(part->phystype==PART_PHYS_KEYED){
- if(psys->flag & PSYS_FIRST_KEYED)
- return psys->part->disp;
- else
- return 100;
+ return psys->part->disp;
}
else
return psys->part->disp;
@@ -199,7 +196,7 @@ static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart)
if(psys->particles->keys)
MEM_freeN(psys->particles->keys);
- for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++)
+ for(i=0, pa=newpars; i<totsaved; i++, pa++)
if(pa->keys) {
pa->keys= NULL;
pa->totkey= 0;
@@ -1976,64 +1973,59 @@ static void reset_all_particles(Scene *scene, Object *ob, ParticleSystem *psys,
/************************************************/
/* Keyed particles */
/************************************************/
-/* a bit of an unintuitive function :) counts objects in a keyed chain and returns 1 if some of them were selected (used in drawing) */
-int psys_count_keyed_targets(Object *ob, ParticleSystem *psys)
+/* Counts valid keyed targets */
+void psys_count_keyed_targets(Object *ob, ParticleSystem *psys)
{
- ParticleSystem *kpsys=psys,*tpsys;
- ParticleSettings *tpart;
- Object *kob=ob,*tob;
- int select=ob->flag&SELECT;
- short totkeyed=0;
- Base *base;
-
- ListBase lb;
- lb.first=lb.last=0;
-
- tob=psys->keyed_ob;
- while(tob){
- if((tpsys=BLI_findlink(&tob->particlesystem,kpsys->keyed_psys-1))){
- tpart=tpsys->part;
-
- if(tpart->phystype==PART_PHYS_KEYED){
- if(lb.first){
- for(base=lb.first;base;base=base->next){
- if(tob==base->object){
- fprintf(stderr,"Error: loop in keyed chain!\n");
- BLI_freelistN(&lb);
- return select;
- }
- }
- }
- base=MEM_callocN(sizeof(Base), "keyed base");
- base->object=tob;
- BLI_addtail(&lb,base);
-
- if(tob->flag&SELECT)
- select++;
- kob=tob;
- kpsys=tpsys;
- tob=tpsys->keyed_ob;
- totkeyed++;
+ ParticleSystem *kpsys;
+ KeyedParticleTarget *kpt = psys->keyed_targets.first;
+ int psys_num = BLI_findindex(&ob->particlesystem, psys);
+ int keys_valid = 1;
+ psys->totkeyed = 0;
+
+ for(; kpt; kpt=kpt->next) {
+ kpsys = NULL;
+ if(kpt->ob==ob || kpt->ob==NULL) {
+ if(kpt->psys >= psys_num)
+ kpsys = BLI_findlink(&ob->particlesystem, kpt->psys-1);
+
+ if(kpsys && kpsys->totpart) {
+ kpt->flag |= KEYED_TARGET_VALID;
+ psys->totkeyed += keys_valid;
+ if(psys->flag & PSYS_KEYED_TIMING && kpt->duration != 0.0f)
+ psys->totkeyed += 1;
}
- else{
- tob=0;
- totkeyed++;
+ else {
+ kpt->flag &= ~KEYED_TARGET_VALID;
+ keys_valid = 0;
+ }
+ }
+ else {
+ if(kpt->ob)
+ kpsys = BLI_findlink(&kpt->ob->particlesystem, kpt->psys-1);
+
+ if(kpsys && kpsys->totpart) {
+ kpt->flag |= KEYED_TARGET_VALID;
+ psys->totkeyed += keys_valid;
+ if(psys->flag & PSYS_KEYED_TIMING && kpt->duration != 0.0f)
+ psys->totkeyed += 1;
+ }
+ else {
+ kpt->flag &= ~KEYED_TARGET_VALID;
+ keys_valid = 0;
}
}
- else
- tob=0;
}
- psys->totkeyed=totkeyed;
- BLI_freelistN(&lb);
- return select;
+
+ psys->totkeyed *= psys->flag & PSYS_KEYED_TIMING ? 1 : psys->part->keyed_loops;
}
static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys)
{
Object *kob = ob;
ParticleSystem *kpsys = psys;
+ KeyedParticleTarget *kpt;
ParticleData *pa;
- int totpart = psys->totpart, i, k, totkeys = psys->totkeyed + 1;
+ int totpart = psys->totpart, i, k, totkeys = psys->totkeyed;
float prevtime, nexttime, keyedtime;
/* no proper targets so let's clear and bail out */
@@ -2046,7 +2038,7 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys)
if(totpart && psys->particles->totkey != totkeys) {
free_keyed_keys(psys);
- psys->particles->keys = MEM_callocN(psys->totpart*totkeys*sizeof(ParticleKey), "Keyed keys");
+ psys->particles->keys = MEM_callocN(totpart*totkeys*sizeof(ParticleKey), "Keyed keys");
psys->particles->totkey = totkeys;
for(i=1, pa=psys->particles+1; i<totpart; i++,pa++){
@@ -2057,32 +2049,36 @@ static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys)
psys->flag &= ~PSYS_KEYED;
+
+ kpt = psys->keyed_targets.first;
for(k=0; k<totkeys; k++) {
+ if(kpt->ob)
+ kpsys = BLI_findlink(&kpt->ob->particlesystem, kpt->psys - 1);
+ else
+ kpsys = BLI_findlink(&ob->particlesystem, kpt->psys - 1);
+
for(i=0,pa=psys->particles; i<totpart; i++, pa++) {
(pa->keys + k)->time = -1.0; /* use current time */
- if(kpsys->totpart > 0)
- psys_get_particle_state(scene, kob, kpsys, i%kpsys->totpart, pa->keys + k, 1);
+ psys_get_particle_state(scene, kpt->ob, kpsys, i%kpsys->totpart, pa->keys + k, 1);
- if(k==0)
- pa->keys->time = pa->time;
- else if(k==totkeys-1)
- (pa->keys + k)->time = pa->time + pa->lifetime;
- else{
- if(psys->flag & PSYS_KEYED_TIME){
- prevtime = (pa->keys + k - 1)->time;
- nexttime = pa->time + pa->lifetime;
- keyedtime = kpsys->part->keyed_time;
- (pa->keys + k)->time = (1.0f - keyedtime) * prevtime + keyedtime * nexttime;
+ if(psys->flag & PSYS_KEYED_TIMING){
+ (pa->keys+k)->time = pa->time + kpt->time;
+ if(kpt->duration != 0.0f && k+1 < totkeys) {
+ copy_particle_key(pa->keys+k+1, pa->keys+k, 1);
+ (pa->keys+k+1)->time = pa->time + kpt->time + kpt->duration;
}
- else
- (pa->keys+k)->time = pa->time + (float)k / (float)(totkeys - 1) * pa->lifetime;
}
+ else if(totkeys > 1)
+ (pa->keys+k)->time = pa->time + (float)k / (float)(totkeys - 1) * pa->lifetime;
+ else
+ pa->keys->time = pa->time;
}
- if(kpsys->keyed_ob){
- kob = kpsys->keyed_ob;
- kpsys = BLI_findlink(&kob->particlesystem, kpsys->keyed_psys - 1);
- }
+
+ if(psys->flag & PSYS_KEYED_TIMING && kpt->duration!=0.0f)
+ k++;
+
+ kpt = (kpt->next && kpt->next->flag & KEYED_TARGET_VALID) ? kpt = kpt->next : psys->keyed_targets.first;
}
psys->flag |= PSYS_KEYED;
@@ -2198,6 +2194,60 @@ void psys_get_reactor_target(Object *ob, ParticleSystem *psys, Object **target_o
/************************************************/
/* Point Cache */
/************************************************/
+void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys)
+{
+ PointCache *cache = psys->pointcache;
+ PTCacheFile *pf = NULL;
+ PTCacheMem *pm = NULL;
+ PTCacheID pid;
+ int cfra, sfra = cache->startframe, efra = cache->endframe;
+ int totelem = psys->totpart;
+ int float_count = sizeof(ParticleKey) / sizeof(float);
+ int tot = totelem * float_count;
+
+ if((cache->flag & PTCACHE_DISK_CACHE)==0 || cache->mem_cache.first)
+ return;
+
+ BKE_ptcache_id_from_particles(&pid, ob, psys);
+
+ for(cfra=sfra; cfra <= efra; cfra++) {
+ pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, cfra);
+
+ if(pf) {
+ pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache temp mem");
+ pm->data = MEM_callocN(sizeof(float)*tot, "Pointcache temp mem data");
+
+ if(fread(pm->data, sizeof(float), tot, pf->fp)!= tot) {
+ printf("Error reading from disk cache\n");
+
+ MEM_freeN(pm->data);
+ MEM_freeN(pm);
+ BKE_ptcache_file_close(pf);
+ return;
+ }
+
+ pm->frame = cfra;
+ pm->totpoint = totelem;
+
+ BLI_addtail(&cache->mem_cache, pm);
+
+ BKE_ptcache_file_close(pf);
+ }
+ }
+}
+void psys_clear_temp_pointcache(ParticleSystem *psys)
+{
+ PTCacheMem *pm = psys->pointcache->mem_cache.first;
+
+ if((psys->pointcache->flag & PTCACHE_DISK_CACHE)==0)
+ return;
+
+ for(; pm; pm=pm->next) {
+ MEM_freeN(pm->data);
+ }
+
+ BLI_freelistN(&psys->pointcache->mem_cache);
+}
void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra)
{
ParticleSettings *part = psys->part;
@@ -3912,61 +3962,6 @@ static void boid_body(Scene *scene, BoidVecFunc *bvf, ParticleData *pa, Particle
if(part->flag & PART_BOIDS_2D){
pa->state.vel[2]=0.0;
pa->state.co[2]=part->groundz;
-
- if(psys->keyed_ob && (psys->keyed_ob->type == OB_MESH)){
- Object *zob=psys->keyed_ob;
- int min_face;
- float co1[3],co2[3],min_d=2.0,min_w[4],imat[4][4];
- VECCOPY(co1,pa->state.co);
- VECCOPY(co2,pa->state.co);
-
- co1[2]=1000.0f;
- co2[2]=-1000.0f;
-
- Mat4Invert(imat,zob->obmat);
- Mat4MulVecfl(imat,co1);
- Mat4MulVecfl(imat,co2);
-
- if(psys_intersect_dm(scene,zob,0,0,co1,co2,&min_d,&min_face,min_w,0,0,0,0)){
- DerivedMesh *dm;
- MFace *mface;
- MVert *mvert;
- float loc[3],nor[3],q1[4];
-
- psys_disable_all(zob);
- dm=mesh_get_derived_final(scene, zob, 0);
- psys_enable_all(zob);
-
- mface=dm->getFaceDataArray(dm,CD_MFACE);
- mface+=min_face;
- mvert=dm->getVertDataArray(dm,CD_MVERT);
-
- /* get deflection point & normal */
- psys_interpolate_face(mvert,mface,0,0,min_w,loc,nor,0,0,0,0);
-
- Mat4MulVecfl(zob->obmat,loc);
- Mat4Mul3Vecfl(zob->obmat,nor);
-
- Normalize(nor);
-
- VECCOPY(pa->state.co,loc);
-
- zvec[2]=1.0;
-
- Crossf(loc,zvec,nor);
-
- bank=VecLength(loc);
- if(bank>0.0){
- bank=saasin(bank);
-
- VecRotToQuat(loc,bank,q);
-
- QUATCOPY(q1,pa->state.rot);
-
- QuatMul(pa->state.rot,q,q1);
- }
- }
- }
}
length=bvf->Length(pa->state.vel);
@@ -4238,7 +4233,7 @@ static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModif
if((psys->part->childtype && psys->totchild != get_psys_tot_child(scene, psys)) || psys->recalc&PSYS_RECALC_RESET)
alloc=1;
- if(alloc || psys->recalc&PSYS_RECALC_RESET || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT)))
+ if(alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT)))
distr=1;
if(distr){
@@ -4416,12 +4411,15 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps
MEM_freeN(vg_size);
}
-void psys_changed_type(ParticleSystem *psys)
+static void psys_changed_type(Object *ob, ParticleSystem *psys)
{
ParticleSettings *part;
+ PTCacheID pid;
part= psys->part;
+ BKE_ptcache_id_from_particles(&pid, ob, psys);
+
/* system type has changed so set sensible defaults and clear non applicable flags */
if(part->from == PART_FROM_PARTICLE) {
if(part->type != PART_REACTOR)
@@ -4430,7 +4428,7 @@ void psys_changed_type(ParticleSystem *psys)
part->distr = PART_DISTR_JIT;
}
- if(psys->part->phystype != PART_PHYS_KEYED)
+ if(part->phystype != PART_PHYS_KEYED)
psys->flag &= ~PSYS_KEYED;
if(part->type == PART_HAIR) {
@@ -4442,6 +4440,8 @@ void psys_changed_type(ParticleSystem *psys)
CLAMP(part->path_start, 0.0f, 100.0f);
CLAMP(part->path_end, 0.0f, 100.0f);
+
+ BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
}
else {
free_hair(psys, 1);
@@ -4454,7 +4454,18 @@ void psys_changed_type(ParticleSystem *psys)
psys_reset(psys, PSYS_RESET_ALL);
}
-
+void psys_changed_physics(Object *ob, ParticleSystem *psys)
+{
+ if(ELEM(psys->part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) {
+ PTCacheID pid;
+ BKE_ptcache_id_from_particles(&pid, ob, psys);
+ BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
+ }
+ else {
+ free_keyed_keys(psys);
+ psys->flag &= ~PSYS_KEYED;
+ }
+}
static void particles_fluid_step(Scene *scene, Object *ob, ParticleSystem *psys, int cfra)
{
if(psys->particles){
@@ -4588,6 +4599,8 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
BKE_ptcache_id_from_particles(&pid, ob, psys);
BKE_ptcache_id_time(&pid, scene, 0.0f, &startframe, &endframe, NULL);
+ psys_clear_temp_pointcache(psys);
+
/* update ipo's */
#if 0 // XXX old animation system
if((part->flag & PART_ABS_TIME) && part->ipo) {
@@ -4736,7 +4749,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
if(usecache && psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
write_particles_to_cache(ob, psys, startframe);
- if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED)
+ if(part->phystype==PART_PHYS_KEYED)
psys_count_keyed_targets(ob,psys);
/* initialize vertex groups */
@@ -4783,7 +4796,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
write_particles_to_cache(ob, psys, framenr);
/* for keyed particles the path is allways known so it can be drawn */
- if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED){
+ if(part->phystype==PART_PHYS_KEYED) {
set_keyed_keys(scene, ob, psys);
psys_update_path_cache(scene, ob, psmd, psys,(int)cfra);
}
@@ -4866,7 +4879,9 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
return;
if(psys->recalc & PSYS_RECALC_TYPE)
- psys_changed_type(psys);
+ psys_changed_type(ob, psys);
+ else if(psys->recalc & PSYS_RECALC_PHYS)
+ psys_changed_physics(ob, psys);
/* (re-)create hair */
if(psys->part->type==PART_HAIR && hair_needs_recalc(psys)) {
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 2fe46be7a89..6107510fa47 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -315,8 +315,10 @@ static int ptcache_pid_totelem(PTCacheID *pid)
ParticleSystem *psys = pid->data;
return psys->totpart;
}
- else if(pid->type==PTCACHE_TYPE_CLOTH)
- return 0; // TODO
+ else if(pid->type==PTCACHE_TYPE_CLOTH) {
+ ClothModifierData *clmd = pid->data;
+ return clmd->clothObject->numverts;
+ }
return 0;
}
@@ -429,6 +431,7 @@ int BKE_ptcache_read_cache(PTCacheReader *reader)
if(pf) {
BKE_ptcache_file_close(pf);
+ pf = NULL;
MEM_freeN(data);
}
@@ -523,7 +526,9 @@ int BKE_ptcache_read_cache(PTCacheReader *reader)
if(pf) {
BKE_ptcache_file_close(pf);
+ pf = NULL;
BKE_ptcache_file_close(pf2);
+ pf2 = NULL;
MEM_freeN(data1);
MEM_freeN(data2);
}
@@ -567,10 +572,13 @@ int BKE_ptcache_read_cache(PTCacheReader *reader)
if(pf) {
BKE_ptcache_file_close(pf);
+ pf = NULL;
MEM_freeN(data);
}
- if(pf2)
+ if(pf2) {
BKE_ptcache_file_close(pf2);
+ pf = NULL;
+ }
ret = PTCACHE_READ_OLD;
}
@@ -602,13 +610,15 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer)
PTCacheFile *pf= NULL;
int elemsize = ptcache_pid_elemsize(writer->pid);
int i, incr = elemsize / sizeof(float);
- int add = 0, overwrite = 0, ocfra;
+ int add = 0, overwrite = 0;
float temp[14];
if(writer->totelem == 0 || writer->cfra <= 0)
return 0;
if(cache->flag & PTCACHE_DISK_CACHE) {
+ int cfra = cache->endframe;
+
/* allways start from scratch on the first frame */
if(writer->cfra == cache->startframe) {
BKE_ptcache_id_clear(writer->pid, PTCACHE_CLEAR_ALL, writer->cfra);
@@ -616,7 +626,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer)
add = 1;
}
else {
- int cfra = cache->endframe;
+ int ocfra;
/* find last cached frame */
while(cfra > cache->startframe && !BKE_ptcache_id_exist(writer->pid, cfra))
cfra--;
@@ -626,7 +636,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer)
while(ocfra > cache->startframe && !BKE_ptcache_id_exist(writer->pid, ocfra))
ocfra--;
- if(writer->cfra > cfra) {
+ if(cfra >= cache->startframe && writer->cfra > cfra) {
if(ocfra >= cache->startframe && cfra - ocfra < cache->step)
overwrite = 1;
else
@@ -636,7 +646,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer)
if(add || overwrite) {
if(overwrite)
- BKE_ptcache_id_clear(writer->pid, PTCACHE_CLEAR_FRAME, ocfra);
+ BKE_ptcache_id_clear(writer->pid, PTCACHE_CLEAR_FRAME, cfra);
pf = BKE_ptcache_file_open(writer->pid, PTCACHE_FILE_WRITE, writer->cfra);
if(!pf)
@@ -665,7 +675,7 @@ int BKE_ptcache_write_cache(PTCacheWriter *writer)
pm2 = cache->mem_cache.last;
if(pm2 && writer->cfra > pm2->frame) {
- if(pm2 && pm2->prev && pm2->frame - pm2->prev->frame < cache->step)
+ if(pm2->prev && pm2->frame - pm2->prev->frame < cache->step)
overwrite = 1;
else
add = 1;
@@ -1102,6 +1112,10 @@ PointCache *BKE_ptcache_copy(PointCache *cache)
ncache= MEM_dupallocN(cache);
+ /* hmm, should these be copied over instead? */
+ ncache->mem_cache.first = NULL;
+ ncache->mem_cache.last = NULL;
+
ncache->flag= 0;
ncache->simframe= 0;
@@ -1211,8 +1225,9 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker)
cache = pid->cache;
if((cache->flag & PTCACHE_BAKED)==0) {
if(pid->type==PTCACHE_TYPE_PARTICLES) {
- /* skip hair particles */
- if(((ParticleSystem*)pid->data)->part->type == PART_HAIR)
+ ParticleSystem *psys = (ParticleSystem*)pid->data;
+ /* skip hair & keyed particles */
+ if(psys->part->type == PART_HAIR || psys->part->phystype == PART_PHYS_KEYED)
continue;
psys_get_pointcache_start_end(scene, pid->data, &cache->startframe, &cache->endframe);
@@ -1310,6 +1325,7 @@ void BKE_ptcache_toggle_disk_cache(PTCacheID *pid) {
if (!G.relbase_valid){
cache->flag &= ~PTCACHE_DISK_CACHE;
+ printf("File must be saved before using disk cache!\n");
return;
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 479fa760423..c2b19a804ee 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2968,6 +2968,9 @@ static void direct_link_pointcache(FileData *fd, PointCache *cache)
for(; pm; pm=pm->next)
pm->data = newdataadr(fd, pm->data);
}
+ else
+ cache->mem_cache.first = cache->mem_cache.last = NULL;
+
cache->flag &= ~(PTCACHE_SIMULATION_VALID|PTCACHE_BAKE_EDIT_ACTIVE);
cache->simframe= 0;
}
@@ -3011,12 +3014,18 @@ static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase
psys->part = newlibadr_us(fd, id->lib, psys->part);
if(psys->part) {
+ KeyedParticleTarget *kpt = psys->keyed_targets.first;
+
+ for(; kpt; kpt=kpt->next)
+ kpt->ob=newlibadr(fd, id->lib, kpt->ob);
+
psys->target_ob = newlibadr(fd, id->lib, psys->target_ob);
- psys->keyed_ob = newlibadr(fd, id->lib, psys->keyed_ob);
for(a=0,pa=psys->particles; a<psys->totpart; a++,pa++){
pa->stick_ob=newlibadr(fd, id->lib, pa->stick_ob);
}
+
+
}
else {
/* particle modifier must be removed before particle system */
@@ -3066,6 +3075,8 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
direct_link_pointcache(fd, sb->pointcache);
}
+ link_list(fd, &psys->keyed_targets);
+
psys->edit = 0;
psys->free_edit = NULL;
psys->pathcache = 0;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 4b52da83019..65a4a355717 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -589,6 +589,7 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase)
static void write_particlesystems(WriteData *wd, ListBase *particles)
{
ParticleSystem *psys= particles->first;
+ KeyedParticleTarget *kpt;
int a;
for(; psys; psys=psys->next) {
@@ -604,6 +605,10 @@ static void write_particlesystems(WriteData *wd, ListBase *particles)
writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair);
}
}
+ kpt = psys->keyed_targets.first;
+ for(; kpt; kpt=kpt->next)
+ writestruct(wd, DATA, "KeyedParticleTarget", 1, kpt);
+
if(psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild ,psys->child);
writestruct(wd, DATA, "SoftBody", 1, psys->soft);
if(psys->soft) write_pointcaches(wd, psys->soft->pointcache, PTCACHE_WRITE_PSYS);
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index 65c2976d57c..f16a232f26d 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -75,6 +75,10 @@ void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);
void OBJECT_OT_particle_system_remove(struct wmOperatorType *ot);
void PARTICLE_OT_new(struct wmOperatorType *ot);
+void PARTICLE_OT_new_keyed_target(struct wmOperatorType *ot);
+void PARTICLE_OT_remove_keyed_target(struct wmOperatorType *ot);
+void PARTICLE_OT_keyed_target_move_up(struct wmOperatorType *ot);
+void PARTICLE_OT_keyed_target_move_down(struct wmOperatorType *ot);
#endif /* ED_BUTTONS_INTERN_H */
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index 66b380ab413..6fb52c61131 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -49,6 +49,7 @@
#include "BKE_world.h"
#include "BLI_editVert.h"
+#include "BLI_listbase.h"
#include "RNA_access.h"
@@ -473,33 +474,32 @@ static int new_particle_settings_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Main *bmain= CTX_data_main(C);
- ParticleSettings *part= CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings).data;
+ ParticleSystem *psys;
+ ParticleSettings *part = NULL;
Object *ob;
PointerRNA ptr;
+ ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
+
+ psys = ptr.data;
+
/* add or copy particle setting */
- if(part)
- part= psys_copy_settings(part);
+ if(psys->part)
+ part= psys_copy_settings(psys->part);
else
part= psys_new_settings("PSys", bmain);
- /* attempt to assign to material slot */
- ptr= CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
+ ob= ptr.id.data;
- if(ptr.data) {
- ParticleSystem *psys = (ParticleSystem*)ptr.data;
- ob= ptr.id.data;
-
- if(psys->part)
- psys->part->id.us--;
+ if(psys->part)
+ psys->part->id.us--;
- psys->part = part;
+ psys->part = part;
- DAG_scene_sort(scene);
- DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+ DAG_scene_sort(scene);
+ DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
- }
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
return OPERATOR_FINISHED;
}
@@ -517,3 +517,175 @@ void PARTICLE_OT_new(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
+/********************** keyed particle target operators *********************/
+
+static int new_keyed_particle_target_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
+ ParticleSystem *psys= ptr.data;
+ Object *ob = ptr.id.data;
+
+ KeyedParticleTarget *kpt;
+
+ if(!psys)
+ return OPERATOR_CANCELLED;
+
+ kpt = psys->keyed_targets.first;
+ for(; kpt; kpt=kpt->next)
+ kpt->flag &= ~KEYED_TARGET_CURRENT;
+
+ kpt = MEM_callocN(sizeof(KeyedParticleTarget), "keyed particle target");
+
+ kpt->flag |= KEYED_TARGET_CURRENT;
+ kpt->psys = 1;
+
+ BLI_addtail(&psys->keyed_targets, kpt);
+
+ DAG_scene_sort(scene);
+ DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_new_keyed_target(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "New Keyed Particle Target";
+ ot->idname= "PARTICLE_OT_new_keyed_target";
+
+ /* api callbacks */
+ ot->exec= new_keyed_particle_target_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int remove_keyed_particle_target_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
+ ParticleSystem *psys= ptr.data;
+ Object *ob = ptr.id.data;
+
+ KeyedParticleTarget *kpt;
+
+ if(!psys)
+ return OPERATOR_CANCELLED;
+
+ kpt = psys->keyed_targets.first;
+ for(; kpt; kpt=kpt->next) {
+ if(kpt->flag & KEYED_TARGET_CURRENT) {
+ BLI_remlink(&psys->keyed_targets, kpt);
+ MEM_freeN(kpt);
+ break;
+ }
+
+ }
+ kpt = psys->keyed_targets.last;
+
+ if(kpt)
+ kpt->flag |= KEYED_TARGET_CURRENT;
+
+ DAG_scene_sort(scene);
+ DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_remove_keyed_target(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Remove Keyed Particle Target";
+ ot->idname= "PARTICLE_OT_remove_keyed_target";
+
+ /* api callbacks */
+ ot->exec= remove_keyed_particle_target_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/************************ move up modifier operator *********************/
+
+static int keyed_target_move_up_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
+ ParticleSystem *psys= ptr.data;
+ Object *ob = ptr.id.data;
+ KeyedParticleTarget *kpt;
+
+ if(!psys)
+ return OPERATOR_CANCELLED;
+
+ kpt = psys->keyed_targets.first;
+ for(; kpt; kpt=kpt->next) {
+ if(kpt->flag & KEYED_TARGET_CURRENT && kpt->prev) {
+ BLI_remlink(&psys->keyed_targets, kpt);
+ BLI_insertlink(&psys->keyed_targets, kpt->prev->prev, kpt);
+
+ DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+ break;
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_keyed_target_move_up(wmOperatorType *ot)
+{
+ ot->name= "Move Up Keyed Target";
+ ot->description= "Move keyed particle target up in the list.";
+ ot->idname= "PARTICLE_OT_keyed_target_move_up";
+
+ ot->exec= keyed_target_move_up_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/************************ move down modifier operator *********************/
+
+static int keyed_target_move_down_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
+ ParticleSystem *psys= ptr.data;
+ Object *ob = ptr.id.data;
+ KeyedParticleTarget *kpt;
+
+ if(!psys)
+ return OPERATOR_CANCELLED;
+ kpt = psys->keyed_targets.first;
+ for(; kpt; kpt=kpt->next) {
+ if(kpt->flag & KEYED_TARGET_CURRENT && kpt->next) {
+ BLI_remlink(&psys->keyed_targets, kpt);
+ BLI_insertlink(&psys->keyed_targets, kpt->next, kpt);
+
+ DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+ break;
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_keyed_target_move_down(wmOperatorType *ot)
+{
+ ot->name= "Move Down Keyed Target";
+ ot->description= "Move keyed particle target down in the list.";
+ ot->idname= "PARTICLE_OT_keyed_target_move_down";
+
+ ot->exec= keyed_target_move_down_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index f7be323a4c5..6cdb4dbf93d 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -224,6 +224,10 @@ void buttons_operatortypes(void)
WM_operatortype_append(OBJECT_OT_particle_system_remove);
WM_operatortype_append(PARTICLE_OT_new);
+ WM_operatortype_append(PARTICLE_OT_new_keyed_target);
+ WM_operatortype_append(PARTICLE_OT_remove_keyed_target);
+ WM_operatortype_append(PARTICLE_OT_keyed_target_move_up);
+ WM_operatortype_append(PARTICLE_OT_keyed_target_move_down);
}
void buttons_keymap(struct wmWindowManager *wm)
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index e8749537f5e..f83a0b9686e 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -3161,15 +3161,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
/* 2. */
if(part->phystype==PART_PHYS_KEYED){
- if(psys->flag & PSYS_FIRST_KEYED){
- if(psys->flag&PSYS_KEYED){
- select=psys_count_keyed_targets(ob,psys);
- if(psys->totkeyed==0)
- return;
- }
+ if(psys->flag&PSYS_KEYED){
+ psys_count_keyed_targets(ob,psys);
+ if(psys->totkeyed==0)
+ return;
}
- else
- return;
}
if(select){
@@ -3226,8 +3222,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
else
draw_as = part->draw_as;
- if(part->flag&PART_GLOB_TIME)
- cfra=bsystem_time(scene, 0, (float)CFRA, 0.0f);
+ //if(part->flag&PART_GLOB_TIME)
+ cfra=bsystem_time(scene, 0, (float)CFRA, 0.0f);
if(draw_as==PART_DRAW_PATH && psys->pathcache==NULL)
draw_as=PART_DRAW_DOT;
@@ -3306,8 +3302,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if(draw_as && draw_as!=PART_DRAW_PATH) {
int tot_vec_size = (totpart + totchild) * 3 * sizeof(float);
- if(part->draw_as == PART_DRAW_REND && part->trail_count > 1)
+ if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
tot_vec_size *= part->trail_count;
+ psys_make_temp_pointcache(ob, psys);
+ }
if(draw_as!=PART_DRAW_CIRC) {
switch(draw_as) {
@@ -3361,8 +3359,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
pa_dietime = pa->dietime;
pa_size=pa->size;
- if((part->flag&PART_ABS_TIME)==0){
-#if 0 // XXX old animation system
+#if 0 // XXX old animation system
+ if((part->flag&PART_ABS_TIME)==0){
if(ma && ma->ipo){
IpoCurve *icu;
@@ -3389,8 +3387,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
pa_size = icu->curval;
}
}
-#endif // XXX old animation system
}
+#endif // XXX old animation system
r_tilt = 1.0f + pa->r_ave[0];
r_length = 0.5f * (1.0f + pa->r_ave[1]);
@@ -3400,9 +3398,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
pa_time=psys_get_child_time(psys,cpa,cfra,&pa_birthtime,&pa_dietime);
+#if 0 // XXX old animation system
if((part->flag&PART_ABS_TIME)==0) {
if(ma && ma->ipo){
-#if 0 // XXX old animation system
IpoCurve *icu;
/* correction for lifetime */
@@ -3416,9 +3414,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
else if(icu->adrcode == MA_COL_B)
ma_b = icu->curval;
}
-#endif // XXX old animation system
}
}
+#endif // XXX old animation system
pa_size=psys_get_child_size(psys,cpa,cfra,0);
@@ -3444,7 +3442,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
else if(ct < 0.0f || ct > 1.0f)
continue;
- state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct;
+ state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime));
psys_get_particle_on_path(scene,ob,psys,a,&state,need_v);
if(psys->parent)
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index c793362c223..0b3309bfc0c 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -61,6 +61,14 @@ typedef struct ChildParticle {
float rand[3];
} ChildParticle;
+typedef struct KeyedParticleTarget {
+ struct KeyedParticleTarget *next, *prev;
+ struct Object *ob;
+ int psys;
+ short flag, rt;
+ float time, duration;
+} KeyedParticleTarget;
+
/* Everything that's non dynamic for a particle: */
typedef struct ParticleData {
struct Object *stick_ob;/* object that particle sticks to when dead */
@@ -131,7 +139,7 @@ typedef struct ParticleSettings {
/* general values */
float sta, end, lifetime, randlife;
- float timetweak, jitfac, keyed_time, eff_hair;
+ float timetweak, jitfac, eff_hair;
int totpart, userjit, grid_res;
/* initial velocity factors */
@@ -142,11 +150,11 @@ typedef struct ParticleSettings {
/* global physical properties */
float acc[3], dragfac, brownfac, dampfac;
/* length */
- float length, abslength, randlength;
+ float randlength;
/* children */
int child_nbr, ren_child_nbr;
float parents, childsize, childrandsize;
- float childrad, childflat, childspread;
+ float childrad, childflat, rt;
/* clumping */
float clumpfac, clumppow;
/* kink */
@@ -155,12 +163,16 @@ typedef struct ParticleSettings {
float rough1, rough1_size;
float rough2, rough2_size, rough2_thres;
float rough_end, rough_end_shape;
+ /* length */
+ float clength, clength_thres;
/* branching */
float branch_thres;
/* drawing stuff */
float draw_line[2];
float path_start, path_end;
int trail_count;
+ /* keyed particles */
+ int keyed_loops;
/* boids */
float max_vel, max_lat_acc, max_tan_acc;
@@ -195,17 +207,18 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
struct SoftBody *soft; /* hair softbody */
struct Object *target_ob;
- struct Object *keyed_ob;
struct Object *lattice;
struct Object *parent; /* particles from global space -> parent space */
struct ListBase effectors, reactevents; /* runtime */
+
+ struct ListBase keyed_targets;
float imat[4][4]; /* used for duplicators */
float cfra;
int seed;
int flag, totpart, totchild, totcached, totchildcache, rt;
- short recalc, target_psys, keyed_psys, totkeyed, softflag, bakespace;
+ short recalc, target_psys, totkeyed, softflag, bakespace, rt2;
char bb_uvname[3][32]; /* billboard uv name */
@@ -255,10 +268,10 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
#define PART_ROT_DYN (1<<14) /* dynamic rotation */
#define PART_SIZEMASS (1<<16)
-#define PART_ABS_LENGTH (1<<15)
+//#define PART_KEYED_TIMING (1<<15)
-#define PART_ABS_TIME (1<<17)
-#define PART_GLOB_TIME (1<<18)
+//#define PART_ABS_TIME (1<<17)
+//#define PART_GLOB_TIME (1<<18)
#define PART_BOIDS_2D (1<<19)
@@ -396,14 +409,15 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
#define PSYS_RECALC_RESET 2 /* reset everything including pointcache */
#define PSYS_RECALC_TYPE 4 /* handle system type change */
#define PSYS_RECALC_CHILD 16 /* only child settings changed */
+#define PSYS_RECALC_PHYS 32 /* physics type changed */
/* psys->flag */
#define PSYS_CURRENT 1
//#define PSYS_BAKING 2
//#define PSYS_BAKE_UI 4
-#define PSYS_KEYED_TIME 8
+#define PSYS_KEYED_TIMING 8
#define PSYS_ENABLED 16 /* deprecated */
-#define PSYS_FIRST_KEYED 32
+//#define PSYS_FIRST_KEYED 32
#define PSYS_DRAWING 64
//#define PSYS_SOFT_BAKE 128
#define PSYS_DELETE 256 /* remove particlesystem as soon as possible */
@@ -458,6 +472,10 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
#define BOID_GOAL 6
#define BOID_LEVEL 7
+/* psys->keyed_targets->flag */
+#define KEYED_TARGET_CURRENT 1
+#define KEYED_TARGET_VALID 2
+
//#define PSYS_INTER_CUBIC 0
//#define PSYS_INTER_LINEAR 1
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 3631d83310a..ed1a8052acd 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -221,6 +221,7 @@ extern StructRNA RNA_Key;
extern StructRNA RNA_KeyboardSensor;
extern StructRNA RNA_KeyingSet;
extern StructRNA RNA_KeyingSetPath;
+extern StructRNA RNA_KeyedParticleTarget;
extern StructRNA RNA_KinematicConstraint;
extern StructRNA RNA_Lamp;
extern StructRNA RNA_LampSkySettings;
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 98ed12afd5a..39411752792 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -140,6 +140,35 @@ static void rna_Particle_reset(bContext *C, PointerRNA *ptr)
}
}
+static void rna_Particle_keyed_reset(bContext *C, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ if(ptr->type==&RNA_KeyedParticleTarget) {
+ Object *ob = (Object*)ptr->id.data;
+ ParticleSystem *psys = psys_get_current(ob);
+
+ psys->recalc = PSYS_RECALC_RESET;
+
+ DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+ DAG_scene_sort(scene);
+ }
+}
+
+static void rna_Particle_keyed_redo(bContext *C, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ if(ptr->type==&RNA_KeyedParticleTarget) {
+ Object *ob = (Object*)ptr->id.data;
+ ParticleSystem *psys = psys_get_current(ob);
+
+ psys->recalc = PSYS_RECALC_REDO;
+
+ DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+ }
+}
+
static void rna_Particle_change_type(bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
@@ -161,6 +190,13 @@ static void rna_Particle_change_type(bContext *C, PointerRNA *ptr)
}
}
+static void rna_Particle_change_physics(bContext *C, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+ ParticleSettings *part = ptr->id.data;
+ psys_flush_particle_settings(scene, part, PSYS_RECALC_RESET|PSYS_RECALC_PHYS);
+}
+
static void rna_Particle_redo_child(bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
@@ -299,6 +335,97 @@ static void rna_ParticleSystem_name_get(PointerRNA *ptr, char *str)
strcpy(str, "");
}
+static PointerRNA rna_ParticleSystem_active_keyed_target_get(PointerRNA *ptr)
+{
+ ParticleSystem *psys= (ParticleSystem*)ptr->data;
+ KeyedParticleTarget *kpt = psys->keyed_targets.first;
+
+ for(; kpt; kpt=kpt->next) {
+ if(kpt->flag & KEYED_TARGET_CURRENT)
+ return rna_pointer_inherit_refine(ptr, &RNA_KeyedParticleTarget, kpt);
+ }
+ return rna_pointer_inherit_refine(ptr, &RNA_KeyedParticleTarget, NULL);
+}
+static void rna_ParticleSystem_active_keyed_target_index_range(PointerRNA *ptr, int *min, int *max)
+{
+ ParticleSystem *psys= (ParticleSystem*)ptr->data;
+ *min= 0;
+ *max= BLI_countlist(&psys->keyed_targets)-1;
+ *max= MAX2(0, *max);
+}
+
+static int rna_ParticleSystem_active_keyed_target_index_get(PointerRNA *ptr)
+{
+ ParticleSystem *psys= (ParticleSystem*)ptr->data;
+ KeyedParticleTarget *kpt = psys->keyed_targets.first;
+ int i=0;
+
+ for(; kpt; kpt=kpt->next, i++)
+ if(kpt->flag & KEYED_TARGET_CURRENT)
+ return i;
+
+ return 0;
+}
+
+static void rna_ParticleSystem_active_keyed_target_index_set(struct PointerRNA *ptr, int value)
+{
+ ParticleSystem *psys= (ParticleSystem*)ptr->data;
+ KeyedParticleTarget *kpt = psys->keyed_targets.first;
+ int i=0;
+
+ for(; kpt; kpt=kpt->next, i++) {
+ if(i==value)
+ kpt->flag |= KEYED_TARGET_CURRENT;
+ else
+ kpt->flag &= ~KEYED_TARGET_CURRENT;
+ }
+}
+static int rna_KeyedParticleTarget_name_length(PointerRNA *ptr)
+{
+ KeyedParticleTarget *kpt= ptr->data;
+
+ if(kpt->flag & KEYED_TARGET_VALID) {
+ if(kpt->ob)
+ return strlen(kpt->ob->id.name+2) + 4;
+ else
+ return 20;
+ }
+ else
+ return 15;
+
+ return 0;
+}
+
+static void rna_KeyedParticleTarget_name_get(PointerRNA *ptr, char *str)
+{
+ KeyedParticleTarget *kpt= ptr->data;
+
+ if(kpt->flag & KEYED_TARGET_VALID) {
+ if(kpt->ob)
+ sprintf(str, "%s: %i", kpt->ob->id.name+2, kpt->psys);
+ else
+ sprintf(str, "Particle System: %i", kpt->psys);
+
+ }
+ else
+ strcpy(str, "Invalid target!");
+}
+
+static EnumPropertyItem from_items[] = {
+ {PART_FROM_VERT, "VERT", 0, "Vertexes", ""},
+ {PART_FROM_FACE, "FACE", 0, "Faces", ""},
+ {PART_FROM_VOLUME, "VOLUME", 0, "Volume", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem reactor_from_items[] = {
+ {PART_FROM_VERT, "VERT", 0, "Vertexes", ""},
+ {PART_FROM_FACE, "FACE", 0, "Faces", ""},
+ {PART_FROM_VOLUME, "VOLUME", 0, "Volume", ""},
+ {PART_FROM_PARTICLE, "PARTICLE", 0, "Particle", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
static EnumPropertyItem *rna_Particle_from_itemf(bContext *C, PointerRNA *ptr, int *free)
{
ParticleSettings *part = ptr->id.data;
@@ -660,16 +787,19 @@ static void rna_def_particle_settings(BlenderRNA *brna)
/* flag */
prop= RNA_def_property(srna, "react_start_end", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_REACT_STA_END);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Start/End", "Give birth to unreacted particles eventually.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "react_multiple", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_REACT_MULTIPLE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Multi React", "React multiple times.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "loop", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_LOOP);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Loop", "Loop particle lives.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
@@ -690,54 +820,46 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop= RNA_def_property(srna, "trand", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_TRAND);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Random", "Emit in random order of elements");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "even_distribution", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_EDISTR);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Even Distribution", "Use even distribution from faces based on face areas or edge lengths.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "sticky", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_STICKY);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Sticky", "Particles stick to collided objects if they die in the collision.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "die_on_collision", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_DIE_ON_COL);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Die on hit", "Particles die when they collide with a deflector object.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "size_deflect", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_SIZE_DEFL);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Size Deflect", "Use particle's size in deflection.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "rotation_dynamic", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_ROT_DYN);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Dynamic", "Sets rotation to dynamic/constant");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "sizemass", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_SIZEMASS);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Mass from Size", "Multiply mass with particle size.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
- prop= RNA_def_property(srna, "abs_length", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_ABS_LENGTH);
- RNA_def_property_ui_text(prop, "Abs Length", "Use maximum length for children");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
-
- //prop= RNA_def_property(srna, "absolute_time", PROP_BOOLEAN, PROP_NONE);
- //RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_ABS_TIME);
- //RNA_def_property_ui_text(prop, "Absolute Time", "Set all ipos that work on particles to be calculated in absolute/relative time.");
- //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
-
- //prop= RNA_def_property(srna, "global_time", PROP_BOOLEAN, PROP_NONE);
- //RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_GLOB_TIME);
- //RNA_def_property_ui_text(prop, "Global Time", "Set all ipos that work on particles to be calculated in global/object time.");
- //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
-
prop= RNA_def_property(srna, "boids_2d", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_BOIDS_2D);
RNA_def_property_ui_text(prop, "Boids 2D", "Constrain boids to a surface");
@@ -796,18 +918,21 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_ui_text(prop, "Type", "");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_change_type");
prop= RNA_def_property(srna, "emit_from", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "from");
RNA_def_property_enum_items(prop, part_reactor_from_items);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Particle_from_itemf");
RNA_def_property_ui_text(prop, "Emit From", "Where to emit particles from");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "distr");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_enum_items(prop, dist_items);
RNA_def_property_ui_text(prop, "Distribution", "How to distribute particles on selected element");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
@@ -815,24 +940,28 @@ static void rna_def_particle_settings(BlenderRNA *brna)
/* physics modes */
prop= RNA_def_property(srna, "physics_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "phystype");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_enum_items(prop, phys_type_items);
RNA_def_property_ui_text(prop, "Physics Type", "Particle physics type");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
+ RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_change_physics");
prop= RNA_def_property(srna, "rotation_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "rotmode");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_enum_items(prop, rot_mode_items);
RNA_def_property_ui_text(prop, "Rotation", "Particles initial rotation");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "angular_velocity_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "avemode");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_enum_items(prop, ave_mode_items);
RNA_def_property_ui_text(prop, "Angular Velocity Mode", "Particle angular velocity mode.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "react_event", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "reactevent");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_enum_items(prop, react_event_items);
RNA_def_property_ui_text(prop, "React On", "The event of target particles to react on.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
@@ -843,11 +972,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Velocity", "Show particle velocity");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
- //prop= RNA_def_property(srna, "draw_path_length", PROP_BOOLEAN, PROP_NONE);
- //RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_PATH_LEN);
- //RNA_def_property_ui_text(prop, "Path length", "Draw path length");
- //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
-
prop= RNA_def_property(srna, "show_size", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_SIZE);
RNA_def_property_ui_text(prop, "Size", "Show particle size");
@@ -936,7 +1060,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "childtype");
RNA_def_property_enum_items(prop, child_type_items);
RNA_def_property_ui_text(prop, "Children From", "Create child particles");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
+ RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child");
prop= RNA_def_property(srna, "draw_step", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 7);
@@ -1091,12 +1215,15 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop= RNA_def_property(srna, "start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sta");//optional if prop names are the same
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_float_funcs(prop, NULL, "rna_PartSettings_start_set", NULL);
RNA_def_property_ui_text(prop, "Start", "Frame # to start emitting particles.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "end", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
+
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_float_funcs(prop, NULL, "rna_PartSettings_end_set", NULL);
RNA_def_property_ui_text(prop, "End", "Frame # to stop emitting particles.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
@@ -1119,38 +1246,35 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "jitter_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_float_sdna(prop, NULL, "jitfac");
RNA_def_property_range(prop, 0.0f, 2.0f);
RNA_def_property_ui_text(prop, "Amount", "Amount of jitter applied to the sampling.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
- prop= RNA_def_property(srna, "keyed_time", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Time", "Keyed key time relative to remaining particle life.");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
-
prop= RNA_def_property(srna, "effect_hair", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "eff_hair");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Stiffnes", "Hair stiffness for effectors");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
- //float rt; TODO:find where rt is used - can't find it in UI
-
prop= RNA_def_property(srna, "amount", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "totpart");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_range(prop, 0, 100000);
RNA_def_property_ui_text(prop, "Amount", "Total number of particles.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "userjit", PROP_INT, PROP_UNSIGNED);//TODO: can we get a better name for userjit?
RNA_def_property_int_sdna(prop, NULL, "userjit");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_text(prop, "P/F", "Emission locations / face (0 = automatic).");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "grid_resolution", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "grid_res");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_text(prop, "Resolution", "The resolution of the particle grid.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
@@ -1273,19 +1397,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Damp", "Specify the amount of damping");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
- /* length */
- //TODO: is this readonly?
- prop= RNA_def_property(srna, "length", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "length");
-// RNA_def_property_range(prop, 0.0f, upperLimitf);//TODO: limits
- RNA_def_property_ui_text(prop, "Length", "");
-
- prop= RNA_def_property(srna, "absolute_length", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "abslength");
- RNA_def_property_range(prop, 0.0f, 10000.0f);
- RNA_def_property_ui_text(prop, "Max Length", "Absolute maximum path length for children, in blender units.");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
-
+ /* random length */
prop= RNA_def_property(srna, "random_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "randlength");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -1334,13 +1446,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Child Roundness", "Roundness of children around parent.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child");
- //TODO: is this readonly?
- prop= RNA_def_property(srna, "child_spread", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "childspread");
-// RNA_def_property_range(prop, 0.0f, upperLimitf); TODO: limits
- RNA_def_property_ui_text(prop, "Child Spread", "");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child");
-
/* clumping */
prop= RNA_def_property(srna, "clump_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "clumpfac");
@@ -1414,6 +1519,18 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Shape", "Shape of end point rough");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child");
+ prop= RNA_def_property(srna, "child_length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "clength");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Length", "Length of child paths");
+ RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child");
+
+ prop= RNA_def_property(srna, "child_length_thres", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "clength_thres");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Threshold", "Amount of particles left untouched by child path length.");
+ RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo_child");
+
/* branching */
prop= RNA_def_property(srna, "branch_threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "branch_thres");
@@ -1451,7 +1568,14 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 1.0f, 100.0f);
RNA_def_property_ui_text(prop, "Trail Count", "Number of trail particles.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
-
+
+ /* keyed particles */
+ prop= RNA_def_property(srna, "keyed_loops", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "keyed_loops");
+ RNA_def_property_range(prop, 1.0f, 100.0f);
+ RNA_def_property_ui_text(prop, "Loop count", "Number of times the keys are looped.");
+ RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
+
/* boids */
prop= RNA_def_property(srna, "max_velocity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "max_vel");
@@ -1494,14 +1618,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Ground Z", "Default Z value");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
- /*TODO: not sure how to deal with this
- prop= RNA_def_property(srna, "boid_factor", PROP_FLOAT, PROP_VECTOR);
- RNA_def_property_float_sdna(prop, NULL, "boidfac");
- RNA_def_property_ui_text(prop, "Boid Factor", "");
-
- //char boidrule[8];
- */
-
prop= RNA_def_property(srna, "dupli_group", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "dup_group");
RNA_def_property_struct_type(prop, "Group");
@@ -1537,6 +1653,52 @@ static void rna_def_particle_settings(BlenderRNA *brna)
// struct PartDeflect *pd2;
}
+static void rna_def_keyed_particle_target(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "KeyedParticleTarget", NULL);
+ RNA_def_struct_ui_text(srna, "Keyed Particle Target", "Target particle system for keyed particles.");
+
+ prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_KeyedParticleTarget_name_get", "rna_KeyedParticleTarget_name_length", NULL);
+ RNA_def_property_ui_text(prop, "Name", "Keyed particle target name.");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+
+ prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "ob");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Target Object", "The object that has the target particle system (empty if same object).");
+ RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_reset");
+
+ prop= RNA_def_property(srna, "system", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "psys");
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_ui_text(prop, "Target Particle System", "The index of particle system on the target object.");
+ RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_reset");
+
+ prop= RNA_def_property(srna, "time", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "time");
+ RNA_def_property_range(prop, 0.0, 30000.0f); //TODO: replace 30000 with MAXFRAMEF when available in 2.5
+ RNA_def_property_ui_text(prop, "Time", "");
+ RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_redo");
+
+ prop= RNA_def_property(srna, "duration", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "duration");
+ RNA_def_property_range(prop, 0.0, 30000.0f); //TODO: replace 30000 with MAXFRAMEF when available in 2.5
+ RNA_def_property_ui_text(prop, "Duration", "");
+ RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_keyed_redo");
+
+ prop= RNA_def_property(srna, "valid", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYED_TARGET_VALID);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
+ RNA_def_property_ui_text(prop, "Valid", "Keyed particles target is valid.");
+
+
+
+}
static void rna_def_particle_system(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1604,34 +1766,33 @@ static void rna_def_particle_system(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
/* boids */
- prop= RNA_def_property(srna, "boids_surface_object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "keyed_ob");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Boids Surface Object", "For boids physics systems, constrain boids to this object's surface.");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
+ //prop= RNA_def_property(srna, "boids_surface_object", PROP_POINTER, PROP_NONE);
+ //RNA_def_property_pointer_sdna(prop, NULL, "keyed_ob");
+ //RNA_def_property_flag(prop, PROP_EDITABLE);
+ //RNA_def_property_ui_text(prop, "Boids Surface Object", "For boids physics systems, constrain boids to this object's surface.");
+ //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
/* keyed */
- prop= RNA_def_property(srna, "keyed_object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "keyed_ob");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Keyed Object", "For keyed physics systems, the object that has the target particle system.");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
+ prop= RNA_def_property(srna, "keyed_timing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_KEYED_TIMING);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
+ RNA_def_property_ui_text(prop, "Keyed timing", "Use key times");
+ RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
- prop= RNA_def_property(srna, "keyed_particle_system", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "keyed_psys");
- RNA_def_property_range(prop, 1, INT_MAX);
- RNA_def_property_ui_text(prop, "Keyed Particle System", "For keyed physics systems, index of particle system on the keyed object.");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
+ prop= RNA_def_property(srna, "keyed_targets", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "keyed_targets", NULL);
+ RNA_def_property_struct_type(prop, "KeyedParticleTarget");
+ RNA_def_property_ui_text(prop, "Keyed Targets", "Target particle systems for keyed particles");
- prop= RNA_def_property(srna, "keyed_first", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_FIRST_KEYED);
- RNA_def_property_ui_text(prop, "Keyed First", "Set the system to be the starting point of keyed particles");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
+ prop= RNA_def_property(srna, "active_keyed_target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "KeyedParticleTarget");
+ RNA_def_property_pointer_funcs(prop, "rna_ParticleSystem_active_keyed_target_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active Particle System", "Active particle system being displayed");
+
+ prop= RNA_def_property(srna, "active_keyed_target_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_ParticleSystem_active_keyed_target_index_get", "rna_ParticleSystem_active_keyed_target_index_set", "rna_ParticleSystem_active_keyed_target_index_range");
+ RNA_def_property_ui_text(prop, "Active Particle System Index", "Index of active particle system slot.");
- prop= RNA_def_property(srna, "keyed_timed", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_KEYED_TIME);
- RNA_def_property_ui_text(prop, "Keyed Timed", "Use intermediate key times for keyed particles (setting for starting point only).");
- RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
/* billboard */
prop= RNA_def_property(srna, "billboard_normal_uv", PROP_STRING, PROP_NONE);
@@ -1782,7 +1943,6 @@ static void rna_def_particle_system(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Parent", "Use this object's coordinate system instead of global coordinate system.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
-
}
void RNA_def_particle(BlenderRNA *brna)
@@ -1791,6 +1951,7 @@ void RNA_def_particle(BlenderRNA *brna)
rna_def_particle_key(brna);
rna_def_child_particle(brna);
rna_def_particle(brna);
+ rna_def_keyed_particle_target(brna);
rna_def_particle_system(brna);
rna_def_particle_settings(brna);
}
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 74686511b21..1d6d98bebdf 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -1513,12 +1513,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
return 1;
/* 2. start initialising things */
- if(part->phystype==PART_PHYS_KEYED){
- if(psys->flag & PSYS_FIRST_KEYED)
- psys_count_keyed_targets(ob,psys);
- else
- return 1;
- }
+ if(part->phystype==PART_PHYS_KEYED)
+ psys_count_keyed_targets(ob,psys);
/* last possibility to bail out! */
psmd= psys_get_modifier(ob,psys);
@@ -1606,10 +1602,10 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
calc_ipo(part->ipo, cfra);
execute_ipo((ID *)part, part->ipo);
}
-#endif // XXX old animation system
if(part->flag & PART_GLOB_TIME)
- cfra = bsystem_time(re->scene, 0, (float)re->scene->r.cfra, 0.0);
+#endif // XXX old animation system
+ cfra = bsystem_time(re->scene, 0, (float)re->scene->r.cfra, 0.0);
/* 2.4 setup reactors */
if(part->type == PART_REACTOR){
@@ -1707,8 +1703,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
pa_time=(cfra-pa->time)/pa->lifetime;
pa_birthtime = pa->time;
pa_dietime = pa->dietime;
- if((part->flag&PART_ABS_TIME) == 0){
#if 0 // XXX old animation system
+ if((part->flag&PART_ABS_TIME) == 0){
if(ma->ipo) {
/* correction for lifetime */
calc_ipo(ma->ipo, 100.0f * pa_time);
@@ -1719,8 +1715,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
calc_ipo(part->ipo, 100.0f*pa_time);
execute_ipo((ID *)part, part->ipo);
}
-#endif // XXX old animation system
}
+#endif // XXX old animation system
hasize = ma->hasize;
@@ -1767,8 +1763,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
- if((part->flag & PART_ABS_TIME) == 0) {
#if 0 // XXX old animation system
+ if((part->flag & PART_ABS_TIME) == 0) {
if(ma->ipo){
/* correction for lifetime */
calc_ipo(ma->ipo, 100.0f * pa_time);
@@ -1779,8 +1775,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
calc_ipo(part->ipo, 100.0f * pa_time);
execute_ipo((ID *)part, part->ipo);
}
-#endif // XXX old animation system
}
+#endif // XXX old animation system
pa_size = psys_get_child_size(psys, cpa, cfra, &pa_time);