A bunch of fun stuff now possible because of new pointcache code:
authorJanne Karhu <jhkarh@gmail.com>
Sat, 4 Jul 2009 03:50:12 +0000 (03:50 +0000)
committerJanne Karhu <jhkarh@gmail.com>
Sat, 4 Jul 2009 03:50:12 +0000 (03:50 +0000)
* Baked normal particles can now use the "Path" visualization.
* Path "max length" & "abs length" are now history:
- New option to set path start & end times + random variation to length.
- Much more flexible (and calculated better) than previous options.
- This works with parents, children, hair & normal particles unlike old length option.
- Only known issue for now is that children from faces don't get calculated correctly when using path start time.
* New option "trails" for "halo", "line" and "billboard" visualizations:
- Draws user controllable number of particle instances along particles path backwards from current position.
- Works with children too for cool/weird visualizations that weren't possible before.
* Normal particle children's velocities are now approximated better when needed so that "line" visualization trails will look nice.
* New particle instance modifier options:
- "path"-option works better and has controllable (max)position along path (with random variation possible).
- "keep shape"-option for hair, keyed, or baked particles allows to place the instances to a single point (with random variation possible) along particle path.
- "axis" option to make rotation handling better (still not perfect, but will have to do for now).

Some fixes & cleanup done along the way:
* Random path length didn't work for non-child particles.
* Cached & unborn particles weren't reset to emit locations.
* Particle numbers weren't drawn in the correct place.
* Setting proper render & draw visualizations was lost somewhere when initializing new particle settings.
* Changing child mode wasn't working correctly.
* Some cleanup & modularization of particle child effector code and particle drawing & rendering code.
* Object & group visualizations didn't work.
* Child simplification didn't work.

18 files changed:
release/ui/buttons_data_modifier.py
release/ui/buttons_particle.py
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/intern/anim.c
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/modifier.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/editors/interface/interface_templates.c
source/blender/editors/object/object_modifier.c
source/blender/editors/space_view3d/drawobject.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_particle_types.h
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_particle.c
source/blender/render/intern/source/convertblender.c

index 2400461b6233d054af2b0d0b6c3aa49498870851..477be27e820956e9631e6f18dedb75fa62d76f0b 100644 (file)
@@ -300,9 +300,18 @@ class DATA_PT_modifiers(DataButtonsPanel):
                col.itemR(md, "normal")
                col.itemR(md, "children")
                col.itemR(md, "path")
+               if md.path:
+                       col.itemR(md, "keep_shape")
                col.itemR(md, "unborn")
                col.itemR(md, "alive")
                col.itemR(md, "dead")
+               if md.path:
+                       col.itemR(md, "axis", text="")
+               
+               if md.path:
+                       row = layout.row()
+                       row.itemR(md, "position", slider=True)
+                       row.itemR(md, "random_position", text = "Random", slider=True)
                
        def particlesystem(self, layout, ob, md):
                layout.itemL(text="See Particle panel.")
index 49ceaf6aae1873ef67bfac4a20918f860abf1709..93ce9c5c74532115601c0038e429da378b613c22 100644 (file)
@@ -353,19 +353,14 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
                        colsub.itemR(part, "adaptive_pix")
                        sub.itemR(part, "hair_bspline")
                        sub.itemR(part, "render_step", text="Steps")
-                       sub = split.column()
-                       sub.itemL(text="Length:")
-                       sub.itemR(part, "abs_length", text="Absolute")
-                       sub.itemR(part, "absolute_length", text="Maximum")
+                       sub = split.column()    
+
+                       sub.itemL(text="Timing:")
+                       sub.itemR(part, "abs_path_time")
+                       sub.itemR(part, "path_start", text="Start", slider= not part.abs_path_time)
+                       sub.itemR(part, "path_end", text="End", slider= not part.abs_path_time)         
                        sub.itemR(part, "random_length", text="Random", slider=True)
                        
-                       #row = layout.row()
-                       #row.itemR(part, "timed_path")
-                       #col = row.column(align=True)
-                       #col.active = part.timed_path == True
-                       #col.itemR(part, "line_length_tail", text="Start")
-                       #col.itemR(part, "line_length_head", text="End")
-                       
                        row = layout.row()
                        col = row.column()
                        
@@ -384,7 +379,6 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
                        
 
                elif part.ren_as == 'OBJECT':
-                       #sub = split.column()
                        sub.itemR(part, "dupli_object")
                elif part.ren_as == 'GROUP':
                        sub.itemR(part, "dupli_group")
@@ -428,7 +422,19 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
                        row.itemR(part, "billboard_animation", expand=True)
                        row.itemL(text="Offset:")
                        row.itemR(part, "billboard_split_offset", expand=True)
-               
+               if part.ren_as == 'HALO' or part.ren_as == 'LINE' or part.ren_as=='BILLBOARD':
+                       row = layout.row()
+                       col = row.column()
+                       col.itemR(part, "trail_count")
+                       if part.trail_count > 1:
+                               col.itemR(part, "abs_path_time", text="Length in frames")
+                               col = row.column()
+                               col.itemR(part, "path_end", text="Length", slider=not part.abs_path_time)
+                               col.itemR(part, "random_length", text="Random", slider=True)
+                       else:
+                               col = row.column()
+                               col.itemL(text="")
+                               
 class PARTICLE_PT_draw(ParticleButtonsPanel):
        __idname__= "PARTICLE_PT_draw"
        __label__ = "Display"
@@ -475,11 +481,12 @@ class PARTICLE_PT_draw(ParticleButtonsPanel):
                        col.itemR(part, "draw_health")
                
                col = row.column()
+               col.itemR(part, "material_color", text="Use material color")
+               
                if (path):
                        box = col.box()                         
                        box.itemR(part, "draw_step")
                else:
-                       col.itemR(part, "material_color", text="Use material color")
                        subcol = col.column()
                        subcol.active = part.material_color==False
                        #subcol.itemL(text="color")
index 73f0195d1d87a16f5c2212d9cc1615c8cc87e990..aa24706077d5b6324b34b22c491b613b0a1b6546 100644 (file)
@@ -91,7 +91,8 @@ typedef struct ParticleTexture{
        float ivel;                                                     /* used in reset */
        float time, life, exist, size;          /* used in init */
        float pvel[3];                                          /* used in physics */
-       float length, clump, kink, rough;       /* used in path caching */
+       float length, clump, kink, effector;/* used in path caching */
+       float rough1, rough2, roughe;           /* used in path caching */
 } ParticleTexture;
 
 typedef struct BoidVecFunc{
@@ -270,7 +271,7 @@ void psys_update_world_cos(struct Object *ob, struct ParticleSystem *psys);
 int do_guide(struct Scene *scene, struct ParticleKey *state, int pa_num, float time, struct ListBase *lb);
 float psys_get_size(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct IpoCurve *icu_size, struct ParticleSystem *psys, struct ParticleSettings *part, struct ParticleData *pa, float *vg_size);
 float psys_get_timestep(struct ParticleSettings *part);
-float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra);
+float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime);
 float psys_get_child_size(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *pa_time);
 void psys_get_particle_on_path(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, int pa_num, struct ParticleKey *state, int vel);
 int psys_get_particle_state(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, int p, struct ParticleKey *state, int always);
index 1aceca454d2b23925a125227772c46dd55642928..6c1b8eb9000cb192e7954bec3aedf235a47b7bcf 100644 (file)
@@ -786,8 +786,9 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
        BLI_srandom(31415926 + psys->seed);
        
        lay= scene->lay;
