Second try at committing IPO code cleanups...
authorJoshua Leung <aligorith@gmail.com>
Sun, 28 Sep 2008 23:17:44 +0000 (23:17 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sun, 28 Sep 2008 23:17:44 +0000 (23:17 +0000)
source/blender/blenkernel/BKE_ipo.h
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/ipo.c
source/blender/makesdna/DNA_ipo_types.h
source/blender/src/drawobject.c

index 5b209cb8f5b80838d71f4a486618936271e76f05..fdd176e0e643ea1e8bfa19e4469e53c05bc34fec 100644 (file)
@@ -54,41 +54,71 @@ struct bPoseChannel;
 struct bActionChannel;
 struct rctf;
 
+/* ------------ Time Management ------------ */
+
 float frame_to_float(int cfra);
 
+/* ------------ IPO Management ---------- */
+
 void free_ipo_curve(struct IpoCurve *icu);
 void free_ipo(struct Ipo *ipo);
+
 void ipo_default_v2d_cur(int blocktype, struct rctf *cur);
+
 struct Ipo *add_ipo(char *name, int idcode);
 struct Ipo *copy_ipo(struct Ipo *ipo);
+
 void ipo_idnew(struct Ipo *ipo);
+
+struct IpoCurve *find_ipocurve(struct Ipo *ipo, int adrcode);
+short has_ipo_code(struct Ipo *ipo, int code);
+
+/* -------------- Make Local -------------- */
+
 void make_local_obipo(struct Ipo *ipo);
 void make_local_matipo(struct Ipo *ipo);
 void make_local_keyipo(struct Ipo *ipo);
 void make_local_ipo(struct Ipo *ipo);
-struct IpoCurve *find_ipocurve(struct Ipo *ipo, int adrcode);
+
+/* ------------ IPO-Curve Sanity ---------------- */
 
 void calchandles_ipocurve(struct IpoCurve *icu);
 void testhandles_ipocurve(struct IpoCurve *icu);
 void sort_time_ipocurve(struct IpoCurve *icu);
 int test_time_ipocurve(struct IpoCurve *icu);
+
+/* -------- IPO-Curve (Bezier) Calculations ---------- */
+
 void correct_bezpart(float *v1, float *v2, float *v3, float *v4);
 int findzero(float x, float q0, float q1, float q2, float q3, float *o);
 void berekeny(float f1, float f2, float f3, float f4, float *o, int b);
 void berekenx(float *f, float *o, int b);
+
+/* -------- IPO Curve Calculation and Evaluation --------- */
+
 float eval_icu(struct IpoCurve *icu, float ipotime);
 void calc_icu(struct IpoCurve *icu, float ctime);
 float calc_ipo_time(struct Ipo *ipo, float ctime);
 void calc_ipo(struct Ipo *ipo, float ctime);
+
+/* ------------ Keyframe Column Tools -------------- */
+
+void add_to_cfra_elem(struct ListBase *lb, struct BezTriple *bezt);
+void make_cfra_list(struct Ipo *ipo, struct ListBase *elems);
+
+/* ---------------- IPO DataAPI ----------------- */
+
 void write_ipo_poin(void *poin, int type, float val);
 float read_ipo_poin(void *poin, int type);
-void *give_mtex_poin(struct MTex *mtex, int adrcode );
 
-void *get_ipo_poin(struct ID *id, struct IpoCurve *icu, int *type);
+void *give_mtex_poin(struct MTex *mtex, int adrcode );
 void *get_pchan_ipo_poin(struct bPoseChannel *pchan, int adrcode);
+void *get_ipo_poin(struct ID *id, struct IpoCurve *icu, int *type);
 
 void set_icu_vars(struct IpoCurve *icu);
 
+/* ---------------- IPO Execution --------------- */
+
 void execute_ipo(struct ID *id, struct Ipo *ipo);
 void execute_action_ipo(struct bActionChannel *achan, struct bPoseChannel *pchan);
 
@@ -99,21 +129,16 @@ void do_ob_ipo(struct Object *ob);
 void do_seq_ipo(struct Sequence *seq, int cfra);
 void do_ob_ipodrivers(struct Object *ob, struct Ipo *ipo, float ctime);
 
-int has_ipo_code(struct Ipo *ipo, int code);
 void do_all_data_ipos(void);
-int calc_ipo_spec(struct Ipo *ipo, int adrcode, float *ctime);
+short calc_ipo_spec(struct Ipo *ipo, int adrcode, float *ctime);
 void clear_delta_obipo(struct Ipo *ipo);
-void add_to_cfra_elem(struct ListBase *lb, struct BezTriple *bezt);
-void make_cfra_list(struct Ipo *ipo, struct ListBase *elems);
 
-/* the sort is an IPO_Channel... */
-int IPO_GetChannels(struct Ipo *ipo, short *channels);
+/* ----------- IPO <-> GameEngine API ---------------- */
+
+/* the short is an IPO_Channel... */
 
-float IPO_GetFloatValue(struct Ipo *ipo,
-/*                                             struct IPO_Channel channel, */
-                                               /* channels are shorts... bit ugly for now*/
-                                               short c,
-                                               float ctime);
+short IPO_GetChannels(struct Ipo *ipo, short *channels);
+float IPO_GetFloatValue(struct Ipo *ipo, short c, float ctime);
 
 #ifdef __cplusplus
 };
index 06c1dd4ffe6f41cc84f72d985fc31f505a7f9145..6ece16deb4b3147173fda9e3d41ab8dd374d7bde 100644 (file)
@@ -1509,7 +1509,7 @@ void makeBevelList(Object *ob)
        BevList *bl, *blnew, *blnext;
        BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0;
        float min, inp, x1, x2, y1, y2, vec[3];
-       float *coord_array, *tilt_array=NULL, *radius_array=NULL, *coord_fp, *tilt_fp=NULL, *radius_fp;
+       float *coord_array, *tilt_array=NULL, *radius_array=NULL, *coord_fp, *tilt_fp=NULL, *radius_fp=NULL;
        float *v1, *v2;
        struct bevelsort *sortdata, *sd, *sd1;
        int a, b, nr, poly, resolu, len=0;
index b58a9e51b05632e9a47238f689d5dddd3002cd04..ff03221bbb07ba0681574262c8e020e4f4be5345 100644 (file)
@@ -23,7 +23,7 @@
  *
  * The Original Code is: all of this file.
  *
- * Contributor(s): none yet.
+ * Contributor(s): 2008, Joshua Leung (IPO System cleanup)
  *
  * ***** END GPL LICENSE BLOCK *****
  */
 
 #define SMALL -1.0e-10
 
+/* ***************************** Adrcode Blocktype Defines ********************************* */
+
 /* This array concept was meant to make sure that defines such as OB_LOC_X
    don't have to be enumerated, also for backward compatibility, future changes,
    and to enable it all can be accessed with a for-next loop.
+   
+   This should whole adrcode system should eventually be replaced by a proper Data API
 */
 
+
 int co_ar[CO_TOTIPO]= {
        CO_ENFORCE, CO_HEADTAIL
 };
