2.5 - Animation Playback Tweaks
[blender.git] / source / blender / blenkernel / intern / anim.c
index bfc0779368acb6d584ba98ee0b3b7eaae08ac21b..6c1b8eb9000cb192e7954bec3aedf235a47b7bcf 100644 (file)
@@ -3,15 +3,12 @@
  *
  * $Id$
  *
- * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version. The Blender
- * Foundation also sells licenses for use in proprietary software under
- * the Blender License.  See http://www.blender.org/BL/ for information
- * about this.
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -29,7 +26,7 @@
  *
  * Contributor(s): none yet.
  *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * ***** END GPL LICENSE BLOCK *****
  */
 
 #include <math.h>
@@ -37,6 +34,7 @@
 
 #include "MEM_guardedalloc.h"
 #include "BLI_blenlib.h"
+#include "BLI_editVert.h"
 #include "BLI_arithb.h"
 #include "BLI_rand.h"
 #include "DNA_listBase.h"
@@ -55,6 +53,7 @@
 #include "DNA_vfont_types.h"
 
 #include "BKE_anim.h"
+#include "BKE_curve.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_displist.h"
 #include "BKE_effect.h"
 #include "BKE_key.h"
 #include "BKE_lattice.h"
 #include "BKE_main.h"
+#include "BKE_mesh.h"
 #include "BKE_object.h"
 #include "BKE_particle.h"
 #include "BKE_utildefines.h"
 
-#include "BKE_bad_level_calls.h"
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#define MAX_DUPLI_RECUR 4
+#include "ED_mesh.h"
 
-static void object_duplilist_recursive(ID *id, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level);
+static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated);
 
 void free_path(Path *path)
 {
@@ -103,8 +101,10 @@ void calc_curvepath(Object *ob)
        
        if(ob==NULL || ob->type != OB_CURVE) return;
        cu= ob->data;
-       if(ob==G.obedit) nu= editNurb.first;
-       else nu= cu->nurb.first;
+       if(cu->editnurb) 
+               nu= cu->editnurb->first;
+       else 
+               nu= cu->nurb.first;
        
        if(cu->path) free_path(cu->path);
        cu->path= NULL;
@@ -122,7 +122,7 @@ void calc_curvepath(Object *ob)
        
        path->len= tot+1;
        /* exception: vector handle paths and polygon paths should be subdivided at least a factor resolu */
-       if(path->len<nu->resolu*nu->pntsu) path->len= nu->resolu*nu->pntsu;
+       if(path->len<nu->resolu*SEGMENTSU(nu)) path->len= nu->resolu*SEGMENTSU(nu);
        
        dist= (float *)MEM_mallocN((tot+1)*4, "calcpathdist");
 
@@ -226,14 +226,16 @@ int where_on_path(Object *ob, float ctime, float *vec, float *dir)        /* returns OK
        cu= ob->data;
        if(cu->path==NULL || cu->path->data==NULL) {
                printf("no path!\n");
+               return 0;
        }
        path= cu->path;
        fp= path->data;
        
        /* test for cyclic */
        bl= cu->bev.first;
+       if (!bl) return 0;
        if (!bl->nr) return 0;
-       if(bl && bl->poly> -1) cycl= 1;
+       if(bl->poly> -1) cycl= 1;
 
        ctime *= (path->len-1);
        
@@ -285,7 +287,7 @@ int where_on_path(Object *ob, float ctime, float *vec, float *dir)  /* returns OK
 
 /* ****************** DUPLICATOR ************** */
 
-static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int type)
+static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int type, int animated)
 {
        DupliObject *dob= MEM_callocN(sizeof(DupliObject), "dupliobject");
        
@@ -296,17 +298,18 @@ static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], i
        dob->origlay= ob->lay;
        dob->index= index;
        dob->type= type;
+       dob->animated= (type == OB_DUPLIGROUP) && animated;
        ob->lay= lay;
        
        return dob;
 }
 
