2.5 - Animation Playback Tweaks
[blender.git] / source / blender / blenkernel / intern / anim.c
index 0d91f106ed77ce5fd810a4675c2ce467ea0fcac5..6c1b8eb9000cb192e7954bec3aedf235a47b7bcf 100644 (file)
@@ -34,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"
@@ -52,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_particle.h"
 #include "BKE_utildefines.h"
 
-#include "BKE_bad_level_calls.h"
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-static void object_duplilist_recursive(ID *id, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated);
+#include "ED_mesh.h"
+
+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)
 {
@@ -99,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;
@@ -118,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");
 
@@ -222,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);
        
@@ -298,12 +304,12 @@ static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], i
        return dob;
 }
 
-static void group_duplilist(ListBase *lb, Object *ob, int level, int animated)
+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;
@@ -313,59 +319,71 @@ static void group_duplilist(ListBase *lb, Object *ob, int level, int animated)
        
        /* 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);
+                       /* 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, animated);
+                               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, int animated)
+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, animated);
+#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;
 }
 
@@ -376,6 +394,7 @@ struct vertexDupliData {
        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];
 };
@@ -416,36 +435,39 @@ static void vertex_dupli__mapFunc(void *userData, int index, float *co, float *n
                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, vdd->animated);
+               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, int animated)
+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;
+       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);
-       else
-               dm= mesh_get_derived_deform(par, 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) {
-               me= par->data;
                vdd.orco= (float(*)[3])get_mesh_orco_verts(par);
                transform_mesh_orco_verts(me, vdd.orco, me->totvert, 0);
        }
@@ -475,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) {
@@ -496,13 +518,14 @@ static void vertex_duplilist(ListBase *lb, ID *id, Object *par, float par_space_
                                        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 {
@@ -528,13 +551,13 @@ static void vertex_duplilist(ListBase *lb, ID *id, Object *par, float par_space_
        dm->release(dm);
 }
 
-static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_mat[][4], int level, int animated)
+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;
+       Mesh *me= par->data;
        MTFace *mtface;
        MFace *mface;
        MVert *mvert;
@@ -543,16 +566,19 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma
        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 */
        if(level>MAX_DUPLI_RECUR) return;
        
        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");
@@ -560,9 +586,11 @@ 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);
@@ -570,7 +598,6 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma
        }
 
        if(G.rendering) {
-               me= (Mesh*)par->data;
 
                orco= (float(*)[3])get_mesh_orco_verts(par);
                transform_mesh_orco_verts(me, orco, me->totvert, 0);
@@ -602,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) {
@@ -695,7 +722,7 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma
                                                        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, animated);
+                                                       object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level+1, animated);
                                                        Mat4CpyMat4(ob->obmat, tmpmat);
                                                }
                                        }
@@ -709,7 +736,7 @@ 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);
        }
@@ -720,10 +747,10 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma
        dm->release(dm);
 }
 
-static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated)
+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;
@@ -732,10 +759,9 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_
        ParticleCacheKey *cache;
        ParticleSystemModifierData *psmd;
        float ctime, pa_time, scale = 1.0f;
-       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[4];
-       int lay, a, b, k, step_nbr = 0, counter, hair = 0;
+       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;
@@ -752,21 +778,17 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_
        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;
+       
+       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) {
@@ -774,58 +796,63 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_
                                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 */
-                               cpa= &psys->child[a - totpart];
+                               /* handle child particle */
+                               cpa = &psys->child[a - totpart];
+
                                pa_num = a;
                                pa_time = psys->particles[cpa->parent].time;
-
-                               size=psys_get_child_size(psys, cpa, ctime, 0);
+                               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)
@@ -834,90 +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];
-                                               psys_get_dupli_path_transform(par, psys, psmd, pa, 0, cache, pamat, &scale);
-                                       }
-                                       else {
-                                               cache = psys->childcache[a-totpart];
-                                               psys_get_dupli_path_transform(par, psys, psmd, 0, cpa, cache, pamat, &scale);
-                                       }
-
-                                       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*scale);
-                                               if(par_space_mat)
-                                                       Mat4MulMat4(mat, tmat, par_space_mat);
-                                               else
-                                                       Mat4CpyMat4(mat, tmat);
+                               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;
 
-                                               dob= new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated);
-                                               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(ob, ctime-pa_time);
-                                       
-                                       if(!hair) {
-                                               vectoquat(xvec, ob->trackflag, ob->upflag, q);
-                                               QuatToMat4(q, obrotmat);
-                                               obrotmat[3][3]= 1.0f;
-                                               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);
+                       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);
 
-                                       dob= new_dupli_object(lb, ob, mat, par->lay, counter, OB_DUPLIPARTS, animated);
+                                       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;
        }
 }
 
@@ -926,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);
        
@@ -938,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, int animated)
+static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int level, int animated)
 {
        Object *ob, *obar[256];
        Curve *cu;
@@ -959,7 +989,7 @@ static void font_duplilist(ListBase *lb, Object *par, int level, int animated)
        
        /* 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 *));
@@ -993,7 +1023,7 @@ static void font_duplilist(ListBase *lb, Object *par, int level, int animated)
 }
 
 /* ***************************** */
-static void object_duplilist_recursive(ID *id, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated)
+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;
@@ -1012,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, animated);
+                       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, animated);
+                       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, animated);
+                               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, animated);
+                       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, animated);
+                       frames_duplilist(duplilist, scene, ob, level+1, animated);
                }
        } else if(ob->transflag & OB_DUPLIGROUP) {
                DupliObject *dob;
                
-               group_duplilist(duplilist, ob, level+1, animated); /* now recursive */
+               group_duplilist(duplilist, scene, ob, level+1, animated); /* now recursive */
 
                if (level==0) {
                        for(dob= duplilist->first; dob; dob= dob->next)
@@ -1045,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, 0);
+       object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0);
        return duplilist;
 }