Keyed physics refresh:
authorJanne Karhu <jhkarh@gmail.com>
Sun, 12 Jul 2009 23:38:47 +0000 (23:38 +0000)
committerJanne Karhu <jhkarh@gmail.com>
Sun, 12 Jul 2009 23:38:47 +0000 (23:38 +0000)
- Keyed targets in one list instead of "chaining", this opens up many more possibilities than before and is much less obscure.
- Better keyed timing possibilities (time & duration in frames).
- Looping over keyed targets list.

Other changes:
- New child setting "length" with threshold (great for guard & underfur with a single particle system)
- Modularization of path interpolation code.
- Cleared "animateable" flags from many particle settings that shouldn't be animateable.

Fixes:
- Keyed particles weren't copied properly (ancient bug).
- Hair rotations depended on global z-axis for root rotation so downward facing strands could flip rotation randomly. Now initial hair rotation is derived from face dependent hair matrix. (This caused for example ugly flipping of child strands on some cases).
- Children from faces weren't calculated straight after activating them.
- Multiple disk cache fixes:
* Disk cache didn't work correctly with frame steps.
* Conversion from memory cache to disk cache didn't work with cloth.
* Disk cache crashed on some frames trying to close an already closed cache file.
* Trails didn't work with disk cached particles.
- Child rough effects were effected by emitter object loc/rot making them next to useless with animation, why didn't anybody tell me this!!
- Lots of random code cleanup.

17 files changed:
release/ui/buttons_particle.py
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/pointcache.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/space_buttons/buttons_intern.h
source/blender/editors/space_buttons/buttons_ops.c
source/blender/editors/space_buttons/space_buttons.c
source/blender/editors/space_view3d/drawobject.c
source/blender/makesdna/DNA_particle_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_particle.c
source/blender/render/intern/source/convertblender.c

index ef7ede15d6e21ae4ea1899dc9bfc89dc46c09209..2d269967e4b151e66a783d38826f6f1205d1fd1f 100644 (file)
@@ -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)
                
index aa24706077d5b6324b34b22c491b613b0a1b6546..bb0b905b8e3fa4b29509227593210f66779107a2 100644 (file)
@@ -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);
index de036e25d828f0e76ab7a5ff14e48562a2ca1887..f52eec34cc74a5773b4308f40c74de583eef3c3f 100644 (file)
@@ -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) {
index 6490ff3c72482970a1fd10c7e6320afd486c791f..7d6a83d79001614204df859f351eb21d98f3a74f 100644 (file)
@@ -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;
index 4488f8cdffd819ddd6cd724b1fdb380b64c5e199..cefeafcdd5038617b7aa760d0f6d659962b2cfcd 100644 (file)
@@ -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;
index 07e0e82a86de02366e22d24daf50169a0a97600d..56ca3e8e22b21a87da86a929332c0aa38ae771bc 100644 (file)
@@ -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)) {
index 2fe46be7a89c81251c5ed0023a341baea82ff7ee..6107510fa47b8248f6881eaf6b39ad2a8d859fbc 100644 (file)
@@ -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;
        }
 
index 479fa7604238b1587f7d888a755c247ff58c9e1c..c2b19a804eefd1eef905275547e8327e2462fb52 100644 (file)
@@ -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;
index 4b52da830191a86daeb2d3e175cce204c185268a..65a4a355717424182b373d14adb53b386c4fcbaf 100644 (file)
@@ -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);
index 65c2976d57cb53e98a611aaacf1b37dae6ee3a2e..f16a232f26dd48751bdd21dafb2ee869120090c1 100644 (file)
@@ -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 */
 
index 66b380ab413cb166c046944bd6dd559effee9db6..6fb52c611313d9c9d7300df567616ee837a786b4 100644 (file)
@@ -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;
+}
+
index f7be323a4c5fc8e52eb6348a4e5eebccbed54a3a..6cdb4dbf93d9e7a328545bf347b00e5ef735cc6b 100644 (file)
@@ -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)
index e8749537f5e70960e9396a1468140c7f65bc419c..f83a0b9686efd67a95d420175a21652b718c2c38 100644 (file)
@@ -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)
index c793362c2238ea8e15edcc0d5a9b8ae81c9da252..0b3309bfc0c5c0f0c682b65d76a7d614df880a6c 100644 (file)
@@ -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
index 3631d83310af45e19690a169b9ffd020a35466ce..ed1a8052acd74b3ac4f548a784d8b8980dc203ee 100644 (file)
@@ -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;
index 98ed12afd5a95f5c8811d22c4a82fbb4f8f70799..3941175279285b0633eae2fcfb6e263cb000fe10 100644 (file)
@@ -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);
 }
index 74686511b21e68ad4a9364affb272b72093daccb..1d6d98bebdfc991632ef4e197b19d5f241a1507a 100644 (file)
@@ -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);