-static void group_duplilist(ListBase *lb, Object *ob, int level)
+static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated)
 {
        DupliObject *dob;
        Group *group;
        GroupObject *go;
-       float mat[4][4];
+       float mat[4][4], tmat[4][4];
        
        if(ob->dup_group==NULL) return;
        group= ob->dup_group;
@@ -316,74 +319,91 @@ static void group_duplilist(ListBase *lb, Object *ob, int level)
        
        /* handles animated groups, and */
        /* we need to check update for objects that are not in scene... */
-       group_handle_recalc_and_update(ob, group);
+       group_handle_recalc_and_update(scene, ob, group);
+       animated= animated || group_is_animated(ob, group);
        
        for(go= group->gobject.first; go; go= go->next) {
                /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
                if(go->ob!=ob) {
                        
-                       Mat4MulMat4(mat, go->ob->obmat, ob->obmat);
-                       dob= new_dupli_object(lb, go->ob, mat, ob->lay, 0, OB_DUPLIGROUP);
+                       /* Group Dupli Offset, should apply after everything else */
+                       if (group->dupli_ofs[0] || group->dupli_ofs[1] || group->dupli_ofs[2]) {
+                               Mat4CpyMat4(tmat, go->ob->obmat);
+                               VecSubf(tmat[3], tmat[3], group->dupli_ofs);
+                               Mat4MulMat4(mat, tmat, ob->obmat);
+                       } else {
+                               Mat4MulMat4(mat, go->ob->obmat, ob->obmat);
+                       }
+                       
+                       dob= new_dupli_object(lb, go->ob, mat, ob->lay, 0, OB_DUPLIGROUP, animated);
                        dob->no_draw= (dob->origlay & group->layer)==0;
                        
                        if(go->ob->transflag & OB_DUPLI) {
                                Mat4CpyMat4(dob->ob->obmat, dob->mat);
-                               object_duplilist_recursive((ID *)group, go->ob, lb, ob->obmat, level+1);
+                               object_duplilist_recursive((ID *)group, scene, go->ob, lb, ob->obmat, level+1, animated);
                                Mat4CpyMat4(dob->ob->obmat, dob->omat);
                        }
                }
        }
 }
 
-static void frames_duplilist(ListBase *lb, Object *ob, int level)
+static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated)
 {
        extern int enable_cu_speed;     /* object.c */
        Object copyob;
+       DupliObject *dob;
        int cfrao, ok;
        
        /* simple preventing of too deep nested groups */
        if(level>MAX_DUPLI_RECUR) return;
        
-       cfrao= G.scene->r.cfra;
+       cfrao= scene->r.cfra;
        if(ob->parent==NULL && ob->track==NULL && ob->ipo==NULL && ob->constraints.first==NULL) return;
 
        if(ob->transflag & OB_DUPLINOSPEED) enable_cu_speed= 0;
        copyob= *ob;    /* store transform info */
 
-       for(G.scene->r.cfra= ob->dupsta; G.scene->r.cfra<=ob->dupend; G.scene->r.cfra++) {
+       for(scene->r.cfra= ob->dupsta; scene->r.cfra<=ob->dupend; scene->r.cfra++) {
 
                ok= 1;
                if(ob->dupoff) {
-                       ok= G.scene->r.cfra - ob->dupsta;
+                       ok= scene->r.cfra - ob->dupsta;
                        ok= ok % (ob->dupon+ob->dupoff);
                        if(ok < ob->dupon) ok= 1;
                        else ok= 0;
                }
                if(ok) {
-                       do_ob_ipo(ob);
-                       where_is_object_time(ob, (float)G.scene->r.cfra);
-                       new_dupli_object(lb, ob, ob->obmat, ob->lay, G.scene->r.cfra, OB_DUPLIFRAMES);
+#if 0 // XXX old animation system
+                       do_ob_ipo(scene, ob);
+#endif // XXX old animation system
+                       where_is_object_time(scene, ob, (float)scene->r.cfra);
+                       dob= new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, OB_DUPLIFRAMES, animated);
+                       Mat4CpyMat4(dob->omat, copyob.obmat);
                }
        }
 
        *ob= copyob;    /* restore transform info */
-       G.scene->r.cfra= cfrao;
+       scene->r.cfra= cfrao;
        enable_cu_speed= 1;
 }
 
 struct vertexDupliData {
        ID *id; /* scene or group, for recursive loops */
        int level;
+       int animated;
        ListBase *lb;
        float pmat[4][4];
        float obmat[4][4]; /* Only used for dupliverts inside dupligroups, where the ob->obmat is modified */
+       Scene *scene;
        Object *ob, *par;
+       float (*orco)[3];
 };
 
 static void vertex_dupli__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
 {
+       DupliObject *dob;
        struct vertexDupliData *vdd= userData;
-       float vec[3], *q2, mat[3][3], tmat[4][4], obmat[4][4];
+       float vec[3], q2[4], mat[3][3], tmat[4][4], obmat[4][4];
        
        VECCOPY(vec, co);
        Mat4MulVecfl(vdd->pmat, vec);
@@ -401,44 +421,58 @@ static void vertex_dupli__mapFunc(void *userData, int index, float *co, float *n
                        vec[0]= -no_s[0]; vec[1]= -no_s[1]; vec[2]= -no_s[2];
                }
                
-               q2= vectoquat(vec, vdd->ob->trackflag, vdd->ob->upflag);
+               vectoquat(vec, vdd->ob->trackflag, vdd->ob->upflag, q2);
                
                QuatToMat3(q2, mat);
                Mat4CpyMat4(tmat, obmat);
                Mat4MulMat43(obmat, tmat, mat);
        }