@@ -151,9 +156,9 @@ int wo_ar[WO_TOTIPO]= {
 };
 
 int la_ar[LA_TOTIPO]= {
-       LA_ENERGY,  LA_COL_R, LA_COL_G,  LA_COL_B, 
+       LA_ENERGY, LA_COL_R, LA_COL_G, LA_COL_B, 
        LA_DIST, LA_SPOTSI, LA_SPOTBL, 
-       LA_QUAD1,  LA_QUAD2,  LA_HALOINT,  
+       LA_QUAD1, LA_QUAD2, LA_HALOINT,  
 
        MA_MAP1+MAP_OFS_X, MA_MAP1+MAP_OFS_Y, MA_MAP1+MAP_OFS_Z, 
        MA_MAP1+MAP_SIZE_X, MA_MAP1+MAP_SIZE_Y, MA_MAP1+MAP_SIZE_Z, 
@@ -187,450 +192,605 @@ int part_ar[PART_TOTIPO]= {
        PART_BB_TILT, PART_PD_FSTR, PART_PD_FFALL, PART_PD_FMAXD, PART_PD2_FSTR, PART_PD2_FFALL, PART_PD2_FMAXD
 };
 
+/* ************************** Data-Level Functions ************************* */
 
-float frame_to_float(int cfra)         /* see also bsystem_time in object.c */
+/* ---------------------- Freeing --------------------------- */
+
+/* frees the ipo curve itself too */
+void free_ipo_curve (IpoCurve *icu) 
 {
-       extern float bluroffs;  /* bad stuff borrowed from object.c */
-       extern float fieldoffs;
-       float ctime;
+       if (icu == NULL) 
+               return;
        
-       ctime= (float)cfra;
-       ctime+= bluroffs+fieldoffs;
-       ctime*= G.scene->r.framelen;
+       if (icu->bezt) 
+               MEM_freeN(icu->bezt);
+       if (icu->driver) 
+               MEM_freeN(icu->driver);
        
-       return ctime;
-}
-
-/* includes ipo curve itself */
-void free_ipo_curve(IpoCurve *icu) 
-{
-       if(icu->bezt) MEM_freeN(icu->bezt);
-       if(icu->bp) MEM_freeN(icu->bp);
-       if(icu->driver) MEM_freeN(icu->driver);
        MEM_freeN(icu);
 }
 
 /* do not free ipo itself */
-void free_ipo(Ipo *ipo)
+void free_ipo (Ipo *ipo)
 {
-       IpoCurve *icu;
+       IpoCurve *icu, *icn;
+       
+       if (ipo == NULL) 
+               return;
        
-       while( (icu= ipo->curve.first) ) {
+       for (icu= ipo->curve.first; icu; icu= icn) {
+               icn= icu->next;
+               
+               /* must remove the link before freeing, as the curve is freed too */
                BLI_remlink(&ipo->curve, icu);
                free_ipo_curve(icu);
        }
 }
 
+/* ---------------------- Init --------------------------- */
+
 /* on adding new ipos, or for empty views */
-void ipo_default_v2d_cur(int blocktype, rctf *cur)
+void ipo_default_v2d_cur (int blocktype, rctf *cur)
 {
-       if(blocktype==ID_CA) {
+       switch (blocktype) {
+       case ID_CA:
                cur->xmin= G.scene->r.sfra;
                cur->xmax= G.scene->r.efra;
                cur->ymin= 0.0;
                cur->ymax= 100.0;
-       }
-       else if ELEM5(blocktype, ID_MA, ID_CU, ID_WO, ID_LA, ID_CO) {
+               break;
+               
+       case ID_MA: case ID_WO: case ID_LA: 
+       case ID_CU: case ID_CO:
                cur->xmin= (float)G.scene->r.sfra-0.1;
                cur->xmax= G.scene->r.efra;
                cur->ymin= (float)-0.1;
                cur->ymax= (float)+1.1;
-       }
-       else if(blocktype==ID_TE) {
+               break;
+               
+       case ID_TE:
                cur->xmin= (float)G.scene->r.sfra-0.1;
                cur->xmax= G.scene->r.efra;
                cur->ymin= (float)-0.1;
                cur->ymax= (float)+1.1;
-       }
-       else if(blocktype==ID_SEQ) {
+               break;
+               
+       case ID_SEQ:
                cur->xmin= -5.0;
                cur->xmax= 105.0;
                cur->ymin= (float)-0.1;
                cur->ymax= (float)+1.1;
-       }
-       else if(blocktype==ID_KE) {
+               break;
+               
+       case ID_KE:
                cur->xmin= (float)G.scene->r.sfra-0.1;
                cur->xmax= G.scene->r.efra;
                cur->ymin= (float)-0.1;
                cur->ymax= (float)+2.1;
-       }
-       else {  /* ID_OB and everything else */
+               break;
+               
+       default:        /* ID_OB and everything else */
                cur->xmin= G.scene->r.sfra;
                cur->xmax= G.scene->r.efra;
                cur->ymin= -5.0;
                cur->ymax= +5.0;
+               break;
        }
 }
 
-
-Ipo *add_ipo(char *name, int idcode)
+/* create a new IPO block (allocates the block) */
+Ipo *add_ipo (char name[], int blocktype)
 {
        Ipo *ipo;
        
        ipo= alloc_libblock(&G.main->ipo, ID_IP, name);
-       ipo->blocktype= idcode;
-       ipo_default_v2d_cur(idcode, &ipo->cur);
+       ipo->blocktype= blocktype;
+       ipo_default_v2d_cur(blocktype, &ipo->cur);
 
        return ipo;
 }
 
-Ipo *copy_ipo(Ipo *ipo)
+/* ---------------------- Copy --------------------------- */
+
+/* duplicate an IPO block and all its data  */
+Ipo *copy_ipo (Ipo *src)
 {
-       Ipo *ipon;
+       Ipo *dst;
        IpoCurve *icu;
        
-       if(ipo==NULL) return 0;
-       
-       ipon= copy_libblock(ipo);
+       if (src == NULL) 
+               return NULL;
        
-       duplicatelist(&(ipon->curve), &(ipo->curve));
+       dst= copy_libblock(src);
+       duplicatelist(&dst->curve, &src->curve);
 
-       for(icu= ipo->curve.first; icu; icu= icu->next) {
+       for (icu= src->curve.first; icu; icu= icu->next) {
                icu->bezt= MEM_dupallocN(icu->bezt);
-               if(icu->driver) icu->driver= MEM_dupallocN(icu->driver);
+               
+               if (icu->driver) 
+                       icu->driver= MEM_dupallocN(icu->driver);
        }
        
-       return ipon;
+       return dst;
 }
 
-/* uses id->newid to match pointers with other copied data */
-void ipo_idnew(Ipo *ipo)
+/* ---------------------- Relink --------------------------- */
+
+/* uses id->newid to match pointers with other copied data 
+ *     - called after single-user or other such
+ */
+void ipo_idnew (Ipo *ipo)
 {
-       if(ipo) {
+       if (ipo) {
                IpoCurve *icu;
                
-               for(icu= ipo->curve.first; icu; icu= icu->next) {
-                       if(icu->driver) {
+               for (icu= ipo->curve.first; icu; icu= icu->next) {
+                       if (icu->driver)
                                ID_NEW(icu->driver->ob);
-                       }
                }
        }
 }
 
-void make_local_obipo(Ipo *ipo)
+/* --------------------- Find + Check ----------------------- */
+
+/* find the IPO-curve within a given IPO-block with the adrcode of interest */
+IpoCurve *find_ipocurve (Ipo *ipo, int adrcode)
+{
+       if (ipo) {
+               IpoCurve *icu;
+               
+               for (icu= ipo->curve.first; icu; icu= icu->next) {
+                       if (icu->adrcode == adrcode) 
+                               return icu;
+               }
+       }
+       return NULL;
+}
+
+/* return whether the given IPO block has a IPO-curve with the given adrcode */
+short has_ipo_code(Ipo *ipo, int adrcode)
+{
+       /* return success of faliure from trying to find such an IPO-curve */
+       return (find_ipocurve(ipo, adrcode) != NULL);
+}
+
+/* ---------------------- Make Local --------------------------- */
+
+
+/* make the given IPO local (for Objects)
+ * - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+void make_local_obipo (Ipo *src)
 {
        Object *ob;
-       Ipo *ipon;
+       Ipo *dst;
        int local=0, lib=0;
        
-       /* - only lib users: do nothing
-        * - only local users: set flag
-        * - mixed: make copy
-        */
-
-       ob= G.main->object.first;
-       while(ob) {
-               if(ob->ipo==ipo) {
-                       if(ob->id.lib) lib= 1;
+       /* check if only local and/or lib */
+       for (ob= G.main->object.first; ob; ob= ob->id.next) {
+               if (ob->ipo == src) {
+                       if (ob->id.lib) lib= 1;
                        else local= 1;
                }
-               ob= ob->id.next;
        }
        
-       if(local && lib==0) {
-               ipo->id.lib= 0;
-               ipo->id.flag= LIB_LOCAL;
-               new_id(0, (ID *)ipo, 0);
+       /* only local - set flag */
+       if (local && lib==0) {
+               src->id.lib= 0;
+               src->id.flag= LIB_LOCAL;
+               new_id(0, (ID *)src, 0);
        }
-       else if(local && lib) {
-               ipon= copy_ipo(ipo);
-               ipon->id.us= 0;
+       /* mixed: make copy */
+       else if (local && lib) {
+               dst= copy_ipo(src);
+               dst->id.us= 0;
                
-               ob= G.main->object.first;
-               while(ob) {
-                       if(ob->ipo==ipo) {
-                               
-                               if(ob->id.lib==NULL) {
-                                       ob->ipo= ipon;
-                                       ipon->id.us++;
-                                       ipo->id.us--;
+               for (ob= G.main->object.first; ob; ob= ob->id.next) {
+                       if (ob->ipo == src) {
+                               if (ob->id.lib == NULL) {
+                                       ob->ipo= dst;
+                                       dst->id.us++;
+                                       src->id.us--;
                                }
                        }
-                       ob= ob->id.next;
                }
        }
 }
 
-void make_local_matipo(Ipo *ipo)
+/* make the given IPO local (for Materials)
+ * - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+void make_local_matipo (Ipo *src)
 {
        Material *ma;
-       Ipo *ipon;
+       Ipo *dst;
        int local=0, lib=0;
-
-       /* - only lib users: do nothing
-           * - only local users: set flag
-           * - mixed: make copy
-       */
        
-       ma= G.main->mat.first;
-       while(ma) {
-               if(ma->ipo==ipo) {
-                       if(ma->id.lib) lib= 1;
+       /* check if only local and/or lib */
+       for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+               if (ma->ipo == src) {
+                       if (ma->id.lib) lib= 1;
                        else local= 1;
                }
-               ma= ma->id.next;
        }
        
-       if(local && lib==0) {
-               ipo->id.lib= 0;
-               ipo->id.flag= LIB_LOCAL;
-               new_id(0, (ID *)ipo, 0);
+       /* only local - set flag */
+       if (local && lib==0) {
+               src->id.lib= 0;
+               src->id.flag= LIB_LOCAL;
+               new_id(0, (ID *)src, 0);
        }
-       else if(local && lib) {
-               ipon= copy_ipo(ipo);
-               ipon->id.us= 0;
+       /* mixed: make copy */
+       else if (local && lib) {
+               dst= copy_ipo(src);
+               dst->id.us= 0;
                
-               ma= G.main->mat.first;
-               while(ma) {
-                       if(ma->ipo==ipo) {
-                               
-                               if(ma->id.lib==NULL) {
-                                       ma->ipo= ipon;
-                                       ipon->id.us++;
-                                       ipo->id.us--;
+               for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+                       if (ma->ipo == src) {
+                               if (ma->id.lib == NULL) {
+                                       ma->ipo= dst;
+                                       dst->id.us++;
+                                       src->id.us--;
                                }
                        }
-                       ma= ma->id.next;
                }
        }
 }
 
-void make_local_keyipo(Ipo *ipo)
+/* make the given IPO local (for ShapeKeys)
+ * - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+void make_local_keyipo (Ipo *src)
 {
        Key *key;
-       Ipo *ipon;
+       Ipo *dst;
        int local=0, lib=0;
-
-       /* - only lib users: do nothing
-        * - only local users: set flag
-        * - mixed: make copy
-        */
        
-       key= G.main->key.first;
-       while(key) {
-               if(key->ipo==ipo) {
-                       if(key->id.lib) lib= 1;
+       /* check if only local and/or lib */
+       for (key= G.main->key.first; key; key= key->id.next) {
+               if (key->ipo == src) {
+                       if (key->id.lib) lib= 1;
                        else local= 1;
                }
-               key= key->id.next;
        }
        
-       if(local && lib==0) {
-               ipo->id.lib= 0;
-               ipo->id.flag= LIB_LOCAL;
-               new_id(0, (ID *)ipo, 0);
+       /* only local - set flag */
+       if (local && lib==0) {
+               src->id.lib= 0;
+               src->id.flag= LIB_LOCAL;
+               new_id(0, (ID *)src, 0);
        }
-       else if(local && lib) {
-               ipon= copy_ipo(ipo);
-               ipon->id.us= 0;
+       /* mixed: make copy */
+       else if (local && lib) {
+               dst= copy_ipo(src);
+               dst->id.us= 0;
                
-               key= G.main->key.first;
-               while(key) {
-                       if(key->ipo==ipo) {
-                               
-                               if(key->id.lib==NULL) {
-                                       key->ipo= ipon;
-                                       ipon->id.us++;
-                                       ipo->id.us--;
+               for (key= G.main->key.first; key; key= key->id.next) {
+                       if (key->ipo == src) {
+                               if (key->id.lib == NULL) {
+                                       key->ipo= dst;
+                                       dst->id.us++;
+                                       src->id.us--;
                                }
                        }
-                       key= key->id.next;
                }
        }
 }
 
 
-void make_local_ipo(Ipo *ipo)
+/* generic call to make IPO's local */
+void make_local_ipo (Ipo *ipo)
 {
-       
-       if(ipo->id.lib==NULL) return;
-       if(ipo->id.us==1) {
+       /* can't touch lib-linked data */
+       if (ipo->id.lib == NULL) 
+               return;
+               
+       /* with only one user, just set local flag */
+       if (ipo->id.us == 1) {
                ipo->id.lib= 0;
                ipo->id.flag= LIB_LOCAL;
                new_id(0, (ID *)ipo, 0);
                return;
        }
        
-       if(ipo->blocktype==ID_OB) make_local_obipo(ipo);
-       else if(ipo->blocktype==ID_MA) make_local_matipo(ipo);
-       else if(ipo->blocktype==ID_KE) make_local_keyipo(ipo);
-
+       /* when more than 1 user, can only make local for certain blocktypes */
+       switch (ipo->blocktype) {
+               case ID_OB:
+                       make_local_obipo(ipo);
+                       break;
+               case ID_MA:
+                       make_local_matipo(ipo);
+                       break;
+               case ID_KE:
+                       make_local_keyipo(ipo);
+                       break;
+       }
 }
 
-IpoCurve *find_ipocurve(Ipo *ipo, int adrcode)
+/* ***************************** Keyframe Column Tools ********************************* */
+
+/* add a BezTriple to a column */
+void add_to_cfra_elem(ListBase *lb, BezTriple *bezt)
 {
-       if(ipo) {
-               IpoCurve *icu;
-               for(icu= ipo->curve.first; icu; icu= icu->next) {
-                       if(icu->adrcode==adrcode) return icu;
+       CfraElem *ce, *cen;
+       
+       for (ce= lb->first; ce; ce= ce->next) {
+               /* double key? */
+               if (ce->cfra == bezt->vec[1][0]) {
+                       if (bezt->f2 & SELECT) ce->sel= bezt->f2;
+                       return;
                }
+               /* should key be inserted before this column? */
+               else if (ce->cfra > bezt->vec[1][0]) break;
        }
-       return NULL;
+       
+       /* create a new column */
+       cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); 
+       if (ce) BLI_insertlinkbefore(lb, ce, cen);
+       else BLI_addtail(lb, cen);
+
+       cen->cfra= bezt->vec[1][0];
+       cen->sel= bezt->f2;
 }
 
-void calchandles_ipocurve(IpoCurve *icu)
+/* make a list of keyframe 'columns' in an IPO block */
+void make_cfra_list (Ipo *ipo, ListBase *elems)
 {
-       BezTriple *bezt, *prev, *next;
+       IpoCurve *icu;
+       BezTriple *bezt;
        int a;
+       
+       for (icu= ipo->curve.first; icu; icu= icu->next) {
+               if (icu->flag & IPO_VISIBLE) {
+                       /* ... removed old checks for adrcode types from here ...
+                        *      - (was this used for IpoKeys in the past?)
+                        */
+                       
+                       bezt= icu->bezt;
+                       if (bezt) {
+                               for (a=0; a < icu->totvert; a++, bezt++) {
+                                       add_to_cfra_elem(elems, bezt);
+                               }
+                       }
+               }
+       }
+}
 
-       a= icu->totvert;
+/* ***************************** Timing Stuff ********************************* */
 
-       /* IPO_CONST doesn't have handles */
-       if(a<2 || icu->ipo==IPO_CONST || icu->ipo==IPO_LIN) return;
+/* This (evil) function is needed to cope with two legacy Blender rendering features
+ * mblur (motion blur that renders 'subframes' and blurs them together), and fields 
+ * rendering. Thus, the use of ugly globals from object.c
+ */
+// BAD... EVIL... JUJU...!!!!
+float frame_to_float (int cfra)                /* see also bsystem_time in object.c */
+{
+       extern float bluroffs;  /* bad stuff borrowed from object.c */
+       extern float fieldoffs;
+       float ctime;
        
-       bezt= icu->bezt;
-       prev= 0;
-       next= bezt+1;
+       ctime= (float)cfra;
+       ctime+= bluroffs+fieldoffs;
+       ctime*= G.scene->r.framelen;
+       
+       return ctime;
+}
 
-       while(a--) {
+/* ***************************** IPO Curve Sanity ********************************* */
+/* The functions here are used in various parts of Blender, usually after some editing
+ * of keyframe data has occurred. They ensure that keyframe data is properly ordered and
+ * that the handles are correctly 
+ */
 
-               if(bezt->vec[0][0]>bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0];
-               if(bezt->vec[2][0]<bezt->vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0];
+/* This function recalculates the handles of an IPO-Curve 
+ * If the BezTriples have been rearranged, sort them first before using this.
+ */
+void calchandles_ipocurve (IpoCurve *icu)
+{
+       BezTriple *bezt, *prev, *next;
+       int a= icu->totvert;
 
-               if(icu->flag & IPO_AUTO_HORIZ) 
+       /* Error checking:
+        *      - need at least two points
+        *      - need bezier keys
+        *      - only bezier-interpolation has handles (for now)
+        */
+       if (ELEM(NULL, icu, icu->bezt) || (a < 2) || ELEM(icu->ipo, IPO_CONST, IPO_LIN)) 
+               return;
+       
+       /* get initial pointers */
+       bezt= icu->bezt;
+       prev= NULL;
+       next= (bezt + 1);
+       
+       /* loop over all beztriples, adjusting handles */
+       while (a--) {
+               /* clamp timing of handles to be on either side of beztriple */
+               if (bezt->vec[0][0] > bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0];
+               if (bezt->vec[2][0] < bezt->vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0];
+               
+               /* calculate autohandles */
+               if (icu->flag & IPO_AUTO_HORIZ) 
                        calchandleNurb(bezt, prev, next, 2);    /* 2==special autohandle && keep extrema horizontal */
                else
                        calchandleNurb(bezt, prev, next, 1);    /* 1==special autohandle */
-       
-               prev= bezt;
-               if(a==1) {
-                       next= 0;
-               }
-               else next++;
-                       
+               
                /* for automatic ease in and out */
-               if(bezt->h1==HD_AUTO && bezt->h2==HD_AUTO) {
-                       if(a==0 || a==icu->totvert-1) {
-                               if(icu->extrap==IPO_HORIZ) {
+               if ((bezt->h1==HD_AUTO) && (bezt->h2==HD_AUTO)) {
+                       /* only do this on first or last beztriple */
+                       if ((a==0) || (a==icu->totvert-1)) {
+                               /* set both handles to have same horizontal value as keyframe */
+                               if (icu->extrap==IPO_HORIZ) {
                                        bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
                                }
                        }
                }
                
+               /* advance pointers for next iteration */
+               prev= bezt;
+               if (a == 1) next= NULL;
+               else next++;
                bezt++;
        }
 }
 
-void testhandles_ipocurve(IpoCurve *icu)
+/* Use when IPO-Curve with handles has changed
+ * It treats all BezTriples with the following rules:
+ *  - PHASE 1: do types have to be altered?
+ *             -> Auto handles: become aligned when selection status is NOT(000 || 111)
+ *             -> Vector handles: become 'nothing' when (one half selected AND other not)
+ *  - PHASE 2: recalculate handles
+*/
+void testhandles_ipocurve (IpoCurve *icu)
 {
-    /* use when something has changed with handles.
-    it treats all BezTriples with the following rules:
-    PHASE 1: do types have to be altered?
-     Auto handles: become aligned when selection status is NOT(000 || 111)
-     Vector handles: become 'nothing' when (one half selected AND other not)
-    PHASE 2: recalculate handles
-    */
-    BezTriple *bezt;
-       int flag, a;
+       BezTriple *bezt;
+       int a;
 
-       bezt= icu->bezt;
-       if(bezt==NULL) return;
+       /* only beztriples have handles (bpoints don't though) */
+       if (ELEM(NULL, icu, icu->bezt))
+               return;
        
-       a= icu->totvert;
-       while(a--) {
-               flag= 0;
-               if(bezt->f1 & SELECT) flag++;
-               if(bezt->f2 & SELECT) flag += 2;
-               if(bezt->f3 & SELECT) flag += 4;
-
-               if( !(flag==0 || flag==7) ) {
-                       if(bezt->h1==HD_AUTO) {   /* auto */
+       /* loop over beztriples */
+       for (a=0, bezt=icu->bezt; a < icu->totvert; a++, bezt++) {
+               short flag= 0;
+               
+               /* flag is initialised as selection status
+                * of beztriple control-points (labelled 0,1,2)
+                */
+               if (bezt->f1 & SELECT) flag |= (1<<0); // == 1
+               if (bezt->f2 & SELECT) flag |= (1<<1); // == 2
+               if (bezt->f3 & SELECT) flag |= (1<<2); // == 4
+               
+               /* one or two handles selected only */
+               if (ELEM(flag, 0, 7)==0) {
+                       /* auto handles become aligned */
+                       if (bezt->h1==HD_AUTO)
                                bezt->h1= HD_ALIGN;
-                       }
-                       if(bezt->h2==HD_AUTO) {   /* auto */
+                       if(bezt->h2==HD_AUTO)
                                bezt->h2= HD_ALIGN;
+                       
+                       /* vector handles become 'free' when only one half selected */
+                       if(bezt->h1==HD_VECT) {
+                               /* only left half (1 or 2 or 1+2) */
+                               if (flag < 4) 
+                                       bezt->h1= 0;
                        }
-
-                       if(bezt->h1==HD_VECT) {   /* vector */
-                               if(flag < 4) bezt->h1= 0;
-                       }
-                       if(bezt->h2==HD_VECT) {   /* vector */
-                               if( flag > 3) bezt->h2= 0;
+                       if(bezt->h2==HD_VECT) {
+                               /* only right half (4 or 2+4) */
+                               if (flag > 3) 
+                                       bezt->h2= 0;
                        }
                }
-               bezt++;
        }
 
+       /* recalculate handles */
        calchandles_ipocurve(icu);
 }
 
-
+/* This function sorts BezTriples so that they are arranged in chronological order,
+ * as tools working on IPO-Curves expect that the BezTriples are in order.
+ */
 void sort_time_ipocurve(IpoCurve *icu)
 {
-       BezTriple *bezt;
-       int a, ok= 1;
+       short ok= 1;
        
-       while(ok) {
+       /* keep adjusting order of beztriples until nothing moves (bubble-sort) */
+       while (ok) {
                ok= 0;
-
-               if(icu->bezt) {
-                       bezt= icu->bezt;
-                       a= icu->totvert;
-                       while(a--) {
-                               if(a>0) {
-                                       if( bezt->vec[1][0] > (bezt+1)->vec[1][0]) {
+               
+               /* currently, will only be needed when there are beztriples */
+               if (icu->bezt) {
+                       BezTriple *bezt;
+                       int a;
+                       
+                       /* loop over ALL points to adjust position in array and recalculate handles */
+                       for (a=0, bezt=icu->bezt; a < icu->totvert; a++, bezt++) {
+                               /* check if thee's a next beztriple which we could try to swap with current */
+                               if (a < (icu->totvert-1)) {
+                                       /* swap if one is after the other (and indicate that order has changed) */
+                                       if (bezt->vec[1][0] > (bezt+1)->vec[1][0]) {
                                                SWAP(BezTriple, *bezt, *(bezt+1));
                                                ok= 1;
                                        }
+                                       
+                                       /* if either one of both of the points exceeds crosses over the keyframe time... */
+                                       if ( (bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0]) ) {
+                                               /* swap handles if they have switched sides for some reason */
+                                               SWAP(float, bezt->vec[0][0], bezt->vec[2][0]);
+                                               SWAP(float, bezt->vec[0][1], bezt->vec[2][1]);
+                                       }
+                                       else {
+                                               /* clamp handles */
+                                               if (bezt->vec[0][0] > bezt->vec[1][0]) 
+                                                       bezt->vec[0][0]= bezt->vec[1][0];
+                                               if (bezt->vec[2][0] < bezt->vec[1][0]) 
+                                                       bezt->vec[2][0]= bezt->vec[1][0];
+                                       }
                                }
-                               if(bezt->vec[0][0]>bezt->vec[1][0] && bezt->vec[2][0]<bezt->vec[1][0]) {
-                                       SWAP(float, bezt->vec[0][0], bezt->vec[2][0]);
-                                       SWAP(float, bezt->vec[0][1], bezt->vec[2][1]);
-                               }
-                               else {
-                                       if(bezt->vec[0][0]>bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0];
-                                       if(bezt->vec[2][0]<bezt->vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0];
-                               }
-                               bezt++;
                        }
                }
-               else {
-                       
-               }
        }
 }
 
-int test_time_ipocurve(IpoCurve *icu)
+/* This function tests if any BezTriples are out of order, thus requiring a sort */
+int test_time_ipocurve (IpoCurve *icu)
 {
-       BezTriple *bezt;
        int a;
        
-       if(icu->bezt) {
-               bezt= icu->bezt;
-               a= icu->totvert-1;
-               while(a--) {
-                       if( bezt->vec[1][0] > (bezt+1)->vec[1][0]) {
-                               return 1;
-                       }
-                       bezt++;
-               }       
-       }
-       else {
+       /* currently, only need to test beztriples */
+       if (icu->bezt) {
+               BezTriple *bezt;
                
+               /* loop through all beztriples, stopping when one exceeds the one after it */
+               for (a=0, bezt= icu->bezt; a < (icu->totvert - 1); a++, bezt++) {
+                       if (bezt->vec[1][0] > (bezt+1)->vec[1][0])
+                               return 1;
+               }
        }
-
+       
+       /* none need any swapping */
        return 0;
 }
 
-void correct_bezpart(float *v1, float *v2, float *v3, float *v4)
+/* --------- */
+
+/* The total length of the handles is not allowed to be more
+ * than the horizontal distance between (v1-v4).
+ * This is to prevent curve loops.
+*/
+void correct_bezpart (float *v1, float *v2, float *v3, float *v4)
 {
-       /* the total length of the handles is not allowed to be more
-        * than the horizontal distance between (v1-v4)
-         * this to prevent curve loops
-        */
        float h1[2], h2[2], len1, len2, len, fac;
        
+       /* calculate handle deltas */
        h1[0]= v1[0]-v2[0];
        h1[1]= v1[1]-v2[1];
        h2[0]= v4[0]-v3[0];
        h2[1]= v4[1]-v3[1];
        
+       /* calculate distances: 
+        *      - len   = span of time between keyframes 
+        *      - len1  = length of handle of start key
+        *      - len2  = length of handle of end key
+        */
        len= v4[0]- v1[0];
        len1= (float)fabs(h1[0]);
        len2= (float)fabs(h2[0]);
        
-       if(len1+len2==0.0) return;
-       if(len1+len2 > len) {
+       /* if the handles have no length, no need to do any corrections */
+       if ((len1+len2) == 0.0) 
+               return;
+               
+       /* the two handles cross over each other, so force them
+        * apart using the proportion they overlap 
+        */
+       if ((len1+len2) > len) {
                fac= len/(len1+len2);
                
                v2[0]= (v1[0]-fac*h1[0]);
@@ -638,57 +798,86 @@ void correct_bezpart(float *v1, float *v2, float *v3, float *v4)
                
                v3[0]= (v4[0]-fac*h2[0]);
                v3[1]= (v4[1]-fac*h2[1]);
-               
        }
 }
 
-/* *********************** ARITH *********************** */
+#if 0 // TODO: enable when we have per-segment interpolation
+/* This function sets the interpolation mode for an entire Ipo-Curve. 
+ * It is primarily used for patching old files, but is also used in the interface
+ * to make sure that all segments of the curve use the same interpolation.
+ */
+void set_interpolation_ipocurve (IpoCurve *icu, short ipo)
+{
+       BezTriple *bezt;
+       int a;
+       
+       /* validate arguments */
+       if (icu == NULL) return;
+       if (ELEM3(ipo, IPO_CONST, IPO_LIN, IPO_BEZ)==0) return;
+
+       /* set interpolation mode for whole curve */
+       icu->ipo= ipo;
+       
+       /* set interpolation mode of all beztriples */
+       for (a=0, bezt=icu->bezt; a<icu->totvert; a++, bezt++)
+               bezt->ipo= ipo;
+}
+#endif // TODO: enable when we have per-segment interpolation
+
+/* ***************************** Curve Calculations ********************************* */
 
-int findzero(float x, float q0, float q1, float q2, float q3, float *o)
+/* find root/zero */
+int findzero (float x, float q0, float q1, float q2, float q3, float *o)
 {
        double c0, c1, c2, c3, a, b, c, p, q, d, t, phi;
        int nr= 0;
 
-       c0= q0-x;
-       c1= 3*(q1-q0);
-       c2= 3*(q0-2*q1+q2);
-       c3= q3-q0+3*(q1-q2);
+       c0= q0 - x;
+       c1= 3 * (q1 - q0);
+       c2= 3 * (q0 - 2*q1 + q2);
+       c3= q3 - q0 + 3 * (q1 - q2);
        
-       if(c3!=0.0) {
+       if (c3 != 0.0) {
                a= c2/c3;
                b= c1/c3;
                c= c0/c3;
                a= a/3;
-
-               p= b/3-a*a;
-               q= (2*a*a*a-a*b+c)/2;
-               d= q*q+p*p*p;
-
-               if(d>0.0) {
+               
+               p= b/3 - a*a;
+               q= (2*a*a*a - a*b + c) / 2;
+               d= q*q + p*p*p;
+               
+               if (d > 0.0) {
                        t= sqrt(d);
-                       o[0]= (float)(Sqrt3d(-q+t)+Sqrt3d(-q-t)-a);
-                       if(o[0]>= SMALL && o[0]<=1.000001) return 1;
+                       o[0]= (float)(Sqrt3d(-q+t) + Sqrt3d(-q-t) - a);
+                       
+                       if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1;
                        else return 0;
                }
-               else if(d==0.0) {
+               else if (d == 0.0) {
                        t= Sqrt3d(-q);
-                       o[0]= (float)(2*t-a);
-                       if(o[0]>=SMALL && o[0]<=1.000001) nr++;
+                       o[0]= (float)(2*t - a);
+                       
+                       if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++;
                        o[nr]= (float)(-t-a);
-                       if(o[nr]>=SMALL && o[nr]<=1.000001) return nr+1;
+                       
+                       if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1;
                        else return nr;
                }
                else {
-                       phi= acos(-q/sqrt(-(p*p*p)));
+                       phi= acos(-q / sqrt(-(p*p*p)));
                        t= sqrt(-p);
                        p= cos(phi/3);
-                       q= sqrt(3-3*p*p);
-                       o[0]= (float)(2*t*p-a);
-                       if(o[0]>=SMALL && o[0]<=1.000001) nr++;
-                       o[nr]= (float)(-t*(p+q)-a);
-                       if(o[nr]>=SMALL && o[nr]<=1.000001) nr++;
-                       o[nr]= (float)(-t*(p-q)-a);
-                       if(o[nr]>=SMALL && o[nr]<=1.000001) return nr+1;
+                       q= sqrt(3 - 3*p*p);
+                       o[0]= (float)(2*t*p - a);
+                       
+                       if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++;
+                       o[nr]= (float)(-t * (p + q) - a);
+                       
+                       if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) nr++;
+                       o[nr]= (float)(-t * (p - q) - a);
+                       
+                       if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1;
                        else return nr;
                }
        }
@@ -697,83 +886,97 @@ int findzero(float x, float q0, float q1, float q2, float q3, float *o)
                b=c1;
                c=c0;
                
-               if(a!=0.0) {
-                       p=b*b-4*a*c;
-                       if(p>0) {
+               if (a != 0.0) {
+                       // discriminant
+                       p= b*b - 4*a*c;
+                       
+                       if (p > 0) {
                                p= sqrt(p);
-                               o[0]= (float)((-b-p)/(2*a));
-                               if(o[0]>=SMALL && o[0]<=1.000001) nr++;
+                               o[0]= (float)((-b-p) / (2 * a));
+                               
+                               if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++;
                                o[nr]= (float)((-b+p)/(2*a));
-                               if(o[nr]>=SMALL && o[nr]<=1.000001) return nr+1;
+                               
+                               if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1;
                                else return nr;
                        }
-                       else if(p==0) {
-                               o[0]= (float)(-b/(2*a));
-                               if(o[0]>=SMALL && o[0]<=1.000001) return 1;
+                       else if (p == 0) {
+                               o[0]= (float)(-b / (2 * a));
+                               if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1;
                                else return 0;
                        }
                }
-               else if(b!=0.0) {
+               else if (b != 0.0) {
                        o[0]= (float)(-c/b);
-                       if(o[0]>=SMALL && o[0]<=1.000001) return 1;
+                       
+                       if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1;
                        else return 0;
                }
-               else if(c==0.0) {
+               else if (c == 0.0) {
                        o[0]= 0.0;
                        return 1;
                }
+               
                return 0;       
        }
 }
 
-void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
+void berekeny (float f1, float f2, float f3, float f4, float *o, int b)
 {
        float t, c0, c1, c2, c3;
        int a;
 
        c0= f1;
-       c1= 3.0f*(f2 - f1);
-       c2= 3.0f*(f1 - 2.0f*f2 + f3);
-       c3= f4 - f1 + 3.0f*(f2-f3);
+       c1= 3.0f * (f2 - f1);
+       c2= 3.0f * (f1 - 2.0f*f2 + f3);
+       c3= f4 - f1 + 3.0f * (f2 - f3);
        
-       for(a=0; a<b; a++) {
+       for (a=0; a < b; a++) {
                t= o[a];
-               o[a]= c0+t*c1+t*t*c2+t*t*t*c3;
+               o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3;
        }
 }
 
-void berekenx(float *f, float *o, int b)
+void berekenx (float *f, float *o, int b)
 {
        float t, c0, c1, c2, c3;
        int a;
 
        c0= f[0];
-       c1= 3*(f[3]-f[0]);
-       c2= 3*(f[0]-2*f[3]+f[6]);
-       c3= f[9]-f[0]+3*(f[3]-f[6]);
-       for(a=0; a<b; a++) {
+       c1= 3 * (f[3] - f[0]);
+       c2= 3 * (f[0] - 2*f[3] + f[6]);
+       c3= f[9] - f[0] + 3 * (f[3] - f[6]);
+       
+       for (a=0; a < b; a++) {
                t= o[a];
-               o[a]= c0+t*c1+t*t*c2+t*t*t*c3;
+               o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3;
        }
 }
 
-/* we need the local transform = current transform - (parent transform + bone transform) */
-/* (local transform is on action channel level) */
-static void posechannel_get_local_transform(bPoseChannel *pchan, float *loc, float *eul, float *size)
+/* ***************************** IPO - Calculations ********************************* */
+
+/* ---------------------- Curve Evaluation --------------------------- */
+
+/* helper function for evaluating drivers: 
+ *     - we need the local transform = current transform - (parent transform + bone transform)
+ *     - (local transform is on action channel level)
+ */
+static void posechannel_get_local_transform (bPoseChannel *pchan, float loc[], float eul[], float size[])
 {
-       float diff_mat[4][4];
        float parmat[4][4], offs_bone[4][4], imat[4][4];
+       float diff_mat[4][4];
        
+       /* get first the parent + bone transform in parmat */
        if (pchan->parent) {
-               /* get first the parent + bone transform in parmat */
-               
                /* bone transform itself */
                Mat4CpyMat3(offs_bone, pchan->bone->bone_mat);
+               
                /* The bone's root offset (is in the parent's coordinate system) */
                VECCOPY(offs_bone[3], pchan->bone->head);
+               
                /* Get the length translation of parent (length along y axis) */
                offs_bone[3][1]+= pchan->parent->bone->length;
-       
+               
                Mat4MulSerie(parmat, pchan->parent->pose_mat, offs_bone, NULL, NULL, NULL, NULL, NULL, NULL);
                
                /* invert it */
@@ -782,63 +985,78 @@ static void posechannel_get_local_transform(bPoseChannel *pchan, float *loc, flo
        else {
                Mat4CpyMat3(offs_bone, pchan->bone->bone_mat);
                VECCOPY(offs_bone[3], pchan->bone->head);
-
+               
                /* invert it */
                Mat4Invert(imat, offs_bone);
-               
        }
        
        /* difference: current transform - (parent transform + bone transform)  */
        Mat4MulMat4(diff_mat, pchan->pose_mat, imat);
 
-       if(loc)
+       /* extract relevant components */
+       if (loc)
                VECCOPY(loc, diff_mat[3]);
-       if(eul)
+       if (eul)
                Mat4ToEul(diff_mat, eul);
-       if(size)
+       if (size)
                Mat4ToSize(diff_mat, size);
-       
 }
 
-/* has to return a float value */
-static float eval_driver(IpoDriver *driver, float ipotime)
+/* evaluate an IPO-driver to get a 'time' value to use instead of "ipotime"
+ *     - "ipotime" is the frame at which IPO-curve is being evaluated
+ *     - has to return a float value 
+ */
+static float eval_driver (IpoDriver *driver, float ipotime)
 {
-       
-       if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
+       /* currently, drivers are either PyDrivers (evaluating a PyExpression, or Object/Pose-Channel transforms) */
+       if (driver->type == IPO_DRIVER_TYPE_PYTHON) {
                /* check for empty or invalid expression */
-               if ((driver->name[0] == '\0') ||
-                       (driver->flag & IPO_DRIVER_FLAG_INVALID))
+               if ( (driver->name[0] == '\0') ||
+                        (driver->flag & IPO_DRIVER_FLAG_INVALID) )
+               {
                        return 0.0f;
-               /* this evals the expression and returns its result:
-                * (on errors it reports, then returns 0.0f) */
+               }
+               
+               /* this evaluates the expression using Python,and returns its result:
+                *      - on errors it reports, then returns 0.0f
+                */
                return BPY_pydriver_eval(driver);
        }
        else {
                Object *ob= driver->ob;
-
-               if(ob==NULL) return 0.0f;
-               if(ob->proxy_from)
+               
+               /* must have an object to evaluate */
+               if (ob == NULL) 
+                       return 0.0f;
+                       
+               /* if a proxy, use the proxy source*/
+               if (ob->proxy_from)
                        ob= ob->proxy_from;
                
-               if(driver->blocktype==ID_OB) {
-                       /* depsgraph failure; ob ipos are calculated in where_is_object, this might get called too late */
-                       if(ob->ipo && ob->ctime!=ipotime) {
+               /* use given object as driver */
+               if (driver->blocktype == ID_OB) {
+                       /* depsgraph failure: ob ipos are calculated in where_is_object, this might get called too late */
+                       if ((ob->ipo) && (ob->ctime != ipotime)) {
+                               /* calculate the value of relevant channel on the Object, but do not write the value
+                                * calculated on to the Object but onto "ipotime" instead
+                                */
                                calc_ipo_spec(ob->ipo, driver->adrcode, &ipotime);
                                return ipotime;
                        }
                        
-                       switch(driver->adrcode) {
+                       /* return the value of the relevant channel */
+                       switch (driver->adrcode) {
                        case OB_LOC_X:
                                return ob->loc[0];
                        case OB_LOC_Y:
                                return ob->loc[1];
                        case OB_LOC_Z:
                                return ob->loc[2];
-                       case OB_ROT_X:
+                       case OB_ROT_X:  /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */
                                return ob->rot[0]/(M_PI_2/9.0);
-                       case OB_ROT_Y:
+                       case OB_ROT_Y:  /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */
                                return ob->rot[1]/(M_PI_2/9.0);
-                       case OB_ROT_Z:
+                       case OB_ROT_Z:  /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */
                                return ob->rot[2]/(M_PI_2/9.0);
                        case OB_SIZE_X:
                                return ob->size[0];
@@ -848,14 +1066,20 @@ static float eval_driver(IpoDriver *driver, float ipotime)
                                return ob->size[2];
                        }
                }
+               
+               /* use given pose-channel as driver */
                else {  /* ID_AR */
                        bPoseChannel *pchan= get_pose_channel(ob->pose, driver->name);
-                       if(pchan && pchan->bone) {
-                               
-                               /* rotation difference is not a simple driver (i.e. value drives value), but the angle between 2 bones is driving stuff... which is useful */
-                               if(driver->adrcode==OB_ROT_DIFF) {
+                       
+                       /* must have at least 1 bone to use */
+                       if (pchan && pchan->bone) {
+                               /* rotation difference is not a simple driver (i.e. value drives value), but the angle between 2 bones is driving stuff... 
+                                *      - the name of the second pchan is also stored in driver->name, but packed after the other one by DRIVER_NAME_OFFS chars
+                                */
+                               if (driver->adrcode == OB_ROT_DIFF) {
                                        bPoseChannel *pchan2= get_pose_channel(ob->pose, driver->name+DRIVER_NAME_OFFS);
-                                       if(pchan2 && pchan2->bone) {
+                                       
+                                       if (pchan2 && pchan2->bone) {
                                                float q1[4], q2[4], quat[4], angle;
                                                
                                                Mat4ToQuat(pchan->pose_mat, q1);
@@ -866,26 +1090,32 @@ static float eval_driver(IpoDriver *driver, float ipotime)
                                                angle = 2.0f * (saacos(quat[0]));
                                                angle= ABS(angle);
                                                
-                                               return angle>M_PI?2.0f*M_PI-angle:angle;
+                                               return (angle > M_PI) ? ((2.0f * M_PI) - angle) : (angle);
                                        }
                                }
+                               
+                               /* standard driver */
                                else {
                                        float loc[3], eul[3], size[3];
                                        
+                                       /* retrieve local transforms to return 
+                                        *      - we use eulers here NOT quats, so that Objects can be driven by bones easily
+                                        *        also, this way is more understandable for users
+                                        */
                                        posechannel_get_local_transform(pchan, loc, eul, size);
-
-                                       switch(driver->adrcode) {
+                                       
+                                       switch (driver->adrcode) {
                                        case OB_LOC_X:
                                                return loc[0];
                                        case OB_LOC_Y:
                                                return loc[1];
                                        case OB_LOC_Z:
                                                return loc[2];
-                                       case OB_ROT_X:
+                                       case OB_ROT_X: /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */
                                                return eul[0]/(M_PI_2/9.0);
-                                       case OB_ROT_Y:
+                                       case OB_ROT_Y: /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */
                                                return eul[1]/(M_PI_2/9.0);
-                                       case OB_ROT_Z:
+                                       case OB_ROT_Z: /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */
                                                return eul[2]/(M_PI_2/9.0);
                                        case OB_SIZE_X:
                                                return size[0];
@@ -898,1139 +1128,666 @@ static float eval_driver(IpoDriver *driver, float ipotime)
                        }
                }
        }       
+       
+       /* return 0.0f, as couldn't find relevant data to use */
        return 0.0f;
 }
 
-float eval_icu(IpoCurve *icu, float ipotime) 
+/* evaluate and return the value of the given IPO-curve at the specified frame ("evaltime") */
+float eval_icu(IpoCurve *icu, float evaltime) 
 {
-       BezTriple *bezt, *prevbezt;
-       float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac;
-       float cycdx, cycdy, ofs, cycyofs, cvalue = 0.0;
-       int a, b;
+       float cvalue = 0.0f;
        
-       cycyofs= 0.0;
-       
-       if(icu->driver) {
+       /* if there is a driver, evaluate it to find value to use as "evaltime" 
+        *      - this value will also be returned as the value of the 'curve', if there are no keyframes
+        */
+       if (icu->driver) {
                /* ipotime now serves as input for the curve */
-               ipotime= cvalue= eval_driver(icu->driver, ipotime);
+               evaltime= cvalue= eval_driver(icu->driver, evaltime);
        }
-       if(icu->bezt) {
+       
+       /* there are keyframes (in the form of BezTriples) which can be interpolated between */
+       if (icu->bezt) {
+               /* get pointers */
+               BezTriple *bezt, *prevbezt, *lastbezt;
+               float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac;
+               float cycdx, cycdy, ofs, cycyofs= 0.0;
+               int a, b;
+               
+               /* get pointers */
+               a= icu->totvert-1;
                prevbezt= icu->bezt;
                bezt= prevbezt+1;
-               a= icu->totvert-1;
+               lastbezt= prevbezt + a;
                
-               /* cyclic? */
-               if(icu->extrap & IPO_CYCL) {
-                       ofs= icu->bezt->vec[1][0];
-                       cycdx= (icu->bezt+icu->totvert-1)->vec[1][0] - ofs;
-                       cycdy= (icu->bezt+icu->totvert-1)->vec[1][1] - icu->bezt->vec[1][1];
-                       if(cycdx!=0.0) {
-                               
-                               if(icu->extrap & IPO_DIR) {
-                                       cycyofs= (float)floor((ipotime-ofs)/cycdx);
-                                       cycyofs*= cycdy;
+               /* extrapolation mode is 'cyclic' - find relative place within a cycle */
+               if (icu->extrap & IPO_CYCL) {
+                       /* ofs is start frame of cycle */
+                       ofs= prevbezt->vec[1][0];
+                       
+                       /* calculate period and amplitude (total height) of a cycle */
+                       cycdx= lastbezt->vec[1][0] - prevbezt->vec[1][0];
+                       cycdy= lastbezt->vec[1][1] - prevbezt->vec[1][1];
+                       
+                       /* cycle occurs over some period of time (cycdx should be positive all the time) */
+                       if (cycdx) {
+                               /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle
+                                *      - IPO_CYCLX = (IPO_CYCL + IPO_DIR)
+                                */
+                               if (icu->extrap & IPO_DIR) {
+                                       cycyofs = (float)floor((evaltime - ofs) / cycdx);
+                                       cycyofs *= cycdy;
                                }
-
-                               ipotime= (float)(fmod(ipotime-ofs, cycdx)+ofs);
-                               if(ipotime<ofs) ipotime+= cycdx;
+                               
+                               /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
+                               evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs);
+                               if (evaltime < ofs) evaltime += cycdx;
                        }
                }
                
-               /* endpoints? */
-       
-               if(prevbezt->vec[1][0]>=ipotime) {
-                       if( (icu->extrap & IPO_DIR) && icu->ipo!=IPO_CONST) {
+               /* evaluation time at or past endpoints? */
+               // TODO: for per-bezt interpolation, replace all icu->ipo with (bezt)->ipo
+               if (prevbezt->vec[1][0] >= evaltime) {
+                       /* before or on first keyframe */
+                       if ((icu->extrap & IPO_DIR) && (icu->ipo != IPO_CONST)) {
+                               /* linear or bezier interpolation */
                                if (icu->ipo==IPO_LIN) {
-                                       if (icu->totvert==1) cvalue= prevbezt->vec[1][1];
+                                       /* Use the next center point instead of our own handle for
+                                        * linear interpolated extrapolate 
+                                        */
+                                       if (icu->totvert == 1) 
+                                               cvalue= prevbezt->vec[1][1];
                                        else {
-                                               /* use the next center point instead of our own handle for
-                                                * linear interpolated extrapolate */
                                                bezt = prevbezt+1;
-                                               dx= prevbezt->vec[1][0]-ipotime;
-                                               fac= bezt->vec[1][0]-prevbezt->vec[1][0];
-                                               if(fac!=0.0) {
-                                                       fac= (bezt->vec[1][1]-prevbezt->vec[1][1])/fac;
-                                                       cvalue= prevbezt->vec[1][1]-fac*dx;
+                                               dx= prevbezt->vec[1][0] - evaltime;
+                                               fac= bezt->vec[1][0] - prevbezt->vec[1][0];
+                                               
+                                               /* prevent division by zero */
+                                               if (fac) {
+                                                       fac= (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
+                                                       cvalue= prevbezt->vec[1][1] - (fac * dx);
                                                }
-                                               else cvalue= prevbezt->vec[1][1];
+                                               else 
+                                                       cvalue= prevbezt->vec[1][1];
                                        }
-                               } else {
-                                       dx= prevbezt->vec[1][0]-ipotime;
-                                       fac= prevbezt->vec[1][0]-prevbezt->vec[0][0];
-                                       if(fac!=0.0) {
-                                               fac= (prevbezt->vec[1][1]-prevbezt->vec[0][1])/fac;
-                                               cvalue= prevbezt->vec[1][1]-fac*dx;
+                               } 
+                               else {
+                                       /* Use the first handle (earlier) of first BezTriple to calculate the
+                                        * gradient and thus the value of the curve at evaltime
+                                        */
+                                       dx= prevbezt->vec[1][0] - evaltime;
+                                       fac= prevbezt->vec[1][0] - prevbezt->vec[0][0];
+                                       
+                                       /* prevent division by zero */
+                                       if (fac) {
+                                               fac= (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac;
+                                               cvalue= prevbezt->vec[1][1] - (fac * dx);
                                        }
-                                       else cvalue= prevbezt->vec[1][1];
+                                       else 
+                                               cvalue= prevbezt->vec[1][1];
                                }
                        }
-                       else cvalue= prevbezt->vec[1][1];
-                       
-                       cvalue+= cycyofs;
+                       else {
+                               /* constant (IPO_HORIZ) extrapolation or constant interpolation, 
+                                * so just extend first keyframe's value 
+                                */
+                               cvalue= prevbezt->vec[1][1];
+                       }
                }
-               else if( (prevbezt+a)->vec[1][0]<=ipotime) {
-                       if( (icu->extrap & IPO_DIR) && icu->ipo!=IPO_CONST) {
-                               prevbezt+= a;
-                               
+               else if (lastbezt->vec[1][0] <= evaltime) {
+                       /* after or on last keyframe */
+                       if( (icu->extrap & IPO_DIR) && (icu->ipo != IPO_CONST)) {
+                               /* linear or bezier interpolation */
                                if (icu->ipo==IPO_LIN) {
-                                       if (icu->totvert==1) cvalue= prevbezt->vec[1][1];
+                                       /* Use the next center point instead of our own handle for
+                                        * linear interpolated extrapolate 
+                                        */
+                                       if (icu->totvert == 1) 
+                                               cvalue= lastbezt->vec[1][1];
                                        else {
-                                               /* use the previous center point instead of our own handle for
-                                                * linear interpolated extrapolate */
-                                               bezt = prevbezt-1;
-                                               dx= ipotime-prevbezt->vec[1][0];
-                                               fac= prevbezt->vec[1][0]-bezt->vec[1][0];
-
-                                               if(fac!=0) {
-                                                       fac= (prevbezt->vec[1][1]-bezt->vec[1][1])/fac;
-                                                       cvalue= prevbezt->vec[1][1]+fac*dx;
+                                               prevbezt = lastbezt - 1;
+                                               dx= evaltime - lastbezt->vec[1][0];
+                                               fac= lastbezt->vec[1][0] - prevbezt->vec[1][0];
+                                               
+                                               /* prevent division by zero */
+                                               if (fac) {
+                                                       fac= (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
+                                                       cvalue= lastbezt->vec[1][1] + (fac * dx);
                                                }
-                                               else cvalue= prevbezt->vec[1][1];
+                                               else 
+                                                       cvalue= lastbezt->vec[1][1];
                                        }
-                               } else {
-                                       dx= ipotime-prevbezt->vec[1][0];
-                                       fac= prevbezt->vec[2][0]-prevbezt->vec[1][0];
-
-                                       if(fac!=0) {
-                                               fac= (prevbezt->vec[2][1]-prevbezt->vec[1][1])/fac;
-                                               cvalue= prevbezt->vec[1][1]+fac*dx;
+                               } 
+                               else {
+                                       /* Use the gradient of the second handle (later) of last BezTriple to calculate the
+                                        * gradient and thus the value of the curve at evaltime
+                                        */
+                                       dx= evaltime - lastbezt->vec[1][0];
+                                       fac= lastbezt->vec[2][0] - lastbezt->vec[1][0];
+                                       
+                                       /* prevent division by zero */
+                                       if (fac) {
+                                               fac= (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac;
+                                               cvalue= lastbezt->vec[1][1] + (fac * dx);
                                        }
-                                       else cvalue= prevbezt->vec[1][1];
+                                       else 
+                                               cvalue= lastbezt->vec[1][1];
                                }
                        }
-                       else cvalue= (prevbezt+a)->vec[1][1];
-                       
-                       cvalue+= cycyofs;
+                       else {
+                               /* constant (IPO_HORIZ) extrapolation or constant interpolation, 
+                                * so just extend last keyframe's value 
+                                */
+                               cvalue= lastbezt->vec[1][1];
+                       }
                }
                else {
-                       while(a--) {
-                               if(prevbezt->vec[1][0]<=ipotime && bezt->vec[1][0]>=ipotime) {
-                                       if(icu->ipo==IPO_CONST) {
-                                               cvalue= prevbezt->vec[1][1]+cycyofs;
+                       /* evaltime occurs somewhere in the middle of the curve */
+                       // TODO: chould be optimised by using a binary search instead???
+                       for (a=0; prevbezt && bezt && (a < icu->totvert-1); a++, prevbezt=bezt, bezt++) {  
+                               /* evaltime occurs within the interval defined by these two keyframes */
+                               if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) {
+                                       /* value depends on interpolation mode */
+                                       if (icu->ipo == IPO_CONST) {
+                                               /* constant (evaltime not relevant, as no interpolation needed) */
+                                               cvalue= prevbezt->vec[1][1];
+                                               
+                                               /* value found already, so no need to keep looping */
+                                               break;
                                        }
-                                       else if(icu->ipo==IPO_LIN) {
-                                               fac= bezt->vec[1][0]-prevbezt->vec[1][0];
-                                               if(fac==0) cvalue= cycyofs+prevbezt->vec[1][1];
-                                               else {
-                                                       fac= (ipotime-prevbezt->vec[1][0])/fac;
-                                                       cvalue= cycyofs+prevbezt->vec[1][1]+ fac*(bezt->vec[1][1]-prevbezt->vec[1][1]);
+                                       else if (icu->ipo == IPO_LIN) {
+                                               /* linear - interpolate between values of the two keyframes */
+                                               fac= bezt->vec[1][0] - prevbezt->vec[1][0];
+                                               
+                                               /* prevent division by zero */
+                                               if (fac) {
+                                                       fac= (evaltime - prevbezt->vec[1][0])/fac;
+                                                       cvalue= prevbezt->vec[1][1] + (fac * (bezt->vec[1][1] - prevbezt->vec[1][1]));
                                                }
+                                               else
+                                                       cvalue= prevbezt->vec[1][1];
+                                                       
+                                               /* value found already, so no need to keep looping */
+                                               break;
                                        }
                                        else {
+                                               /* bezier interpolation */
+                                                       /* v1,v2 are the first keyframe and its 2nd handle */
                                                v1[0]= prevbezt->vec[1][0];
                                                v1[1]= prevbezt->vec[1][1];
                                                v2[0]= prevbezt->vec[2][0];
                                                v2[1]= prevbezt->vec[2][1];
-                                               
+                                                       /* v3,v4 are the last keyframe's 1st handle + the last keyframe */
                                                v3[0]= bezt->vec[0][0];
                                                v3[1]= bezt->vec[0][1];
                                                v4[0]= bezt->vec[1][0];
                                                v4[1]= bezt->vec[1][1];
-
+                                               
+                                               /* adjust handles so that they don't overlap (forming a loop) */
                                                correct_bezpart(v1, v2, v3, v4);
                                                
-                                               b= findzero(ipotime, v1[0], v2[0], v3[0], v4[0], opl);
-                                               if(b) {
+                                               /* try to get a value for this position - if failure, try another set of points */
+                                               b= findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl);
+                                               if (b) {
                                                        berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
-                                                       cvalue= opl[0]+cycyofs;
+                                                       cvalue= opl[0];
                                                        break;
                                                }
                                        }
                                }
-                               prevbezt= bezt;
-                               bezt++;
                        }
                }
+               
+               /* apply y-offset (for 'cyclic extrapolation') to calculated value */
+               cvalue+= cycyofs;
        }
-
-       if(icu->ymin < icu->ymax) {
-               if(cvalue < icu->ymin) cvalue= icu->ymin;
-               else if(cvalue > icu->ymax) cvalue= icu->ymax;
+       
+       /* clamp evaluated value to lie within allowable value range for this channel */
+       if (icu->ymin < icu->ymax) {
+               CLAMP(cvalue, icu->ymin, icu->ymax);
        }
        
+       /* return evaluated value */
        return cvalue;
 }
 
-void calc_icu(IpoCurve *icu, float ctime)
+/* ------------------- IPO-Block/Curve Calculation - General API ----------------------- */
+
+/* calculate the value of the given IPO-curve at the current frame, and set its curval */
+void calc_icu (IpoCurve *icu, float ctime)
 {
+       /* calculate and set curval (evaluates driver too) */
        icu->curval= eval_icu(icu, ctime);
 }
 
-float calc_ipo_time(Ipo *ipo, float ctime)
+/* calculate for the current frame, all IPO-curves in IPO-block that can be evaluated 
+ *     - icu->curval is set for all IPO-curves which are evaluated!
+ */
+void calc_ipo (Ipo *ipo, float ctime)
 {
+       IpoCurve *icu;
+       
+       /* if there is no IPO block to evaluate, or whole block is "muted" */
+       if (ipo == NULL) return;
+       if (ipo->muteipo) return;
+       
+       /* loop over all curves */
+       for (icu= ipo->curve.first; icu; icu= icu->next) {
+               /* only evaluated curve if allowed to:
+                *      - Muted channels should not be evaluated as they shouldn't have any effect 
+                *              --> user explictly turned them off!
+                *      - Drivers should be evaluated at all updates
+                *              --> TODO Note: drivers should be separated from standard channels
+                *      - IPO_LOCK is not set, as it is set by some internal mechanisms to prevent
+                *              IPO-curve from overwriting data (currently only used for IPO-Record). 
+                */
+               if ((icu->driver) || (icu->flag & IPO_LOCK)==0) { 
+                       if ((icu->flag & IPO_MUTE)==0)
+                               calc_icu(icu, ctime);
+               }
+       }
+}
 
-       if(ipo && ipo->blocktype==ID_OB) {
-               IpoCurve *icu= ipo->curve.first;
+/* ------------------- IPO-Block/Curve Calculation - Special Hacks ----------------------- */
 
-               while(icu) {
-                       if (icu->adrcode==OB_TIME) {
-                               calc_icu(icu, ctime);
-                               return 10.0f*icu->curval;
-                       }
-                       icu= icu->next;
-               }       
+/* Calculate and return the value of the 'Time' Ipo-Curve from an Object,
+ * OR return the current time if not found
+ *     - used in object.c -> bsystem_time() 
+ */
+float calc_ipo_time (Ipo *ipo, float ctime)
+{
+       /* only Time IPO from Object IPO-blocks are relevant */
+       if ((ipo) && (ipo->blocktype == ID_OB)) {
+               IpoCurve *icu= find_ipocurve(ipo, OB_TIME);
+               
+               /* only calculate (and set icu->curval) for time curve */
+               if (icu) {
+                       calc_icu(icu, ctime);
+                       return (10.0f * icu->curval);
+               }
        }
        
+       /* no appropriate time-curve found */
        return ctime;
 }
 
-void calc_ipo(Ipo *ipo, float ctime)
+/* Evaluate the specified channel in the given IPO block on the specified frame (ctime),
+ * writing the value into that channel's icu->curval, but ALSO dumping it in ctime.
+ *     - Returns success and modifies ctime! 
+ */
+short calc_ipo_spec (Ipo *ipo, int adrcode, float *ctime)
+{
+       IpoCurve *icu= find_ipocurve(ipo, adrcode);
+       
+       /* only evaluate if found */
+       if (icu) {
+               /* only calculate if allowed to (not locked and not muted) 
+                *      - drivers not taken into account, because this may be called when calculating a driver
+                */
+               if ((icu->flag & (IPO_LOCK|IPO_MUTE))==0) 
+                       calc_icu(icu, *ctime);
+               
+               /* value resulting from calculations is written into ctime! */
+               *ctime= icu->curval;
+               return 1;
+       }
+       
+       /* couldn't evaluate */
+       return 0;
+}
+
+/* ***************************** IPO - DataAPI ********************************* */
+
+/* --------------------- Flush/Execute IPO Values ----------------------------- */
+
+/* Flush IpoCurve->curvals to the data they affect (defined by ID)
+ *      - not for Actions or Constraints!  (those have their own special handling)
+ */
+void execute_ipo (ID *id, Ipo *ipo)
 {
        IpoCurve *icu;
+       void *poin;
+       int type;
        
-       if(ipo==NULL) return;
-       if(ipo->muteipo) return;
+       /* don't do anything without an IPO block */
+       if (ipo == NULL) 
+               return;
        
-       for(icu= ipo->curve.first; icu; icu= icu->next) {
-               if(icu->driver || (icu->flag & IPO_LOCK)==0) { 
-                       if((icu->flag & IPO_MUTE)==0)
-                               calc_icu(icu, ctime);
+       /* loop over IPO Curves, getting pointer to var to affect, and write into that pointer */
+       for (icu= ipo->curve.first; icu; icu= icu->next) {
+               poin= get_ipo_poin(id, icu, &type);
+               if (poin) write_ipo_poin(poin, type, icu->curval);
+       }
+}
+
+/* Flush Action-Channel IPO data to Pose Channel */
+void execute_action_ipo (bActionChannel *achan, bPoseChannel *pchan)
+{
+       /* only do this if there's an Action Channel and Pose Channel to use */
+       if (achan && achan->ipo && pchan) {
+               IpoCurve *icu;
+               
+               /* loop over IPO-curves, getting a pointer to pchan var to write to
+                *      - assume for now that only 'float' channels will ever get written into
+                */
+               for (icu= achan->ipo->curve.first; icu; icu= icu->next) {
+                       void *poin= get_pchan_ipo_poin(pchan, icu->adrcode);
+                       if (poin) write_ipo_poin(poin, IPO_FLOAT, icu->curval);
                }
        }
 }
 
-/* ************************************** */
-/*             DO THE IPO!                                               */
-/* ************************************** */
 
-void write_ipo_poin(void *poin, int type, float val)
-{
+/* --------------------- Force Calculation + Flush IPO Values ----------------------------- */
 
-       switch(type) {
-       case IPO_FLOAT:
-               *( (float *)poin)= val;
-               break;
-       case IPO_FLOAT_DEGR:
-               *( (float *)poin)= (float)(val*M_PI_2/9.0);
-               break;
-       case IPO_INT:
-       case IPO_INT_BIT:
-       case IPO_LONG:
-               *( (int *)poin)= (int)val;
-               break;
-       case IPO_SHORT:
-       case IPO_SHORT_BIT:
-               *( (short *)poin)= (short)val;
-               break;
-       case IPO_CHAR:
-       case IPO_CHAR_BIT:
-               *( (char *)poin)= (char)val;
-               break;
+/* Calculate values for given IPO block, then flush to all of block's users
+ *      - for general usage 
+ */
+void do_ipo (Ipo *ipo)
+{
+       if (ipo) {
+               float ctime= frame_to_float(G.scene->r.cfra);
+               
+               /* calculate values, then flush to all users of this IPO block */
+               calc_ipo(ipo, ctime);
+               do_ipo_nocalc(ipo);
        }
 }
 
-float read_ipo_poin(void *poin, int type)
+/* Calculate values for given Material's IPO block, then flush to given Material only */
+void do_mat_ipo (Material *ma)
 {
-       float val = 0.0;
+       float ctime;
        
-       switch(type) {
-       case IPO_FLOAT:
-               val= *( (float *)poin);
-               break;
-       case IPO_FLOAT_DEGR:
-               val= *( (float *)poin);
-               val = (float)(val/(M_PI_2/9.0));
-               break;
-       case IPO_INT:
-       case IPO_INT_BIT:
-       case IPO_LONG:
-               val= (float)(*( (int *)poin));
-               break;
-       case IPO_SHORT:
-       case IPO_SHORT_BIT:
-               val= *( (short *)poin);
-               break;
-       case IPO_CHAR:
-       case IPO_CHAR_BIT:
-               val= *( (char *)poin);
-               break;
-       }
-       return val;
+       if (ELEM(NULL, ma, ma->ipo)) 
+               return;
+       
+       ctime= frame_to_float(G.scene->r.cfra);
+       /* if(ob->ipoflag & OB_OFFS_OB) ctime-= ob->sf; */
+       
+       /* calculate values for current time, then flush values to given material only */
+       calc_ipo(ma->ipo, ctime);
+       execute_ipo((ID *)ma, ma->ipo);
 }
 
-static void *give_tex_poin(Tex *tex, int adrcode, int *type )
+/* Calculate values for given Object's IPO block, then flush to given Object only
+ *     - there's also some funky stuff that looks like it's for scene layers
+ */
+void do_ob_ipo (Object *ob)
 {
-       void *poin=0;
-
-       switch(adrcode) {
-       case TE_NSIZE:
-               poin= &(tex->noisesize); break;
-       case TE_TURB:
-               poin= &(tex->turbul); break;
-       case TE_NDEPTH:
-               poin= &(tex->noisedepth); *type= IPO_SHORT; break;
-       case TE_NTYPE:
-               poin= &(tex->noisetype); *type= IPO_SHORT; break;
-       case TE_VNW1:
-               poin= &(tex->vn_w1); break;
-       case TE_VNW2:
-               poin= &(tex->vn_w2); break;
-       case TE_VNW3:
-               poin= &(tex->vn_w3); break;
-       case TE_VNW4:
-               poin= &(tex->vn_w4); break;
-       case TE_VNMEXP:
-               poin= &(tex->vn_mexp); break;
-       case TE_ISCA:
-               poin= &(tex->ns_outscale); break;
-       case TE_DISTA:
-               poin= &(tex->dist_amount); break;
-       case TE_VN_COLT:
-               poin= &(tex->vn_coltype); *type= IPO_SHORT; break;
-       case TE_VN_DISTM:
-               poin= &(tex->vn_distm); *type= IPO_SHORT; break;
-       case TE_MG_TYP:
-               poin= &(tex->stype); *type= IPO_SHORT; break;
-       case TE_MGH:
-               poin= &(tex->mg_H); break;
-       case TE_MG_LAC:
-               poin= &(tex->mg_lacunarity); break;
-       case TE_MG_OCT:
-               poin= &(tex->mg_octaves); break;
-       case TE_MG_OFF:
-               poin= &(tex->mg_offset); break;
-       case TE_MG_GAIN:
-               poin= &(tex->mg_gain); break;
-       case TE_N_BAS1:
-               poin= &(tex->noisebasis); *type= IPO_SHORT; break;
-       case TE_N_BAS2:
-               poin= &(tex->noisebasis2); *type= IPO_SHORT; break;
-       case TE_COL_R:
-               poin= &(tex->rfac); break;
-       case TE_COL_G:
-               poin= &(tex->gfac); break;
-       case TE_COL_B:
-               poin= &(tex->bfac); break;
-       case TE_BRIGHT:
-               poin= &(tex->bright); break;
-       case TE_CONTRA:
-               poin= &(tex->contrast); break;
-
+       float ctime;
+       unsigned int lay;
+       
+       if (ob->ipo == NULL) 
+               return;
+       
+       /* do not set ob->ctime here: for example when parent in invisible layer */
+       ctime= bsystem_time(ob, (float) G.scene->r.cfra, 0.0);
+       
+       /* calculate values of */
+       calc_ipo(ob->ipo, ctime);
+       
+       /* Patch: remember localview */
+       lay= ob->lay & 0xFF000000;
+       
+       /* flush IPO values to this object only */
+       execute_ipo((ID *)ob, ob->ipo);
+       
+       /* hack: for layer animation??? - is this what this is? (Aligorith, 28Sep2008) */
+       ob->lay |= lay;
+       if ((ob->id.name[2]=='S') && (ob->id.name[3]=='C') && (ob->id.name[4]=='E')) {
+               if (strcmp(G.scene->id.name+2, ob->id.name+6)==0) {
+                       G.scene->lay= ob->lay;
+                       copy_view3d_lock(0);
+                       /* no redraw here! creates too many calls */
+               }
        }
+}
+
+/* Only execute those IPO-Curves with drivers, on the current frame, for the given Object
+ *     - TODO: Drivers should really be made separate from standard anim channels
+ */
+void do_ob_ipodrivers (Object *ob, Ipo *ipo, float ctime)
+{
+       IpoCurve *icu;
+       void *poin;
+       int type;
        
-       return poin;
+       for (icu= ipo->curve.first; icu; icu= icu->next) {
+               if (icu->driver) {
+                       icu->curval= eval_icu(icu, ctime);
+                       
+                       poin= get_ipo_poin((ID *)ob, icu, &type);
+                       if (poin) write_ipo_poin(poin, type, icu->curval);
+               }
+       }
 }
 
-void *give_mtex_poin(MTex *mtex, int adrcode )
+/* Special variation to calculate IPO values for Sequence + perform other stuff */
+void do_seq_ipo (Sequence *seq, int cfra)
 {
-       void *poin=0;
+       float ctime, div;
+       
+       /* seq_ipo has an exception: calc both fields immediately */
+       if (seq->ipo) {
+               if ((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
+                       ctime = frame_to_float(cfra);
+                       div = 1.0;
+               } 
+               else {
+                       ctime= frame_to_float(cfra - seq->startdisp);
+                       div= (seq->enddisp - seq->startdisp) / 100.0f;
+                       if (div == 0.0) return;
+               }
                
-       switch(adrcode) {
-       case MAP_OFS_X:
-               poin= &(mtex->ofs[0]); break;
-       case MAP_OFS_Y:
-               poin= &(mtex->ofs[1]); break;
-       case MAP_OFS_Z:
-               poin= &(mtex->ofs[2]); break;
-       case MAP_SIZE_X:
-               poin= &(mtex->size[0]); break;
-       case MAP_SIZE_Y:
-               poin= &(mtex->size[1]); break;
-       case MAP_SIZE_Z:
-               poin= &(mtex->size[2]); break;
-       case MAP_R:
-               poin= &(mtex->r); break;
-       case MAP_G:
-               poin= &(mtex->g); break;
-       case MAP_B:
-               poin= &(mtex->b); break;
-       case MAP_DVAR:
-               poin= &(mtex->def_var); break;
-       case MAP_COLF:
-               poin= &(mtex->colfac); break;
-       case MAP_NORF:
-               poin= &(mtex->norfac); break;
-       case MAP_VARF:
-               poin= &(mtex->varfac); break;
-       case MAP_DISP:
-               poin= &(mtex->dispfac); break;
+               /* 2nd field */
+               calc_ipo(seq->ipo, (ctime+0.5f)/div);
+               execute_ipo((ID *)seq, seq->ipo);
+               seq->facf1= seq->facf0;
+               
+               /* 1st field */
+               calc_ipo(seq->ipo, ctime/div);
+               execute_ipo((ID *)seq, seq->ipo);
        }
-       
-       return poin;
+       else 
+               seq->facf1= seq->facf0= 1.0f;
 }
 
-/* GS reads the memory pointed at in a specific ordering. There are,
- * however two definitions for it. I have jotted them down here, both,
- * but I think the first one is actually used. The thing is that
- * big-endian systems might read this the wrong way round. OTOH, we
- * constructed the IDs that are read out with this macro explicitly as
- * well. I expect we'll sort it out soon... */
-
-/* from blendef: */
-#define GS(a)  (*((short *)(a)))
+/* --------- */
 
-/* from misc_util: flip the bytes from x  */
-/*  #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */
 
-void *get_ipo_poin(ID *id, IpoCurve *icu, int *type)
+/* exception: it does calc for objects...
+ * now find out why this routine was used anyway!
+ */
+void do_ipo_nocalc (Ipo *ipo)
 {
-       void *poin= NULL;
        Object *ob;
        Material *ma;
-       MTex *mtex;
        Tex *tex;
-       Lamp *la;
-       Sequence *seq;
        World *wo;
-       ParticleSettings *part;
-
-       *type= IPO_FLOAT;
-
-       if( GS(id->name)==ID_OB) {
-               
-               ob= (Object *)id;
-
-               switch(icu->adrcode) {
-               case OB_LOC_X:
-                       poin= &(ob->loc[0]); break;
-               case OB_LOC_Y:
-                       poin= &(ob->loc[1]); break;
-               case OB_LOC_Z:
-                       poin= &(ob->loc[2]); break;
-               case OB_DLOC_X:
-                       poin= &(ob->dloc[0]); break;
-               case OB_DLOC_Y:
-                       poin= &(ob->dloc[1]); break;
-               case OB_DLOC_Z:
-                       poin= &(ob->dloc[2]); break;
-       
-               case OB_ROT_X:
-                       poin= &(ob->rot[0]); *type= IPO_FLOAT_DEGR; break;
-               case OB_ROT_Y:
-                       poin= &(ob->rot[1]); *type= IPO_FLOAT_DEGR; break;
-               case OB_ROT_Z:
-                       poin= &(ob->rot[2]); *type= IPO_FLOAT_DEGR; break;
-               case OB_DROT_X:
-                       poin= &(ob->drot[0]); *type= IPO_FLOAT_DEGR; break;
-               case OB_DROT_Y:
-                       poin= &(ob->drot[1]); *type= IPO_FLOAT_DEGR; break;
-               case OB_DROT_Z:
-                       poin= &(ob->drot[2]); *type= IPO_FLOAT_DEGR; break;
-                       
-               case OB_SIZE_X:
-                       poin= &(ob->size[0]); break;
-               case OB_SIZE_Y:
-                       poin= &(ob->size[1]); break;
-               case OB_SIZE_Z:
-                       poin= &(ob->size[2]); break;
-               case OB_DSIZE_X:
-                       poin= &(ob->dsize[0]); break;
-               case OB_DSIZE_Y:
-                       poin= &(ob->dsize[1]); break;
-               case OB_DSIZE_Z:
-                       poin= &(ob->dsize[2]); break;
-
-               case OB_LAY:
-                       poin= &(ob->lay); *type= IPO_INT_BIT; break;
-                       
-               case OB_COL_R:  
-                       poin= &(ob->col[0]);
-                       break;
-               case OB_COL_G:
-                       poin= &(ob->col[1]);
-                       break;
-               case OB_COL_B:
-                       poin= &(ob->col[2]);
-                       break;
-               case OB_COL_A:
-                       poin= &(ob->col[3]);
-                       break;
-               case OB_PD_FSTR:
-                       if(ob->pd) poin= &(ob->pd->f_strength);
-                       break;
-               case OB_PD_FFALL:
-                       if(ob->pd) poin= &(ob->pd->f_power);
-                       break;
-               case OB_PD_SDAMP:
-                       if(ob->pd) poin= &(ob->pd->pdef_damp);
-                       break;
-               case OB_PD_RDAMP:
-                       if(ob->pd) poin= &(ob->pd->pdef_rdamp);
-                       break;
-               case OB_PD_PERM:
-                       if(ob->pd) poin= &(ob->pd->pdef_perm);
-                       break;
-               case OB_PD_FMAXD:
-                       if(ob->pd) poin= &(ob->pd->maxdist);
-                       break;
-               }
-       }
-       else if( GS(id->name)==ID_MA) {
-               
-               ma= (Material *)id;
-               
-               switch(icu->adrcode) {
-               case MA_COL_R:
-                       poin= &(ma->r); break;
-               case MA_COL_G:
-                       poin= &(ma->g); break;
-               case MA_COL_B:
-                       poin= &(ma->b); break;
-               case MA_SPEC_R:
-                       poin= &(ma->specr); break;
-               case MA_SPEC_G:
-                       poin= &(ma->specg); break;
-               case MA_SPEC_B:
-                       poin= &(ma->specb); break;
-               case MA_MIR_R:
-                       poin= &(ma->mirr); break;
-               case MA_MIR_G:
-                       poin= &(ma->mirg); break;
-               case MA_MIR_B:
-                       poin= &(ma->mirb); break;
-               case MA_REF:
-                       poin= &(ma->ref); break;
-               case MA_ALPHA:
-                       poin= &(ma->alpha); break;
-               case MA_EMIT:
-                       poin= &(ma->emit); break;
-               case MA_AMB:
-                       poin= &(ma->amb); break;
-               case MA_SPEC:
-                       poin= &(ma->spec); break;
-               case MA_HARD:
-                       poin= &(ma->har); *type= IPO_SHORT; break;
-               case MA_SPTR:
-                       poin= &(ma->spectra); break;
-               case MA_IOR:
-                       poin= &(ma->ang); break;
-               case MA_MODE:
-                       poin= &(ma->mode); *type= IPO_INT_BIT; break;
-               case MA_HASIZE:
-                       poin= &(ma->hasize); break;
-               case MA_TRANSLU:
-                       poin= &(ma->translucency); break;
-               case MA_RAYM:
-                       poin= &(ma->ray_mirror); break;
-               case MA_FRESMIR:
-                       poin= &(ma->fresnel_mir); break;
-               case MA_FRESMIRI:
-                       poin= &(ma->fresnel_mir_i); break;
-               case MA_FRESTRA:
-                       poin= &(ma->fresnel_tra); break;
-               case MA_FRESTRAI:
-                       poin= &(ma->fresnel_tra_i); break;
-               case MA_ADD:
-                       poin= &(ma->add); break;
-               }
-               
-               if(poin==NULL) {
-                       mtex= 0;
-                       if(icu->adrcode & MA_MAP1) mtex= ma->mtex[0];
-                       else if(icu->adrcode & MA_MAP2) mtex= ma->mtex[1];
-                       else if(icu->adrcode & MA_MAP3) mtex= ma->mtex[2];
-                       else if(icu->adrcode & MA_MAP4) mtex= ma->mtex[3];
-                       else if(icu->adrcode & MA_MAP5) mtex= ma->mtex[4];
-                       else if(icu->adrcode & MA_MAP6) mtex= ma->mtex[5];
-                       else if(icu->adrcode & MA_MAP7) mtex= ma->mtex[6];
-                       else if(icu->adrcode & MA_MAP8) mtex= ma->mtex[7];
-                       else if(icu->adrcode & MA_MAP9) mtex= ma->mtex[8];
-                       else if(icu->adrcode & MA_MAP10) mtex= ma->mtex[9];
-                       else if(icu->adrcode & MA_MAP12) mtex= ma->mtex[11];
-                       else if(icu->adrcode & MA_MAP11) mtex= ma->mtex[10];
-                       else if(icu->adrcode & MA_MAP13) mtex= ma->mtex[12];
-                       else if(icu->adrcode & MA_MAP14) mtex= ma->mtex[13];
-                       else if(icu->adrcode & MA_MAP15) mtex= ma->mtex[14];
-                       else if(icu->adrcode & MA_MAP16) mtex= ma->mtex[15];
-                       else if(icu->adrcode & MA_MAP17) mtex= ma->mtex[16];
-                       else if(icu->adrcode & MA_MAP18) mtex= ma->mtex[17];
-                       
-                       if(mtex) {
-                               poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) );
-                       }
-               }
-       }
-       else if( GS(id->name)==ID_TE) {
-               tex= (Tex *)id;
-               
-               if(tex) poin= give_tex_poin(tex, icu->adrcode, type);
-       }
-       else if( GS(id->name)==ID_SEQ) {
-               seq= (Sequence *)id;
-               
-               switch(icu->adrcode) {
-               case SEQ_FAC1:
-                       poin= &(seq->facf0); break;
+       Lamp *la;
+       Camera *ca;
+       bSound *snd;
+       
+       if (ipo == NULL) 
+               return;
+       
+       /* only flush IPO values (without calculating first/again) on 
+        * to the datablocks that use the given IPO block 
+        */
+       switch (ipo->blocktype) {
+       case ID_OB:
+               for (ob= G.main->object.first; ob; ob= ob->id.next) {
+                       if (ob->ipo == ipo) do_ob_ipo(ob);
                }
-       }
-       else if( GS(id->name)==ID_CU) {
-               
-               poin= &(icu->curval);
-               
-       }
-       else if( GS(id->name)==ID_KE) {
-               KeyBlock *kb= ((Key *)id)->block.first;
-               
-               for(; kb; kb= kb->next)
-                       if(kb->adrcode==icu->adrcode)
-                               break;
-               if(kb)
-                       poin= &(kb->curval);
-               
-       }
-       else if(GS(id->name)==ID_WO) {
-               
-               wo= (World *)id;
-               
-               switch(icu->adrcode) {
-               case WO_HOR_R:
-                       poin= &(wo->horr); break;
-               case WO_HOR_G:
-                       poin= &(wo->horg); break;
-               case WO_HOR_B:
-                       poin= &(wo->horb); break;
-               case WO_ZEN_R:
-                       poin= &(wo->zenr); break;
-               case WO_ZEN_G:
-                       poin= &(wo->zeng); break;
-               case WO_ZEN_B:
-                       poin= &(wo->zenb); break;
-
-               case WO_EXPOS:
-                       poin= &(wo->exposure); break;
-
-               case WO_MISI:
-                       poin= &(wo->misi); break;
-               case WO_MISTDI:
-                       poin= &(wo->mistdist); break;
-               case WO_MISTSTA:
-                       poin= &(wo->miststa); break;
-               case WO_MISTHI:
-                       poin= &(wo->misthi); break;
-
-               case WO_STAR_R:
-                       poin= &(wo->starr); break;
-               case WO_STAR_G:
-                       poin= &(wo->starg); break;
-               case WO_STAR_B:
-                       poin= &(wo->starb); break;
-
-               case WO_STARDIST:
-                       poin= &(wo->stardist); break;
-               case WO_STARSIZE:
-                       poin= &(wo->starsize); break;
-               }
-
-               if(poin==NULL) {
-                       mtex= 0;
-                       if(icu->adrcode & MA_MAP1) mtex= wo->mtex[0];
-                       else if(icu->adrcode & MA_MAP2) mtex= wo->mtex[1];
-                       else if(icu->adrcode & MA_MAP3) mtex= wo->mtex[2];
-                       else if(icu->adrcode & MA_MAP4) mtex= wo->mtex[3];
-                       else if(icu->adrcode & MA_MAP5) mtex= wo->mtex[4];
-                       else if(icu->adrcode & MA_MAP6) mtex= wo->mtex[5];
-                       else if(icu->adrcode & MA_MAP7) mtex= wo->mtex[6];
-                       else if(icu->adrcode & MA_MAP8) mtex= wo->mtex[7];
-                       else if(icu->adrcode & MA_MAP9) mtex= wo->mtex[8];
-                       else if(icu->adrcode & MA_MAP10) mtex= wo->mtex[9];
-                       else if(icu->adrcode & MA_MAP11) mtex= wo->mtex[10];
-                       else if(icu->adrcode & MA_MAP12) mtex= wo->mtex[11];
-                       else if(icu->adrcode & MA_MAP13) mtex= wo->mtex[12];
-                       else if(icu->adrcode & MA_MAP14) mtex= wo->mtex[13];
-                       else if(icu->adrcode & MA_MAP15) mtex= wo->mtex[14];
-                       else if(icu->adrcode & MA_MAP16) mtex= wo->mtex[15];
-                       else if(icu->adrcode & MA_MAP17) mtex= wo->mtex[16];
-                       else if(icu->adrcode & MA_MAP18) mtex= wo->mtex[17];
-                       if(mtex) {
-                               poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) );
-                       }
+               break;
+       case ID_MA:
+               for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+                       if (ma->ipo == ipo) execute_ipo((ID *)ma, ipo);
                }
-       }
-       else if( GS(id->name)==ID_LA) {
-               
-               la= (Lamp *)id;
-       
-               switch(icu->adrcode) {
-               case LA_ENERGY:
-                       poin= &(la->energy); break;             
-               case LA_COL_R:
-                       poin= &(la->r); break;
-               case LA_COL_G:
-                       poin= &(la->g); break;
-               case LA_COL_B:
-                       poin= &(la->b); break;
-               case LA_DIST:
-                       poin= &(la->dist); break;               
-               case LA_SPOTSI:
-                       poin= &(la->spotsize); break;
-               case LA_SPOTBL:
-                       poin= &(la->spotblend); break;
-               case LA_QUAD1:
-                       poin= &(la->att1); break;
-               case LA_QUAD2:
-                       poin= &(la->att2); break;
-               case LA_HALOINT:
-                       poin= &(la->haint); break;
+               break;
+       case ID_TE:
+               for (tex= G.main->tex.first; tex; tex= tex->id.next) {
+                       if (tex->ipo == ipo) execute_ipo((ID *)tex, ipo);
                }
-               
-               if(poin==NULL) {
-                       mtex= 0;
-                       if(icu->adrcode & MA_MAP1) mtex= la->mtex[0];
-                       else if(icu->adrcode & MA_MAP2) mtex= la->mtex[1];
-                       else if(icu->adrcode & MA_MAP3) mtex= la->mtex[2];
-                       else if(icu->adrcode & MA_MAP4) mtex= la->mtex[3];
-                       else if(icu->adrcode & MA_MAP5) mtex= la->mtex[4];
-                       else if(icu->adrcode & MA_MAP6) mtex= la->mtex[5];
-                       else if(icu->adrcode & MA_MAP7) mtex= la->mtex[6];
-                       else if(icu->adrcode & MA_MAP8) mtex= la->mtex[7];
-                       else if(icu->adrcode & MA_MAP9) mtex= la->mtex[8];
-                       else if(icu->adrcode & MA_MAP10) mtex= la->mtex[9];
-                       else if(icu->adrcode & MA_MAP11) mtex= la->mtex[10];
-                       else if(icu->adrcode & MA_MAP12) mtex= la->mtex[11];
-                       else if(icu->adrcode & MA_MAP13) mtex= la->mtex[12];
-                       else if(icu->adrcode & MA_MAP14) mtex= la->mtex[13];
-                       else if(icu->adrcode & MA_MAP15) mtex= la->mtex[14];
-                       else if(icu->adrcode & MA_MAP16) mtex= la->mtex[15];
-                       else if(icu->adrcode & MA_MAP17) mtex= la->mtex[16];
-                       else if(icu->adrcode & MA_MAP18) mtex= la->mtex[17];
-                       
-                       if(mtex) {
-                               poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) );
-                       }
+               break;
+       case ID_WO:
+               for (wo= G.main->world.first; wo; wo= wo->id.next) {
+                       if (wo->ipo == ipo) execute_ipo((ID *)wo, ipo);
                }
-       }
-       else if(GS(id->name)==ID_CA) {
-               Camera *ca= (Camera *)id;
-               
-               /* yafray: aperture & focal distance params */
-               switch(icu->adrcode) {
-               case CAM_LENS:
-                       if(ca->type==CAM_ORTHO)
-                               poin= &(ca->ortho_scale);
-                       else
-                               poin= &(ca->lens); 
-                       break;
-               case CAM_STA:
-                       poin= &(ca->clipsta); break;
-               case CAM_END:
-                       poin= &(ca->clipend); break;
-               case CAM_YF_APERT:
-                       poin= &(ca->YF_aperture); break;
-               case CAM_YF_FDIST:
-                       poin= &(ca->YF_dofdist); break;
-               case CAM_SHIFT_X:
-                       poin= &(ca->shiftx); break;
-               case CAM_SHIFT_Y:
-                       poin= &(ca->shifty); break;
+               break;
+       case ID_LA:
+               for (la= G.main->lamp.first; la; la= la->id.next) {
+                       if (la->ipo == ipo) execute_ipo((ID *)la, ipo);
                }
-       }
-       else if(GS(id->name)==ID_SO) {
-               bSound *snd= (bSound *)id;
-               
-               switch(icu->adrcode) {
-               case SND_VOLUME:
-                       poin= &(snd->volume); break;
-               case SND_PITCH:
-                       poin= &(snd->pitch); break;
-               case SND_PANNING:
-                       poin= &(snd->panning); break;
-               case SND_ATTEN:
-                       poin= &(snd->attenuation); break;
+               break;
+       case ID_CA:
+               for (ca= G.main->camera.first; ca; ca= ca->id.next) {
+                       if (ca->ipo == ipo) execute_ipo((ID *)ca, ipo);
                }
-       }
-       else if( GS(id->name)==ID_PA) {
-               
-               part= (ParticleSettings *)id;
-               
-               switch(icu->adrcode) {
-               case PART_EMIT_FREQ:
-               case PART_EMIT_LIFE:
-               case PART_EMIT_VEL:
-               case PART_EMIT_AVE:
-               case PART_EMIT_SIZE:
-                       poin= NULL; break;
-               case PART_CLUMP:
-                       poin= &(part->clumpfac); break;
-               case PART_AVE:
-                       poin= &(part->avefac); break;
-               case PART_SIZE:
-                       poin= &(part->size); break;
-               case PART_DRAG:
-                       poin= &(part->dragfac); break;
-               case PART_BROWN:
-                       poin= &(part->brownfac); break;
-               case PART_DAMP:
-                       poin= &(part->dampfac); break;
-               case PART_LENGTH:
-                       poin= &(part->length); break;
-               case PART_GRAV_X:
-                       poin= &(part->acc[0]); break;
-               case PART_GRAV_Y:
-                       poin= &(part->acc[1]); break;
-               case PART_GRAV_Z:
-                       poin= &(part->acc[2]); break;
-               case PART_KINK_AMP:
-                       poin= &(part->kink_amp); break;
-               case PART_KINK_FREQ:
-                       poin= &(part->kink_freq); break;
-               case PART_KINK_SHAPE:
-                       poin= &(part->kink_shape); break;
-               case PART_BB_TILT:
-                       poin= &(part->bb_tilt); break;
-               case PART_PD_FSTR:
-                       poin= (part->pd?(&(part->pd->f_strength)):NULL); break;
-               case PART_PD_FFALL:
-                       poin= (part->pd?(&(part->pd->f_power)):NULL); break;
-               case PART_PD_FMAXD:
-                       poin= (part->pd?(&(part->pd->maxdist)):NULL); break;
-               case PART_PD2_FSTR:
-                       poin= (part->pd2?(&(part->pd2->f_strength)):NULL); break;
-               case PART_PD2_FFALL:
-                       poin= (part->pd2?(&(part->pd2->f_power)):NULL); break;
-               case PART_PD2_FMAXD:
-                       poin= (part->pd2?(&(part->pd2->maxdist)):NULL); break;
+               break;
+       case ID_SO:
+               for (snd= G.main->sound.first; snd; snd= snd->id.next) {
+                       if (snd->ipo == ipo) execute_ipo((ID *)snd, ipo);
                }
+               break;
        }
-
-       return poin;
 }
 
-void set_icu_vars(IpoCurve *icu)
+/* Executes IPO's for whole database on frame change, in a specified order,
+ * with datablocks being calculated in alphabetical order
+ *     - called on scene_update_for_newframe() only 
+ */
+void do_all_data_ipos ()
 {
-       /* defaults. 0.0 for y-extents makes these ignored */
-       icu->ymin= icu->ymax= 0.0;
-       icu->ipo= IPO_BEZ;
-       
-       if(icu->blocktype==ID_OB) {
+       Material *ma;
+       Tex *tex;
+       World *wo;
+       Ipo *ipo;
+       Lamp *la;
+       Key *key;
+       Camera *ca;
+       bSound *snd;
+       Sequence *seq;
+       Editing *ed;
+       Base *base;
+       float ctime;
+
+       ctime= frame_to_float(G.scene->r.cfra);
        
-               if(icu->adrcode==OB_LAY) {
-                       icu->ipo= IPO_CONST;
-                       icu->vartype= IPO_BITS;
+       /* this exception cannot be depgraphed yet... what todo with objects in other layers?... */
+       for (base= G.scene->base.first; base; base= base->next) {
+               /* only update layer when an ipo */
+               if (has_ipo_code(base->object->ipo, OB_LAY)) {
+                       do_ob_ipo(base->object);
+                       base->lay= base->object->lay;
                }
-               
        }
-       else if(icu->blocktype==ID_MA) {
-               
-               if(icu->adrcode < MA_MAP1) {
-                       switch(icu->adrcode) {
-                       case MA_HASIZE:
-                               icu->ymax= 10000.0; break;
-                       case MA_HARD:
-                               icu->ymax= 511.0; break;
-                       case MA_SPEC:
-                               icu->ymax= 2.0; break;
-                       case MA_MODE:
-                               icu->ipo= IPO_CONST;
-                               icu->vartype= IPO_BITS; break;
-                       case MA_RAYM:
-                               icu->ymax= 1.0; break;
-                       case MA_TRANSLU:
-                               icu->ymax= 1.0; break;
-                       case MA_IOR:
-                               icu->ymin= 1.0;
-                               icu->ymax= 3.0; break;
-                       case MA_FRESMIR:
-                               icu->ymax= 5.0; break;
-                       case MA_FRESMIRI:
-                               icu->ymin= 1.0;
-                               icu->ymax= 5.0; break;
-                       case MA_FRESTRA:
-                               icu->ymax= 5.0; break;
-                       case MA_FRESTRAI:
-                               icu->ymin= 1.0;
-                               icu->ymax= 5.0; break;
-                       case MA_ADD:
-                               icu->ymax= 1.0; break;
-                       case MA_EMIT:
-                               icu->ymax= 2.0; break;
-                       default:
-                               icu->ymax= 1.0; break;
+       
+       /* layers for the set...*/
+       if (G.scene->set) {
+               for (base= G.scene->set->base.first; base; base= base->next) {
+                       if (has_ipo_code(base->object->ipo, OB_LAY)) {
+                               do_ob_ipo(base->object);
+                               base->lay= base->object->lay;
                        }
                }
-               else {
-                       switch(icu->adrcode & (MA_MAP1-1)) {
-                       case MAP_OFS_X:
-                       case MAP_OFS_Y:
-                       case MAP_OFS_Z:
-                       case MAP_SIZE_X:
-                       case MAP_SIZE_Y:
-                       case MAP_SIZE_Z:
-                               icu->ymax= 1000.0;
-                               icu->ymin= -1000.0;
-                       
-                               break;
-                       case MAP_R:
-                       case MAP_G:
-                       case MAP_B:
-                       case MAP_DVAR:
-                       case MAP_COLF:
-                       case MAP_VARF:
-                       case MAP_DISP:
-                               icu->ymax= 1.0;
-                               break;
-                       case MAP_NORF:
-                               icu->ymax= 25.0;
-                               break;
-                       }
+       }
+       
+       /* Calculate all IPO blocks in use, execept those for Objects */
+       for (ipo= G.main->ipo.first; ipo; ipo= ipo->id.next) {
+               if ((ipo->id.us) && (ipo->blocktype != ID_OB)) {
+                       calc_ipo(ipo, ctime);
                }
        }
-       else if(icu->blocktype==ID_TE) {
-               switch(icu->adrcode & (MA_MAP1-1)) {
-                       case TE_NSIZE:
-                               icu->ymin= 0.0001;
-                               icu->ymax= 2.0; break;
-                       case TE_NDEPTH:
-                               icu->vartype= IPO_SHORT;
-                               icu->ipo= IPO_CONST;
-                               icu->ymax= 6.0; break;
-                       case TE_NTYPE:
-                               icu->vartype= IPO_SHORT;
-                               icu->ipo= IPO_CONST;
-                               icu->ymax= 1.0; break;
-                       case TE_TURB:
-                               icu->ymax= 200.0; break;
-                       case TE_VNW1:
-                       case TE_VNW2:
-                       case TE_VNW3:
-                       case TE_VNW4:
-                               icu->ymax= 2.0;
-                               icu->ymin= -2.0; break;
-                       case TE_VNMEXP:
-                               icu->ymax= 10.0;
-                               icu->ymin= 0.01; break;
-                       case TE_VN_DISTM:
-                               icu->vartype= IPO_SHORT;
-                               icu->ipo= IPO_CONST;
-                               icu->ymax= 6.0; break;
-                       case TE_VN_COLT:
-                               icu->vartype= IPO_SHORT;
-                               icu->ipo= IPO_CONST;
-                               icu->ymax= 3.0; break;
-                       case TE_ISCA:
-                               icu->ymax= 10.0;
-                               icu->ymin= 0.01; break;
-                       case TE_DISTA:
-                               icu->ymax= 10.0; break;
-                       case TE_MG_TYP:
-                               icu->vartype= IPO_SHORT;
-                               icu->ipo= IPO_CONST;
-                               icu->ymax= 6.0; break;
-                       case TE_MGH:
-                               icu->ymin= 0.0001;
-                               icu->ymax= 2.0; break;
-                       case TE_MG_LAC:
-                       case TE_MG_OFF:
-                       case TE_MG_GAIN:
-                               icu->ymax= 6.0; break;
-                       case TE_MG_OCT:
-                               icu->ymax= 8.0; break;
-                       case TE_N_BAS1:
-                       case TE_N_BAS2:
-                               icu->vartype= IPO_SHORT;
-                               icu->ipo= IPO_CONST;
-                               icu->ymax= 8.0; break;
-                       case TE_COL_R:
-                               icu->ymax= 0.0; break;
-                       case TE_COL_G:
-                               icu->ymax= 2.0; break;
-                       case TE_COL_B:
-                               icu->ymax= 2.0; break;
-                       case TE_BRIGHT:
-                               icu->ymax= 2.0; break;
-                       case TE_CONTRA:
-                               icu->ymax= 5.0; break;                          
 
-               }
+       /* Texture Blocks */
+       for (tex= G.main->tex.first; tex; tex= tex->id.next) {
+               if (tex->ipo) execute_ipo((ID *)tex, tex->ipo);
        }
-       else if(icu->blocktype==ID_SEQ) {
        
-               icu->ymax= 1.0;
-               
+       /* Material Blocks */
+       for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+               if (ma->ipo) execute_ipo((ID *)ma, ma->ipo);
        }
-       else if(icu->blocktype==ID_CU) {
        
-               icu->ymax= 1.0;
-               
+       /* World Blocks */
+       for (wo= G.main->world.first; wo; wo= wo->id.next) {
+               if (wo->ipo) execute_ipo((ID *)wo, wo->ipo);
        }
-       else if(icu->blocktype==ID_WO) {
-               
-               if(icu->adrcode < MA_MAP1) {
-                       switch(icu->adrcode) {
-                       case WO_EXPOS:
-                               icu->ymax= 5.0; break;
-                       case WO_MISTDI:
-                       case WO_MISTSTA:
-                       case WO_MISTHI:
-                       case WO_STARDIST:
-                       case WO_STARSIZE:
-                               break;
-                               
-                       default:
-                               icu->ymax= 1.0;
-                               break;
-                       }
-               }
-               else {
-                       switch(icu->adrcode & (MA_MAP1-1)) {
-                       case MAP_OFS_X:
-                       case MAP_OFS_Y:
-                       case MAP_OFS_Z:
-                       case MAP_SIZE_X:
-                       case MAP_SIZE_Y:
-                       case MAP_SIZE_Z:
-                               icu->ymax= 100.0;
-                               icu->ymin= -100.0;
-                       
-                               break;
-                       case MAP_R:
-                       case MAP_G:
-                       case MAP_B:
-                       case MAP_DVAR:
-                       case MAP_COLF:
-                       case MAP_NORF:
-                       case MAP_VARF:
-                       case MAP_DISP:
-                               icu->ymax= 1.0;
-                       }
-               }
+       
+       /* ShapeKey Blocks */
+       for (key= G.main->key.first; key; key= key->id.next) {
+               if (key->ipo) execute_ipo((ID *)key, key->ipo);
        }
-       else if(icu->blocktype==ID_LA) {
-               if(icu->adrcode < MA_MAP1) {
-                       switch(icu->adrcode) {
-                       case LA_ENERGY:
-                       case LA_DIST:
-                               break;          
        
-                       case LA_COL_R:
-                       case LA_COL_G:
-                       case LA_COL_B:
-                       case LA_SPOTBL:
-                       case LA_QUAD1:
-                       case LA_QUAD2:
-                               icu->ymax= 1.0; break;
-                       case LA_SPOTSI:
-                               icu->ymax= 180.0; break;
-                       case LA_HALOINT:
-                               icu->ymax= 5.0; break;
-                       }
-               }
-               else {
-                       switch(icu->adrcode & (MA_MAP1-1)) {
-                       case MAP_OFS_X:
-                       case MAP_OFS_Y:
-                       case MAP_OFS_Z:
-                       case MAP_SIZE_X:
-                       case MAP_SIZE_Y:
-                       case MAP_SIZE_Z:
-                               icu->ymax= 100.0;
-                               icu->ymin= -100.0;
-                               break;
-                       case MAP_R:
-                       case MAP_G:
-                       case MAP_B:
-                       case MAP_DVAR:
-                       case MAP_COLF:
-                       case MAP_NORF:
-                       case MAP_VARF:
-                       case MAP_DISP:
-                               icu->ymax= 1.0;
-                       }
-               }
-       }       
-       else if(icu->blocktype==ID_CA) {
-
-               /* yafray: aperture & focal distance params */
-               switch(icu->adrcode) {
-               case CAM_LENS:
-                       icu->ymin= 1.0;
-                       icu->ymax= 1000.0;
-                       break;
-               case CAM_STA:
-                       icu->ymin= 0.001f;
-                       break;
-               case CAM_END:
-                       icu->ymin= 0.1f;
-                       break;
-               case CAM_YF_APERT:
-                       icu->ymin = 0.0;
-                       icu->ymax = 2.0;
-                       break;
-               case CAM_YF_FDIST:
-                       icu->ymin = 0.0;
-                       icu->ymax = 5000.0;
-                       break;
-                       
-               case CAM_SHIFT_X:
-               case CAM_SHIFT_Y:
-                       icu->ymin= -2.0f;
-                       icu->ymax= 2.0f;
-                       break;
-               }
+       /* Lamp Blocks */
+       for (la= G.main->lamp.first; la; la= la->id.next) {
+               if (la->ipo) execute_ipo((ID *)la, la->ipo);
        }
-       else if(icu->blocktype==ID_SO) {
-
-               switch(icu->adrcode) {
-               case SND_VOLUME:
-                       icu->ymin= 0.0;
-                       icu->ymax= 1.0;
-                       break;
-               case SND_PITCH:
-                       icu->ymin= -12.0;
-                       icu->ymin= 12.0;
-                       break;
-               case SND_PANNING:
-                       icu->ymin= 0.0;
-                       icu->ymax= 1.0;
-                       break;
-               case SND_ATTEN:
-                       icu->ymin= 0.0;
-                       icu->ymin= 1.0;
-                       break;
-               }
+       
+       /* Camera Blocks */
+       for (ca= G.main->camera.first; ca; ca= ca->id.next) {
+               if (ca->ipo) execute_ipo((ID *)ca, ca->ipo);
        }
-       else if(icu->blocktype==ID_PA){
-
-               switch(icu->adrcode) {
-               case PART_EMIT_LIFE:
-               case PART_SIZE:
-               case PART_KINK_FREQ:
-               case PART_EMIT_VEL:
-               case PART_EMIT_AVE:
-               case PART_EMIT_SIZE:
-                       icu->ymin= 0.0;
-                       break;
-               case PART_CLUMP:
-                       icu->ymin= -1.0;
-                       icu->ymax= 1.0;
-                       break;
-               case PART_DRAG:
-               case PART_DAMP:
-               case PART_LENGTH:
-                       icu->ymin= 0.0;
-                       icu->ymax= 1.0;
-                       break;
-               case PART_KINK_SHAPE:
-                       icu->ymin= -0.999;
-                       icu->ymax= 0.999;
-                       break;
-               }
+       
+       /* Sound Blocks (Old + Unused) */
+       for (snd= G.main->sound.first; snd; snd= snd->id.next) {
+               if (snd->ipo) execute_ipo((ID *)snd, snd->ipo);
        }
-       else if(icu->blocktype==ID_CO) {
-               icu->ymin= 0.0;
-               icu->ymax= 1.0f;
+
+       /* Sequencer: process FAC Ipos used as volume envelopes */
+       ed= G.scene->ed;
+       if (ed) {
+               for (seq= ed->seqbasep->first; seq; seq= seq->next) {
+                       if ( ((seq->type == SEQ_RAM_SOUND) || (seq->type == SEQ_HD_SOUND)) &&
+                                (seq->startdisp <= G.scene->r.cfra+2) && 
+                            (seq->enddisp>G.scene->r.cfra) &&
+                                (seq->ipo) ) 
+                       {
+                                       do_seq_ipo(seq, G.scene->r.cfra);
+                       }
+               }
        }
-       
-       /* by default, slider limits will be icu->ymin and icu->ymax */
-       icu->slide_min= icu->ymin;
-       icu->slide_max= icu->ymax;
 }
 
-/* not for actions or constraints! */
-void execute_ipo(ID *id, Ipo *ipo)
+
+/* --------------------- Assorted ----------------------------- */ 
+
+/* clear delta-transforms on all Objects which use the given IPO block */
+void clear_delta_obipo(Ipo *ipo)
 {
-       IpoCurve *icu;
-       void *poin;
-       int type;
+       Object *ob;
        
-       if(ipo==NULL) return;
+       /* only search if there's an IPO */
+       if (ipo == NULL) 
+               return;
        
-       for(icu= ipo->curve.first; icu; icu= icu->next) {
-               poin= get_ipo_poin(id, icu, &type);
-               if(poin) write_ipo_poin(poin, type, icu->curval);
+       /* search through all objects in database */
+       for (ob= G.main->object.first; ob; ob= ob->id.next) {
+               /* can only update if not a library */
+               if (ob->id.lib == NULL) {
+                       if (ob->ipo == ipo)  {
+                               memset(&ob->dloc, 0, 12);
+                               memset(&ob->drot, 0, 12);
+                               memset(&ob->dsize, 0, 12);
+                       }
+               }
        }
 }
 
-void *get_pchan_ipo_poin(bPoseChannel *pchan, int adrcode)
+/* ***************************** IPO - DataAPI ********************************* */
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!! FIXME - BAD CRUFT WARNING !!!!!!!!!!!!!!!!!!!!!!!
+
+/* These functions here should be replaced eventually by the Data API, as this is 
+ * inflexible duplication...
+ */
+
+/* --------------------- Get Pointer API ----------------------------- */ 
+
+/* get pointer to pose-channel's channel, but set appropriate flags first */
+void *get_pchan_ipo_poin (bPoseChannel *pchan, int adrcode)
 {
        void *poin= NULL;
        
@@ -2051,6 +1808,7 @@ void *get_pchan_ipo_poin(bPoseChannel *pchan, int adrcode)
                        poin= &(pchan->quat[3]); 
                        pchan->flag |= POSE_ROT;
                        break;
+                       
                case AC_LOC_X:
                        poin= &(pchan->loc[0]); 
                        pchan->flag |= POSE_LOC;
@@ -2062,7 +1820,8 @@ void *get_pchan_ipo_poin(bPoseChannel *pchan, int adrcode)
                case AC_LOC_Z:
                        poin= &(pchan->loc[2]); 
                        pchan->flag |= POSE_LOC;
-                       break;                  
+                       break;
+               
                case AC_SIZE_X:
                        poin= &(pchan->size[0]); 
                        pchan->flag |= POSE_SIZE;
@@ -2076,507 +1835,1031 @@ void *get_pchan_ipo_poin(bPoseChannel *pchan, int adrcode)
                        pchan->flag |= POSE_SIZE;
                        break;
        }
+       
+       /* return pointer */
        return poin;
 }
 
-void execute_action_ipo(bActionChannel *achan, bPoseChannel *pchan)
+/* get texture channel */
+static void *give_tex_poin (Tex *tex, int adrcode, int *type )
 {
+       void *poin= NULL;
 
-       if(achan && achan->ipo) {
-               IpoCurve *icu;
-               for(icu= achan->ipo->curve.first; icu; icu= icu->next) {
-                       void *poin= get_pchan_ipo_poin(pchan, icu->adrcode);
-                       if(poin) {
-                               write_ipo_poin(poin, IPO_FLOAT, icu->curval);
-                               //printf("execute_action_ipo wrote_ipo_poin: %f\n", icu->curval);
-                               //printf("%s has poin %p value %f\n", achan->name, poin, icu->curval);
-                       }
-               }
-       }
-}
-
-/* exception: it does calc for objects...
- * now find out why this routine was used anyway!
- */
-void do_ipo_nocalc(Ipo *ipo)
-{
-       Object *ob;
-       Material *ma;
-       Tex *tex;
-       World *wo;
-       Lamp *la;
-       Camera *ca;
-       bSound *snd;
-       
-       if(ipo==NULL) return;
-       
-       switch(ipo->blocktype) {
-       case ID_OB:
-               ob= G.main->object.first;
-               while(ob) {
-                       if(ob->ipo==ipo) {
-                               do_ob_ipo(ob);
-                               /* execute_ipo((ID *)ob, ipo); */
-                       }
-                       ob= ob->id.next;
-               }
-               break;
-       case ID_MA:
-               ma= G.main->mat.first;
-               while(ma) {
-                       if(ma->ipo==ipo) execute_ipo((ID *)ma, ipo);
-                       ma= ma->id.next;
-               }
-               break;
-       case ID_TE:
-               tex= G.main->tex.first;
-               while(tex) {
-                       if(tex->ipo==ipo) execute_ipo((ID *)tex, ipo);
-                       tex=tex->id.next;
-               }
-               break;
-       case ID_WO:
-               wo= G.main->world.first;
-               while(wo) {
-                       if(wo->ipo==ipo) execute_ipo((ID *)wo, ipo);
-                       wo= wo->id.next;
-               }
-               break;
-       case ID_LA:
-               la= G.main->lamp.first;
-               while(la) {
-                       if(la->ipo==ipo) execute_ipo((ID *)la, ipo);
-                       la= la->id.next;
-               }
-               break;
-       case ID_CA:
-               ca= G.main->camera.first;
-               while(ca) {
-                       if(ca->ipo==ipo) execute_ipo((ID *)ca, ipo);
-                       ca= ca->id.next;
-               }
-               break;
-       case ID_SO:
-               snd= G.main->sound.first;
-               while(snd) {
-                       if(snd->ipo==ipo) execute_ipo((ID *)snd, ipo);
-                       snd= snd->id.next;
-               }
-               break;
+       switch (adrcode) {
+       case TE_NSIZE:
+               poin= &(tex->noisesize); break;
+       case TE_TURB:
+               poin= &(tex->turbul); break;
+       case TE_NDEPTH:
+               poin= &(tex->noisedepth); *type= IPO_SHORT; break;
+       case TE_NTYPE:
+               poin= &(tex->noisetype); *type= IPO_SHORT; break;
+       case TE_VNW1:
+               poin= &(tex->vn_w1); break;
+       case TE_VNW2:
+               poin= &(tex->vn_w2); break;
+       case TE_VNW3:
+               poin= &(tex->vn_w3); break;
+       case TE_VNW4:
+               poin= &(tex->vn_w4); break;
+       case TE_VNMEXP:
+               poin= &(tex->vn_mexp); break;
+       case TE_ISCA:
+               poin= &(tex->ns_outscale); break;
+       case TE_DISTA:
+               poin= &(tex->dist_amount); break;
+       case TE_VN_COLT:
+               poin= &(tex->vn_coltype); *type= IPO_SHORT; break;
+       case TE_VN_DISTM:
+               poin= &(tex->vn_distm); *type= IPO_SHORT; break;
+       case TE_MG_TYP:
+               poin= &(tex->stype); *type= IPO_SHORT; break;
+       case TE_MGH:
+               poin= &(tex->mg_H); break;
+       case TE_MG_LAC:
+               poin= &(tex->mg_lacunarity); break;
+       case TE_MG_OCT:
+               poin= &(tex->mg_octaves); break;
+       case TE_MG_OFF:
+               poin= &(tex->mg_offset); break;
+       case TE_MG_GAIN:
+               poin= &(tex->mg_gain); break;
+       case TE_N_BAS1:
+               poin= &(tex->noisebasis); *type= IPO_SHORT; break;
+       case TE_N_BAS2:
+               poin= &(tex->noisebasis2); *type= IPO_SHORT; break;
+       case TE_COL_R:
+               poin= &(tex->rfac); break;
+       case TE_COL_G:
+               poin= &(tex->gfac); break;
+       case TE_COL_B:
+               poin= &(tex->bfac); break;
+       case TE_BRIGHT:
+               poin= &(tex->bright); break;
+       case TE_CONTRA:
+               poin= &(tex->contrast); break;
        }
+       
+       /* return pointer */
+       return poin;
 }
 
-void do_ipo(Ipo *ipo)
+/* get texture-slot/mapping channel */
+void *give_mtex_poin (MTex *mtex, int adrcode )
 {
-       if(ipo) {
-               float ctime= frame_to_float(G.scene->r.cfra);
-               calc_ipo(ipo, ctime);
+       void *poin= NULL;
        
-               do_ipo_nocalc(ipo);
+       switch (adrcode) {
+       case MAP_OFS_X:
+               poin= &(mtex->ofs[0]); break;
+       case MAP_OFS_Y:
+               poin= &(mtex->ofs[1]); break;
+       case MAP_OFS_Z:
+               poin= &(mtex->ofs[2]); break;
+       case MAP_SIZE_X:
+               poin= &(mtex->size[0]); break;
+       case MAP_SIZE_Y:
+               poin= &(mtex->size[1]); break;
+       case MAP_SIZE_Z:
+               poin= &(mtex->size[2]); break;
+       case MAP_R:
+               poin= &(mtex->r); break;
+       case MAP_G:
+               poin= &(mtex->g); break;
+       case MAP_B:
+               poin= &(mtex->b); break;
+       case MAP_DVAR:
+               poin= &(mtex->def_var); break;
+       case MAP_COLF:
+               poin= &(mtex->colfac); break;
+       case MAP_NORF:
+               poin= &(mtex->norfac); break;
+       case MAP_VARF:
+               poin= &(mtex->varfac); break;
+       case MAP_DISP:
+               poin= &(mtex->dispfac); break;
        }
+       
+       /* return pointer */
+       return poin;
 }
 
+/* GS reads the memory pointed at in a specific ordering. There are,
+ * however two definitions for it. I have jotted them down here, both,
+ * but I think the first one is actually used. The thing is that
+ * big-endian systems might read this the wrong way round. OTOH, we
+ * constructed the IDs that are read out with this macro explicitly as
+ * well. I expect we'll sort it out soon... */
 
+/* from blendef: */
+#define GS(a)  (*((short *)(a)))
 
-void do_mat_ipo(Material *ma)
-{
-       float ctime;
-       
-       if(ma==NULL || ma->ipo==NULL) return;
-       
-       ctime= frame_to_float(G.scene->r.cfra);
-       /* if(ob->ipoflag & OB_OFFS_OB) ctime-= ob->sf; */
+/* from misc_util: flip the bytes from x  */
+/*  #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */
 
-       calc_ipo(ma->ipo, ctime);
-       
-       execute_ipo((ID *)ma, ma->ipo);
-}
 
-void do_ob_ipo(Object *ob)
+/* general function to get pointer to source/destination data  */
+void *get_ipo_poin (ID *id, IpoCurve *icu, int *type)
 {
-       float ctime;
-       unsigned int lay;
-       
-       if(ob->ipo==NULL) return;
-
-       /* do not set ob->ctime here: for example when parent in invisible layer */
-       
-       ctime= bsystem_time(ob, (float) G.scene->r.cfra, 0.0);
-
-       calc_ipo(ob->ipo, ctime);
+       void *poin= NULL;
+       MTex *mtex= NULL;
 
-       /* Patch: remember localview */
-       lay= ob->lay & 0xFF000000;
-       
-       execute_ipo((ID *)ob, ob->ipo);
+       /* most channels will have float data, but those with other types will override this */
+       *type= IPO_FLOAT;
 
-       ob->lay |= lay;
-       if(ob->id.name[2]=='S' && ob->id.name[3]=='C' && ob->id.name[4]=='E') {
-               if(strcmp(G.scene->id.name+2, ob->id.name+6)==0) {
-                       G.scene->lay= ob->lay;
-                       copy_view3d_lock(0);
-                       /* no redraw here! creates too many calls */
+       /* data is divided into 'blocktypes' based on ID-codes */
+       switch (GS(id->name)) {
+               case ID_OB: /* object channels -----------------------------  */
+               {
+                       Object *ob= (Object *)id;
+                       
+                       switch (icu->adrcode) {
+                       case OB_LOC_X:
+                               poin= &(ob->loc[0]); break;
+                       case OB_LOC_Y:
+                               poin= &(ob->loc[1]); break;
+                       case OB_LOC_Z:
+                               poin= &(ob->loc[2]); break;
+                       case OB_DLOC_X:
+                               poin= &(ob->dloc[0]); break;
+                       case OB_DLOC_Y:
+                               poin= &(ob->dloc[1]); break;
+                       case OB_DLOC_Z:
+                               poin= &(ob->dloc[2]); break;
+                       
+                       case OB_ROT_X:
+                               poin= &(ob->rot[0]); *type= IPO_FLOAT_DEGR; break;
+                       case OB_ROT_Y:
+                               poin= &(ob->rot[1]); *type= IPO_FLOAT_DEGR; break;
+                       case OB_ROT_Z:
+                               poin= &(ob->rot[2]); *type= IPO_FLOAT_DEGR; break;
+                       case OB_DROT_X:
+                               poin= &(ob->drot[0]); *type= IPO_FLOAT_DEGR; break;
+                       case OB_DROT_Y:
+                               poin= &(ob->drot[1]); *type= IPO_FLOAT_DEGR; break;
+                       case OB_DROT_Z:
+                               poin= &(ob->drot[2]); *type= IPO_FLOAT_DEGR; break;
+                               
+                       case OB_SIZE_X:
+                               poin= &(ob->size[0]); break;
+                       case OB_SIZE_Y:
+                               poin= &(ob->size[1]); break;
+                       case OB_SIZE_Z:
+                               poin= &(ob->size[2]); break;
+                       case OB_DSIZE_X:
+                               poin= &(ob->dsize[0]); break;
+                       case OB_DSIZE_Y:
+                               poin= &(ob->dsize[1]); break;
+                       case OB_DSIZE_Z:
+                               poin= &(ob->dsize[2]); break;
+                       
+                       case OB_LAY:
+                               poin= &(ob->lay); *type= IPO_INT_BIT; break;
+                               
+                       case OB_COL_R:  
+                               poin= &(ob->col[0]); break;
+                       case OB_COL_G:
+                               poin= &(ob->col[1]); break;
+                       case OB_COL_B:
+                               poin= &(ob->col[2]); break;
+                       case OB_COL_A:
+                               poin= &(ob->col[3]); break;
+                               
+                       case OB_PD_FSTR:
+                               if (ob->pd) poin= &(ob->pd->f_strength);
+                               break;
+                       case OB_PD_FFALL:
+                               if (ob->pd) poin= &(ob->pd->f_power);
+                               break;
+                       case OB_PD_SDAMP:
+                               if (ob->pd) poin= &(ob->pd->pdef_damp);
+                               break;
+                       case OB_PD_RDAMP:
+                               if (ob->pd) poin= &(ob->pd->pdef_rdamp);
+                               break;
+                       case OB_PD_PERM:
+                               if (ob->pd) poin= &(ob->pd->pdef_perm);
+                               break;
+                       case OB_PD_FMAXD:
+                               if (ob->pd) poin= &(ob->pd->maxdist);
+                               break;
+                       }
                }
-       }
-}
-
-void do_ob_ipodrivers(Object *ob, Ipo *ipo, float ctime)
-{
-       IpoCurve *icu;
-       void *poin;
-       int type;
-       
-       for(icu= ipo->curve.first; icu; icu= icu->next) {
-               if(icu->driver) {
-                       icu->curval= eval_icu(icu, ctime);
-                       poin= get_ipo_poin((ID *)ob, icu, &type);
-                       if(poin) write_ipo_poin(poin, type, icu->curval);
+                       break;
+               case ID_MA: /* material channels -----------------------------  */
+               {
+                       Material *ma= (Material *)id;
+                       
+                       switch (icu->adrcode) {
+                       case MA_COL_R:
+                               poin= &(ma->r); break;
+                       case MA_COL_G:
+                               poin= &(ma->g); break;
+                       case MA_COL_B:
+                               poin= &(ma->b); break;
+                       case MA_SPEC_R:
+                               poin= &(ma->specr); break;
+                       case MA_SPEC_G:
+                               poin= &(ma->specg); break;
+                       case MA_SPEC_B:
+                               poin= &(ma->specb); break;
+                       case MA_MIR_R:
+                               poin= &(ma->mirr); break;
+                       case MA_MIR_G:
+                               poin= &(ma->mirg); break;
+                       case MA_MIR_B:
+                               poin= &(ma->mirb); break;
+                       case MA_REF:
+                               poin= &(ma->ref); break;
+                       case MA_ALPHA:
+                               poin= &(ma->alpha); break;
+                       case MA_EMIT:
+                               poin= &(ma->emit); break;
+                       case MA_AMB:
+                               poin= &(ma->amb); break;
+                       case MA_SPEC:
+                               poin= &(ma->spec); break;
+                       case MA_HARD:
+                               poin= &(ma->har); *type= IPO_SHORT; break;
+                       case MA_SPTR:
+                               poin= &(ma->spectra); break;
+                       case MA_IOR:
+                               poin= &(ma->ang); break;
+                       case MA_MODE:
+                               poin= &(ma->mode); *type= IPO_INT_BIT; break; // evil... dumping bitflags directly to user!
+                       case MA_HASIZE:
+                               poin= &(ma->hasize); break;
+                       case MA_TRANSLU:
+                               poin= &(ma->translucency); break;
+                       case MA_RAYM:
+                               poin= &(ma->ray_mirror); break;
+                       case MA_FRESMIR:
+                               poin= &(ma->fresnel_mir); break;
+                       case MA_FRESMIRI:
+                               poin= &(ma->fresnel_mir_i); break;
+                       case MA_FRESTRA:
+                               poin= &(ma->fresnel_tra); break;
+                       case MA_FRESTRAI:
+                               poin= &(ma->fresnel_tra_i); break;
+                       case MA_ADD:
+                               poin= &(ma->add); break;
+                       }
+                       
+                       if (poin == NULL) {
+                               if (icu->adrcode & MA_MAP1) mtex= ma->mtex[0];
+                               else if (icu->adrcode & MA_MAP2) mtex= ma->mtex[1];
+                               else if (icu->adrcode & MA_MAP3) mtex= ma->mtex[2];
+                               else if (icu->adrcode & MA_MAP4) mtex= ma->mtex[3];
+                               else if (icu->adrcode & MA_MAP5) mtex= ma->mtex[4];
+                               else if (icu->adrcode & MA_MAP6) mtex= ma->mtex[5];
+                               else if (icu->adrcode & MA_MAP7) mtex= ma->mtex[6];
+                               else if (icu->adrcode & MA_MAP8) mtex= ma->mtex[7];
+                               else if (icu->adrcode & MA_MAP9) mtex= ma->mtex[8];
+                               else if (icu->adrcode & MA_MAP10) mtex= ma->mtex[9];
+                               else if (icu->adrcode & MA_MAP12) mtex= ma->mtex[11];
+                               else if (icu->adrcode & MA_MAP11) mtex= ma->mtex[10];
+                               else if (icu->adrcode & MA_MAP13) mtex= ma->mtex[12];
+                               else if (icu->adrcode & MA_MAP14) mtex= ma->mtex[13];
+                               else if (icu->adrcode & MA_MAP15) mtex= ma->mtex[14];
+                               else if (icu->adrcode & MA_MAP16) mtex= ma->mtex[15];
+                               else if (icu->adrcode & MA_MAP17) mtex= ma->mtex[16];
+                               else if (icu->adrcode & MA_MAP18) mtex= ma->mtex[17];
+                               
+                               if (mtex)
+                                       poin= give_mtex_poin(mtex, (icu->adrcode & (MA_MAP1-1)));
+                       }
                }
-       }
-}
-
-void do_seq_ipo(Sequence *seq, int cfra)
-{
-       float ctime, div;
-       
-       /* seq_ipo has an exception: calc both fields immediately */
-       
-       if(seq->ipo) {
-               if((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
-                       ctime = frame_to_float(cfra);
-                       div = 1.0;
-               } else {
-                       ctime= frame_to_float(cfra - seq->startdisp);
-                       div= (seq->enddisp - seq->startdisp)/100.0f;
-                       if(div==0.0) return;
+                       break;
+               case ID_TE: /* texture channels -----------------------------  */
+               {
+                       Tex *tex= (Tex *)id;
+                       
+                       if (tex) 
+                               poin= give_tex_poin(tex, icu->adrcode, type);
                }
-               
-               /* 2nd field */
-               calc_ipo(seq->ipo, (ctime+0.5f)/div);
-               execute_ipo((ID *)seq, seq->ipo);
-               seq->facf1= seq->facf0;
-
-               /* 1st field */
-               calc_ipo(seq->ipo, ctime/div);
-               execute_ipo((ID *)seq, seq->ipo);
-
-       }
-       else seq->facf1= seq->facf0= 1.0f;
-}
-
-int has_ipo_code(Ipo *ipo, int code)
-{
-       IpoCurve *icu;
-       
-       if(ipo==NULL) return 0;
-       
-       for(icu= ipo->curve.first; icu; icu= icu->next) {
-               if(icu->adrcode==code) return 1;
-       }
-       return 0;
-}
-
-void do_all_data_ipos()
-{
-       Material *ma;
-       Tex *tex;
-       World *wo;
-       Ipo *ipo;
-       Lamp *la;
-       Key *key;
-       Camera *ca;
-       bSound *snd;
-       Sequence *seq;
-       Editing *ed;
-       Base *base;
-       float ctime;
-
-       ctime= frame_to_float(G.scene->r.cfra);
-       
-       /* this exception cannot be depgraphed yet... what todo with objects in other layers?... */
-       for(base= G.scene->base.first; base; base= base->next) {
-               /* only update layer when an ipo */
-               if( has_ipo_code(base->object->ipo, OB_LAY) ) {
-                       do_ob_ipo(base->object);
-                       base->lay= base->object->lay;
+                       break;
+               case ID_SEQ: /* sequence channels -----------------------------  */
+               {
+                       Sequence *seq= (Sequence *)id;
+                       
+                       switch (icu->adrcode) {
+                       case SEQ_FAC1:
+                               poin= &(seq->facf0); break;
+                       }
                }
-       }
-       
-       /* layers for the set...*/
-       if(G.scene->set) {
-               for(base= G.scene->set->base.first; base; base= base->next) {
-                       if( has_ipo_code(base->object->ipo, OB_LAY) ) {
-                               do_ob_ipo(base->object);
-                               base->lay= base->object->lay;
+                       break;
+               case ID_CU: /* curve channels -----------------------------  */
+               {
+                       poin= &(icu->curval);
+               }
+                       break;
+               case ID_KE: /* shapekey channels -----------------------------  */
+               {
+                       Key *key= (Key *)id;
+                       KeyBlock *kb;
+                       
+                       for(kb= key->block.first; kb; kb= kb->next) {
+                               if (kb->adrcode == icu->adrcode)
+                                       break;
                        }
+                       
+                       if (kb)
+                               poin= &(kb->curval);
                }
-       }
-       
-       
-       ipo= G.main->ipo.first;
-       while(ipo) {
-               if(ipo->id.us && ipo->blocktype!=ID_OB) {
-                       calc_ipo(ipo, ctime);
+                       break;
+               case ID_WO: /* world channels -----------------------------  */
+               {
+                       World *wo= (World *)id;
+                       
+                       switch (icu->adrcode) {
+                       case WO_HOR_R:
+                               poin= &(wo->horr); break;
+                       case WO_HOR_G:
+                               poin= &(wo->horg); break;
+                       case WO_HOR_B:
+                               poin= &(wo->horb); break;
+                       case WO_ZEN_R:
+                               poin= &(wo->zenr); break;
+                       case WO_ZEN_G:
+                               poin= &(wo->zeng); break;
+                       case WO_ZEN_B:
+                               poin= &(wo->zenb); break;
+                       
+                       case WO_EXPOS:
+                               poin= &(wo->exposure); break;
+                       
+                       case WO_MISI:
+                               poin= &(wo->misi); break;
+                       case WO_MISTDI:
+                               poin= &(wo->mistdist); break;
+                       case WO_MISTSTA:
+                               poin= &(wo->miststa); break;
+                       case WO_MISTHI:
+                               poin= &(wo->misthi); break;
+                       
+                       case WO_STAR_R:
+                               poin= &(wo->starr); break;
+                       case WO_STAR_G:
+                               poin= &(wo->starg); break;
+                       case WO_STAR_B:
+                               poin= &(wo->starb); break;
+                       
+                       case WO_STARDIST:
+                               poin= &(wo->stardist); break;
+                       case WO_STARSIZE:
+                               poin= &(wo->starsize); break;
+                       }
+                       
+                       if (poin == NULL) {
+                               if (icu->adrcode & MA_MAP1) mtex= wo->mtex[0];
+                               else if (icu->adrcode & MA_MAP2) mtex= wo->mtex[1];
+                               else if (icu->adrcode & MA_MAP3) mtex= wo->mtex[2];
+                               else if (icu->adrcode & MA_MAP4) mtex= wo->mtex[3];
+                               else if (icu->adrcode & MA_MAP5) mtex= wo->mtex[4];
+                               else if (icu->adrcode & MA_MAP6) mtex= wo->mtex[5];
+                               else if (icu->adrcode & MA_MAP7) mtex= wo->mtex[6];
+                               else if (icu->adrcode & MA_MAP8) mtex= wo->mtex[7];
+                               else if (icu->adrcode & MA_MAP9) mtex= wo->mtex[8];
+                               else if (icu->adrcode & MA_MAP10) mtex= wo->mtex[9];
+                               else if (icu->adrcode & MA_MAP11) mtex= wo->mtex[10];
+                               else if (icu->adrcode & MA_MAP12) mtex= wo->mtex[11];
+                               else if (icu->adrcode & MA_MAP13) mtex= wo->mtex[12];
+                               else if (icu->adrcode & MA_MAP14) mtex= wo->mtex[13];
+                               else if (icu->adrcode & MA_MAP15) mtex= wo->mtex[14];
+                               else if (icu->adrcode & MA_MAP16) mtex= wo->mtex[15];
+                               else if (icu->adrcode & MA_MAP17) mtex= wo->mtex[16];
+                               else if (icu->adrcode & MA_MAP18) mtex= wo->mtex[17];
+                               
+                               if (mtex)
+                                       poin= give_mtex_poin(mtex, (icu->adrcode & (MA_MAP1-1)));
+                       }
                }
-               ipo= ipo->id.next;
-       }
-
-       for(tex= G.main->tex.first; tex; tex= tex->id.next) {
-               if(tex->ipo) execute_ipo((ID *)tex, tex->ipo);
-       }
-
-       for(ma= G.main->mat.first; ma; ma= ma->id.next) {
-               if(ma->ipo) execute_ipo((ID *)ma, ma->ipo);
-       }
-
-       for(wo= G.main->world.first; wo; wo= wo->id.next) {
-               if(wo->ipo) execute_ipo((ID *)wo, wo->ipo);
-       }
-       
-       for(key= G.main->key.first; key; key= key->id.next) {
-               if(key->ipo) execute_ipo((ID *)key, key->ipo);
-       }
-       
-       la= G.main->lamp.first;
-       while(la) {
-               if(la->ipo) execute_ipo((ID *)la, la->ipo);
-               la= la->id.next;
-       }
-
-       ca= G.main->camera.first;
-       while(ca) {
-               if(ca->ipo) execute_ipo((ID *)ca, ca->ipo);
-               ca= ca->id.next;
-       }
-
-       snd= G.main->sound.first;
-       while(snd) {
-               if(snd->ipo) execute_ipo((ID *)snd, snd->ipo);
-               snd= snd->id.next;
-       }
-
-       /* process FAC Ipos used as volume envelopes */
-       ed= G.scene->ed;
-       if (ed) {
-               seq= ed->seqbasep->first;
-               while(seq) {
-                       if ((seq->type == SEQ_RAM_SOUND
-                            || seq->type == SEQ_HD_SOUND) && (seq->ipo) && 
-                               (seq->startdisp<=G.scene->r.cfra+2) && 
-                           (seq->enddisp>G.scene->r.cfra)) 
-                                       do_seq_ipo(seq, G.scene->r.cfra);
-                       seq= seq->next;
+                       break;
+               case ID_LA: /* lamp channels -----------------------------  */
+               {
+                       Lamp *la= (Lamp *)id;
+                       
+                       switch (icu->adrcode) {
+                       case LA_ENERGY:
+                               poin= &(la->energy); break;             
+                       case LA_COL_R:
+                               poin= &(la->r); break;
+                       case LA_COL_G:
+                               poin= &(la->g); break;
+                       case LA_COL_B:
+                               poin= &(la->b); break;
+                       case LA_DIST:
+                               poin= &(la->dist); break;               
+                       case LA_SPOTSI:
+                               poin= &(la->spotsize); break;
+                       case LA_SPOTBL:
+                               poin= &(la->spotblend); break;
+                       case LA_QUAD1:
+                               poin= &(la->att1); break;
+                       case LA_QUAD2:
+                               poin= &(la->att2); break;
+                       case LA_HALOINT:
+                               poin= &(la->haint); break;
+                       }
+                       
+                       if (poin == NULL) {
+                               if (icu->adrcode & MA_MAP1) mtex= la->mtex[0];
+                               else if (icu->adrcode & MA_MAP2) mtex= la->mtex[1];
+                               else if (icu->adrcode & MA_MAP3) mtex= la->mtex[2];
+                               else if (icu->adrcode & MA_MAP4) mtex= la->mtex[3];
+                               else if (icu->adrcode & MA_MAP5) mtex= la->mtex[4];
+                               else if (icu->adrcode & MA_MAP6) mtex= la->mtex[5];
+                               else if (icu->adrcode & MA_MAP7) mtex= la->mtex[6];
+                               else if (icu->adrcode & MA_MAP8) mtex= la->mtex[7];
+                               else if (icu->adrcode & MA_MAP9) mtex= la->mtex[8];
+                               else if (icu->adrcode & MA_MAP10) mtex= la->mtex[9];
+                               else if (icu->adrcode & MA_MAP11) mtex= la->mtex[10];
+                               else if (icu->adrcode & MA_MAP12) mtex= la->mtex[11];
+                               else if (icu->adrcode & MA_MAP13) mtex= la->mtex[12];
+                               else if (icu->adrcode & MA_MAP14) mtex= la->mtex[13];
+                               else if (icu->adrcode & MA_MAP15) mtex= la->mtex[14];
+                               else if (icu->adrcode & MA_MAP16) mtex= la->mtex[15];
+                               else if (icu->adrcode & MA_MAP17) mtex= la->mtex[16];
+                               else if (icu->adrcode & MA_MAP18) mtex= la->mtex[17];
+                               
+                               if (mtex)
+                                       poin= give_mtex_poin(mtex, (icu->adrcode & (MA_MAP1-1)));
+                       }
                }
-       }
-
-}
-
-
-int calc_ipo_spec(Ipo *ipo, int adrcode, float *ctime)
-{
-       IpoCurve *icu;
-
-       if(ipo==NULL) return 0;
-
-       for(icu= ipo->curve.first; icu; icu= icu->next) {
-               if(icu->adrcode == adrcode) {
-                       if(icu->flag & IPO_LOCK);
-                       else calc_icu(icu, *ctime);
+                       break;
+               case ID_CA: /* camera channels -----------------------------  */
+               {
+                       Camera *ca= (Camera *)id;
                        
-                       *ctime= icu->curval;
-                       return 1;
+                       switch (icu->adrcode) {
+                       case CAM_LENS:
+                               if (ca->type == CAM_ORTHO)
+                                       poin= &(ca->ortho_scale);
+                               else
+                                       poin= &(ca->lens); 
+                               break;
+                       case CAM_STA:
+                               poin= &(ca->clipsta); break;
+                       case CAM_END:
+                               poin= &(ca->clipend); break;
+                               
+                       case CAM_YF_APERT:
+                               poin= &(ca->YF_aperture); break;
+                       case CAM_YF_FDIST:
+                               poin= &(ca->YF_dofdist); break;
+                               
+                       case CAM_SHIFT_X:
+                               poin= &(ca->shiftx); break;
+                       case CAM_SHIFT_Y:
+                               poin= &(ca->shifty); break;
+                       }
                }
-       }
-       
-       return 0;
-}
-
-
-/* ************************** */
-
-void clear_delta_obipo(Ipo *ipo)
-{
-       Object *ob;
-       
-       if(ipo==NULL) return;
-       
-       ob= G.main->object.first;
-       while(ob) {
-               if(ob->id.lib==NULL) {
-                       if(ob->ipo==ipo) {
-                               memset(&ob->dloc, 0, 12);
-                               memset(&ob->drot, 0, 12);
-                               memset(&ob->dsize, 0, 12);
+                       break;
+               case ID_SO: /* sound channels -----------------------------  */
+               {
+                       bSound *snd= (bSound *)id;
+                       
+                       switch (icu->adrcode) {
+                       case SND_VOLUME:
+                               poin= &(snd->volume); break;
+                       case SND_PITCH:
+                               poin= &(snd->pitch); break;
+                       case SND_PANNING:
+                               poin= &(snd->panning); break;
+                       case SND_ATTEN:
+                               poin= &(snd->attenuation); break;
                        }
                }
-               ob= ob->id.next;
-       }
-}
-
-void add_to_cfra_elem(ListBase *lb, BezTriple *bezt)
-{
-       CfraElem *ce, *cen;
-       
-       ce= lb->first;
-       while(ce) {
-               
-               if( ce->cfra==bezt->vec[1][0] ) {
-                       /* do because of double keys */
-                       if(bezt->f2 & SELECT) ce->sel= bezt->f2;
-                       return;
+                       break;
+               case ID_PA: /* particle channels -----------------------------  */
+               {
+                       ParticleSettings *part= (ParticleSettings *)id;
+                       
+                       switch (icu->adrcode) {
+                       case PART_EMIT_FREQ:
+                       case PART_EMIT_LIFE:
+                       case PART_EMIT_VEL:
+                       case PART_EMIT_AVE:
+                       case PART_EMIT_SIZE:
+                               poin= NULL; 
+                               break;
+                       
+                       case PART_CLUMP:
+                               poin= &(part->clumpfac); break;
+                       case PART_AVE:
+                               poin= &(part->avefac); break;
+                       case PART_SIZE:
+                               poin= &(part->size); break;
+                       case PART_DRAG:
+                               poin= &(part->dragfac); break;
+                       case PART_BROWN:
+                               poin= &(part->brownfac); break;
+                       case PART_DAMP:
+                               poin= &(part->dampfac); break;
+                       case PART_LENGTH:
+                               poin= &(part->length); break;
+                       case PART_GRAV_X:
+                               poin= &(part->acc[0]); break;
+                       case PART_GRAV_Y:
+                               poin= &(part->acc[1]); break;
+                       case PART_GRAV_Z:
+                               poin= &(part->acc[2]); break;
+                       case PART_KINK_AMP:
+                               poin= &(part->kink_amp); break;
+                       case PART_KINK_FREQ:
+                               poin= &(part->kink_freq); break;
+                       case PART_KINK_SHAPE:
+                               poin= &(part->kink_shape); break;
+                       case PART_BB_TILT:
+                               poin= &(part->bb_tilt); break;
+                               
+                       case PART_PD_FSTR:
+                               if (part->pd) poin= &(part->pd->f_strength);
+                               break;
+                       case PART_PD_FFALL:
+                               if (part->pd) poin= &(part->pd->f_power);
+                               break;
+                       case PART_PD_FMAXD:
+                               if (part->pd) poin= &(part->pd->maxdist);
+                               break;
+                       case PART_PD2_FSTR:
+                               if (part->pd2) poin= &(part->pd2->f_strength);
+                               break;
+                       case PART_PD2_FFALL:
+                               if (part->pd2) poin= &(part->pd2->f_power);
+                               break;
+                       case PART_PD2_FMAXD:
+                               if (part->pd2) poin= &(part->pd2->maxdist);
+                               break;
+                       }
                }
-               else if(ce->cfra > bezt->vec[1][0]) break;
-               
-               ce= ce->next;
-       }       
-       
-       cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); 
-       if(ce) BLI_insertlinkbefore(lb, ce, cen);
-       else BLI_addtail(lb, cen);
+                       break;
+       }
 
-       cen->cfra= bezt->vec[1][0];
-       cen->sel= bezt->f2;
+       /* return pointer */
+       return poin;
 }
 
+/* --------------------- IPO-Curve Limits ----------------------------- */
 
-
-void make_cfra_list(Ipo *ipo, ListBase *elems)
+/* set limits for IPO-curve 
+ * Note: must be synced with UI and PyAPI
+ */
+void set_icu_vars (IpoCurve *icu)
 {
-       IpoCurve *icu;
-       BezTriple *bezt;
-       int a;
+       /* defaults. 0.0 for y-extents makes these ignored */
+       icu->ymin= icu->ymax= 0.0;
+       icu->ipo= IPO_BEZ;
        
-       if(ipo->blocktype==ID_OB) {
-               for(icu= ipo->curve.first; icu; icu= icu->next) {
-                       if(icu->flag & IPO_VISIBLE) {
-                               switch(icu->adrcode) {
-                               case OB_DLOC_X:
-                               case OB_DLOC_Y:
-                               case OB_DLOC_Z:
-                               case OB_DROT_X:
-                               case OB_DROT_Y:
-                               case OB_DROT_Z:
-                               case OB_DSIZE_X:
-                               case OB_DSIZE_Y:
-                               case OB_DSIZE_Z:
-
-                               case OB_LOC_X:
-                               case OB_LOC_Y:
-                               case OB_LOC_Z:
-                               case OB_ROT_X:
-                               case OB_ROT_Y:
-                               case OB_ROT_Z:
-                               case OB_SIZE_X:
-                               case OB_SIZE_Y:
-                               case OB_SIZE_Z:
-                               case OB_PD_FSTR:
-                               case OB_PD_FFALL:
-                               case OB_PD_SDAMP:
-                               case OB_PD_RDAMP:
-                               case OB_PD_PERM:
-                               case OB_PD_FMAXD:
-                                       bezt= icu->bezt;
-                                       if(bezt) {
-                                               a= icu->totvert;
-                                               while(a--) {
-                                                       add_to_cfra_elem(elems, bezt);
-                                                       bezt++;
-                                               }
-                                       }
+       switch (icu->blocktype) {
+               case ID_OB: /* object channels -----------------------------  */
+               {
+                       if (icu->adrcode == OB_LAY) {
+                               icu->ipo= IPO_CONST;
+                               icu->vartype= IPO_BITS;
+                       }
+               }
+                       break;
+               case ID_MA: /* material channels -----------------------------  */
+               {
+                       if (icu->adrcode < MA_MAP1) {
+                               switch (icu->adrcode) {
+                               case MA_HASIZE:
+                                       icu->ymax= 10000.0; break;
+                               case MA_HARD:
+                                       icu->ymax= 511.0; break;
+                               case MA_SPEC:
+                                       icu->ymax= 2.0; break;
+                               case MA_MODE:
+                                       icu->ipo= IPO_CONST;
+                                       icu->vartype= IPO_BITS; break;
+                               case MA_RAYM:
+                                       icu->ymax= 1.0; break;
+                               case MA_TRANSLU:
+                                       icu->ymax= 1.0; break;
+                               case MA_IOR:
+                                       icu->ymin= 1.0;
+                                       icu->ymax= 3.0; break;
+                               case MA_FRESMIR:
+                                       icu->ymax= 5.0; break;
+                               case MA_FRESMIRI:
+                                       icu->ymin= 1.0;
+                                       icu->ymax= 5.0; break;
+                               case MA_FRESTRA:
+                                       icu->ymax= 5.0; break;
+                               case MA_FRESTRAI:
+                                       icu->ymin= 1.0;
+                                       icu->ymax= 5.0; break;
+                               case MA_ADD:
+                                       icu->ymax= 1.0; break;
+                               case MA_EMIT:
+                                       icu->ymax= 2.0; break;
+                               default:
+                                       icu->ymax= 1.0; break;
+                               }
+                       }
+                       else {
+                               switch (icu->adrcode & (MA_MAP1-1)) {
+                               case MAP_OFS_X:
+                               case MAP_OFS_Y:
+                               case MAP_OFS_Z:
+                               case MAP_SIZE_X:
+                               case MAP_SIZE_Y:
+                               case MAP_SIZE_Z:
+                                       icu->ymax= 1000.0;
+                                       icu->ymin= -1000.0;
+                                       break;
+                               case MAP_R:
+                               case MAP_G:
+                               case MAP_B:
+                               case MAP_DVAR:
+                               case MAP_COLF:
+                               case MAP_VARF:
+                               case MAP_DISP:
+                                       icu->ymax= 1.0;
+                                       break;
+                               case MAP_NORF:
+                                       icu->ymax= 25.0;
                                        break;
                                }
                        }
                }
-       }
-       else if(ipo->blocktype==ID_AC) {
-               for(icu= ipo->curve.first; icu; icu= icu->next) {
-                       if(icu->flag & IPO_VISIBLE) {
-                               switch(icu->adrcode) {
-                               case AC_LOC_X:
-                               case AC_LOC_Y:
-                               case AC_LOC_Z:
-                               case AC_SIZE_X:
-                               case AC_SIZE_Y:
-                               case AC_SIZE_Z:
-                               case AC_QUAT_W:
-                               case AC_QUAT_X:
-                               case AC_QUAT_Y:
-                               case AC_QUAT_Z:
-                                       bezt= icu->bezt;
-                                       if(bezt) {
-                                               a= icu->totvert;
-                                               while(a--) {
-                                                       add_to_cfra_elem(elems, bezt);
-                                                       bezt++;
-                                               }
-                                       }
+                       break;
+               case ID_TE: /* texture channels -----------------------------  */
+               {
+                       switch (icu->adrcode & (MA_MAP1-1)) {
+                               case TE_NSIZE:
+                                       icu->ymin= 0.0001;
+                                       icu->ymax= 2.0; break;
+                               case TE_NDEPTH:
+                                       icu->vartype= IPO_SHORT;
+                                       icu->ipo= IPO_CONST;
+                                       icu->ymax= 6.0; break;
+                               case TE_NTYPE:
+                                       icu->vartype= IPO_SHORT;
+                                       icu->ipo= IPO_CONST;
+                                       icu->ymax= 1.0; break;
+                               case TE_TURB:
+                                       icu->ymax= 200.0; break;
+                               case TE_VNW1:
+                               case TE_VNW2:
+                               case TE_VNW3:
+                               case TE_VNW4:
+                                       icu->ymax= 2.0;
+                                       icu->ymin= -2.0; break;
+                               case TE_VNMEXP:
+                                       icu->ymax= 10.0;
+                                       icu->ymin= 0.01; break;
+                               case TE_VN_DISTM:
+                                       icu->vartype= IPO_SHORT;
+                                       icu->ipo= IPO_CONST;
+                                       icu->ymax= 6.0; break;
+                               case TE_VN_COLT:
+                                       icu->vartype= IPO_SHORT;
+                                       icu->ipo= IPO_CONST;
+                                       icu->ymax= 3.0; break;
+                               case TE_ISCA:
+                                       icu->ymax= 10.0;
+                                       icu->ymin= 0.01; break;
+                               case TE_DISTA:
+                                       icu->ymax= 10.0; break;
+                               case TE_MG_TYP:
+                                       icu->vartype= IPO_SHORT;
+                                       icu->ipo= IPO_CONST;
+                                       icu->ymax= 6.0; break;
+                               case TE_MGH:
+                                       icu->ymin= 0.0001;
+                                       icu->ymax= 2.0; break;
+                               case TE_MG_LAC:
+                               case TE_MG_OFF:
+                               case TE_MG_GAIN:
+                                       icu->ymax= 6.0; break;
+                               case TE_MG_OCT:
+                                       icu->ymax= 8.0; break;
+                               case TE_N_BAS1:
+                               case TE_N_BAS2:
+                                       icu->vartype= IPO_SHORT;
+                                       icu->ipo= IPO_CONST;
+                                       icu->ymax= 8.0; break;
+                               case TE_COL_R:
+                                       icu->ymax= 0.0; break;
+                               case TE_COL_G:
+                                       icu->ymax= 2.0; break;
+                               case TE_COL_B:
+                                       icu->ymax= 2.0; break;
+                               case TE_BRIGHT:
+                                       icu->ymax= 2.0; break;
+                               case TE_CONTRA:
+                                       icu->ymax= 5.0; break;  
+                       }
+               }
+                       break;
+               case ID_SEQ: /* sequence channels -----------------------------  */
+               {
+                       icu->ymax= 1.0;
+               }
+                       break;
+               case ID_CU: /* curve channels -----------------------------  */
+               {
+                       icu->ymax= 1.0;
+               }
+                       break;
+               case ID_WO: /* world channels -----------------------------  */
+               {
+                       if (icu->adrcode < MA_MAP1) {
+                               switch (icu->adrcode) {
+                               case WO_EXPOS:
+                                       icu->ymax= 5.0; break;
+                               case WO_MISTDI:
+                               case WO_MISTSTA:
+                               case WO_MISTHI:
+                               case WO_STARDIST:
+                               case WO_STARSIZE:
+                                       break;
+                                       
+                               default:
+                                       icu->ymax= 1.0;
                                        break;
                                }
                        }
+                       else {
+                               switch (icu->adrcode & (MA_MAP1-1)) {
+                               case MAP_OFS_X:
+                               case MAP_OFS_Y:
+                               case MAP_OFS_Z:
+                               case MAP_SIZE_X:
+                               case MAP_SIZE_Y:
+                               case MAP_SIZE_Z:
+                                       icu->ymax= 100.0;
+                                       icu->ymin= -100.0;
+                                       break;
+                               case MAP_R:
+                               case MAP_G:
+                               case MAP_B:
+                               case MAP_DVAR:
+                               case MAP_COLF:
+                               case MAP_NORF:
+                               case MAP_VARF:
+                               case MAP_DISP:
+                                       icu->ymax= 1.0;
+                               }
+                       }
                }
-       }
-       else {
-               for(icu= ipo->curve.first; icu; icu= icu->next) {
-                       if(icu->flag & IPO_VISIBLE) {
-                               bezt= icu->bezt;
-                               if(bezt) {
-                                       a= icu->totvert;
-                                       while(a--) {
-                                               add_to_cfra_elem(elems, bezt);
-                                               bezt++;
-                                       }
+                       break;
+               case ID_LA: /* lamp channels -----------------------------  */
+               {
+                       if (icu->adrcode < MA_MAP1) {
+                               switch (icu->adrcode) {
+                               case LA_ENERGY:
+                               case LA_DIST:
+                                       break;          
+                               
+                               case LA_COL_R:
+                               case LA_COL_G:
+                               case LA_COL_B:
+                               case LA_SPOTBL:
+                               case LA_QUAD1:
+                               case LA_QUAD2:
+                                       icu->ymax= 1.0; break;
+                                       
+                               case LA_SPOTSI:
+                                       icu->ymax= 180.0; break;
+                               
+                               case LA_HALOINT:
+                                       icu->ymax= 5.0; break;
+                               }
+                       }
+                       else {
+                               switch (icu->adrcode & (MA_MAP1-1)) {
+                               case MAP_OFS_X:
+                               case MAP_OFS_Y:
+                               case MAP_OFS_Z:
+                               case MAP_SIZE_X:
+                               case MAP_SIZE_Y:
+                               case MAP_SIZE_Z:
+                                       icu->ymax= 100.0;
+                                       icu->ymin= -100.0;
+                                       break;
+                               case MAP_R:
+                               case MAP_G:
+                               case MAP_B:
+                               case MAP_DVAR:
+                               case MAP_COLF:
+                               case MAP_NORF:
+                               case MAP_VARF:
+                               case MAP_DISP:
+                                       icu->ymax= 1.0;
                                }
                        }
+               }       
+                       break;
+               case ID_CA: /* camera channels -----------------------------  */
+               {
+                       switch (icu->adrcode) {
+                       case CAM_LENS:
+                               icu->ymin= 1.0;
+                               icu->ymax= 1000.0;
+                               break;
+                       case CAM_STA:
+                               icu->ymin= 0.001f;
+                               break;
+                       case CAM_END:
+                               icu->ymin= 0.1f;
+                               break;
+                               
+                       case CAM_YF_APERT:
+                               icu->ymin = 0.0;
+                               icu->ymax = 2.0;
+                               break;
+                       case CAM_YF_FDIST:
+                               icu->ymin = 0.0;
+                               icu->ymax = 5000.0;
+                               break;
+                               
+                       case CAM_SHIFT_X:
+                       case CAM_SHIFT_Y:
+                               icu->ymin= -2.0f;
+                               icu->ymax= 2.0f;
+                               break;
+                       }
+               }
+                       break;
+               case ID_SO: /* sound channels -----------------------------  */
+               {
+                       switch (icu->adrcode) {
+                       case SND_VOLUME:
+                               icu->ymin= 0.0;
+                               icu->ymax= 1.0;
+                               break;
+                       case SND_PITCH:
+                               icu->ymin= -12.0;
+                               icu->ymin= 12.0;
+                               break;
+                       case SND_PANNING:
+                               icu->ymin= 0.0;
+                               icu->ymax= 1.0;
+                               break;
+                       case SND_ATTEN:
+                               icu->ymin= 0.0;
+                               icu->ymin= 1.0;
+                               break;
+                       }
+               }
+                       break;
+               case ID_PA: /* particle channels -----------------------------  */
+               {
+                       switch (icu->adrcode) {
+                       case PART_EMIT_LIFE:
+                       case PART_SIZE:
+                       case PART_KINK_FREQ:
+                       case PART_EMIT_VEL:
+                       case PART_EMIT_AVE:
+                       case PART_EMIT_SIZE:
+                               icu->ymin= 0.0;
+                               break;
+                       case PART_CLUMP:
+                               icu->ymin= -1.0;
+                               icu->ymax= 1.0;
+                               break;
+                       case PART_DRAG:
+                       case PART_DAMP:
+                       case PART_LENGTH:
+                               icu->ymin= 0.0;
+                               icu->ymax= 1.0;
+                               break;
+                       case PART_KINK_SHAPE:
+                               icu->ymin= -0.999;
+                               icu->ymax= 0.999;
+                               break;
+                       }
+               }
+                       break;
+               case ID_CO: /* constraint channels -----------------------------  */
+               {
+                       icu->ymin= 0.0;
+                       icu->ymax= 1.0f;
                }
+                       break;
        }
+       
+       /* by default, slider limits will be icu->ymin and icu->ymax */
+       icu->slide_min= icu->ymin;
+       icu->slide_max= icu->ymax;
+}
 
-       /* what's the point of this little block of code?  */
-#if 0
-       if(ipo->showkey==0) {
-               /* deselect all keys */
-               ce= elems->first;
-               while(ce) {
-                       ce->sel= 0;
-                       ce= ce->next;
-               }
+/* --------------------- Pointer I/O API ----------------------------- */
+/* write the given value directly into the given pointer */
+void write_ipo_poin (void *poin, int type, float val)
+{
+       /* Note: we only support a limited number of types, with the value
+        * to set needing to be cast to the appropriate type first
+        *      -> (float to integer conversions could be slow)
+        */
+       switch(type) {
+       case IPO_FLOAT:
+               *((float *)poin)= val;
+               break;
+               
+       case IPO_FLOAT_DEGR: /* special hack for rotation so that it fits on same axis as other transforms */
+               *((float *)poin)= (float)(val * M_PI_2 / 9.0);
+               break;
+               
+       case IPO_INT:
+       case IPO_INT_BIT: // fixme... directly revealing bitflag combinations is evil!
+       case IPO_LONG:
+               *((int *)poin)= (int)val;
+               break;
+               
+       case IPO_SHORT:
+       case IPO_SHORT_BIT: // fixme... directly revealing bitflag combinations is evil!
+               *((short *)poin)= (short)val;
+               break;
+               
+       case IPO_CHAR:
+       case IPO_CHAR_BIT: // fixme... directly revealing bitflag combinations is evil!
+               *((char *)poin)= (char)val;
+               break;
        }
-#endif
 }
 
-/* *********************** INTERFACE FOR KETSJI ********** */
+/* read the value from the pointer that was obtained */
+float read_ipo_poin (void *poin, int type)
+{
+       float val = 0.0;
+       
+       /* Note: we only support a limited number of types, with the value
+        * to set needing to be cast to the appropriate type first
+        *      -> (int to float conversions may loose accuracy in rare cases)
+        */
+       switch (type) {
+       case IPO_FLOAT:
+               val= *((float *)poin);
+               break;
+               
+       case IPO_FLOAT_DEGR: /* special hack for rotation so that it fits on same axis as other transforms */
+               val= *( (float *)poin);
+               val = (float)(val / (M_PI_2/9.0));
+               break;
+       
+       case IPO_INT:
+       case IPO_INT_BIT: // fixme... directly revealing bitflag combinations is evil!
+       case IPO_LONG:
+               val= (float)( *((int *)poin) );
+               break;
+               
+       case IPO_SHORT:
+       case IPO_SHORT_BIT: // fixme... directly revealing bitflag combinations is evil!
+               val= *((short *)poin);
+               break;
+       
+       case IPO_CHAR:
+       case IPO_CHAR_BIT: // fixme... directly revealing bitflag combinations is evil
+               val= *((char *)poin);
+               break;
+       }
+       
+       /* return value */
+       return val;
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!! FIXME - BAD CRUFT WARNING !!!!!!!!!!!!!!!!!!!!!!!
 
 
-int IPO_GetChannels(Ipo *ipo, IPO_Channel *channels)
-{
-       /* channels is max 32 items, allocated by calling function */   
+/* ***************************** IPO <--> GameEngine Interface ********************************* */
 
+/* channels is max 32 items, allocated by calling function */
+short IPO_GetChannels (Ipo *ipo, IPO_Channel *channels)
+{
        IpoCurve *icu;
-       int total=0;
+       int total = 0;
        
-       if(ipo==NULL) return 0;
+       /* don't do anything with no IPO-block */
+       if (ipo == NULL) 
+               return 0;
        
-       for(icu= ipo->curve.first; icu; icu= icu->next) {
+       /* store the IPO-curve's adrcode in the relevant channel slot */
+       for (icu=ipo->curve.first; (icu) && (total < 31); icu=icu->next, total++)
                channels[total]= icu->adrcode;
-               total++;
-               if(total>31) break;
-       }
        
+       /* return the number of channels stored */
        return total;
 }
 
-
-
 /* Get the float value for channel 'channel' at time 'ctime' */
-
-float IPO_GetFloatValue(Ipo *ipo, IPO_Channel channel, float ctime)
+float IPO_GetFloatValue (Ipo *ipo, IPO_Channel channel, float ctime)
 {
-       if(ipo==NULL) return 0;
+       /* don't evaluate if no IPO to use */
+       if (ipo == NULL) 
+               return 0;
        
+       /* only calculate the specified channel */
        calc_ipo_spec(ipo, channel, &ctime);
        
-       if (OB_ROT_X <= channel && channel <= OB_DROT_Z) {
+       /* unapply rotation hack, as gameengine doesn't use it */
+       if ((OB_ROT_X <= channel) && (channel <= OB_DROT_Z))
                ctime *= (float)(M_PI_2/9.0); 
-       }
 
+       /* return the value of this channel */
        return ctime;
 }
index 5be6dd727c04ec1abbe24f523d9a74f6688e2176..432399e358100e3f226a1b5dc6989b15ecc1231d 100644 (file)
@@ -201,6 +201,8 @@ typedef struct Ipo {
 #define MA_MAP17       (1<<21)
 #define MA_MAP18       (1<<22)
 
+/* ********** Texture Slots (MTex) ********** */
+
 #define TEX_TOTNAM     14
 
 #define MAP_OFS_X      1
index b9bcf4063a3460747821b7887f019382bd05dab8..b7aa29e2482388aec8b24b6c5aeb24a0477ebf1e 100644 (file)
@@ -4816,7 +4816,8 @@ void draw_object(Base *base, int flag)
                                warning_recursive= 1;
 
                                elems.first= elems.last= 0;
-                               make_cfra_list(ob->ipo, &elems);
+                               // warning: no longer checks for certain ob-keys only... (so does this need to use the proper ipokeys then?)
+                               make_cfra_list(ob->ipo, &elems); 
 
                                cfraont= (G.scene->r.cfra);
                                drawtype= G.vd->drawtype;