-       if((part->draw_as == PART_DRAW_OB && part->dup_ob) ||
-               (part->draw_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first)) {
+       if((psys->renderdata || part->draw_as==PART_DRAW_REND) &&
+               ((part->ren_as == PART_DRAW_OB && part->dup_ob) ||
+               (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first))) {
 
                /* if we have a hair particle system, use the path cache */
                if(part->type == PART_HAIR) {
@@ -804,7 +805,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
                psys->lattice = psys_get_lattice(scene, par, psys);
 
                /* gather list of objects or single object */
-               if(part->draw_as==PART_DRAW_GR) {
+               if(part->ren_as==PART_DRAW_GR) {
                        group_handle_recalc_and_update(scene, par, part->dup_group);
 
                        for(go=part->dup_group->gobject.first; go; go=go->next)
@@ -850,7 +851,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
                                size = psys_get_child_size(psys, cpa, ctime, 0);
                        }
 
-                       if(part->draw_as==PART_DRAW_GR) {
+                       if(part->ren_as==PART_DRAW_GR) {
                                /* for groups, pick the object based on settings */
                                if(part->draw&PART_DRAW_RAND_GR)
                                        b= BLI_rand() % totgroup;
@@ -894,7 +895,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
                                pamat[3][3]= 1.0f;
                        }
 
-                       if(part->draw_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
+                       if(part->ren_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
                                for(go= part->dup_group->gobject.first, b=0; go; go= go->next, b++) {
                                        Mat4MulMat4(tmat, oblist[b]->obmat, pamat);
                                        Mat4MulFloat3((float *)tmat, size*scale);
@@ -930,7 +931,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
                }
 
                /* restore objects since they were changed in where_is_object_time */
-               if(part->draw_as==PART_DRAW_GR) {
+               if(part->ren_as==PART_DRAW_GR) {
                        for(a=0; a<totgroup; a++)
                                *(oblist[a])= obcopylist[a];
                }
index a36b825293e2793398940139394a324cb22d74fa..de036e25d828f0e76ab7a5ff14e48562a2ca1887 100644 (file)
@@ -568,14 +568,14 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
                                dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Keyed Physics");
                        }
 
-                       if(part->draw_as == PART_DRAW_OB && part->dup_ob) {
+                       if(part->ren_as == PART_DRAW_OB && part->dup_ob) {
                                node2 = dag_get_node(dag, part->dup_ob);
                                dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualisation");
                                if(part->dup_ob->type == OB_MBALL)
                                        dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualisation");
                        }
 
-                       if(part->draw_as == PART_DRAW_GR && part->dup_group) {
+                       if(part->ren_as == PART_DRAW_GR && part->dup_group) {
                                for(go=part->dup_group->gobject.first; go; go=go->next) {
                                        node2 = dag_get_node(dag, go->ob);
                                        dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Group Visualisation");
index 9ecf3a32c2be8e21f188a23e2858b834120c0196..71428a9e9477cc5679f0b4f0e0e270835f88b33a 100644 (file)
@@ -6390,6 +6390,7 @@ static void particleSystemModifier_deformVerts(
                  }
 
                  if(psys){
+                         psmd->flag &= ~eParticleSystemFlag_psys_updated;
                          particle_system_update(md->scene, ob, psys);
                          psmd->flag |= eParticleSystemFlag_psys_updated;
                          psmd->flag &= ~eParticleSystemFlag_DM_changed;
@@ -6421,6 +6422,8 @@ static void particleInstanceModifier_initData(ModifierData *md)
        pimd->flag = eParticleInstanceFlag_Parents|eParticleInstanceFlag_Unborn|
                        eParticleInstanceFlag_Alive|eParticleInstanceFlag_Dead;
        pimd->psys = 1;
+       pimd->position = 1.0f;
+       pimd->axis = 2;
 
 }
 static void particleInstanceModifier_copyData(ModifierData *md, ModifierData *target)
@@ -6431,6 +6434,8 @@ static void particleInstanceModifier_copyData(ModifierData *md, ModifierData *ta
        tpimd->ob = pimd->ob;
        tpimd->psys = pimd->psys;
        tpimd->flag = pimd->flag;
+       tpimd->position = pimd->position;
+       tpimd->random_position = pimd->random_position;
 }
 
 static int particleInstanceModifier_dependsOnTime(ModifierData *md) 
@@ -6470,7 +6475,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier(
        MFace *mface, *orig_mface;
        MVert *mvert, *orig_mvert;
        int i,totvert, totpart=0, totface, maxvert, maxface, first_particle=0;
-       short track=ob->trackflag%3, trackneg;
+       short track=ob->trackflag%3, trackneg, axis = pimd->axis;
        float max_co=0.0, min_co=0.0, temp_co[3], cross[3];
 
        trackneg=((ob->trackflag>2)?1:0);
@@ -6508,7 +6513,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier(
 
        psys->lattice=psys_get_lattice(md->scene, ob, psys);
 
-       if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED)){
+       if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED){
 
                float min_r[3], max_r[3];
                INIT_MINMAX(min_r, max_r);
@@ -6533,33 +6538,50 @@ static DerivedMesh * particleInstanceModifier_applyModifier(
 
                /*change orientation based on object trackflag*/
                VECCOPY(temp_co,mv->co);
-               mv->co[0]=temp_co[track];
-               mv->co[1]=temp_co[(track+1)%3];
-               mv->co[2]=temp_co[(track+2)%3];
-
-               if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) && pimd->flag & eParticleInstanceFlag_Path){
-                       state.time=(mv->co[0]-min_co)/(max_co-min_co);
-                       if(trackneg)
-                               state.time=1.0f-state.time;
-                       psys_get_particle_on_path(md->scene, pimd->ob, psys,first_particle + i/totvert, &state,1);
+               mv->co[axis]=temp_co[track];
+               mv->co[(axis+1)%3]=temp_co[(track+1)%3];
+               mv->co[(axis+2)%3]=temp_co[(track+2)%3];
+
+               if((psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && pimd->flag & eParticleInstanceFlag_Path){
+                       float ran = 0.0f;
+                       if(pimd->random_position != 0.0f) {
+                               /* just use some static collection of random numbers */
+                               /* TODO: use something else that's unique to each instanced object */
+                               pa = psys->particles + (i/totvert)%totpart;
+                               ran = pimd->random_position * 0.5 * (1.0f + pa->r_ave[0]);
+                       }
 
-                       mv->co[0] = 0.0;
+                       if(pimd->flag & eParticleInstanceFlag_KeepShape) {
+                               state.time = pimd->position * (1.0f - ran);
+                       }
+                       else {
+                               state.time=(mv->co[axis]-min_co)/(max_co-min_co) * pimd->position * (1.0f - ran);
+
+                               if(trackneg)
+                                       state.time=1.0f-state.time;
+                               
+                               mv->co[axis] = 0.0;
+                       }
+
+                       psys_get_particle_on_path(md->scene, pimd->ob, psys,first_particle + i/totvert, &state,1);
 
                        Normalize(state.vel);
                        
-                       if(state.vel[0] < -0.9999 || state.vel[0] > 0.9999) {
-                               state.rot[0] = 1.0;
+                       /* TODO: incremental rotations somehow */
+                       if(state.vel[axis] < -0.9999 || state.vel[axis] > 0.9999) {
+                               state.rot[0] = 1;
                                state.rot[1] = state.rot[2] = state.rot[3] = 0.0f;
                        }
                        else {
-                               /* a cross product of state.vel and a unit vector in x-direction */
-                               cross[0] = 0.0f;
-                               cross[1] = -state.vel[2];
-                               cross[2] = state.vel[1];
+                               float temp[3] = {0.0f,0.0f,0.0f};
+                               temp[axis] = 1.0f;
 
-                               /* state.vel[0] is the only component surviving from a dot product with a vector in x-direction*/
-                               VecRotToQuat(cross,saacos(state.vel[0]),state.rot);
+                               Crossf(cross, temp, state.vel);
+
+                               /* state.vel[axis] is the only component surviving from a dot product with the axis */
+                               VecRotToQuat(cross,saacos(state.vel[axis]),state.rot);
                        }
+
                }
                else{
                        state.time=-1.0;
index 5bf9335d211590cd363201e027f3d6958b77368a..6ab8d72aa6d1ab08c5c055ffcc494f9f9e54937a 100644 (file)
 static void key_from_object(Object *ob, ParticleKey *key);
 static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index,
                                float *fuv, float *orco, ParticleTexture *ptex, int event);
+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);
 
 /* few helpers for countall etc. */
 int count_particles(ParticleSystem *psys){
@@ -452,7 +456,7 @@ void psys_free(Object *ob, ParticleSystem * psys)
                for(tpsys=ob->particlesystem.first; tpsys; tpsys=tpsys->next){
                        if(tpsys->part)
                        {
-                               if(ELEM(tpsys->part->draw_as,PART_DRAW_OB,PART_DRAW_GR))
+                               if(ELEM(tpsys->part->ren_as,PART_DRAW_OB,PART_DRAW_GR))
                                {
                                        nr++;
                                        break;
@@ -491,6 +495,7 @@ typedef struct ParticleRenderData {
        ChildParticle *child;
        ParticleCacheKey **pathcache;
        ParticleCacheKey **childcache;
+       ListBase pathcachebufs, childcachebufs;
        int totchild, totcached, totchildcache;
        DerivedMesh *dm;
        int totdmvert, totdmedge, totdmface;
@@ -577,8 +582,12 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float
        data->child= psys->child;
        data->totchild= psys->totchild;
        data->pathcache= psys->pathcache;
+       data->pathcachebufs.first = psys->pathcachebufs.first;
+       data->pathcachebufs.last = psys->pathcachebufs.last;
        data->totcached= psys->totcached;
        data->childcache= psys->childcache;
+       data->childcachebufs.first = psys->childcachebufs.first;
+       data->childcachebufs.last = psys->childcachebufs.last;
        data->totchildcache= psys->totchildcache;
 
        if(psmd->dm)
@@ -591,6 +600,8 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float
        psys->pathcache= NULL;
        psys->childcache= NULL;
        psys->totchild= psys->totcached= psys->totchildcache= 0;
+       psys->pathcachebufs.first = psys->pathcachebufs.last = NULL;
+       psys->childcachebufs.first = psys->childcachebufs.last = NULL;
 
        Mat4CpyMat4(data->winmat, winmat);
        Mat4MulMat4(data->viewmat, ob->obmat, viewmat);
@@ -631,8 +642,12 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
        psys->child= data->child;
        psys->totchild= data->totchild;
        psys->pathcache= data->pathcache;
+       psys->pathcachebufs.first = data->pathcachebufs.first;
+       psys->pathcachebufs.last = data->pathcachebufs.last;
        psys->totcached= data->totcached;
        psys->childcache= data->childcache;
+       psys->childcachebufs.first = data->childcachebufs.first;
+       psys->childcachebufs.last = data->childcachebufs.last;
        psys->totchildcache= data->totchildcache;
 
        psmd->dm= data->dm;
@@ -663,7 +678,7 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
        int *origindex, *facetotvert;
        int a, b, totorigface, totface, newtot, skipped;
 
-       if(part->draw_as!=PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND))
+       if(part->ren_as!=PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND))
                return tot;
        if(!ctx->psys->renderdata)
                return tot;
@@ -1992,11 +2007,9 @@ 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, rough_t, cpa_1st[3], dvec[3];
+       float co[3], orco[3], ornor[3], t, cpa_1st[3], dvec[3];
        float branch_begin, branch_end, branch_prob, branchfac, rough_rand;
-       float pa_rough1, pa_rough2, pa_roughe;
-       float length, pa_length, pa_clump, pa_kink, pa_effector;
-       float max_length = 1.0f, cur_length = 0.0f;
+       float length, max_length = 1.0f, cur_length = 0.0f;
        float eff_length, eff_vec[3];
        int k, cpa_num, guided = 0;
        short cpa_from;
@@ -2059,9 +2072,11 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
 
                psys_particle_on_emitter(ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,ornor,0,0,orco,0);
 
-               /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
-               VECCOPY(cpa_1st,co);
-               Mat4MulVecfl(ob->obmat,cpa_1st);
+               if(part->path_start==0.0f) {
+                       /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
+                       VECCOPY(cpa_1st,co);
+                       Mat4MulVecfl(ob->obmat,cpa_1st);
+               }
 
                pa=0;
        }
@@ -2098,43 +2113,13 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
 #endif // XXX old animation system
 
        /* get different child parameters from textures & vgroups */
-       ptex.length=part->length*(1.0f - part->randlength*cpa->rand[0]);
-       ptex.clump=1.0;
-       ptex.kink=1.0;
-       ptex.rough= 1.0;
-       ptex.exist= 1.0;
-
-       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);
-       
-       pa_length=ptex.length;
-       pa_clump=ptex.clump;
-       pa_kink=ptex.kink;
-       pa_rough1=ptex.rough;
-       pa_rough2=ptex.rough;
-       pa_roughe=ptex.rough;
-       pa_effector= 1.0f;
+       get_child_modifier_parameters(part, ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
 
        if(ptex.exist < cpa->rand[1]) {
                keys->steps = -1;
                return;
        }
 
-       if(ctx->vg_length)
-               pa_length*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_length);
-       if(ctx->vg_clump)
-               pa_clump*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_clump);
-       if(ctx->vg_kink)
-               pa_kink*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_kink);
-       if(ctx->vg_rough1)
-               pa_rough1*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough1);
-       if(ctx->vg_rough2)
-               pa_rough2*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough2);
-       if(ctx->vg_roughe)
-               pa_roughe*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_roughe);
-       if(ctx->vg_effector)
-               pa_effector*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_effector);
-
        /* create the child path */
        for(k=0,state=keys; k<=ctx->steps; k++,state++){
                if(ctx->between){
@@ -2158,12 +2143,14 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
                                key[w]++;
                                w++;
                        }
-                       if(k==0){
-                               /* calculate the offset between actual child root position and first position interpolated from parents */
-                               VECSUB(cpa_1st,cpa_1st,state->co);
+                       if(part->path_start==0.0f) {
+                               if(k==0){
+                                       /* calculate the offset between actual child root position and first position interpolated from parents */
+                                       VECSUB(cpa_1st,cpa_1st,state->co);
+                               }
+                               /* apply offset for correct positioning */
+                               VECADD(state->co,state->co,cpa_1st);
                        }
-                       /* apply offset for correct positioning */
-                       VECADD(state->co,state->co,cpa_1st);
                }
                else{
                        /* offset the child from the parent position */
@@ -2177,7 +2164,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
        if(part->flag & PART_CHILD_EFFECT) {
                for(k=0,state=keys; k<=ctx->steps; k++,state++) {
                        if(k) {
-                               do_path_effectors(ctx->scene, ob, psys, cpa->pa[0], state, k, ctx->steps, keys->co, pa_effector, 0.0f, ctx->cfra, &eff_length, eff_vec);
+                               do_path_effectors(ctx->scene, ob, psys, cpa->pa[0], state, k, ctx->steps, keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec);
                        }
                        else {
                                VecSubf(eff_vec,(state+1)->co,state->co);
@@ -2203,67 +2190,50 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
                }
 
                /* apply different deformations to the child path */
-               if(part->flag & PART_CHILD_EFFECT)
-                       /* state is safe to cast, since only co and vel are used */
-                       guided = do_guide(ctx->scene, (ParticleKey*)state, cpa->parent, t, &(psys->effectors));
-
-               if(guided==0){
-                       if(part->kink)
-                               do_prekink((ParticleKey*)state, (ParticleKey*)par, par_rot, t,
-                               part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat);
-                                       
-                       do_clump((ParticleKey*)state, (ParticleKey*)par, t, part->clumpfac, part->clumppow, pa_clump);
-               }
-
-               if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING)
-                       rough_t = t * rough_rand;
-               else
-                       rough_t = t;
+               do_child_modifiers(ctx->scene, ob, psys, part, &ptex, (ParticleKey *)par, par_rot, cpa, orco, (ParticleKey *)state, t);
 
-               if(part->rough1 != 0.0 && pa_rough1 != 0.0)
-                       do_rough(orco, rough_t, pa_rough1*part->rough1, part->rough1_size, 0.0, (ParticleKey*)state);
-
-               if(part->rough2 != 0.0 && pa_rough2 != 0.0)
-                       do_rough(cpa->rand, rough_t, pa_rough2*part->rough2, part->rough2_size, part->rough2_thres, (ParticleKey*)state);
-
-               if(part->rough_end != 0.0 && pa_roughe != 0.0)
-                       do_rough_end(cpa->rand, rough_t, pa_roughe*part->rough_end, part->rough_end_shape, (ParticleKey*)state, (ParticleKey*)par);
-
-               if(part->flag & PART_BRANCHING && ctx->between==0){
-                       if(branch_prob > part->branch_thres){
-                               branchfac=0.0f;
-                       }
-                       else{
-                               if(part->flag & PART_SYMM_BRANCHING){
-                                       if(t < branch_begin || t > branch_end)
-                                               branchfac=0.0f;
-                                       else{
-                                               if((t-branch_begin)/(branch_end-branch_begin)<0.5)
-                                                       branchfac=2.0f*(t-branch_begin)/(branch_end-branch_begin);
-                                               else
-                                                       branchfac=2.0f*(branch_end-t)/(branch_end-branch_begin);
+               /* TODO: better branching */
+               //if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING)
+               //      rough_t = t * rough_rand;
+               //else
+               //      rough_t = t;
 
-                                               CLAMP(branchfac,0.0f,1.0f);
-                                       }
-                               }
-                               else{
-                                       if(t < branch_begin){
-                                               branchfac=0.0f;
-                                       }
-                                       else{
-                                               branchfac=(t-branch_begin)/((1.0f-branch_begin)*0.5f);
-                                               CLAMP(branchfac,0.0f,1.0f);
-                                       }
-                               }
-                       }
+               /* TODO: better branching */
+               //if(part->flag & PART_BRANCHING && ctx->between==0){
+               //      if(branch_prob > part->branch_thres){
+               //              branchfac=0.0f;
+               //      }
+               //      else{
+               //              if(part->flag & PART_SYMM_BRANCHING){
+               //                      if(t < branch_begin || t > branch_end)
+               //                              branchfac=0.0f;
+               //                      else{
+               //                              if((t-branch_begin)/(branch_end-branch_begin)<0.5)
+               //                                      branchfac=2.0f*(t-branch_begin)/(branch_end-branch_begin);
+               //                              else
+               //                                      branchfac=2.0f*(branch_end-t)/(branch_end-branch_begin);
+
+               //                              CLAMP(branchfac,0.0f,1.0f);
+               //                      }
+               //              }
+               //              else{
+               //                      if(t < branch_begin){
+               //                              branchfac=0.0f;
+               //                      }
+               //                      else{
+               //                              branchfac=(t-branch_begin)/((1.0f-branch_begin)*0.5f);
+               //                              CLAMP(branchfac,0.0f,1.0f);
+               //                      }
+               //              }
+               //      }
 
-                       if(i<psys->totpart)
-                               VecLerpf(state->co, (pcache[i] + k)->co, state->co, branchfac);
-                       else
-                               /* this is not threadsafe, but should only happen for
-                                * branching particles particles, which are not threaded */
-                               VecLerpf(state->co, (cache[i - psys->totpart] + k)->co, state->co, branchfac);
-               }
+               //      if(i<psys->totpart)
+               //              VecLerpf(state->co, (pcache[i] + k)->co, state->co, branchfac);
+               //      else
+               //              /* this is not threadsafe, but should only happen for
+               //               * branching particles particles, which are not threaded */
+               //              VecLerpf(state->co, (cache[i - psys->totpart] + k)->co, state->co, branchfac);
+               //}
 
                /* we have to correct velocity because of kink & clump */
                if(k>1){
@@ -2287,9 +2257,9 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
                else{
                        /* initialize length calculation */
                        if(part->flag&PART_ABS_LENGTH)
-                               max_length= part->abslength*pa_length;
+                               max_length= part->abslength*ptex.length;
                        else
-                               max_length= pa_length;
+                               max_length= ptex.length;
 
                        cur_length= 0.0f;
                }
@@ -2383,7 +2353,36 @@ 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.                          */
@@ -2409,7 +2408,7 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
        
        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[3] = {0.5f, 0.5f, 0.5f};
+       float col[4] = {0.5f, 0.5f, 0.5f, 1.0f};
        float prev_tangent[3], hairmat[4][4];
        int k,i;
        int steps = (int)pow(2.0, (double)psys->part->draw_step);
@@ -2419,12 +2418,17 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
        float length, vec[3];
        float *vg_effector= NULL, effector=0.0f;
        float *vg_length= NULL, pa_length=1.0f, max_length=1.0f, cur_length=0.0f;
-       float len, dvec[3];
+       int keyed, baked;
 
        /* we don't have anything valid to create paths from so let's quit here */
-       if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0)
+       if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0 && (psys->pointcache->flag & PTCACHE_BAKED)==0)
                return;
 
+       BLI_srandom(psys->seed);
+
+       keyed = psys->flag & PSYS_KEYED;
+       baked = psys->pointcache->flag & PTCACHE_BAKED;
+
        if(psys->renderdata) {
                steps = (int)pow(2.0, (double)psys->part->ren_step);
        }
@@ -2488,7 +2492,8 @@ 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 = 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);
                }
@@ -2499,13 +2504,19 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
                        ekey = edit->keys[i];
 
                /*--get the first data points--*/
-               if(psys->flag & PSYS_KEYED) {
+               if(keyed) {
                        kkey[0] = pa->keys;
                        kkey[1] = kkey[0] + 1;
 
                        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;
@@ -2516,6 +2527,25 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
                        psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
                }
 
+               if(!edit) {
+                       if(part->draw & PART_ABS_PATH_TIME) {
+                               birthtime = MAX2(birthtime, part->path_start);
+                               dietime = MIN2(dietime, part->path_end);
+                       }
+                       else {
+                               float tb = birthtime;
+                               birthtime = tb + part->path_start * (dietime - tb);
+                               dietime = tb + part->path_end * (dietime - tb);
+                       }
+
+                       if(birthtime >= dietime) {
+                               cache[i]->steps = -1;
+                               continue;
+                       }
+
+                       dietime = birthtime + pa_length * (dietime - birthtime);
+               }
+
                if(soft){
                        bp[0] = soft->bpoint + pa->bpi;
                        bp[1] = bp[0] + 1;
@@ -2527,13 +2557,16 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
 
                        t = birthtime + time * (dietime - birthtime);
 
-                       if(psys->flag & PSYS_KEYED) {
+                       if(keyed) {
                                while(kkey[1]->time < t) {
                                        kkey[1]++;
                                }
 
                                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]++;
@@ -2548,17 +2581,19 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
                                bp_to_particle(keys + 1, bp[0], hkey[0]);
                                bp_to_particle(keys + 2, bp[1], hkey[1]);
                        }
-                       else if(psys->flag & PSYS_KEYED) {
+                       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((psys->flag & PSYS_KEYED)==0) {
+                       if(!keyed && !baked) {
                                if(soft) {
                                        if(hkey[0] != pa->hair)
                                                bp_to_particle(keys, bp[0] - 1, hkey[0] - 1);
@@ -2591,18 +2626,18 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
                        keytime = (t - keys[1].time) / dfra;
 
                        /* convert velocity to timestep size */
-                       if(psys->flag & PSYS_KEYED){
+                       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((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic 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(psys->flag & PSYS_KEYED){
+                       if(keyed || baked){
                                VecMulf(result.vel, frs_sec / dfra);
                        }
                        else if(soft==NULL) { /* softbody and keyed are allready in global space */
@@ -2717,28 +2752,6 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
                                }
 
                        }
-
-                       if(!edit && !psys->totchild) {
-                               /* check if path needs to be cut before actual end of data points */
-                               if(k){
-                                       VECSUB(dvec,ca->co,(ca-1)->co);
-                                       if(part->flag&PART_ABS_LENGTH)
-                                               len=VecLength(dvec);
-                                       else
-                                               len=1.0f/(float)steps;
-
-                                       k=check_path_length(k,cache[i],ca,max_length,&cur_length,len,dvec);
-                               }
-                               else{
-                                       /* initialize length calculation */
-                                       if(part->flag&PART_ABS_LENGTH)
-                                               max_length= part->abslength*pa_length;
-                                       else
-                                               max_length= pa_length;
-
-                                       cur_length= 0.0f;
-                               }
-                       }
                }
        }
 
@@ -2990,7 +3003,8 @@ static void default_particle_settings(ParticleSettings *part)
 
        part->type= PART_EMITTER;
        part->distr= PART_DISTR_JIT;
-       part->draw_as=PART_DRAW_DOT;
+       part->draw_as = PART_DRAW_REND;
+       part->ren_as = PART_DRAW_HALO;
        part->bb_uv_split=1;
        part->bb_align=PART_BB_VIEW;
        part->bb_split_offset=PART_BB_OFF_LINEAR;
@@ -3046,6 +3060,8 @@ static void default_particle_settings(ParticleSettings *part)
        part->rough_end_shape=1.0;
 
        part->draw_line[0]=0.5;
+       part->path_start = 0.0f;
+       part->path_end = 1.0f;
 
        part->banking=1.0;
        part->max_bank=1.0;
@@ -3282,7 +3298,7 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float
                        if((event & mtex->pmapto) & MAP_PA_KINK)
                                ptex->kink= texture_value_blend(def,ptex->kink,value,var,blend,neg & MAP_PA_KINK);
                        if((event & mtex->pmapto) & MAP_PA_ROUGH)
-                               ptex->rough= texture_value_blend(def,ptex->rough,value,var,blend,neg & MAP_PA_ROUGH);
+                               ptex->rough1= ptex->rough2= ptex->roughe= texture_value_blend(def,ptex->rough1,value,var,blend,neg & MAP_PA_ROUGH);
                        if((event & mtex->pmapto) & MAP_PA_DENS)
                                ptex->exist= texture_value_blend(def,ptex->exist,value,var,blend,neg & MAP_PA_DENS);
                }
@@ -3291,7 +3307,11 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float
        if(event & MAP_PA_LENGTH) { CLAMP(ptex->length,0.0,1.0); }
        if(event & MAP_PA_CLUMP) { CLAMP(ptex->clump,0.0,1.0); }
        if(event & MAP_PA_KINK) { CLAMP(ptex->kink,0.0,1.0); }
-       if(event & MAP_PA_ROUGH) { CLAMP(ptex->rough,0.0,1.0); }
+       if(event & MAP_PA_ROUGH) {
+               CLAMP(ptex->rough1,0.0,1.0);
+               CLAMP(ptex->rough2,0.0,1.0);
+               CLAMP(ptex->roughe,0.0,1.0);
+       }
        if(event & MAP_PA_DENS) { CLAMP(ptex->exist,0.0,1.0); }
 }
 void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd, ParticleSystem *psys, ParticleData *pa, ParticleTexture *ptex, int event)
@@ -3392,12 +3412,12 @@ float psys_get_size(Object *ob, Material *ma, ParticleSystemModifierData *psmd,
 
        return size*part->size;
 }
-float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra)
+float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra, float *birthtime, float *dietime)
 {
        ParticleSettings *part = psys->part;
+       float time, life;
 
        if(part->childtype==PART_CHILD_FACES){
-               float time;
                int w=0;
                time=0.0;
                while(w<4 && cpa->pa[w]>=0){
@@ -3405,12 +3425,21 @@ float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra)
                        w++;
                }
 
-               return (cfra-time)/(part->lifetime*(1.0f-part->randlife*cpa->rand[1]));
+               life = part->lifetime*(1.0f-part->randlife*cpa->rand[1]);
        }
        else{
                ParticleData *pa = psys->particles + cpa->parent;
-               return (cfra-pa->time)/pa->lifetime;
+
+               time = pa->time;
+               life = pa->lifetime;
        }
+
+       if(birthtime)
+               *birthtime = time;
+       if(dietime)
+               *dietime = time+life;
+
+       return (cfra-time)/life;
 }
 float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, float *pa_time)
 {
@@ -3427,7 +3456,7 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra,
                        if(pa_time)
                                time=*pa_time;
                        else
-                               time=psys_get_child_time(psys,cpa,cfra);
+                               time=psys_get_child_time(psys,cpa,cfra,NULL,NULL);
 
                        /* correction for lifetime */
                        calc_ipo(part->ipo, 100*time);
@@ -3449,6 +3478,64 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra,
 
        return size;
 }
+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->clump=1.0;
+       ptex->kink=1.0;
+       ptex->rough1= 1.0;
+       ptex->rough2= 1.0;
+       ptex->roughe= 1.0;
+       ptex->exist= 1.0;
+       ptex->effector= 1.0;
+
+       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);
+
+
+       if(ptex->exist < cpa->rand[1])
+               return;
+
+       if(ctx->vg_length)
+               ptex->length*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_length);
+       if(ctx->vg_clump)
+               ptex->clump*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_clump);
+       if(ctx->vg_kink)
+               ptex->kink*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_kink);
+       if(ctx->vg_rough1)
+               ptex->rough1*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough1);
+       if(ctx->vg_rough2)
+               ptex->rough2*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough2);
+       if(ctx->vg_roughe)
+               ptex->roughe*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_roughe);
+       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)
+{
+       int guided = 0;
+
+       if(part->flag & PART_CHILD_EFFECT)
+               /* state is safe to cast, since only co and vel are used */
+               guided = do_guide(scene, (ParticleKey*)state, cpa->parent, t, &(psys->effectors));
+
+       if(guided==0){
+               if(part->kink)
+                       do_prekink(state, par, par_rot, t, part->kink_freq * ptex->kink, part->kink_shape,
+                       part->kink_amp, part->kink, part->kink_axis, ob->obmat);
+                               
+               do_clump(state, par, t, part->clumpfac, part->clumppow, ptex->clump);
+       }
+
+       if(part->rough1 != 0.0 && ptex->rough1 != 0.0)
+               do_rough(orco, 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);
+
+       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);
+}
 /* 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)
 {
@@ -3460,7 +3547,8 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
        ParticleTexture ptex;
        ParticleKey *kkey[2] = {NULL, NULL};
        HairKey *hkey[2] = {NULL, NULL};
-       ParticleKey *par=0, keys[4];
+       ParticleKey *par=0, keys[4], tstate;
+       ParticleThreadContext ctx; /* fake thread context for child modifiers */
 
        float t, real_t, dfra, keytime, frs_sec = scene->r.frs_sec;
        float co[3], orco[3];