-       new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, OB_DUPLIVERTS);
+       dob= new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, OB_DUPLIVERTS, vdd->animated);
+       if(vdd->orco)
+               VECCOPY(dob->orco, vdd->orco[index]);
        
        if(vdd->ob->transflag & OB_DUPLI) {
                float tmpmat[4][4];
                Mat4CpyMat4(tmpmat, vdd->ob->obmat);
                Mat4CpyMat4(vdd->ob->obmat, obmat); /* pretend we are really this mat */
-               object_duplilist_recursive((ID *)vdd->id, vdd->ob, vdd->lb, obmat, vdd->level+1);
+               object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->level+1, vdd->animated);
                Mat4CpyMat4(vdd->ob->obmat, tmpmat);
        }
 }
 
-static void vertex_duplilist(ListBase *lb, ID *id, Object *par, float par_space_mat[][4], int level)
+static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated)
 {
        Object *ob, *ob_iter;
+       Mesh *me= par->data;
        Base *base = NULL;
-       float vec[3], no[3], pmat[4][4];
-       int lay, totvert, a, oblay;
        DerivedMesh *dm;
        struct vertexDupliData vdd;
        Scene *sce = NULL;
        Group *group = NULL;
        GroupObject * go = NULL;
+       EditMesh *em;
+       float vec[3], no[3], pmat[4][4];
+       int lay, totvert, a, oblay;
        
        Mat4CpyMat4(pmat, par->obmat);
        
        /* simple preventing of too deep nested groups */
        if(level>MAX_DUPLI_RECUR) return;
        
-       if(par==G.obedit)
-               dm= editmesh_get_derived_cage(CD_MASK_BAREMESH);
+       em = BKE_mesh_get_editmesh(me);
+       
+       if(em) {
+               dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
+               BKE_mesh_end_editmesh(me, em);
+       } else
+               dm= mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
+       
+       if(G.rendering) {
+               vdd.orco= (float(*)[3])get_mesh_orco_verts(par);
+               transform_mesh_orco_verts(me, vdd.orco, me->totvert, 0);
+       }
        else
-               dm = mesh_get_derived_deform(par, CD_MASK_BAREMESH);
+               vdd.orco= NULL;
        
        totvert = dm->getNumVerts(dm);
 
@@ -463,7 +497,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Object *par, float par_space_
                        oblay = ob_iter->lay;
                }
                
