diff options
Diffstat (limited to 'source/blender/blenkernel/intern/ipo.c')
-rw-r--r-- | source/blender/blenkernel/intern/ipo.c | 3654 |
1 files changed, 2004 insertions, 1650 deletions
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 59eb3837aab..a115ac39e1a 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -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 ***** */ @@ -77,11 +77,16 @@ #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, @@ -175,460 +180,617 @@ int fluidsim_ar[FLUIDSIM_TOTIPO]= { FLUIDSIM_VISC, FLUIDSIM_TIME, FLUIDSIM_GRAV_X , FLUIDSIM_GRAV_Y , FLUIDSIM_GRAV_Z , FLUIDSIM_VEL_X , FLUIDSIM_VEL_Y , FLUIDSIM_VEL_Z , - FLUIDSIM_ACTIVE + FLUIDSIM_ACTIVE, + FLUIDSIM_ATTR_FORCE_STR, FLUIDSIM_ATTR_FORCE_RADIUS, + FLUIDSIM_VEL_FORCE_STR, FLUIDSIM_VEL_FORCE_RADIUS, }; int part_ar[PART_TOTIPO]= { PART_EMIT_FREQ, PART_EMIT_LIFE, PART_EMIT_VEL, PART_EMIT_AVE, PART_EMIT_SIZE, PART_AVE, PART_SIZE, PART_DRAG, PART_BROWN, PART_DAMP, PART_LENGTH, PART_CLUMP, PART_GRAV_X, PART_GRAV_Y, PART_GRAV_Z, PART_KINK_AMP, PART_KINK_FREQ, PART_KINK_SHAPE, - PART_BB_TILT + PART_BB_TILT, PART_PD_FSTR, PART_PD_FFALL, PART_PD_FMAXD, PART_PD2_FSTR, PART_PD2_FFALL, PART_PD2_FMAXD }; +/* ************************** Data-Level Functions ************************* */ + +/* ---------------------- Freeing --------------------------- */ -float frame_to_float(int cfra) /* see also bsystem_time in object.c */ +/* 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; - while( (icu= ipo->curve.first) ) { + if (ipo == NULL) + return; + + 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); + } + } + } + } +} + +/* ***************************** Timing Stuff ********************************* */ - a= icu->totvert; +/* 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; - /* IPO_CONST doesn't have handles */ - if(a<2 || icu->ipo==IPO_CONST) return; + ctime= (float)cfra; + ctime+= bluroffs+fieldoffs; + ctime*= G.scene->r.framelen; - bezt= icu->bezt; - prev= 0; - next= bezt+1; + 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]); @@ -636,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; -int findzero(float x, float q0, float q1, float q2, float q3, float *o) + /* 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 ********************************* */ + +/* 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; } } @@ -695,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 */ @@ -780,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]; @@ -846,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); @@ -864,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]; @@ -896,227 +1128,722 @@ 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; - - cycyofs= 0.0; + float cvalue = 0.0f; - 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) { - 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; + /* 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) { + /* Use the next center point instead of our own handle for + * linear interpolated extrapolate + */ + if (icu->totvert == 1) + cvalue= prevbezt->vec[1][1]; + else { + bezt = prevbezt+1; + 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 { + /* 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; - 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 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) { + /* Use the next center point instead of our own handle for + * linear interpolated extrapolate + */ + if (icu->totvert == 1) + cvalue= lastbezt->vec[1][1]; + else { + 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= lastbezt->vec[1][1]; + } + } + 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= lastbezt->vec[1][1]; } - else cvalue= prevbezt->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, so no interpolation needed) */ + cvalue= prevbezt->vec[1][1]; } - 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]; } 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 ----------------------------- */ + +/* 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); + } +} - 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 Material's IPO block, then flush to given Material only */ +void do_mat_ipo (Material *ma) +{ + float ctime; + + 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); +} + +/* 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) +{ + 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 */ + } } } -float read_ipo_poin(void *poin, int type) +/* 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) { - float val = 0.0; + IpoCurve *icu; + void *poin; + int type; - switch(type) { - case IPO_FLOAT: - val= *( (float *)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); + } + } +} + +/* Special variation to calculate IPO values for Sequence + perform other stuff */ +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; + } + + /* 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; +} + +/* --------- */ + + +/* 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; + + /* 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); + } break; - case IPO_FLOAT_DEGR: - val= *( (float *)poin); - val = (float)(val/(M_PI_2/9.0)); + case ID_MA: + for (ma= G.main->mat.first; ma; ma= ma->id.next) { + if (ma->ipo == ipo) execute_ipo((ID *)ma, ipo); + } break; - case IPO_INT: - case IPO_INT_BIT: - case IPO_LONG: - val= (float)(*( (int *)poin)); + case ID_TE: + for (tex= G.main->tex.first; tex; tex= tex->id.next) { + if (tex->ipo == ipo) execute_ipo((ID *)tex, ipo); + } break; - case IPO_SHORT: - case IPO_SHORT_BIT: - val= *( (short *)poin); + case ID_WO: + for (wo= G.main->world.first; wo; wo= wo->id.next) { + if (wo->ipo == ipo) execute_ipo((ID *)wo, ipo); + } break; - case IPO_CHAR: - case IPO_CHAR_BIT: - val= *( (char *)poin); + case ID_LA: + for (la= G.main->lamp.first; la; la= la->id.next) { + if (la->ipo == ipo) execute_ipo((ID *)la, ipo); + } + break; + case ID_CA: + for (ca= G.main->camera.first; ca; ca= ca->id.next) { + if (ca->ipo == ipo) execute_ipo((ID *)ca, ipo); + } + 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 val; } -static void *give_tex_poin(Tex *tex, int adrcode, int *type ) +/* 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 () { - void *poin=0; + 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) { + Object *ob= base->object; + + /* only update layer when an ipo */ + if (has_ipo_code(ob->ipo, OB_LAY)) { + do_ob_ipo(ob); + base->lay= ob->lay; + } + } + + /* layers for the set...*/ + if (G.scene->set) { + for (base= G.scene->set->base.first; base; base= base->next) { + Object *ob= base->object; + + if (has_ipo_code(ob->ipo, OB_LAY)) { + do_ob_ipo(ob); + base->lay= ob->lay; + } + } + } + + /* 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); + } + } + + /* Texture Blocks */ + for (tex= G.main->tex.first; tex; tex= tex->id.next) { + if (tex->ipo) execute_ipo((ID *)tex, tex->ipo); + } + + /* Material Blocks */ + for (ma= G.main->mat.first; ma; ma= ma->id.next) { + if (ma->ipo) execute_ipo((ID *)ma, ma->ipo); + } + + /* World Blocks */ + for (wo= G.main->world.first; wo; wo= wo->id.next) { + if (wo->ipo) execute_ipo((ID *)wo, wo->ipo); + } + + /* ShapeKey Blocks */ + for (key= G.main->key.first; key; key= key->id.next) { + if (key->ipo) execute_ipo((ID *)key, key->ipo); + } + + /* Lamp Blocks */ + for (la= G.main->lamp.first; la; la= la->id.next) { + if (la->ipo) execute_ipo((ID *)la, la->ipo); + } + + /* Camera Blocks */ + for (ca= G.main->camera.first; ca; ca= ca->id.next) { + if (ca->ipo) execute_ipo((ID *)ca, ca->ipo); + } + + /* Sound Blocks (Old + Unused) */ + for (snd= G.main->sound.first; snd; snd= snd->id.next) { + if (snd->ipo) execute_ipo((ID *)snd, snd->ipo); + } + + /* 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); + } + } + } +} + + +/* --------------------- Assorted ----------------------------- */ + +/* clear delta-transforms on all Objects which use the given IPO block */ +void clear_delta_obipo(Ipo *ipo) +{ + Object *ob; + + /* only search if there's an IPO */ + if (ipo == NULL) + return; + + /* 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); + } + } + } +} + +/* ***************************** IPO - DataAPI ********************************* */ + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!! FIXME - BAD CRUFT WARNING !!!!!!!!!!!!!!!!!!!!!!! + +/* These functions here should be replaced eventually by the Data API, as this is + * inflexible duplication... + */ - switch(adrcode) { +/* --------------------- 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; + + switch (adrcode) { + case AC_QUAT_W: + poin= &(pchan->quat[0]); + pchan->flag |= POSE_ROT; + break; + case AC_QUAT_X: + poin= &(pchan->quat[1]); + pchan->flag |= POSE_ROT; + break; + case AC_QUAT_Y: + poin= &(pchan->quat[2]); + pchan->flag |= POSE_ROT; + break; + case AC_QUAT_Z: + poin= &(pchan->quat[3]); + pchan->flag |= POSE_ROT; + break; + + case AC_LOC_X: + poin= &(pchan->loc[0]); + pchan->flag |= POSE_LOC; + break; + case AC_LOC_Y: + poin= &(pchan->loc[1]); + pchan->flag |= POSE_LOC; + break; + case AC_LOC_Z: + poin= &(pchan->loc[2]); + pchan->flag |= POSE_LOC; + break; + + case AC_SIZE_X: + poin= &(pchan->size[0]); + pchan->flag |= POSE_SIZE; + break; + case AC_SIZE_Y: + poin= &(pchan->size[1]); + pchan->flag |= POSE_SIZE; + break; + case AC_SIZE_Z: + poin= &(pchan->size[2]); + pchan->flag |= POSE_SIZE; + break; + } + + /* return pointer */ + return poin; +} + +/* get texture channel */ +static void *give_tex_poin (Tex *tex, int adrcode, int *type ) +{ + void *poin= NULL; + + switch (adrcode) { case TE_NSIZE: poin= &(tex->noisesize); break; case TE_TURB: @@ -1169,17 +1896,18 @@ static void *give_tex_poin(Tex *tex, int adrcode, int *type ) poin= &(tex->bright); break; case TE_CONTRA: poin= &(tex->contrast); break; - } + /* return pointer */ return poin; } -void *give_mtex_poin(MTex *mtex, int adrcode ) +/* get texture-slot/mapping channel */ +void *give_mtex_poin (MTex *mtex, int adrcode) { - void *poin=0; - - switch(adrcode) { + void *poin= NULL; + + switch (adrcode) { case MAP_OFS_X: poin= &(mtex->ofs[0]); break; case MAP_OFS_Y: @@ -1210,6 +1938,7 @@ void *give_mtex_poin(MTex *mtex, int adrcode ) poin= &(mtex->dispfac); break; } + /* return pointer */ return poin; } @@ -1226,1284 +1955,909 @@ void *give_mtex_poin(MTex *mtex, int adrcode ) /* 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) + +/* general function to get pointer to source/destination data */ +void *get_ipo_poin (ID *id, IpoCurve *icu, int *type) { void *poin= NULL; - Object *ob; - Material *ma; - MTex *mtex; - Tex *tex; - Lamp *la; - Sequence *seq; - World *wo; - ParticleSettings *part; + MTex *mtex= NULL; + /* most channels will have float data, but those with other types will override this */ *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; + /* data is divided into 'blocktypes' based on ID-codes */ + switch (GS(id->name)) { + case ID_OB: /* object channels ----------------------------- */ + { + Object *ob= (Object *)id; - 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; + 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_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]; + 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; - 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; - } - } - 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) + 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; - 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]; - - if(mtex) { - poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) ); - } - } - } - 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; - } - - 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]; - - if(mtex) { - poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) ); } } - } - 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; - } - } - 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; - } - } - 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; - } - } - - return poin; -} - -void set_icu_vars(IpoCurve *icu) -{ - /* defaults. 0.0 for y-extents makes these ignored */ - icu->ymin= icu->ymax= 0.0; - icu->ipo= IPO_BEZ; - - if(icu->blocktype==ID_OB) { - - if(icu->adrcode==OB_LAY) { - icu->ipo= IPO_CONST; - icu->vartype= IPO_BITS; - } - - } - 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 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: - icu->ymax= 2.0; break; + 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: - icu->ipo= IPO_CONST; - icu->vartype= IPO_BITS; break; - case MA_RAYM: - icu->ymax= 1.0; break; + poin= &(ma->mode); *type= IPO_INT_BIT; break; // evil... dumping bitflags directly to user! + case MA_HASIZE: + poin= &(ma->hasize); break; case MA_TRANSLU: - icu->ymax= 1.0; break; - case MA_IOR: - icu->ymin= 1.0; - icu->ymax= 3.0; break; + poin= &(ma->translucency); break; + case MA_RAYM: + poin= &(ma->ray_mirror); break; case MA_FRESMIR: - icu->ymax= 5.0; break; + poin= &(ma->fresnel_mir); break; case MA_FRESMIRI: - icu->ymin= 1.0; - icu->ymax= 5.0; break; + poin= &(ma->fresnel_mir_i); break; case MA_FRESTRA: - icu->ymax= 5.0; break; + poin= &(ma->fresnel_tra); break; case MA_FRESTRAI: - icu->ymin= 1.0; - icu->ymax= 5.0; break; + poin= &(ma->fresnel_tra_i); break; case MA_ADD: - icu->ymax= 1.0; break; - default: - icu->ymax= 1.0; break; + 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))); } } - 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 ID_TE: /* texture channels ----------------------------- */ + { + Tex *tex= (Tex *)id; - 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; + if (tex) + poin= give_tex_poin(tex, icu->adrcode, type); + } + break; + case ID_SEQ: /* sequence channels ----------------------------- */ + { + Sequence *seq= (Sequence *)id; + + switch (icu->adrcode) { + case SEQ_FAC1: + poin= &(seq->facf0); break; } } - } - 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; - + break; + case ID_CU: /* curve channels ----------------------------- */ + { + poin= &(icu->curval); } - } - else if(icu->blocktype==ID_SEQ) { - - icu->ymax= 1.0; - - } - else if(icu->blocktype==ID_CU) { - - icu->ymax= 1.0; - - } - else if(icu->blocktype==ID_WO) { - - if(icu->adrcode < MA_MAP1) { - switch(icu->adrcode) { + 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); + } + 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: - icu->ymax= 5.0; break; + 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: - break; - - default: - icu->ymax= 1.0; - break; + poin= &(wo->starsize); 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; + 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))); } } - } - else if(icu->blocktype==ID_LA) { - if(icu->adrcode < MA_MAP1) { - switch(icu->adrcode) { + break; + case ID_LA: /* lamp channels ----------------------------- */ + { + Lamp *la= (Lamp *)id; + + switch (icu->adrcode) { case LA_ENERGY: - case LA_DIST: - break; - + 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: - icu->ymax= 1.0; break; - case LA_SPOTSI: - icu->ymax= 180.0; break; + poin= &(la->att2); break; case LA_HALOINT: - icu->ymax= 5.0; break; + 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))); } } - 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 ID_CA: /* camera channels ----------------------------- */ + { + Camera *ca= (Camera *)id; + + switch (icu->adrcode) { + case CAM_LENS: + if (ca->type == CAM_ORTHO) + poin= &(ca->ortho_scale); + else + poin= &(ca->lens); 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; + 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; } } - } - 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 ID_SO: /* sound channels ----------------------------- */ + { + bSound *snd= (bSound *)id; - case CAM_SHIFT_X: - case CAM_SHIFT_Y: - icu->ymin= -2.0f; - icu->ymax= 2.0f; - break; + 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; + } } - } - 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; + 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(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; - } - } - else if(icu->blocktype==ID_CO) { - icu->ymin= 0.0; - icu->ymax= 1.0f; } - - /* 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) -{ - IpoCurve *icu; - void *poin; - int type; - - 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); - } + /* return pointer */ + return poin; } -void *get_pchan_ipo_poin(bPoseChannel *pchan, int adrcode) +/* --------------------- IPO-Curve Limits ----------------------------- */ + +/* set limits for IPO-curve + * Note: must be synced with UI and PyAPI + */ +void set_icu_vars (IpoCurve *icu) { - void *poin= NULL; + /* defaults. 0.0 for y-extents makes these ignored */ + icu->ymin= icu->ymax= 0.0; + icu->ipo= IPO_BEZ; - switch (adrcode) { - case AC_QUAT_W: - poin= &(pchan->quat[0]); - pchan->flag |= POSE_ROT; + switch (icu->blocktype) { + case ID_OB: /* object channels ----------------------------- */ + { + if (icu->adrcode == OB_LAY) { + icu->ipo= IPO_CONST; + icu->vartype= IPO_BITS; + } + } break; - case AC_QUAT_X: - poin= &(pchan->quat[1]); - pchan->flag |= POSE_ROT; + 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; + } + } + } break; - case AC_QUAT_Y: - poin= &(pchan->quat[2]); - pchan->flag |= POSE_ROT; + 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 AC_QUAT_Z: - poin= &(pchan->quat[3]); - pchan->flag |= POSE_ROT; + case ID_SEQ: /* sequence channels ----------------------------- */ + { + icu->ymax= 1.0; + } break; - case AC_LOC_X: - poin= &(pchan->loc[0]); - pchan->flag |= POSE_LOC; + case ID_CU: /* curve channels ----------------------------- */ + { + icu->ymax= 1.0; + } break; - case AC_LOC_Y: - poin= &(pchan->loc[1]); - pchan->flag |= POSE_LOC; + 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; + } + } + } break; - case AC_LOC_Z: - poin= &(pchan->loc[2]); - pchan->flag |= POSE_LOC; - break; - case AC_SIZE_X: - poin= &(pchan->size[0]); - pchan->flag |= POSE_SIZE; + 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 AC_SIZE_Y: - poin= &(pchan->size[1]); - pchan->flag |= POSE_SIZE; + 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 AC_SIZE_Z: - poin= &(pchan->size[2]); - pchan->flag |= POSE_SIZE; + 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; - } - return poin; -} - -void execute_action_ipo(bActionChannel *achan, bPoseChannel *pchan) -{ - - 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); + 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; } -/* exception: it does calc for objects... - * now find out why this routine was used anyway! - */ -void do_ipo_nocalc(Ipo *ipo) +/* --------------------- Pointer I/O API ----------------------------- */ + +/* write the given value directly into the given pointer */ +void write_ipo_poin (void *poin, int type, float val) { - 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; - } + /* 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 ID_WO: - wo= G.main->world.first; - while(wo) { - if(wo->ipo==ipo) execute_ipo((ID *)wo, ipo); - wo= wo->id.next; - } + + 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 ID_LA: - la= G.main->lamp.first; - while(la) { - if(la->ipo==ipo) execute_ipo((ID *)la, ipo); - la= la->id.next; - } + + case IPO_INT: + case IPO_INT_BIT: // fixme... directly revealing bitflag combinations is evil! + case IPO_LONG: + *((int *)poin)= (int)val; break; - case ID_CA: - ca= G.main->camera.first; - while(ca) { - if(ca->ipo==ipo) execute_ipo((ID *)ca, ipo); - ca= ca->id.next; - } + + case IPO_SHORT: + case IPO_SHORT_BIT: // fixme... directly revealing bitflag combinations is evil! + *((short *)poin)= (short)val; break; - case ID_SO: - snd= G.main->sound.first; - while(snd) { - if(snd->ipo==ipo) execute_ipo((ID *)snd, ipo); - snd= snd->id.next; - } + + case IPO_CHAR: + case IPO_CHAR_BIT: // fixme... directly revealing bitflag combinations is evil! + *((char *)poin)= (char)val; break; } } -void do_ipo(Ipo *ipo) +/* read the value from the pointer that was obtained */ +float read_ipo_poin (void *poin, int type) { - if(ipo) { - float ctime= frame_to_float(G.scene->r.cfra); - calc_ipo(ipo, ctime); - - do_ipo_nocalc(ipo); - } -} - - - -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; */ - - calc_ipo(ma->ipo, ctime); - - execute_ipo((ID *)ma, ma->ipo); -} - -void do_ob_ipo(Object *ob) -{ - 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); - - /* Patch: remember localview */ - lay= ob->lay & 0xFF000000; - - execute_ipo((ID *)ob, ob->ipo); - - 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 */ - } - } -} - -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); - } - } -} - -void do_seq_ipo(Sequence *seq, int cfra) -{ - float ctime, div; - - /* seq_ipo has an exception: calc both fields immediately */ + float val = 0.0; - 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; - } + /* 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; - /* 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; - } - } - - /* 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; - } - } - } - - - ipo= G.main->ipo.first; - while(ipo) { - if(ipo->id.us && ipo->blocktype!=ID_OB) { - calc_ipo(ipo, ctime); - } - 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; - } - } - -} - - -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); - - *ctime= icu->curval; - return 1; - } - } - - return 0; -} - - -/* ************************** */ - -void clear_delta_obipo(Ipo *ipo) -{ - Object *ob; + 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; - if(ipo==NULL) return; + 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; - 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); - } - } - ob= ob->id.next; + case IPO_CHAR: + case IPO_CHAR_BIT: // fixme... directly revealing bitflag combinations is evil + val= *((char *)poin); + break; } -} - -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; - } - 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); - - cen->cfra= bezt->vec[1][0]; - cen->sel= bezt->f2; + /* return value */ + return val; } +// !!!!!!!!!!!!!!!!!!!!!!!!!!!! FIXME - BAD CRUFT WARNING !!!!!!!!!!!!!!!!!!!!!!! -void make_cfra_list(Ipo *ipo, ListBase *elems) -{ - IpoCurve *icu; - BezTriple *bezt; - int a; - - 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++; - } - } - 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; - } - } - } - } - 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++; - } - } - } - } - } - - /* 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; - } - } -#endif -} - -/* *********************** INTERFACE FOR KETSJI ********** */ - +/* ***************************** IPO <--> GameEngine Interface ********************************* */ -int IPO_GetChannels(Ipo *ipo, IPO_Channel *channels) +/* channels is max 32 items, allocated by calling function */ +short IPO_GetChannels (Ipo *ipo, IPO_Channel *channels) { - /* channels is max 32 items, allocated by calling function */ - 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; } |