@@ -3471,6 +3559,9 @@ 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 cached = !keyed && part->type != PART_HAIR;
+
        float *cpa_fuv; int cpa_num; short cpa_from;
 
        //if(psys_in_edit_mode(scene, psys)){
@@ -3479,12 +3570,6 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
        //      edit=1;
        //}
 
-       /* user want's cubic interpolation but only without sb it possible */
-       //if(interpolation==PART_INTER_CUBIC && baked && psys->softflag==OB_SB_ENABLE)
-       //      interpolation=PART_INTER_BSPLINE;
-       //else if(baked==0) /* it doesn't make sense to use other types for keyed */
-       //      interpolation=PART_INTER_CUBIC;
-
        t=state->time;
        CLAMP(t, 0.0, 1.0);
 
@@ -3497,20 +3582,29 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
                        return;
                }
                
-               if(psys->flag & PSYS_KEYED) {
+               if(keyed) {
                        kkey[0] = pa->keys;
                        kkey[1] = kkey[0] + 1;
 
-                       real_t = kkey[0]->time + t * (kkey[0][pa->totkey-1].time - kkey[0]->time);
+                       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;
 
-                       real_t = hkey[0]->time + (hkey[0][pa->totkey-1].time - hkey[0]->time) * t;
+                       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(psys->flag & PSYS_KEYED) {
+               if(keyed) {
                        while(kkey[1]->time < real_t) {
                                kkey[1]++;
                        }
@@ -3519,6 +3613,14 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
                        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]++;
@@ -3529,63 +3631,35 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
                        hair_to_particle(keys + 2, hkey[1]);
                }
 
-               if((psys->flag & PSYS_KEYED)==0) {
-               //if(soft){
-               //      if(key[0] != sbel.keys)
-               //              DB_copy_key(&k1,key[0]-1);
-               //      else
-               //              DB_copy_key(&k1,&k2);
-               //}
-               //else{
+               if(!keyed && !cached) {
                        if(hkey[0] != pa->hair)
                                hair_to_particle(keys, hkey[0] - 1);
                        else
                                hair_to_particle(keys, hkey[0]);
-               //}
 
-               //if(soft){
-               //      if(key[1] != sbel.keys + sbel.totkey-1)
-               //              DB_copy_key(&k4,key[1]+1);
-               //      else
-               //              DB_copy_key(&k4,&k3);
-               //}
-               //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]);
                }
-               //}
-
-               //psys_get_particle_on_path(scene, bsys,p,t,bkey,ckey[0]);
-
-               //if(part->rotfrom==PART_ROT_KEYS)
-               //      QuatInterpol(state->rot,k2.rot,k3.rot,keytime);
-               //else{
-               //      /* TODO: different rotations */
-               //      float nvel[3];
-               //      VECCOPY(nvel,state->vel);
-               //      VecMulf(nvel,-1.0f);
-               //      vectoquat(nvel, OB_POSX, OB_POSZ, state->rot);
-               //}
 
                dfra = keys[2].time - keys[1].time;
 
                keytime = (real_t - keys[1].time) / dfra;
 
                /* convert velocity to timestep size */
-               if(psys->flag & PSYS_KEYED){
+               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((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */
+               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(psys->flag & PSYS_KEYED){
+               if(keyed || cached){
                        VecMulf(state->vel, frs_sec / dfra);
                }
                else {
@@ -3606,8 +3680,11 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
        }
        else if(totchild){
                //Mat4Invert(imat,ob->obmat);
-               
+
                cpa=psys->child+p-totpart;
+
+               if(state->time < 0.0f)
+                       t = psys_get_child_time(psys, cpa, -state->time, NULL, NULL);
                
                if(totchild && part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
                        totparent=(int)(totchild*part->parents*0.3);
@@ -3624,7 +3701,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
 
                        /* get parent states */
                        while(w<4 && cpa->pa[w]>=0){
-                               keys[w].time = t;
+                               keys[w].time = state->time;
                                psys_get_particle_on_path(scene, ob, psys, cpa->pa[w], keys+w, 1);
                                w++;
                        }
@@ -3650,7 +3727,7 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
                else{
                        /* get the parent state */
 
-                       keys->time = t;
+                       keys->time = state->time;
                        psys_get_particle_on_path(scene, ob, psys, cpa->parent, keys,1);
 
                        /* get the original coordinates (orco) for texture usage */
@@ -3672,15 +3749,11 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
 #endif // XXX old animation system
                
                /* get different child parameters from textures & vgroups */
-               ptex.clump=1.0;
-               ptex.kink=1.0;
-               
-               get_cpa_texture(psmd->dm,ma,cpa_num,cpa_fuv,orco,&ptex,MAP_PA_CLUMP|MAP_PA_KINK);
-               
-               pa_clump=ptex.clump;
-               pa_kink=ptex.kink;
-
-               /* TODO: vertex groups */
+               memset(&ctx, 0, sizeof(ParticleThreadContext));
+               ctx.dm = psmd->dm;
+               ctx.ma = ma;
+               /* TODO: assign vertex groups */
+               get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
 
                if(between){
                        int w=0;
@@ -3708,46 +3781,34 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
                }
 
                par = keys;
-               //if(totparent){
-               //      if(p-totpart>=totparent){
-               //              key.time=t;
-               //              psys_get_particle_on_path(ob,psys,totpart+cpa->parent,&key,1);
-               //              bti->convert_dynamic_key(bsys,&key,par,cpar);
-               //      }
-               //      else
-               //              par=0;
-               //}
-               //else
-               //      DB_get_key_on_path(bsys,cpa->parent,t,par,cpar);
-
-               /* apply different deformations to the child path */
-               if(part->kink)
-                       do_prekink(state, par, par->rot, t, part->kink_freq * pa_kink, part->kink_shape,
-                       part->kink_amp, part->kink, part->kink_axis, ob->obmat);
-               
-               do_clump(state, par, t, part->clumpfac, part->clumppow, 1.0f);
-
-               if(part->rough1 != 0.0)
-                       do_rough(orco, t, part->rough1, part->rough1_size, 0.0, state);
 
-               if(part->rough2 != 0.0)
-                       do_rough(cpa->rand, t, part->rough2, part->rough2_size, part->rough2_thres, state);
+               if(vel)
+                       copy_particle_key(&tstate, state, 1);
 
-               if(part->rough_end != 0.0)
-                       do_rough_end(cpa->rand, t, part->rough_end, part->rough_end_shape, state, par); 
+               /* apply different deformations to the child path */
+               do_child_modifiers(scene, ob, psys, part, &ptex, par, par->rot, cpa, orco, state, t);
+
+               /* try to estimate correct velocity */
+               if(vel){
+                       ParticleKey tstate;
+                       float length = VecLength(state->vel);
+
+                       if(t>=0.001f){
+                               tstate.time=t-0.001f;
+                               psys_get_particle_on_path(scene,ob,psys,p,&tstate,0);
+                               VECSUB(state->vel,state->co,tstate.co);
+                               Normalize(state->vel);
+                       }
+                       else{
+                               float length = VecLength(state->vel);
+                               tstate.time=t+0.001f;
+                               psys_get_particle_on_path(scene, ob,psys,p,&tstate,0);
+                               VECSUB(state->vel,tstate.co,state->co);
+                               Normalize(state->vel);
+                       }
 
-               //if(vel){
-               //      if(t>=0.001f){
-               //              tstate.time=t-0.001f;
-               //              psys_get_particle_on_path(scene,ob,psys,p,&tstate,0);
-               //              VECSUB(state->vel,state->co,tstate.co);
-               //      }
-               //      else{
-               //              tstate.time=t+0.001f;
-               //              psys_get_particle_on_path(scene, ob,psys,p,&tstate,0);
-               //              VECSUB(state->vel,tstate.co,state->co);
-               //      }
-               //}
+                       VecMulf(state->vel, length);
+               }
        }
 }
 /* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */
@@ -3774,7 +3835,7 @@ int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psy
                pa=psys->particles+p;
 
        if(between){
-               state->time = psys_get_child_time(psys,&psys->child[p-totpart],cfra);
+               state->time = psys_get_child_time(psys,&psys->child[p-totpart],cfra,NULL,NULL);
 
                if(always==0)
                        if((state->time<0.0 && (part->flag & PART_UNBORN)==0)
index 591b6ca9be535cb9d931b3e6d36e4354b9a995c6..92b919f6b0e739829eda4069b7ef5addceb23b12 100644 (file)
@@ -4254,7 +4254,7 @@ static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModif
                }
        }
 
-       if((part->type==PART_HAIR || psys->flag&PSYS_KEYED) && ( psys_in_edit_mode(scene, psys) || (part->type==PART_HAIR 
+       if((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED) && ( psys_in_edit_mode(scene, psys) || (part->type==PART_HAIR 
                || (part->ren_as == PART_DRAW_PATH && (part->draw_as == PART_DRAW_REND || psys->renderdata))))){
 
                psys_cache_paths(scene, ob, psys, cfra, 0);
@@ -4371,8 +4371,10 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps
                dietime = birthtime + (1 + pa->loop) * (pa->dietime - pa->time);
 
                /* update alive status and push events */
-               if(pa->time > cfra)
+               if(pa->time > cfra) {
                        pa->alive = PARS_UNBORN;
+                       reset_particle(scene, pa, psys, psmd, ob, 0.0f, cfra, NULL, NULL, NULL);
+               }
                else if(dietime <= cfra){
                        if(dietime > psys->cfra){
                                state.time = dietime;
@@ -4406,6 +4408,8 @@ static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *ps
                distribute_particles(scene, ob, psys, PART_FROM_CHILD);
        }
 
+       psys_update_path_cache(scene, ob,psmd,psys,cfra);
+
        if(vg_size)
                MEM_freeN(vg_size);
 }
@@ -4433,10 +4437,17 @@ void psys_changed_type(ParticleSystem *psys)
 
                if(ELEM3(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0)
                        part->draw_as = PART_DRAW_REND;
+
+               CLAMP(part->path_start, 0.0f, 100.0f);
+               CLAMP(part->path_end, 0.0f, 100.0f);
        }
-       else
+       else {
                free_hair(psys, 1);
 
+               CLAMP(part->path_start, part->sta, part->end + part->lifetime);
+               CLAMP(part->path_end, part->sta, part->end + part->lifetime);
+       }
+
        psys->softflag= 0;
 
        psys_reset(psys, PSYS_RESET_ALL);
@@ -4629,9 +4640,8 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
                totpart = psys->part->totpart;
        totchild = get_psys_tot_child(scene, psys);
 
-       if(oldtotpart != totpart || (psys->part->childtype && oldtotchild != totchild)) {
+       if(oldtotpart != totpart || oldtotchild != totchild) {
                only_children_changed = (oldtotpart == totpart);
-               realloc_particles(ob, psys, totpart);
                alloc = 1;
                distr= 1;
                init= 1;
@@ -4647,11 +4657,12 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
                        if(alloc) {
                                realloc_particles(ob, psys, totpart);
 
-                               if(usecache)
+                               if(usecache && !only_children_changed)
                                        BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
                        }
 
-                       distribute_particles(scene, ob, psys, part->from);
+                       if(!only_children_changed)
+                               distribute_particles(scene, ob, psys, part->from);
 
                        if((psys->part->type == PART_HAIR) && !(psys->flag & PSYS_HAIR_DONE))
                        /* don't generate children while growing hair - waste of time */
@@ -4660,7 +4671,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
                                distribute_particles(scene, ob, psys, PART_FROM_CHILD);
                }
 
-               if(only_children_changed==0) {
+               if(!only_children_changed) {
                        free_keyed_keys(psys);
 
                        initialize_all_particles(ob, psys, psmd);
@@ -4680,19 +4691,10 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
                int result = get_particles_from_cache(scene, ob, psys, (float)framenr, &old_framenr);
 
                if(result == PTCACHE_READ_EXACT || result == PTCACHE_READ_INTERPOLATED) {
-                       //if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) {
-                       //      psys_count_keyed_targets(ob,psys);
-                       //      set_keyed_keys(scene, ob, psys);
-                       //}
-
                        cached_step(scene, ob, psmd, psys, cfra);
                        psys->cfra=cfra;
                        psys->recalc = 0;
 
-                       //if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) {
-                       //      psys_update_path_cache(scene, ob, psmd, psys, framenr);
-                       //}
-
                        cache->simframe= framenr;
                        cache->flag |= PTCACHE_SIMULATION_VALID;
 
index 64473d071517350885f1a5155be2175b818c181d..b8a0b111324eff7dce4a921e815f813139ca08e8 100644 (file)
@@ -1209,8 +1209,13 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker)
                for(pid=pidlist.first; pid; pid=pid->next) {
                        cache = pid->cache;
                        if((cache->flag & PTCACHE_BAKED)==0) {
-                               if(pid->type==PTCACHE_TYPE_PARTICLES)
+                               if(pid->type==PTCACHE_TYPE_PARTICLES) {
+                                       /* skip hair particles */
+                                       if(((ParticleSystem*)pid->data)->part->type == PART_HAIR)
+                                               continue;
+
                                        psys_get_pointcache_start_end(scene, pid->data, &cache->startframe, &cache->endframe);
+                               }
 
                                if((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID)==0)
                                        && ((cache->flag & PTCACHE_QUICK_CACHE)==0 || render || bake))
@@ -1265,6 +1270,10 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker)
                BKE_ptcache_ids_from_object(&pidlist, base->object);
 
                for(pid=pidlist.first; pid; pid=pid->next) {
+                       /* skip hair particles */
+                       if(pid->type==PTCACHE_TYPE_PARTICLES && ((ParticleSystem*)pid->data)->part->type == PART_HAIR)
+                               continue;
+               
                        cache = pid->cache;
 
                        if(step > 1)
@@ -1282,7 +1291,9 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker)
 
        scene->r.framelen = frameleno;
        CFRA = cfrao;
-       scene_update_for_newframe(scene, scene->lay);
+
+       if(bake) /* already on cfra unless baking */
+               scene_update_for_newframe(scene, scene->lay);
 
        /* TODO: call redraw all windows somehow */
 }
index c89f515f319859992464e9a6adb6c85bdc61f80f..93de096e7b453ade95f273bbe8fd63320d5de2c5 100644 (file)
@@ -9059,6 +9059,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                                        part->draw_as = PART_DRAW_REND;
                                }
                        }
+                       part->path_end = 1.0f;
                }
                /* set old pointcaches to have disk cache flag */
                for(ob = main->object.first; ob; ob= ob->id.next) {
index d9bc2d4d426b53ddd0f275500255f248489fcd5b..1ce352444e68996cb7ce380f247e0a2e3abbc3f5 100644 (file)
@@ -487,7 +487,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, i
                        ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
 
                        if(!(G.f & G_PARTICLEEDIT))
-                                       if(ELEM3(psys->part->draw_as, PART_DRAW_PATH, PART_DRAW_GR, PART_DRAW_OB) && psys->pathcache)
+                                       if(ELEM3(psys->part->ren_as, PART_DRAW_PATH, PART_DRAW_GR, PART_DRAW_OB) && psys->pathcache)
                                                uiItemO(row, "Convert", 0, "OBJECT_OT_modifier_convert");
                        }
                        else
index 8bdfaeb65199b421ade2278cac2d97b4aeb285b6..eb723dcca6c13450c1beab3b62b224a99b76b5b8 100644 (file)
@@ -226,11 +226,11 @@ int ED_object_modifier_convert(ReportList *reports, Scene *scene, Object *ob, Mo
        psys=((ParticleSystemModifierData *)md)->psys;
        part= psys->part;
 
-       if(part->draw_as == PART_DRAW_GR || part->draw_as == PART_DRAW_OB) {
+       if(part->ren_as == PART_DRAW_GR || part->ren_as == PART_DRAW_OB) {
                ; // XXX make_object_duplilist_real(NULL);
        }
        else {
-               if(part->draw_as != PART_DRAW_PATH || psys->pathcache == 0)
+               if(part->ren_as != PART_DRAW_PATH || psys->pathcache == 0)
                        return 0;
 
                totpart= psys->totcached;
index 05490e2fce192c1ffb539b121bc6a83df03691ee..b38575b5cebb25625ee242da6471a63785b9cc3c 100644 (file)
@@ -2941,6 +2941,228 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas
        return retval;
 }
 
+/* *********** text drawing for particles ************* */
+static ListBase pstrings= {NULL, NULL};
+
+typedef struct ViewParticleString {
+       struct ViewParticleString *next, *prev;
+       float vec[3], col[4];
+       char str[128]; 
+       short mval[2];
+       short xoffs;
+} ViewParticleString;
+
+
+void view3d_particle_text_draw_add(float x, float y, float z, char *str, short xoffs)
+{
+       ViewObjectString *vos= MEM_callocN(sizeof(ViewObjectString), "ViewObjectString");
+
+       BLI_addtail(&pstrings, vos);
+       BLI_strncpy(vos->str, str, 128);
+       vos->vec[0]= x;
+       vos->vec[1]= y;
+       vos->vec[2]= z;
+       glGetFloatv(GL_CURRENT_COLOR, vos->col);
+       vos->xoffs= xoffs;
+}
+
+static void view3d_particle_text_draw(View3D *v3d, ARegion *ar)
+{
+       ViewObjectString *vos;
+       int tot= 0;
+       
+       /* project first and test */
+       for(vos= pstrings.first; vos; vos= vos->next) {
+               project_short(ar, vos->vec, vos->mval);
+               if(vos->mval[0]!=IS_CLIPPED)
+                       tot++;
+       }
+       
+       if(tot) {
+               RegionView3D *rv3d= ar->regiondata;
+               int a;
+               
+               if(rv3d->rflag & RV3D_CLIPPING)
+                       for(a=0; a<6; a++)
+                               glDisable(GL_CLIP_PLANE0+a);
+               
+               wmPushMatrix();
+               ED_region_pixelspace(ar);
+               
+               if(v3d->zbuf) glDepthMask(0);
+
+               for(vos= pstrings.first; vos; vos= vos->next) {
+                       if(vos->mval[0]!=IS_CLIPPED) {
+                               glColor3fv(vos->col);
+                               BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], 2.0, vos->str);
+                       }
+               }
+               
+               if(v3d->zbuf) glDepthMask(1);
+               
+               wmPopMatrix();
+
+               if(rv3d->rflag & RV3D_CLIPPING)
+                       for(a=0; a<6; a++)
+                               glEnable(GL_CLIP_PLANE0+a);
+       }
+       
+       if(pstrings.first) 
+               BLI_freelistN(&pstrings);
+}
+typedef struct ParticleDrawData {
+       float *vdata, *vd;
+       float *ndata, *nd;
+       float *cdata, *cd;
+       float *vedata, *ved;
+       float *ma_r, *ma_g, *ma_b;
+} ParticleDrawData;
+static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize, float imat[4][4], float *draw_line, ParticleBillboardData *bb, ParticleDrawData *pdd)
+{
+       float vec[3], vec2[3];
+       float *vd = pdd->vd;
+       float *nd = pdd->nd;
+       float *cd = pdd->cd;
+       float ma_r;
+       float ma_g;
+       float ma_b;
+
+       if(pdd->ma_r) {
+               ma_r = *pdd->ma_r;
+               ma_g = *pdd->ma_g;
+               ma_b = *pdd->ma_b;
+       }
+
+       switch(draw_as){
+               case PART_DRAW_DOT:
+               {
+                       if(vd) {
+                               VECCOPY(vd,state->co) pdd->vd+=3;
+                       }
+                       if(cd) {
+                               cd[0]=ma_r;
+                               cd[1]=ma_g;
+                               cd[2]=ma_b;
+                               pdd->cd+=3;
+                       }
+                       break;
+               }
+               case PART_DRAW_CROSS:
+               case PART_DRAW_AXIS:
+               {
+                       vec[0]=2.0f*pixsize;
+                       vec[1]=vec[2]=0.0;
+                       QuatMulVecf(state->rot,vec);
+                       if(draw_as==PART_DRAW_AXIS) {
+                               cd[1]=cd[2]=cd[4]=cd[5]=0.0;
+                               cd[0]=cd[3]=1.0;
+                               cd[6]=cd[8]=cd[9]=cd[11]=0.0;
+                               cd[7]=cd[10]=1.0;
+                               cd[13]=cd[12]=cd[15]=cd[16]=0.0;
+                               cd[14]=cd[17]=1.0;
+                               cd+=18;
+
+                               VECCOPY(vec2,state->co);
+                       }
+                       else {
+                               if(cd) {
+                                       cd[0]=cd[3]=cd[6]=cd[9]=cd[12]=cd[15]=ma_r;
+                                       cd[1]=cd[4]=cd[7]=cd[10]=cd[13]=cd[16]=ma_g;
+                                       cd[2]=cd[5]=cd[8]=cd[11]=cd[14]=cd[17]=ma_b;
+                                       pdd->cd+=18;
+                               }
+                               VECSUB(vec2,state->co,vec);
+                       }
+
+                       VECADD(vec,state->co,vec);
+                       VECCOPY(pdd->vd,vec); pdd->vd+=3;
+                       VECCOPY(pdd->vd,vec2); pdd->vd+=3;
+                               
+                       vec[1]=2.0f*pixsize;
+                       vec[0]=vec[2]=0.0;
+                       QuatMulVecf(state->rot,vec);
+                       if(draw_as==PART_DRAW_AXIS){
+                               VECCOPY(vec2,state->co);
+                       }               
+                       else VECSUB(vec2,state->co,vec);
+
+                       VECADD(vec,state->co,vec);
+                       VECCOPY(pdd->vd,vec); pdd->vd+=3;
+                       VECCOPY(pdd->vd,vec2); pdd->vd+=3;
+
+                       vec[2]=2.0f*pixsize;
+                       vec[0]=vec[1]=0.0;
+                       QuatMulVecf(state->rot,vec);
+                       if(draw_as==PART_DRAW_AXIS){
+                               VECCOPY(vec2,state->co);
+                       }
+                       else VECSUB(vec2,state->co,vec);
+
+                       VECADD(vec,state->co,vec);
+
+                       VECCOPY(pdd->vd,vec); pdd->vd+=3;
+                       VECCOPY(pdd->vd,vec2); pdd->vd+=3;
+                       break;
+               }
+               case PART_DRAW_LINE:
+               {
+                       VECCOPY(vec,state->vel);
+                       Normalize(vec);
+                       if(draw & PART_DRAW_VEL_LENGTH)
+                               VecMulf(vec,VecLength(state->vel));
+                       VECADDFAC(pdd->vd,state->co,vec,-draw_line[0]); pdd->vd+=3;
+                       VECADDFAC(pdd->vd,state->co,vec,draw_line[1]); pdd->vd+=3;
+                       if(cd) {
+                               cd[0]=cd[3]=ma_r;
+                               cd[1]=cd[4]=ma_g;
+                               cd[2]=cd[5]=ma_b;
+                               pdd->cd+=6;
+                       }
+                       break;
+               }
+               case PART_DRAW_CIRC:
+               {
+                       if(pdd->ma_r)
+                               glColor3f(ma_r,ma_g,ma_b);
+                       drawcircball(GL_LINE_LOOP, state->co, pixsize, imat);
+                       break;
+               }
+               case PART_DRAW_BB:
+               {
+                       float xvec[3], yvec[3], zvec[3], bb_center[3];
+                       if(cd) {
+                               cd[0]=cd[3]=cd[6]=cd[9]=ma_r;
+                               cd[1]=cd[4]=cd[7]=cd[10]=ma_g;
+                               cd[2]=cd[5]=cd[8]=cd[11]=ma_b;
+                               pdd->cd+=12;
+                       }
+
+
+                       VECCOPY(bb->vec, state->co);
+                       VECCOPY(bb->vel, state->vel);
+
+                       psys_make_billboard(bb, xvec, yvec, zvec, bb_center);
+                       
+                       VECADD(pdd->vd,bb_center,xvec);
+                       VECADD(pdd->vd,pdd->vd,yvec); pdd->vd+=3;
+
+                       VECSUB(pdd->vd,bb_center,xvec);
+                       VECADD(pdd->vd,pdd->vd,yvec); pdd->vd+=3;
+
+                       VECSUB(pdd->vd,bb_center,xvec);
+                       VECSUB(pdd->vd,pdd->vd,yvec); pdd->vd+=3;
+
+                       VECADD(pdd->vd,bb_center,xvec);
+                       VECSUB(pdd->vd,pdd->vd,yvec); pdd->vd+=3;
+
+                       VECCOPY(pdd->nd, zvec); pdd->nd+=3;
+                       VECCOPY(pdd->nd, zvec); pdd->nd+=3;
+                       VECCOPY(pdd->nd, zvec); pdd->nd+=3;
+                       VECCOPY(pdd->nd, zvec); pdd->nd+=3;
+                       break;
+               }
+       }
+}
 /* unified drawing of all new particle systems draw types except dupli ob & group      */
 /* mostly tries to use vertex arrays for speed                                                                         */
 
@@ -2951,7 +3173,7 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas
 /* 5. start filling the arrays                         */
 /* 6. draw the arrays                                          */
 /* 7. clean up                                                         */
-static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, ParticleSystem *psys, int dt)
+static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, ParticleSystem *psys, int ob_dt)
 {
        Object *ob=base->object;
        ParticleSystemModifierData *psmd;
@@ -2959,14 +3181,15 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
        ParticleData *pars, *pa;
        ParticleKey state, *states=0;
        ParticleBillboardData bb;
+       ParticleDrawData pdd;
        Material *ma;
-       float vel[3], vec[3], vec2[3], imat[4][4], bb_center[3];
-       float timestep, pixsize=1.0, pa_size, pa_time, r_tilt;
+       float vel[3], imat[4][4];
+       float timestep, pixsize=1.0, pa_size, r_tilt, r_length;
+       float pa_time, pa_birthtime, pa_dietime;
        float cfra= bsystem_time(scene, ob,(float)CFRA,0.0);
-       float *vdata=0, *vedata=0, *cdata=0, *ndata=0, *vd=0, *ved=0, *cd=0, *nd=0, xvec[3], yvec[3], zvec[3];
        float ma_r=0.0f, ma_g=0.0f, ma_b=0.0f;
-       int a, totpart, totpoint=0, draw_as, totchild=0;
-       int select=ob->flag&SELECT, create_cdata=0;
+       int a, totpart, totpoint=0, totve=0, drawn, draw_as, totchild=0;
+       int select=ob->flag&SELECT, create_cdata=0, need_v=0;
        GLint polygonmode[2];
        char val[32];
 
@@ -3015,13 +3238,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
        else
                totchild=psys->totchild*part->disp/100;
        
-       ma= give_current_material(ob,part->omat);
+       memset(&pdd, 0, sizeof(ParticleDrawData));
 
-       if(ma) {
-               ma_r = ma->r;
-               ma_g = ma->g;
-               ma_b = ma->b;
-       }
+       ma= give_current_material(ob,part->omat);
 
        if(v3d->zbuf) glDepthMask(1);
 
@@ -3029,6 +3248,15 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                cpack(0xFFFFFF);
        else if((ma) && (part->draw&PART_DRAW_MAT_COL)) {
                glColor3f(ma->r,ma->g,ma->b);
+
+               ma_r = ma->r;
+               ma_g = ma->g;
+               ma_b = ma->b;
+
+               pdd.ma_r = &ma_r;
+               pdd.ma_g = &ma_g;
+               pdd.ma_b = &ma_b;
+
                create_cdata = 1;
        }
        else
@@ -3038,8 +3266,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
        timestep= psys_get_timestep(part);
 
-       wmLoadMatrix(rv3d->viewmat);
-
        if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) {
                float mat[4][4];
                Mat4MulMat4(mat, psys->imat, ob->obmat);
@@ -3119,6 +3345,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                        break;
                case PART_DRAW_PATH:
                        break;
+               case PART_DRAW_LINE:
+                       need_v=1;
+                       break;
        }
        if(part->draw & PART_DRAW_SIZE && part->draw_as!=PART_DRAW_CIRC){
                Mat4CpyMat4(imat, rv3d->viewinv);
@@ -3129,40 +3358,45 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 /* 4. */
        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)
+                       tot_vec_size *= part->trail_count;
 
                if(draw_as!=PART_DRAW_CIRC) {
                        switch(draw_as) {
                                case PART_DRAW_AXIS:
                                case PART_DRAW_CROSS:
                                        if(draw_as != PART_DRAW_CROSS || create_cdata)
-                                               cdata = MEM_callocN(tot_vec_size * 6, "particle_cdata");
-                                       vdata = MEM_callocN(tot_vec_size * 6, "particle_vdata");
+                                               pdd.cdata = MEM_callocN(tot_vec_size * 6, "particle_cdata");
+                                       pdd.vdata = MEM_callocN(tot_vec_size * 6, "particle_vdata");
                                        break;
                                case PART_DRAW_LINE:
                                        if(create_cdata)
-                                               cdata = MEM_callocN(tot_vec_size * 2, "particle_cdata");
-                                       vdata = MEM_callocN(tot_vec_size * 2, "particle_vdata");
+                                               pdd.cdata = MEM_callocN(tot_vec_size * 2, "particle_cdata");
+                                       pdd.vdata = MEM_callocN(tot_vec_size * 2, "particle_vdata");
                                        break;
                                case PART_DRAW_BB:
                                        if(create_cdata)
-                                               cdata = MEM_callocN(tot_vec_size * 4, "particle_cdata");
-                                       vdata = MEM_callocN(tot_vec_size * 4, "particle_vdata");
-                                       ndata = MEM_callocN(tot_vec_size * 4, "particle_vdata");
+                                               pdd.cdata = MEM_callocN(tot_vec_size * 4, "particle_cdata");
+                                       pdd.vdata = MEM_callocN(tot_vec_size * 4, "particle_vdata");
+                                       pdd.ndata = MEM_callocN(tot_vec_size * 4, "particle_vdata");
                                        break;
                                default:
                                        if(create_cdata)
-                                               cdata=MEM_callocN(tot_vec_size, "particle_cdata");
-                                       vdata=MEM_callocN(tot_vec_size, "particle_vdata");
+                                               pdd.cdata=MEM_callocN(tot_vec_size, "particle_cdata");
+                                       pdd.vdata=MEM_callocN(tot_vec_size, "particle_vdata");
                        }
                }
 
-               if(part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE)
-                       vedata = MEM_callocN(tot_vec_size * 2, "particle_vedata");
+               if(part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) {
+                       pdd.vedata = MEM_callocN(tot_vec_size * 2, "particle_vedata");
+                       need_v = 1;
+               }
 
-               vd=vdata;
-               ved=vedata;
-               cd=cdata;
-               nd=ndata;
+               pdd.vd= pdd.vdata;
+               pdd.ved= pdd.vedata;
+               pdd.cd= pdd.cdata;
+               pdd.nd= pdd.ndata;
 
                psys->lattice= psys_get_lattice(scene, ob, psys);
        }
@@ -3176,6 +3410,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                if(pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue;
 
                                pa_time=(cfra-pa->time)/pa->lifetime;
+                               pa_birthtime=pa->time;
+                               pa_dietime = pa->dietime;
                                pa_size=pa->size;
 
                                if((part->flag&PART_ABS_TIME)==0){      
@@ -3209,12 +3445,13 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 #endif // XXX old animation system
                                }
 
-                               r_tilt=1.0f+pa->r_ave[0];
+                               r_tilt = 1.0f + pa->r_ave[0];
+                               r_length = 0.5f * (1.0f + pa->r_ave[1]);
                        }
                        else{
                                ChildParticle *cpa= &psys->child[a-totpart];
 
-                               pa_time=psys_get_child_time(psys,cpa,cfra);
+                               pa_time=psys_get_child_time(psys,cpa,cfra,&pa_birthtime,&pa_dietime);
 
                                if((part->flag&PART_ABS_TIME)==0) {
                                        if(ma && ma->ipo){
@@ -3238,148 +3475,80 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
                                pa_size=psys_get_child_size(psys,cpa,cfra,0);
 
-                               r_tilt=2.0f*cpa->rand[2];
+                               r_tilt = 2.0f * cpa->rand[2];
+                               r_length = cpa->rand[1];
                        }
 
                        if(draw_as!=PART_DRAW_PATH){
-                               state.time=cfra;
-                               if(psys_get_particle_state(scene,ob,psys,a,&state,0)){
-                                       if(psys->parent)
-                                               Mat4MulVecfl(psys->parent->obmat, state.co);
-
-                                       /* create actiual particle data */
-                                       switch(draw_as){
-                                               case PART_DRAW_DOT:
-                                                       if(vd){
-                                                               VECCOPY(vd,state.co) vd+=3;
-                                                       }
-                                                       if(cd) {
-                                                               cd[0]=ma_r;
-                                                               cd[1]=ma_g;
-                                                               cd[2]=ma_b;
-                                                               cd+=3;
-                                                       }
-                                                       break;
-                                               case PART_DRAW_CROSS:
-                                               case PART_DRAW_AXIS:
-                                                       vec[0]=2.0f*pixsize;
-                                                       vec[1]=vec[2]=0.0;
-                                                       QuatMulVecf(state.rot,vec);
-                                                       if(draw_as==PART_DRAW_AXIS){
-                                                               cd[1]=cd[2]=cd[4]=cd[5]=0.0;
-                                                               cd[0]=cd[3]=1.0;
-                                                               cd[6]=cd[8]=cd[9]=cd[11]=0.0;
-                                                               cd[7]=cd[10]=1.0;
-                                                               cd[13]=cd[12]=cd[15]=cd[16]=0.0;
-                                                               cd[14]=cd[17]=1.0;
-                                                               cd+=18;
-
-                                                               VECCOPY(vec2,state.co);
-                                                       }
-                                                       else {
-                                                               if(cd) {
-                                                                       cd[0]=cd[3]=cd[6]=cd[9]=cd[12]=cd[15]=ma_r;
-                                                                       cd[1]=cd[4]=cd[7]=cd[10]=cd[13]=cd[16]=ma_g;
-                                                                       cd[2]=cd[5]=cd[8]=cd[11]=cd[14]=cd[17]=ma_b;
-                                                                       cd+=18;
-                                                               }
-                                                               VECSUB(vec2,state.co,vec);
-                                                       }
+                               drawn = 0;
+                               if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
+                                       float length = part->path_end * (1.0 - part->randlength * r_length);
+                                       int trail_count = part->trail_count * (1.0 - part->randlength * r_length);
+                                       float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length;
+                                       float dt = length / (trail_count ? (float)trail_count : 1.0f);
+                                       int i=0;
+
+                                       ct+=dt;
+                                       for(i=0; i < trail_count; i++, ct += dt) {
+                                               if(part->draw & PART_ABS_PATH_TIME) {
+                                                       if(ct < pa_birthtime || ct > pa_dietime)
+                                                               continue;
+                                               }
+                                               else if(ct < 0.0f || ct > 1.0f)
+                                                       continue;
 
-                                                       VECADD(vec,state.co,vec);
-                                                       VECCOPY(vd,vec); vd+=3;
-                                                       VECCOPY(vd,vec2); vd+=3;
-                                                               
-                                                       vec[1]=2.0f*pixsize;
-                                                       vec[0]=vec[2]=0.0;
-                                                       QuatMulVecf(state.rot,vec);
-                                                       if(draw_as==PART_DRAW_AXIS){
-                                                               VECCOPY(vec2,state.co);
-                                                       }               
-                                                       else VECSUB(vec2,state.co,vec);
-
-                                                       VECADD(vec,state.co,vec);
-                                                       VECCOPY(vd,vec); vd+=3;
-                                                       VECCOPY(vd,vec2); vd+=3;
-
-                                                       vec[2]=2.0f*pixsize;
-                                                       vec[0]=vec[1]=0.0;
-                                                       QuatMulVecf(state.rot,vec);
-                                                       if(draw_as==PART_DRAW_AXIS){
-                                                               VECCOPY(vec2,state.co);
-                                                       }
-                                                       else VECSUB(vec2,state.co,vec);
-
-                                                       VECADD(vec,state.co,vec);
-
-                                                       VECCOPY(vd,vec); vd+=3;
-                                                       VECCOPY(vd,vec2); vd+=3;
-                                                       break;
-                                               case PART_DRAW_LINE:
-                                                       VECCOPY(vec,state.vel);
-                                                       Normalize(vec);
-                                                       if(part->draw & PART_DRAW_VEL_LENGTH)
-                                                               VecMulf(vec,VecLength(state.vel));
-                                                       VECADDFAC(vd,state.co,vec,-part->draw_line[0]); vd+=3;
-                                                       VECADDFAC(vd,state.co,vec,part->draw_line[1]); vd+=3;
-                                                       if(cd) {
-                                                               cd[0]=cd[3]=ma_r;
-                                                               cd[1]=cd[4]=ma_g;
-                                                               cd[2]=cd[5]=ma_b;
-                                                               cd+=3;
-                                                       }
-                                                       break;
-                                               case PART_DRAW_CIRC:
-                                                       if(create_cdata)
-                                                               glColor3f(ma_r,ma_g,ma_b);
-                                                       drawcircball(GL_LINE_LOOP, state.co, pixsize, imat);
-                                                       break;
-                                               case PART_DRAW_BB:
-                                                       if(cd) {
-                                                               cd[0]=cd[3]=cd[6]=cd[9]=ma_r;
-                                                               cd[1]=cd[4]=cd[7]=cd[10]=ma_g;
-                                                               cd[2]=cd[5]=cd[8]=cd[11]=ma_b;
-                                                               cd+=12;
-                                                       }
+                                               state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct;
+                                               psys_get_particle_on_path(scene,ob,psys,a,&state,need_v);
+                                               
+                                               if(psys->parent)
+                                                       Mat4MulVecfl(psys->parent->obmat, state.co);
 
+                                               /* create actiual particle data */
+                                               if(draw_as == PART_DRAW_BB) {
                                                        bb.size = pa_size;
                                                        bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
-                                                       bb.time = pa_time;
-                                                       VECCOPY(bb.vec, state.co);
-                                                       VECCOPY(bb.vel, state.vel);
-
-                                                       psys_make_billboard(&bb, xvec, yvec, zvec, bb_center);
-                                                       
-                                                       VECADD(vd,bb_center,xvec);
-                                                       VECADD(vd,vd,yvec); vd+=3;
+                                                       bb.time = ct;
+                                               }
 
-                                                       VECSUB(vd,bb_center,xvec);
-                                                       VECADD(vd,vd,yvec); vd+=3;
+                                               draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, &pdd);
 
-                                                       VECSUB(vd,bb_center,xvec);
-                                                       VECSUB(vd,vd,yvec); vd+=3;
+                                               totpoint++;
+                                               drawn = 1;
+                                       }
+                               }
+                               else
+                               {
+                                       state.time=cfra;
+                                       if(psys_get_particle_state(scene,ob,psys,a,&state,0)){
+                                               if(psys->parent)
+                                                       Mat4MulVecfl(psys->parent->obmat, state.co);
+
+                                               /* create actiual particle data */
+                                               if(draw_as == PART_DRAW_BB) {
+                                                       bb.size = pa_size;
+                                                       bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
+                                                       bb.time = pa_time;
+                                               }
 
-                                                       VECADD(vd,bb_center,xvec);
-                                                       VECSUB(vd,vd,yvec); vd+=3;
+                                               draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, &pdd);
 
-                                                       VECCOPY(nd, zvec); nd+=3;
-                                                       VECCOPY(nd, zvec); nd+=3;
-                                                       VECCOPY(nd, zvec); nd+=3;
-                                                       VECCOPY(nd, zvec); nd+=3;
-                                                       break;
+                                               totpoint++;
+                                               drawn = 1;
                                        }
+                               }
 
-                                       totpoint++;
-
+                               if(drawn) {
                                        /* additional things to draw for each particle  */
                                        /* (velocity, size and number)                                  */
-                                       if(vedata){
-                                               VECCOPY(ved,state.co);
-                                               ved+=3;
+                                       if(pdd.vedata){
+                                               VECCOPY(pdd.ved,state.co);
+                                               pdd.ved+=3;
                                                VECCOPY(vel,state.vel);
                                                VecMulf(vel,timestep);
-                                               VECADD(ved,state.co,vel);
-                                               ved+=3;
+                                               VECADD(pdd.ved,state.co,vel);
+                                               pdd.ved+=3;
+
+                                               totve++;
                                        }
 
                                        if(part->draw & PART_DRAW_SIZE){
@@ -3391,7 +3560,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                        if(part->draw&PART_DRAW_NUM && !(G.f & G_RENDER_SHADOW)){
                                                /* in path drawing state.co is the end point */
                                                sprintf(val," %i",a);
-                                               view3d_object_text_draw_add(state.co[0],  state.co[1],  state.co[2], val, 0);
+                                               view3d_particle_text_draw_add(state.co[0],  state.co[1],  state.co[2], val, 0);
                                        }
                                }
                        }
@@ -3408,7 +3577,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                        glEnableClientState(GL_VERTEX_ARRAY);
 
                        /* setup gl flags */
-                       if(dt > OB_WIRE) {
+                       if(ob_dt > OB_WIRE) {
                                glEnableClientState(GL_NORMAL_ARRAY);
 
                                if(part->draw&PART_DRAW_MAT_COL)
@@ -3436,7 +3605,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                if(path->steps > 0) {
                                        glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
 
-                                       if(dt > OB_WIRE) {
+                                       if(ob_dt > OB_WIRE) {
                                                glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
                                                if(part->draw&PART_DRAW_MAT_COL)
                                                        glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
@@ -3452,7 +3621,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                path=cache[a];
                                glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
 
-                               if(dt > OB_WIRE) {
+                               if(ob_dt > OB_WIRE) {
                                        glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
                                        if(part->draw&PART_DRAW_MAT_COL)
                                                glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
@@ -3463,7 +3632,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
 
                        /* restore & clean up */
-                       if(dt > OB_WIRE) {
+                       if(ob_dt > OB_WIRE) {
                                if(part->draw&PART_DRAW_MAT_COL)
                                        glDisable(GL_COLOR_ARRAY);
                                glDisable(GL_COLOR_MATERIAL);
@@ -3479,16 +3648,17 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                        glDisableClientState(GL_COLOR_ARRAY);
 
                        /* setup created data arrays */
-                       if(vdata){
+                       if(pdd.vdata){
                                glEnableClientState(GL_VERTEX_ARRAY);
-                               glVertexPointer(3, GL_FLOAT, 0, vdata);
+                               glVertexPointer(3, GL_FLOAT, 0, pdd.vdata);
                        }
                        else
                                glDisableClientState(GL_VERTEX_ARRAY);
 
-                       if(ndata && dt>OB_WIRE){
+                       /* billboards are drawn this way */
+                       if(pdd.ndata && ob_dt>OB_WIRE){
                                glEnableClientState(GL_NORMAL_ARRAY);
-                               glNormalPointer(GL_FLOAT, 0, ndata);
+                               glNormalPointer(GL_FLOAT, 0, pdd.ndata);
                                glEnable(GL_LIGHTING);
                        }
                        else{
@@ -3496,9 +3666,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                glDisable(GL_LIGHTING);
                        }
 
-                       if(cdata){
+                       if(pdd.cdata){
                                glEnableClientState(GL_COLOR_ARRAY);
-                               glColorPointer(3, GL_FLOAT, 0, cdata);
+                               glColorPointer(3, GL_FLOAT, 0, pdd.cdata);
                        }
 
                        /* draw created data arrays */
@@ -3511,7 +3681,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                        glDrawArrays(GL_LINES, 0, 2*totpoint);
                                        break;
                                case PART_DRAW_BB:
-                                       if(dt<=OB_WIRE)
+                                       if(ob_dt<=OB_WIRE)
                                                glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
 
                                        glDrawArrays(GL_QUADS, 0, 4*totpoint);
@@ -3522,14 +3692,14 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                        }
                }
 
-               if(vedata){
+               if(pdd.vedata){
                        glDisableClientState(GL_COLOR_ARRAY);
                        cpack(0xC0C0C0);
                        
                        glEnableClientState(GL_VERTEX_ARRAY);
-                       glVertexPointer(3, GL_FLOAT, 0, vedata);
+                       glVertexPointer(3, GL_FLOAT, 0, pdd.vedata);
                        
-                       glDrawArrays(GL_LINES, 0, 2*totpoint);
+                       glDrawArrays(GL_LINES, 0, 2*totve);
                }
 
                glPolygonMode(GL_FRONT, polygonmode[0]);
@@ -3544,14 +3714,14 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
        if(states)
                MEM_freeN(states);
-       if(vdata)
-               MEM_freeN(vdata);
-       if(vedata)
-               MEM_freeN(vedata);
-       if(cdata)
-               MEM_freeN(cdata);
-       if(ndata)
-               MEM_freeN(ndata);
+       if(pdd.vdata)
+               MEM_freeN(pdd.vdata);
+       if(pdd.vedata)
+               MEM_freeN(pdd.vedata);
+       if(pdd.cdata)
+               MEM_freeN(pdd.cdata);
+       if(pdd.ndata)
+               MEM_freeN(pdd.ndata);
 
        psys->flag &= ~PSYS_DRAWING;
 
@@ -3560,8 +3730,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                psys->lattice= NULL;
        }
 
-       wmLoadMatrix(rv3d->viewmat);
-       wmMultMatrix(ob->obmat);        // bring back local matrix for dtx
+       if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) )
+               wmLoadMatrix(rv3d->viewmat);
 }
 
 static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, ParticleSystem *psys, int dt)
@@ -3596,8 +3766,6 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob
        if((v3d->flag & V3D_ZBUF_SELECT)==0)
                glDisable(GL_DEPTH_TEST);
 
-       wmLoadMatrix(rv3d->viewmat);
-
        /* get selection theme colors */
        UI_GetThemeColor3ubv(TH_VERTEX_SELECT, sel);
        UI_GetThemeColor3ubv(TH_VERTEX, nosel);
@@ -3706,7 +3874,7 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob
                                                if(key->flag & PEK_HIDE) continue;
 
                                                sprintf(val," %.1f",*key->time);
-                                               view3d_object_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0);
+                                               view3d_particle_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0);
                                        }
                                }
                        }
@@ -3729,7 +3897,7 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob
 
                                        if((pset->flag & PE_SHOW_TIME) && !(G.f & G_RENDER_SHADOW)){
                                                sprintf(val," %.1f",*key->time);
-                                               view3d_object_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0);
+                                               view3d_particle_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0);
                                        }
                                }
                        }
@@ -3744,7 +3912,6 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob
        glEnable(GL_DEPTH_TEST);
        glLineWidth(1.0f);
 
-       wmMultMatrix(ob->obmat);        // bring back local matrix for dtx
        glPointSize(1.0);
 }
 
@@ -5145,7 +5312,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
          ) {
                ParticleSystem *psys;
                if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); /* for visibility, also while wpaint */
-               glDepthMask(GL_FALSE);
+               //glDepthMask(GL_FALSE);
+
+               wmLoadMatrix(rv3d->viewmat);
                
                for(psys=ob->particlesystem.first; psys; psys=psys->next)
                        draw_new_particle_system(scene, v3d, rv3d, base, psys, dt);
@@ -5155,7 +5324,11 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
                        if(psys && !scene->obedit && psys_in_edit_mode(scene, psys))
                                draw_particle_edit(scene, v3d, rv3d, ob, psys, dt);
                }
-               glDepthMask(GL_TRUE); 
+               view3d_particle_text_draw(v3d, ar);
+
+               wmMultMatrix(ob->obmat);
+               
+               //glDepthMask(GL_TRUE);
                if(col) cpack(col);
        }
 
index 76f6b980aa20a51dc493b09924aaf09a813896e2..1fa17760e8d81603bd9970705742332b5efec246 100644 (file)
@@ -503,12 +503,14 @@ typedef enum {
        eParticleInstanceFlag_Unborn =          (1<<3),
        eParticleInstanceFlag_Alive =           (1<<4),
        eParticleInstanceFlag_Dead =            (1<<5),
+       eParticleInstanceFlag_KeepShape =       (1<<6),
 } ParticleInstanceModifierFlag;
 
 typedef struct ParticleInstanceModifierData {
        ModifierData modifier;
        struct Object *ob;
-       short psys, flag, rt[2];
+       short psys, flag, axis, rt;
+       float position, random_position;
 } ParticleInstanceModifierData;
 
 typedef enum {
index 05f1cc1f3516a5ecf7ac652aad9fb62309a094b5..c793362c2238ea8e15edcc0d5a9b8ae81c9da252 100644 (file)
@@ -131,7 +131,7 @@ typedef struct ParticleSettings {
 
        /* general values */
        float sta, end, lifetime, randlife;
-       float timetweak, jitfac, keyed_time, eff_hair, rt;
+       float timetweak, jitfac, keyed_time, eff_hair;
        int totpart, userjit, grid_res;
 
        /* initial velocity factors */
@@ -159,6 +159,8 @@ typedef struct ParticleSettings {
        float branch_thres;
        /* drawing stuff */
        float draw_line[2];
+       float path_start, path_end;
+       int trail_count;
 
        /* boids */
        float max_vel, max_lat_acc, max_tan_acc;
@@ -311,8 +313,8 @@ typedef struct ParticleSystem{                              /* note, make sure all (runtime) are NULL's in
 #define PART_DRAW_SIZE         4
 #define PART_DRAW_EMITTER      8       /* render emitter also */
 //#define PART_DRAW_HEALTH     16
-//#define PART_DRAW_TIMED_PATH  32
-//#define PART_DRAW_CACHED_PATH 64
+#define PART_ABS_PATH_TIME  32
+//#define PART_DRAW_TRAIL              64
 #define PART_DRAW_BB_LOCK      128
 #define PART_DRAW_PARENT       256
 #define PART_DRAW_NUM          512
index 48bfdf70171a69421d691e86b2dc28f32d1f9743..f4c14a51b13c73bbe613a2e0ce9a7bf6a8098cb3 100644 (file)
@@ -1300,6 +1300,13 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna)
        StructRNA *srna;
        PropertyRNA *prop;
 
+       static EnumPropertyItem particleinstance_axis[] = {
+               {0, "X", 0, "X", ""},
+               {1, "Y", 0, "Y", ""},
+               {2, "Z", 0, "Z", ""},
+               {0, NULL, 0, NULL, NULL}
+       };
+
        srna= RNA_def_struct(brna, "ParticleInstanceModifier", "Modifier");
        RNA_def_struct_ui_text(srna, "ParticleInstance Modifier", "Particle system instancing modifier.");
        RNA_def_struct_sdna(srna, "ParticleInstanceModifierData");
@@ -1316,6 +1323,12 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna)
        RNA_def_property_range(prop, 1, 10);
        RNA_def_property_ui_text(prop, "Particle System Number", "");
        RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update");
+
+       prop= RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "axis");
+       RNA_def_property_enum_items(prop, particleinstance_axis);
+       RNA_def_property_ui_text(prop, "Axis", "Pole axis for rotation");
+       RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update");
        
        prop= RNA_def_property(srna, "normal", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", eParticleInstanceFlag_Parents);
@@ -1346,6 +1359,23 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna)
        RNA_def_property_boolean_sdna(prop, NULL, "flag", eParticleInstanceFlag_Dead);
        RNA_def_property_ui_text(prop, "Dead", "Show instances when particles are dead.");
        RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update");
+
+       prop= RNA_def_property(srna, "keep_shape", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", eParticleInstanceFlag_KeepShape);
+       RNA_def_property_ui_text(prop, "Keep Shape", "Don't stretch the object.");
+       RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update");
+
+       prop= RNA_def_property(srna, "position", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "position");
+       RNA_def_property_range(prop, 0.0, 1.0);
+       RNA_def_property_ui_text(prop, "Position", "Position along path.");
+       RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update");
+
+       prop= RNA_def_property(srna, "random_position", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "random_position");
+       RNA_def_property_range(prop, 0.0, 1.0);
+       RNA_def_property_ui_text(prop, "Random Position", "Randomize position along path.");
+       RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update");
 }
 
 static void rna_def_modifier_explode(BlenderRNA *brna)
index d60a215b4985126b41f442b52240aecc37b25655..5c94c81da1f2518784cc4b9355a7de82d6a597fa 100644 (file)
@@ -151,6 +151,20 @@ static void rna_particle_settings_set(PointerRNA *ptr, PointerRNA value)
        if(psys->part)
                psys->part->id.us++;
 }
+static void rna_Particle_abspathtime_update(bContext *C, PointerRNA *ptr)
+{
+       ParticleSettings *settings = (ParticleSettings*)ptr->data;
+       float delta = settings->end + settings->lifetime - settings->sta;
+       if(settings->draw & PART_ABS_PATH_TIME) {
+               settings->path_start = settings->sta + settings->path_start * delta;
+               settings->path_end = settings->sta + settings->path_end * delta;
+       }
+       else {
+               settings->path_start = (settings->path_start - settings->sta)/delta;
+               settings->path_end = (settings->path_end - settings->sta)/delta;
+       }
+       rna_Particle_redo(C, ptr);
+}
 static void rna_PartSettings_start_set(struct PointerRNA *ptr, float value)
 {
        ParticleSettings *settings = (ParticleSettings*)ptr->data;
@@ -189,7 +203,19 @@ static float rna_PartSetting_linelentail_get(struct PointerRNA *ptr)
        ParticleSettings *settings = (ParticleSettings*)ptr->data;
        return settings->draw_line[0];
 }
+static void rna_PartSetting_pathstartend_range(PointerRNA *ptr, float *min, float *max)
+{
+       ParticleSettings *settings = (ParticleSettings*)ptr->data;
 
+       if(settings->type==PART_HAIR) {
+               *min = 0.0f;
+               *max = (settings->draw & PART_ABS_PATH_TIME) ? 100.0f : 1.0;
+       }
+       else {
+               *min = (settings->draw & PART_ABS_PATH_TIME) ? settings->sta : 0.0f;
+               *max= (settings->draw & PART_ABS_PATH_TIME) ? MAXFRAMEF : 1.0f;
+       }
+}
 static void rna_PartSetting_linelenhead_set(struct PointerRNA *ptr, float value)
 {
        ParticleSettings *settings = (ParticleSettings*)ptr->data;
@@ -702,15 +728,15 @@ static void rna_def_particle_settings(BlenderRNA *brna)
        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, "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, "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);
@@ -836,15 +862,10 @@ static void rna_def_particle_settings(BlenderRNA *brna)
        //RNA_def_property_ui_text(prop, "Health", "Draw boid health");
        //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
 
-       //prop= RNA_def_property(srna, "timed_path", PROP_BOOLEAN, PROP_NONE);
-       //RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_TIMED_PATH);
-       //RNA_def_property_ui_text(prop, "Clip with time", "Clip path based on time");
-       //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
-
-       //prop= RNA_def_property(srna, "draw_cached_path", PROP_BOOLEAN, PROP_NONE);
-       //RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_CACHED_PATH);
-       //RNA_def_property_ui_text(prop, "Path", "Draw particle path if the path is baked");
-       //RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
+       prop= RNA_def_property(srna, "abs_path_time", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_ABS_PATH_TIME);
+       RNA_def_property_ui_text(prop, "Absolute Path Time", "Path timing is in absolute frames");
+       RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_abspathtime_update");
 
        prop= RNA_def_property(srna, "billboard_lock", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_BB_LOCK);
@@ -1410,6 +1431,24 @@ static void rna_def_particle_settings(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Head", "Length of the line's head");
        RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
 
+       prop= RNA_def_property(srna, "path_start", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "path_start");
+       RNA_def_property_float_funcs(prop, NULL, NULL, "rna_PartSetting_pathstartend_range");
+       RNA_def_property_ui_text(prop, "Path Start", "Starting time of drawn path.");
+       RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
+
+       prop= RNA_def_property(srna, "path_end", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "path_end");
+       RNA_def_property_float_funcs(prop, NULL, NULL, "rna_PartSetting_pathstartend_range");
+       RNA_def_property_ui_text(prop, "Path End", "End time of drawn path.");
+       RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
+
+       prop= RNA_def_property(srna, "trail_count", PROP_INT, PROP_NONE);
+       RNA_def_property_int_sdna(prop, NULL, "trail_count");
+       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");
+       
        /* boids */
        prop= RNA_def_property(srna, "max_velocity", PROP_FLOAT, PROP_NONE);
        RNA_def_property_float_sdna(prop, NULL, "max_vel");
index a00cd2211fc2f8f18b97ad484c87ed4cac7bf4b1..74686511b21e68ad4a9364affb272b72093daccb 100644 (file)
@@ -1246,6 +1246,19 @@ static void static_particle_wire(ObjectRen *obr, Material *ma, float *vec, float
 
 }
 
+static void particle_curve(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, float *loc, float *loc1, int seed)
+{
+       HaloRen *har=0;
+
+       if(ma->mode&MA_WIRE)
+               static_particle_wire(obr, ma, loc, loc1, sd->first, sd->line);
+       else if(ma->material_type == MA_TYPE_HALO) {
+               har= RE_inithalo_particle(re, obr, dm, ma, loc, loc1, sd->orco, sd->uvco, sd->size, 1.0, seed);
+               if(har) har->lay= obr->ob->lay;
+       }
+       else
+               static_particle_strand(re, obr, ma, sd, loc, loc1);
+}
 static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, ParticleBillboardData *bb)
 {
        VlakRen *vlr;
@@ -1368,18 +1381,55 @@ static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, Particl
                mtf->uv[3][1] = uvy;
        }
 }
-static void render_new_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, float *loc, float *loc1,    int seed)
+static void particle_normal_ren(short ren_as, ParticleSettings *part, Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, ParticleBillboardData *bb, ParticleKey *state, int seed, float hasize)
 {
-       HaloRen *har=0;
+       float loc[3], loc0[3], loc1[3], vel[3];
+       
+       VECCOPY(loc, state->co);
 
-       if(ma->mode&MA_WIRE)
-               static_particle_wire(obr, ma, loc, loc1, sd->first, sd->line);
-       else if(ma->material_type == MA_TYPE_HALO) {
-               har= RE_inithalo_particle(re, obr, dm, ma, loc, loc1, sd->orco, sd->uvco, sd->size, 1.0, seed);
-               if(har) har->lay= obr->ob->lay;
+       if(ren_as != PART_DRAW_BB)
+               MTC_Mat4MulVecfl(re->viewmat, loc);
+
+       switch(ren_as) {
+               case PART_DRAW_LINE:
+                       sd->line = 1;
+                       sd->time = 0.0f;
+                       sd->size = hasize;
+
+                       VECCOPY(vel, state->vel);
+                       MTC_Mat4Mul3Vecfl(re->viewmat, vel);
+                       Normalize(vel);
+
+                       if(part->draw & PART_DRAW_VEL_LENGTH)
+                               VecMulf(vel, VecLength(state->vel));
+
+                       VECADDFAC(loc0, loc, vel, -part->draw_line[0]);
+                       VECADDFAC(loc1, loc, vel, part->draw_line[1]);
+
+                       particle_curve(re, obr, dm, ma, sd, loc0, loc1, seed);
+
+                       break;
+
+               case PART_DRAW_BB:
+
+                       VECCOPY(bb->vec, loc);
+                       VECCOPY(bb->vel, state->vel);
+
+                       particle_billboard(re, obr, ma, bb);
+
+                       break;
+
+               default:
+               {
+                       HaloRen *har=0;
+
+                       har = RE_inithalo_particle(re, obr, dm, ma, loc, NULL, sd->orco, sd->uvco, hasize, 0.0, seed);
+                       
+                       if(har) har->lay= obr->ob->lay;
+
+                       break;
+               }
        }
-       else
-               static_particle_strand(re, obr, ma, sd, loc, loc1);
 }
 static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int num, ParticleStrandData *sd)
 {
@@ -1436,9 +1486,10 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
        StrandBound *sbound= 0;
        StrandRen *strand=0;
        RNG *rng= 0;
-       float loc[3],loc1[3],loc0[3],vel[3],mat[4][4],nmat[3][3],co[3],nor[3],time;
+       float loc[3],loc1[3],loc0[3],mat[4][4],nmat[3][3],co[3],nor[3],time;
        float strandlen=0.0f, curlen=0.0f;
-       float hasize, pa_size, pa_time, r_tilt, cfra=bsystem_time(re->scene, ob, (float)re->scene->r.cfra, 0.0);
+       float hasize, pa_size, r_tilt, r_length, cfra=bsystem_time(re->scene, ob, (float)re->scene->r.cfra, 0.0);
+       float pa_time, pa_birthtime, pa_dietime;
        float random, simplify[2];
        int i, a, k, max_k=0, totpart, dosimplify = 0, dosurfacecache = 0;
        int totchild=0;
@@ -1654,6 +1705,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                        if(pa->flag & PARS_UNEXIST) continue;
 
                        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(ma->ipo) {
@@ -1691,6 +1744,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                        pa_size = pa->size;
 
                        r_tilt = 1.0f + pa->r_ave[0];
+                       r_length = 0.5f * (1.0f + pa->r_ave[1]);
 
                        if(path_nbr) {
                                cache = psys->pathcache[a];
@@ -1711,7 +1765,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                                max_k = (int)cache->steps;
                        }
                        
-                       pa_time = psys_get_child_time(psys, cpa, cfra);
+                       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
@@ -1731,6 +1785,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                        pa_size = psys_get_child_size(psys, cpa, cfra, &pa_time);
 
                        r_tilt = 2.0f * cpa->rand[2];
+                       r_length = cpa->rand[1];
 
                        num = cpa->num;
 
@@ -1864,14 +1919,14 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                                                VECSUB(loc0,loc1,loc);
                                                VECADD(loc0,loc1,loc0);
 
-                                               render_new_particle(re, obr, psmd->dm, ma, &sd, loc1, loc0, seed);
+                                               particle_curve(re, obr, psmd->dm, ma, &sd, loc1, loc0, seed);
                                        }
 
                                        sd.first = 0;
                                        sd.time = time;
 
                                        if(k)
-                                               render_new_particle(re, obr, psmd->dm, ma, &sd, loc, loc1, seed);
+                                               particle_curve(re, obr, psmd->dm, ma, &sd, loc, loc1, seed);
 
                                        VECCOPY(loc1,loc);
                                }
@@ -1880,61 +1935,55 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                }
                else {
                        /* render normal particles */
-                       time=0.0f;
-                       state.time=cfra;
-                       if(psys_get_particle_state(re->scene,ob,psys,a,&state,0)==0)
-                               continue;
-
-                       if(psys->parent)
-                               Mat4MulVecfl(psys->parent->obmat, state.co);
-
-                       VECCOPY(loc,state.co);
-                       if(part->ren_as!=PART_DRAW_BB)
-                               MTC_Mat4MulVecfl(re->viewmat,loc);
-
-                       switch(part->ren_as) {
-                               case PART_DRAW_LINE:
-                                       sd.line = 1;
-                                       sd.time = 0.0f;
-                                       sd.size = hasize;
+                       if(part->trail_count > 1) {
+                               float length = part->path_end * (1.0 - part->randlength * r_length);
+                               int trail_count = part->trail_count * (1.0 - part->randlength * r_length);
+                               float ct = (part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time;
+                               float dt = length / (trail_count ? (float)trail_count : 1.0f);
+
+                               for(i=0; i < trail_count; i++, ct -= dt) {
+                                       if(part->draw & PART_ABS_PATH_TIME) {
+                                               if(ct < pa_birthtime || ct > pa_dietime)
+                                                       continue;
+                                       }
+                                       else if(ct < 0.0f || ct > 1.0f)
+                                               continue;
 
-                                       VECCOPY(vel,state.vel);
-                                       MTC_Mat4Mul3Vecfl(re->viewmat,vel);
-                                       Normalize(vel);
+                                       state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct;
+                                       psys_get_particle_on_path(re->scene,ob,psys,a,&state,1);
 
-                                       if(part->draw & PART_DRAW_VEL_LENGTH)
-                                               VecMulf(vel,VecLength(state.vel));
+                                       if(psys->parent)
+                                               Mat4MulVecfl(psys->parent->obmat, state.co);
 
-                                       VECADDFAC(loc0,loc,vel,-part->draw_line[0]);
-                                       VECADDFAC(loc1,loc,vel,part->draw_line[1]);
+                                       if(part->ren_as == PART_DRAW_BB) {
+                                               bb.random = random;
+                                               bb.size = pa_size;
+                                               bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
+                                               bb.time = ct;
+                                               bb.num = a;
+                                       }
 
-                                       render_new_particle(re,obr,psmd->dm,ma,&sd,loc0,loc1,seed);
+                                       particle_normal_ren(part->ren_as, part, re, obr, psmd->dm, ma, &sd, &bb, &state, seed, hasize);
+                               }
+                       }
+                       else {
+                               time=0.0f;
+                               state.time=cfra;
+                               if(psys_get_particle_state(re->scene,ob,psys,a,&state,0)==0)
+                                       continue;
 
-                                       break;
+                               if(psys->parent)
+                                       Mat4MulVecfl(psys->parent->obmat, state.co);
 
-                               case PART_DRAW_BB:
+                               if(part->ren_as == PART_DRAW_BB) {
                                        bb.random = random;
                                        bb.size = pa_size;
                                        bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
                                        bb.time = pa_time;
                                        bb.num = a;
-                                       VECCOPY(bb.vec, loc);
-                                       VECCOPY(bb.vel, state.vel);
-
-                                       particle_billboard(re, obr, ma, &bb);
-
-                                       break;
-
-                               default:
-                               {
-                                       HaloRen *har=0;
-
-                                       har = RE_inithalo_particle(re, obr, psmd->dm, ma, loc, NULL, sd.orco, sd.uvco, hasize, 0.0, seed);
-                                       
-                                       if(har) har->lay= obr->ob->lay;
-
-                                       break;
                                }
+
+                               particle_normal_ren(part->ren_as, part, re, obr, psmd->dm, ma, &sd, &bb, &state, seed, hasize);
                        }
                }