-               if (lay & oblay && G.obedit!=ob_iter) {
+               if (lay & oblay && scene->obedit!=ob_iter) {
                        ob=ob_iter->parent;
                        while(ob) {
                                if(ob==par) {
@@ -481,15 +515,17 @@ static void vertex_duplilist(ListBase *lb, ID *id, Object *par, float par_space_
 
                                        vdd.id= id;
                                        vdd.level= level;
+                                       vdd.animated= animated;
                                        vdd.lb= lb;
                                        vdd.ob= ob;
+                                       vdd.scene= scene;
                                        vdd.par= par;
                                        Mat4CpyMat4(vdd.pmat, pmat);
                                        
                                        /* mballs have a different dupli handling */
                                        if(ob->type!=OB_MBALL) ob->flag |= OB_DONE;     /* doesnt render */
 
-                                       if(par==G.obedit) {
+                                       if(par==scene->obedit) {
                                                dm->foreachMappedVert(dm, vertex_dupli__mapFunc, (void*) &vdd);
                                        }
                                        else {
@@ -510,22 +546,27 @@ static void vertex_duplilist(ListBase *lb, ID *id, Object *par, float par_space_
                else            go= go->next;           /* group loop */
        }
 
+       if(vdd.orco)
+               MEM_freeN(vdd.orco);
        dm->release(dm);
 }
 
-static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_mat[][4], int level)
+static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated)
 {
        Object *ob, *ob_iter;
        Base *base = NULL;
+       DupliObject *dob;
        DerivedMesh *dm;
+       Mesh *me= par->data;
+       MTFace *mtface;
        MFace *mface;
        MVert *mvert;
-       float pmat[4][4], imat[3][3];
+       float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w;
        int lay, oblay, totface, a;
        Scene *sce = NULL;
        Group *group = NULL;
        GroupObject *go = NULL;
-       
+       EditMesh *em;
        float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
        
        /* simple preventing of too deep nested groups */
@@ -533,9 +574,11 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma
        
        Mat4CpyMat4(pmat, par->obmat);
        
-       if(par==G.obedit) {
+       em = BKE_mesh_get_editmesh(me);
+       if(em) {
                int totvert;
-               dm= editmesh_get_derived_cage(CD_MASK_BAREMESH);
+               
+               dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
                
                totface= dm->getNumFaces(dm);
                mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp");
@@ -543,15 +586,27 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma
                totvert= dm->getNumVerts(dm);
                mvert= MEM_mallocN(sizeof(MVert)*totvert, "mvert temp");
                dm->copyVertArray(dm, mvert);
+
+               BKE_mesh_end_editmesh(me, em);
        }
        else {
-               dm = mesh_get_derived_deform(par, CD_MASK_BAREMESH);
+               dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
                
                totface= dm->getNumFaces(dm);
                mface= dm->getFaceArray(dm);
                mvert= dm->getVertArray(dm);
        }
-       
+
+       if(G.rendering) {
+
+               orco= (float(*)[3])get_mesh_orco_verts(par);
+               transform_mesh_orco_verts(me, orco, me->totvert, 0);
+               mtface= me->mtface;
+       }
+       else {
+               orco= NULL;
+               mtface= NULL;
+       }
        
        /* having to loop on scene OR group objects is NOT FUN */
        if (GS(id->name) == ID_SCE) {
@@ -574,7 +629,7 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma
                        oblay = ob_iter->lay;
                }
                
-               if (lay & oblay && G.obedit!=ob_iter) {
+               if (lay & oblay && scene->obedit!=ob_iter) {
                        ob=ob_iter->parent;
                        while(ob) {
                                if(ob==par) {
@@ -595,10 +650,14 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma
                                        if(ob->type!=OB_MBALL) ob->flag |= OB_DONE;     /* doesnt render */
 
                                        for(a=0; a<totface; a++) {
-                                               float *v1= mvert[ mface[a].v1 ].co;
-                                               float *v2= mvert[ mface[a].v2 ].co;
-                                               float *v3= mvert[ mface[a].v3 ].co;
-                                               float *v4= mface[a].v4?mvert[ mface[a].v4 ].co:NULL;
+                                               int mv1 = mface[a].v1;
+                                               int mv2 = mface[a].v2;
+                                               int mv3 = mface[a].v3;
+                                               int mv4 = mface[a].v4;
+                                               float *v1= mvert[mv1].co;
+                                               float *v2= mvert[mv2].co;
+                                               float *v3= mvert[mv3].co;
+                                               float *v4= (mv4)? mvert[mv4].co: NULL;
                                                float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4];
 
                                                /* translation */
@@ -632,13 +691,38 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma
                                                Mat4CpyMat4(tmat, obmat);
                                                Mat4MulMat43(obmat, tmat, mat);
                                                
-                                               new_dupli_object(lb, ob, obmat, lay, a, OB_DUPLIFACES);
+                                               dob= new_dupli_object(lb, ob, obmat, lay, a, OB_DUPLIFACES, animated);
+                                               if(G.rendering) {
+                                                       w= (mv4)? 0.25f: 1.0f/3.0f;
+
+                                                       if(orco) {
+                                                               VECADDFAC(dob->orco, dob->orco, orco[mv1], w);
+                                                               VECADDFAC(dob->orco, dob->orco, orco[mv2], w);
+                                                               VECADDFAC(dob->orco, dob->orco, orco[mv3], w);
+                                                               if(mv4)
+                                                                       VECADDFAC(dob->orco, dob->orco, orco[mv4], w);
+                                                       }
+
+                                                       if(mtface) {
+                                                               dob->uv[0] += w*mtface[a].uv[0][0];
+                                                               dob->uv[1] += w*mtface[a].uv[0][1];
+                                                               dob->uv[0] += w*mtface[a].uv[1][0];
+                                                               dob->uv[1] += w*mtface[a].uv[1][1];
+                                                               dob->uv[0] += w*mtface[a].uv[2][0];
+                                                               dob->uv[1] += w*mtface[a].uv[2][1];
+
+                                                               if(mv4) {
+                                                                       dob->uv[0] += w*mtface[a].uv[3][0];
+                                                                       dob->uv[1] += w*mtface[a].uv[3][1];
+                                                               }
+                                                       }
+                                               }
                                                
                                                if(ob->transflag & OB_DUPLI) {
                                                        float tmpmat[4][4];
                                                        Mat4CpyMat4(tmpmat, ob->obmat);
                                                        Mat4CpyMat4(ob->obmat, obmat); /* pretend we are really this mat */
-                                                       object_duplilist_recursive((ID *)id, ob, lb, ob->obmat, level+1);
+                                                       object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level+1, animated);
                                                        Mat4CpyMat4(ob->obmat, tmpmat);
                                                }
                                        }
@@ -652,52 +736,32 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma
                else            go= go->next;           /* group loop */
        }
        
-       if(par==G.obedit) {
+       if(par==scene->obedit) {
                MEM_freeN(mface);
                MEM_freeN(mvert);
        }
-       
-       dm->release(dm);
-}
-
-static void particle_dupli_path_rotation(Object *ob, ParticleSettings *part, ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[][4])
-{
-       float loc[3], nor[3], vec[3], side[3];
 
-       VecSubf(vec, (cache+1)->co, cache->co);
-       Normalize(vec);
-
-       if(pa)
-               psys_particle_on_emitter(ob,psmd,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,nor,0,0,0,0);
-       else
-               psys_particle_on_emitter(ob, psmd,
-                       (part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE,
-                       cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,loc,nor,0,0,0,0);
+       if(orco)
+               MEM_freeN(orco);
        
-       Crossf(side, nor, vec);
-       Normalize(side);
-       Crossf(nor, vec, side);
-
-       Mat4One(mat);
-       VECCOPY(mat[0], vec);
-       VECCOPY(mat[1], side);
-       VECCOPY(mat[2], nor);
+       dm->release(dm);
 }
 
-static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level)
+static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated)
 {
        GroupObject *go;
-       Object *ob=0, **oblist=0;
+       Object *ob=0, **oblist=0, obcopy, *obcopylist=0;
+       DupliObject *dob;
        ParticleSettings *part;
        ParticleData *pa;
+       ChildParticle *cpa=0;
        ParticleKey state;
        ParticleCacheKey *cache;
        ParticleSystemModifierData *psmd;
-       float ctime, pa_time;
-       float tmat[4][4], mat[4][4], obrotmat[4][4], pamat[4][4], size=0.0;
-       float obmat[4][4], (*obmatlist)[4][4]=0;
-       float xvec[3] = {-1.0, 0.0, 0.0}, *q;
-       int lay, a, b, k, step_nbr = 0, counter, hair = 0;
+       float ctime, pa_time, scale = 1.0f;
+       float tmat[4][4], mat[4][4], pamat[4][4], size=0.0;
+       float (*obmat)[4], (*oldobmat)[4];
+       int lay, a, b, counter, hair = 0;
        int totpart, totchild, totgroup=0, pa_num;
 
        if(psys==0) return;
@@ -708,76 +772,87 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_
        part=psys->part;
        psmd= psys_get_modifier(par, psys);
 
-       if(part==0) return;
+       if(part==0)
+               return;
+
+       if(!psys_check_enabled(par, psys))
+               return;
 
-       ctime = bsystem_time(par, (float)G.scene->r.cfra, 0.0);
+       ctime = bsystem_time(scene, par, (float)scene->r.cfra, 0.0);
 
        totpart = psys->totpart;
        totchild = psys->totchild;
 
        BLI_srandom(31415926 + psys->seed);
-               
-       lay= G.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->flag & (PSYS_HAIR_DONE|PSYS_KEYED) && part->draw & PART_DRAW_KEYS)
-                       step_nbr = part->keys_step;
-               else
-                       step_nbr = 0;
-
-               if(psys->flag & PSYS_HAIR_DONE)
-                       hair= (totchild == 0 || psys->childcache) && psys->pathcache;
+       
+       lay= scene->lay;
+       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) {
+                       if(psys->flag & PSYS_HAIR_DONE)
+                               hair= (totchild == 0 || psys->childcache) && psys->pathcache;
+                       if(!hair)
+                               return;
+                       
+                       /* we use cache, update totchild according to cached data */
+                       totchild = psys->totchildcache;
+                       totpart = psys->totcached;
+               }
 
-               psys->lattice = psys_get_lattice(par, psys);
+               psys->lattice = psys_get_lattice(scene, par, psys);
 
-               if(part->draw_as==PART_DRAW_GR) {
-                       group_handle_recalc_and_update(par, part->dup_group);
+               /* gather list of objects or single object */
+               if(part->ren_as==PART_DRAW_GR) {
+                       group_handle_recalc_and_update(scene, par, part->dup_group);
 
-                       go= part->dup_group->gobject.first;
-                       while(go) {
-                               go=go->next;
+                       for(go=part->dup_group->gobject.first; go; go=go->next)
                                totgroup++;
-                       }
 
-                       oblist= MEM_callocN(totgroup*sizeof(Object *), "dupgroup object list");
-                       obmatlist= MEM_callocN(totgroup*sizeof(float)*4*4, "dupgroup obmat list");
-                       go= part->dup_group->gobject.first;
+                       /* we also copy the actual objects to restore afterwards, since
+                        * where_is_object_time will change the object which breaks transform */
+                       oblist = MEM_callocN(totgroup*sizeof(Object *), "dupgroup object list");
+                       obcopylist = MEM_callocN(totgroup*sizeof(Object), "dupgroup copy list");
+
+                       go = part->dup_group->gobject.first;
                        for(a=0; a<totgroup; a++, go=go->next) {
-                               oblist[a]=go->ob;
-                               Mat4CpyMat4(obmatlist[a], go->ob->obmat);
+                               oblist[a] = go->ob;
+                               obcopylist[a] = *go->ob;
                        }
                }
                else {
                        ob = part->dup_ob;
-                       Mat4CpyMat4(obmat, ob->obmat);
+                       obcopy = *ob;
                }
 
                if(totchild==0 || part->draw & PART_DRAW_PARENT)
-                       a=0;
+                       a = 0;
                else
-                       a=totpart;
+                       a = totpart;
 
                for(pa=psys->particles,counter=0; a<totpart+totchild; a++,pa++,counter++) {
                        if(a<totpart) {
+                               /* handle parent particle */
                                if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP))
                                        continue;
 
-                               pa_num=pa->num;
-
-                               pa_time=pa->time;
-
-                               size=pa->size;
+                               pa_num = pa->num;
+                               pa_time = pa->time;
+                               size = pa->size;
                        }
                        else {
-                               /* TODO: figure these two out */
-                               pa_num = a;
-                               pa_time = psys->particles[psys->child[a - totpart].parent].time;
+                               /* handle child particle */
+                               cpa = &psys->child[a - totpart];
 
-                               size=psys_get_child_size(psys, &psys->child[a - totpart], ctime, 0);
+                               pa_num = a;
+                               pa_time = psys->particles[cpa->parent].time;
+                               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;
                                else if(part->from==PART_FROM_PARTICLE)
@@ -786,88 +861,93 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_
                                        b= a % totgroup;
 
                                ob = oblist[b];
-                               Mat4CpyMat4(obmat, obmatlist[b]);
+                               obmat = oblist[b]->obmat;
+                               oldobmat = obcopylist[b].obmat;
+                       }
+                       else {
+                               obmat= ob->obmat;
+                               oldobmat= obcopy.obmat;
                        }
 
-                       for(k=0; k<=step_nbr; k++, counter++) {
-                               if(hair) {
-                                       if(a < totpart) {
-                                               cache = psys->pathcache[a];
-                                               particle_dupli_path_rotation(par, part, psmd, pa, 0, cache, pamat);
-                                       }
-                                       else {
-                                               ChildParticle *cpa= psys->child+(a-totpart);
-                                               cache = psys->childcache[a-totpart];
-                                               particle_dupli_path_rotation(par, part, psmd, 0, cpa, cache, pamat);
-                                       }
-
-                                       VECCOPY(pamat[3], cache->co);
-                               }
-                               else if(step_nbr) {
-                                       state.time = (float)k / (float)step_nbr;
-                                       psys_get_particle_on_path(par, psys, a, &state, 0);
-
-                                       QuatToMat4(state.rot, pamat);
-                                       VECCOPY(pamat[3], state.co);
-                                       pamat[3][3]= 1.0f;
+                       if(hair) {
+                               /* hair we handle separate and compute transform based on hair keys */
+                               if(a < totpart) {
+                                       cache = psys->pathcache[a];
+                                       psys_get_dupli_path_transform(par, psys, psmd, pa, 0, cache, pamat, &scale);
                                }
                                else {
-                                       state.time = -1.0;
-                                       if(psys_get_particle_state(par, psys, a, &state, 0) == 0)
-                                               continue;
-
-                                       QuatToMat4(state.rot, pamat);
-                                       VECCOPY(pamat[3], state.co);
-                                       pamat[3][3]= 1.0f;
+                                       cache = psys->childcache[a-totpart];
+                                       psys_get_dupli_path_transform(par, psys, psmd, 0, cpa, cache, pamat, &scale);
                                }
 
-                               if(part->draw_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, obmatlist[b], pamat);
-                                               Mat4MulFloat3((float *)tmat, size);
-                                               if(par_space_mat)
-                                                       Mat4MulMat4(mat, tmat, par_space_mat);
-                                               else
-                                                       Mat4CpyMat4(mat, tmat);
-
-                                               new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS);
-                                       }
-                               }
-                               else {
-                                       /* to give ipos in object correct offset */
-                                       where_is_object_time(ob, ctime-pa_time);
-                                       
-                                       if(!hair) {
-                                               q = vectoquat(xvec, ob->trackflag, ob->upflag);
-                                               QuatToMat4(q, obrotmat);
-                                               obrotmat[3][3]= 1.0f;
+                               VECCOPY(pamat[3], cache->co);
+                               pamat[3][3]= 1.0f;
+                               
+                       }
+                       else {
+                               /* first key */
+                               state.time = ctime;
+                               if(psys_get_particle_state(scene, par, psys, a, &state, 0) == 0)
+                                       continue;
 
-                                               Mat4MulMat4(mat, obrotmat, pamat);
-                                       }
-                                       else
-                                               Mat4CpyMat4(mat, pamat);
+                               QuatToMat4(state.rot, pamat);
+                               VECCOPY(pamat[3], state.co);
+                               pamat[3][3]= 1.0f;
+                       }
 
-                                       Mat4MulMat4(tmat, obmat, mat);
-                                       Mat4MulFloat3((float *)tmat, size);
+                       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);
                                        if(par_space_mat)
                                                Mat4MulMat4(mat, tmat, par_space_mat);
                                        else
                                                Mat4CpyMat4(mat, tmat);
 
-                                       new_dupli_object(lb, ob, mat, par->lay, counter, OB_DUPLIPARTS);
+                                       dob= new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated);
+                                       Mat4CpyMat4(dob->omat, obcopylist[b].obmat);
+                                       if(G.rendering)
+                                               psys_get_dupli_texture(par, part, psmd, pa, cpa, dob->uv, dob->orco);
                                }
                        }
+                       else {
+                               /* to give ipos in object correct offset */
+                               where_is_object_time(scene, ob, ctime-pa_time);
+                               
+                               Mat4CpyMat4(mat, pamat);
+
+                               Mat4MulMat4(tmat, obmat, mat);
+                               Mat4MulFloat3((float *)tmat, size*scale);
+                               if(par_space_mat)
+                                       Mat4MulMat4(mat, tmat, par_space_mat);
+                               else
+                                       Mat4CpyMat4(mat, tmat);
+
+                               dob= new_dupli_object(lb, ob, mat, ob->lay, counter, OB_DUPLIPARTS, animated);
+                               Mat4CpyMat4(dob->omat, oldobmat);
+                               if(G.rendering)
+                                       psys_get_dupli_texture(par, part, psmd, pa, cpa, dob->uv, dob->orco);
+                       }
                }
+
+               /* restore objects since they were changed in where_is_object_time */
+               if(part->ren_as==PART_DRAW_GR) {
+                       for(a=0; a<totgroup; a++)
+                               *(oblist[a])= obcopylist[a];
+               }
+               else
+                       *ob= obcopy;
        }
+
+       /* clean up */
        if(oblist)
                MEM_freeN(oblist);
-       if(obmatlist)
-               MEM_freeN(obmatlist);
+       if(obcopylist)
+               MEM_freeN(obcopylist);
 
        if(psys->lattice) {
-               end_latt_deform();
-               psys->lattice = 0;
+               end_latt_deform(psys->lattice);
+               psys->lattice = NULL;
        }
 }
 
@@ -876,7 +956,7 @@ static Object *find_family_object(Object **obar, char *family, char ch)
        Object *ob;
        int flen;
        
-       if( obar[ch] ) return obar[ch];
+       if( obar[(int)ch] ) return obar[(int)ch];
        
        flen= strlen(family);
        
@@ -888,13 +968,13 @@ static Object *find_family_object(Object **obar, char *family, char ch)
                ob= ob->id.next;
        }
        
-       obar[ch]= ob;
+       obar[(int)ch]= ob;
        
        return ob;
 }
 
 
-static void font_duplilist(ListBase *lb, Object *par, int level)
+static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int level, int animated)
 {
        Object *ob, *obar[256];
        Curve *cu;
@@ -909,7 +989,7 @@ static void font_duplilist(ListBase *lb, Object *par, int level)
        
        /* in par the family name is stored, use this to find the other objects */
        
-       chartransdata= text_to_curve(par, FO_DUPLI);
+       chartransdata= BKE_text_to_curve(scene, par, FO_DUPLI);
        if(chartransdata==0) return;
        
        memset(obar, 0, 256*sizeof(void *));
@@ -935,16 +1015,15 @@ static void font_duplilist(ListBase *lb, Object *par, int level)
                        Mat4CpyMat4(obmat, par->obmat);
                        VECCOPY(obmat[3], vec);
                        
-                       new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIVERTS);
+                       new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIVERTS, animated);
                }
-               
        }
        
        MEM_freeN(chartransdata);
 }
 
 /* ***************************** */
-static void object_duplilist_recursive(ID *id, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level)
+static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated)
 {      
        if((ob->transflag & OB_DUPLI)==0)
                return;
@@ -963,30 +1042,30 @@ static void object_duplilist_recursive(ID *id, Object *ob, ListBase *duplilist,
        if(ob->transflag & OB_DUPLIPARTS) {
                ParticleSystem *psys = ob->particlesystem.first;
                for(; psys; psys=psys->next)
-                       new_particle_duplilist(duplilist, id, ob, par_space_mat, psys, level+1);
+                       new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, psys, level+1, animated);
        }
        else if(ob->transflag & OB_DUPLIVERTS) {
                if(ob->type==OB_MESH) {
-                       vertex_duplilist(duplilist, id, ob, par_space_mat, level+1);
+                       vertex_duplilist(duplilist, id, scene, ob, par_space_mat, level+1, animated);
                }
                else if(ob->type==OB_FONT) {
                        if (GS(id->name)==ID_SCE) { /* TODO - support dupligroups */
-                               font_duplilist(duplilist, ob, level+1);
+                               font_duplilist(duplilist, scene, ob, level+1, animated);
                        }
                }
        }
        else if(ob->transflag & OB_DUPLIFACES) {
                if(ob->type==OB_MESH)
-                       face_duplilist(duplilist, id, ob, par_space_mat, level+1);
+                       face_duplilist(duplilist, id, scene, ob, par_space_mat, level+1, animated);
        }
        else if(ob->transflag & OB_DUPLIFRAMES) {
                if (GS(id->name)==ID_SCE) { /* TODO - support dupligroups */
-                       frames_duplilist(duplilist, ob, level+1);
+                       frames_duplilist(duplilist, scene, ob, level+1, animated);
                }
        } else if(ob->transflag & OB_DUPLIGROUP) {
                DupliObject *dob;
                
-               group_duplilist(duplilist, ob, level+1); /* now recursive */
+               group_duplilist(duplilist, scene, ob, level+1, animated); /* now recursive */
 
                if (level==0) {
                        for(dob= duplilist->first; dob; dob= dob->next)
@@ -996,12 +1075,13 @@ static void object_duplilist_recursive(ID *id, Object *ob, ListBase *duplilist,
        }
 }
 
-/* note; group dupli's already set transform matrix. see note in group_duplilist() */
+/* Returns a list of DupliObject
+ * note; group dupli's already set transform matrix. see note in group_duplilist() */
 ListBase *object_duplilist(Scene *sce, Object *ob)
 {
        ListBase *duplilist= MEM_mallocN(sizeof(ListBase), "duplilist");
        duplilist->first= duplilist->last= NULL;
-       object_duplilist_recursive((ID *)sce, ob, duplilist, NULL, 0);
+       object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0);
        return duplilist;
 }