Blender  V2.59
fcurve.c
Go to the documentation of this file.
00001 /*
00002  * $Id: fcurve.c 36779 2011-05-19 12:39:57Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): Joshua Leung (full recode)
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00036 #include <math.h>
00037 #include <stdio.h>
00038 #include <stddef.h>
00039 #include <string.h>
00040 #include <float.h>
00041 
00042 #include "MEM_guardedalloc.h"
00043 
00044 #include "DNA_anim_types.h"
00045 #include "DNA_object_types.h"
00046 
00047 #include "BLI_blenlib.h"
00048 #include "BLI_math.h"
00049 #include "BLI_utildefines.h"
00050 
00051 #include "BKE_fcurve.h"
00052 #include "BKE_animsys.h"
00053 #include "BKE_action.h"
00054 #include "BKE_armature.h"
00055 #include "BKE_curve.h" 
00056 #include "BKE_global.h"
00057 #include "BKE_object.h"
00058 #include "BKE_utildefines.h"
00059 
00060 #include "RNA_access.h"
00061 
00062 #ifdef WITH_PYTHON
00063 #include "BPY_extern.h" 
00064 #endif
00065 
00066 #define SMALL -1.0e-10
00067 #define SELECT 1
00068 
00069 /* ************************** Data-Level Functions ************************* */
00070 
00071 /* ---------------------- Freeing --------------------------- */
00072 
00073 /* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */
00074 void free_fcurve (FCurve *fcu) 
00075 {
00076         if (fcu == NULL) 
00077                 return;
00078         
00079         /* free curve data */
00080         if (fcu) {
00081                 if (fcu->bezt) MEM_freeN(fcu->bezt);
00082                 if (fcu->fpt) MEM_freeN(fcu->fpt);
00083         }
00084         
00085         /* free RNA-path, as this were allocated when getting the path string */
00086         if (fcu->rna_path)
00087                 MEM_freeN(fcu->rna_path);
00088         
00089         /* free extra data - i.e. modifiers, and driver */
00090         fcurve_free_driver(fcu);
00091         free_fmodifiers(&fcu->modifiers);
00092         
00093         /* free f-curve itself */
00094         MEM_freeN(fcu);
00095 }
00096 
00097 /* Frees a list of F-Curves */
00098 void free_fcurves (ListBase *list)
00099 {
00100         FCurve *fcu, *fcn;
00101         
00102         /* sanity check */
00103         if (list == NULL)
00104                 return;
00105                 
00106         /* free data - no need to call remlink before freeing each curve, 
00107          * as we store reference to next, and freeing only touches the curve
00108          * it's given
00109          */
00110         for (fcu= list->first; fcu; fcu= fcn) {
00111                 fcn= fcu->next;
00112                 free_fcurve(fcu);
00113         }
00114         
00115         /* clear pointers just in case */
00116         list->first= list->last= NULL;
00117 }       
00118 
00119 /* ---------------------- Copy --------------------------- */
00120 
00121 /* duplicate an F-Curve */
00122 FCurve *copy_fcurve (FCurve *fcu)
00123 {
00124         FCurve *fcu_d;
00125         
00126         /* sanity check */
00127         if (fcu == NULL)
00128                 return NULL;
00129                 
00130         /* make a copy */
00131         fcu_d= MEM_dupallocN(fcu);
00132         
00133         fcu_d->next= fcu_d->prev= NULL;
00134         fcu_d->grp= NULL;
00135         
00136         /* copy curve data */
00137         fcu_d->bezt= MEM_dupallocN(fcu_d->bezt);
00138         fcu_d->fpt= MEM_dupallocN(fcu_d->fpt);
00139         
00140         /* copy rna-path */
00141         fcu_d->rna_path= MEM_dupallocN(fcu_d->rna_path);
00142         
00143         /* copy driver */
00144         fcu_d->driver= fcurve_copy_driver(fcu_d->driver);
00145         
00146         /* copy modifiers */
00147         copy_fmodifiers(&fcu_d->modifiers, &fcu->modifiers);
00148         
00149         /* return new data */
00150         return fcu_d;
00151 }
00152 
00153 /* duplicate a list of F-Curves */
00154 void copy_fcurves (ListBase *dst, ListBase *src)
00155 {
00156         FCurve *dfcu, *sfcu;
00157         
00158         /* sanity checks */
00159         if ELEM(NULL, dst, src)
00160                 return;
00161         
00162         /* clear destination list first */
00163         dst->first= dst->last= NULL;
00164         
00165         /* copy one-by-one */
00166         for (sfcu= src->first; sfcu; sfcu= sfcu->next) {
00167                 dfcu= copy_fcurve(sfcu);
00168                 BLI_addtail(dst, dfcu);
00169         }
00170 }
00171 
00172 /* ----------------- Finding F-Curves -------------------------- */
00173 
00174 /* high level function to get an fcurve from C without having the rna */
00175 FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index)
00176 {
00177         /* anim vars */
00178         AnimData *adt= BKE_animdata_from_id(id);
00179         FCurve *fcu= NULL;
00180 
00181         /* rna vars */
00182         PointerRNA ptr;
00183         PropertyRNA *prop;
00184         char *path;
00185         
00186         /* only use the current action ??? */
00187         if (ELEM(NULL, adt, adt->action))
00188                 return NULL;
00189         
00190         RNA_pointer_create(id, type, data, &ptr);
00191         prop = RNA_struct_find_property(&ptr, prop_name);
00192         
00193         if (prop) {
00194                 path= RNA_path_from_ID_to_property(&ptr, prop);
00195                         
00196                 if (path) {
00197                         /* animation takes priority over drivers */
00198                         if ((adt->action) && (adt->action->curves.first))
00199                                 fcu= list_find_fcurve(&adt->action->curves, path, index);
00200                         
00201                         /* if not animated, check if driven */
00202 #if 0
00203                         if ((fcu == NULL) && (adt->drivers.first)) {
00204                                 fcu= list_find_fcurve(&adt->drivers, path, but->rnaindex);
00205                         }
00206 #endif
00207                         
00208                         MEM_freeN(path);
00209                 }
00210         }
00211 
00212         return fcu;
00213 }
00214 
00215 
00216 /* Find the F-Curve affecting the given RNA-access path + index, in the list of F-Curves provided */
00217 FCurve *list_find_fcurve (ListBase *list, const char rna_path[], const int array_index)
00218 {
00219         FCurve *fcu;
00220         
00221         /* sanity checks */
00222         if ( ELEM(NULL, list, rna_path) || (array_index < 0) )
00223                 return NULL;
00224         
00225         /* check paths of curves, then array indices... */
00226         for (fcu= list->first; fcu; fcu= fcu->next) {
00227                 /* simple string-compare (this assumes that they have the same root...) */
00228                 if (fcu->rna_path && !strcmp(fcu->rna_path, rna_path)) {
00229                         /* now check indices */
00230                         if (fcu->array_index == array_index)
00231                                 return fcu;
00232                 }
00233         }
00234         
00235         /* return */
00236         return NULL;
00237 }
00238 
00239 /* quick way to loop over all fcurves of a given 'path' */
00240 FCurve *iter_step_fcurve (FCurve *fcu_iter, const char rna_path[])
00241 {
00242         FCurve *fcu;
00243         
00244         /* sanity checks */
00245         if (ELEM(NULL, fcu_iter, rna_path))
00246                 return NULL;
00247 
00248         /* check paths of curves, then array indices... */
00249         for (fcu= fcu_iter; fcu; fcu= fcu->next) {
00250                 /* simple string-compare (this assumes that they have the same root...) */
00251                 if (fcu->rna_path && !strcmp(fcu->rna_path, rna_path)) {
00252                         return fcu;
00253                 }
00254         }
00255 
00256         /* return */
00257         return NULL;
00258 }
00259 
00260 /* Get list of LinkData's containing pointers to the F-Curves which control the types of data indicated 
00261  * Lists...
00262  *      - dst: list of LinkData's matching the criteria returned. 
00263  *        List must be freed after use, and is assumed to be empty when passed.
00264  *      - src: list of F-Curves to search through
00265  * Filters...
00266  *      - dataPrefix: i.e. 'pose.bones[' or 'nodes['
00267  *      - dataName: name of entity within "" immediately following the prefix
00268  */
00269 int list_find_data_fcurves (ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName)
00270 {
00271         FCurve *fcu;
00272         int matches = 0;
00273         
00274         /* sanity checks */
00275         if (ELEM4(NULL, dst, src, dataPrefix, dataName))
00276                 return 0;
00277         else if ((dataPrefix[0] == 0) || (dataName[0] == 0))
00278                 return 0;
00279         
00280         /* search each F-Curve one by one */
00281         for (fcu= src->first; fcu; fcu= fcu->next) {
00282                 /* check if quoted string matches the path */
00283                 if ((fcu->rna_path) && strstr(fcu->rna_path, dataPrefix)) {
00284                         char *quotedName= BLI_getQuotedStr(fcu->rna_path, dataPrefix);
00285                         
00286                         if (quotedName) {
00287                                 /* check if the quoted name matches the required name */
00288                                 if (strcmp(quotedName, dataName) == 0) {
00289                                         LinkData *ld= MEM_callocN(sizeof(LinkData), "list_find_data_fcurves");
00290                                         
00291                                         ld->data= fcu;
00292                                         BLI_addtail(dst, ld);
00293                                         
00294                                         matches++;
00295                                 }
00296                                 
00297                                 /* always free the quoted string, since it needs freeing */
00298                                 MEM_freeN(quotedName);
00299                         }
00300                 }
00301         }
00302         
00303         /* return the number of matches */
00304         return matches;
00305 }
00306 
00307 FCurve *rna_get_fcurve (PointerRNA *ptr, PropertyRNA *prop, int rnaindex, bAction **action, int *driven)
00308 {
00309         FCurve *fcu= NULL;
00310         
00311         *driven= 0;
00312         
00313         /* there must be some RNA-pointer + property combon */
00314         if (prop && ptr->id.data && RNA_property_animateable(ptr, prop)) {
00315                 AnimData *adt= BKE_animdata_from_id(ptr->id.data);
00316                 char *path;
00317                 
00318                 if (adt) {
00319                         if ((adt->action && adt->action->curves.first) || (adt->drivers.first)) {
00320                                 /* XXX this function call can become a performance bottleneck */
00321                                 path= RNA_path_from_ID_to_property(ptr, prop);
00322                                 
00323                                 if (path) {
00324                                         /* animation takes priority over drivers */
00325                                         if (adt->action && adt->action->curves.first)
00326                                                 fcu= list_find_fcurve(&adt->action->curves, path, rnaindex);
00327                                         
00328                                         /* if not animated, check if driven */
00329                                         if (!fcu && (adt->drivers.first)) {
00330                                                 fcu= list_find_fcurve(&adt->drivers, path, rnaindex);
00331                                                 
00332                                                 if (fcu)
00333                                                         *driven= 1;
00334                                         }
00335                                         
00336                                         if (fcu && action)
00337                                                 *action= adt->action;
00338                                         
00339                                         MEM_freeN(path);
00340                                 }
00341                         }
00342                 }
00343         }
00344         
00345         return fcu;
00346 }
00347 
00348 /* ----------------- Finding Keyframes/Extents -------------------------- */
00349 
00350 /* threshold for binary-searching keyframes - threshold here should be good enough for now, but should become userpref */
00351 #define BEZT_BINARYSEARCH_THRESH        0.01f /* was 0.00001, but giving errors */
00352 
00353 /* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve)
00354  * Returns the index to insert at (data already at that index will be offset if replace is 0)
00355  */
00356 int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen, short *replace)
00357 {
00358         int start=0, end=arraylen;
00359         int loopbreaker= 0, maxloop= arraylen * 2;
00360         
00361         /* initialise replace-flag first */
00362         *replace= 0;
00363         
00364         /* sneaky optimisations (don't go through searching process if...):
00365          *      - keyframe to be added is to be added out of current bounds
00366          *      - keyframe to be added would replace one of the existing ones on bounds
00367          */
00368         if ((arraylen <= 0) || (array == NULL)) {
00369                 printf("Warning: binarysearch_bezt_index() encountered invalid array \n");
00370                 return 0;
00371         }
00372         else {
00373                 /* check whether to add before/after/on */
00374                 float framenum;
00375                 
00376                 /* 'First' Keyframe (when only one keyframe, this case is used) */
00377                 framenum= array[0].vec[1][0];
00378                 if (IS_EQT(frame, framenum, BEZT_BINARYSEARCH_THRESH)) {
00379                         *replace = 1;
00380                         return 0;
00381                 }
00382                 else if (frame < framenum)
00383                         return 0;
00384                         
00385                 /* 'Last' Keyframe */
00386                 framenum= array[(arraylen-1)].vec[1][0];
00387                 if (IS_EQT(frame, framenum, BEZT_BINARYSEARCH_THRESH)) {
00388                         *replace= 1;
00389                         return (arraylen - 1);
00390                 }
00391                 else if (frame > framenum)
00392                         return arraylen;
00393         }
00394         
00395         
00396         /* most of the time, this loop is just to find where to put it
00397          * 'loopbreaker' is just here to prevent infinite loops 
00398          */
00399         for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
00400                 /* compute and get midpoint */
00401                 int mid = start + ((end - start) / 2);  /* we calculate the midpoint this way to avoid int overflows... */
00402                 float midfra= array[mid].vec[1][0];
00403                 
00404                 /* check if exactly equal to midpoint */
00405                 if (IS_EQT(frame, midfra, BEZT_BINARYSEARCH_THRESH)) {
00406                         *replace = 1;
00407                         return mid;
00408                 }
00409                 
00410                 /* repeat in upper/lower half */
00411                 if (frame > midfra)
00412                         start= mid + 1;
00413                 else if (frame < midfra)
00414                         end= mid - 1;
00415         }
00416         
00417         /* print error if loop-limit exceeded */
00418         if (loopbreaker == (maxloop-1)) {
00419                 printf("Error: binarysearch_bezt_index() was taking too long \n");
00420                 
00421                 // include debug info 
00422                 printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
00423         }
00424         
00425         /* not found, so return where to place it */
00426         return start;
00427 }
00428 
00429 /* ...................................... */
00430 
00431 /* helper for calc_fcurve_* functions -> find first and last BezTriple to be used */
00432 static void get_fcurve_end_keyframes (FCurve *fcu, BezTriple **first, BezTriple **last, const short selOnly)
00433 {
00434         /* init outputs */
00435         *first = NULL;
00436         *last = NULL;
00437         
00438         /* sanity checks */
00439         if (fcu->bezt == NULL)
00440                 return;
00441         
00442         /* only include selected items? */
00443         if (selOnly) {
00444                 BezTriple *bezt;
00445                 unsigned int i;
00446                 
00447                 /* find first selected */
00448                 bezt = fcu->bezt;
00449                 for (i=0; i < fcu->totvert; bezt++, i++) {
00450                         if (BEZSELECTED(bezt)) {
00451                                 *first= bezt;
00452                                 break;
00453                         }
00454                 }
00455                 
00456                 /* find last selected */
00457                 bezt = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, sizeof(BezTriple), fcu->totvert);
00458                 for (i=0; i < fcu->totvert; bezt--, i++) {
00459                         if (BEZSELECTED(bezt)) {
00460                                 *last= bezt;
00461                                 break;
00462                         }
00463                 }
00464         }
00465         else {
00466                 /* just full array */
00467                 *first = fcu->bezt;
00468                 *last = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, sizeof(BezTriple), fcu->totvert);
00469         }
00470 }
00471 
00472 
00473 /* Calculate the extents of F-Curve's data */
00474 void calc_fcurve_bounds (FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax, const short selOnly)
00475 {
00476         float xminv=999999999.0f, xmaxv=-999999999.0f;
00477         float yminv=999999999.0f, ymaxv=-999999999.0f;
00478         short foundvert=0;
00479         unsigned int i;
00480         
00481         if (fcu->totvert) {
00482                 if (fcu->bezt) {
00483                         BezTriple *bezt_first= NULL, *bezt_last= NULL;
00484                         
00485                         if (xmin || xmax) {
00486                                 /* get endpoint keyframes */
00487                                 get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, selOnly);
00488                                 
00489                                 if (bezt_first) {
00490                                         BLI_assert(bezt_last != NULL);
00491                                         
00492                                         xminv= MIN2(xminv, bezt_first->vec[1][0]);
00493                                         xmaxv= MAX2(xmaxv, bezt_last->vec[1][0]);
00494                                 }
00495                         }
00496                         
00497                         /* only loop over keyframes to find extents for values if needed */
00498                         if (ymin || ymax) {     
00499                                 BezTriple *bezt;
00500                                 
00501                                 for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) {
00502                                         if ((selOnly == 0) || BEZSELECTED(bezt)) {
00503                                                 if (bezt->vec[1][1] < yminv)
00504                                                         yminv= bezt->vec[1][1];
00505                                                 if (bezt->vec[1][1] > ymaxv)
00506                                                         ymaxv= bezt->vec[1][1];
00507                                         }
00508                                 }
00509                         }
00510                 }
00511                 else if (fcu->fpt) {
00512                         /* frame range can be directly calculated from end verts */
00513                         if (xmin || xmax) {
00514                                 xminv= MIN2(xminv, fcu->fpt[0].vec[0]);
00515                                 xmaxv= MAX2(xmaxv, fcu->fpt[fcu->totvert-1].vec[0]);
00516                         }
00517                         
00518                         /* only loop over keyframes to find extents for values if needed */
00519                         if (ymin || ymax) {
00520                                 FPoint *fpt;
00521                                 
00522                                 for (fpt=fcu->fpt, i=0; i < fcu->totvert; fpt++, i++) {
00523                                         if (fpt->vec[1] < yminv)
00524                                                 yminv= fpt->vec[1];
00525                                         if (fpt->vec[1] > ymaxv)
00526                                                 ymaxv= fpt->vec[1];
00527                                 }
00528                         }
00529                 }
00530                 
00531                 foundvert=1;
00532         }
00533         
00534         if (foundvert) {
00535                 if (xmin) *xmin= xminv;
00536                 if (xmax) *xmax= xmaxv;
00537                 
00538                 if (ymin) *ymin= yminv;
00539                 if (ymax) *ymax= ymaxv;
00540         }
00541         else {
00542                 if (G.f & G_DEBUG)
00543                         printf("F-Curve calc bounds didn't find anything, so assuming minimum bounds of 1.0\n");
00544                         
00545                 if (xmin) *xmin= 0.0f;
00546                 if (xmax) *xmax= 1.0f;
00547                 
00548                 if (ymin) *ymin= 0.0f;
00549                 if (ymax) *ymax= 1.0f;
00550         }
00551 }
00552 
00553 /* Calculate the extents of F-Curve's keyframes */
00554 void calc_fcurve_range (FCurve *fcu, float *start, float *end, const short selOnly)
00555 {
00556         float min=999999999.0f, max=-999999999.0f;
00557         short foundvert=0;
00558 
00559         if (fcu->totvert) {
00560                 if (fcu->bezt) {
00561                         BezTriple *bezt_first= NULL, *bezt_last= NULL;
00562                         
00563                         /* get endpoint keyframes */
00564                         get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, selOnly);
00565                         
00566                         if (bezt_first) {
00567                                 BLI_assert(bezt_last != NULL);
00568                                 
00569                                 min= MIN2(min, bezt_first->vec[1][0]);
00570                                 max= MAX2(max, bezt_last->vec[1][0]);
00571                         }
00572                 }
00573                 else if (fcu->fpt) {
00574                         min= MIN2(min, fcu->fpt[0].vec[0]);
00575                         max= MAX2(max, fcu->fpt[fcu->totvert-1].vec[0]);
00576                 }
00577                 
00578                 foundvert=1;
00579         }
00580         
00581         /* minimum length is 1 frame */
00582         if (foundvert) {
00583                 if (min == max) max += 1.0f;
00584                 *start= min;
00585                 *end= max;
00586         }
00587         else {
00588                 *start= 0.0f;
00589                 *end= 1.0f;
00590         }
00591 }
00592 
00593 /* ----------------- Status Checks -------------------------- */
00594 
00595 /* Are keyframes on F-Curve of any use? 
00596  * Usability of keyframes refers to whether they should be displayed,
00597  * and also whether they will have any influence on the final result.
00598  */
00599 short fcurve_are_keyframes_usable (FCurve *fcu)
00600 {
00601         /* F-Curve must exist */
00602         if (fcu == NULL)
00603                 return 0;
00604                 
00605         /* F-Curve must not have samples - samples are mutually exclusive of keyframes */
00606         if (fcu->fpt)
00607                 return 0;
00608         
00609         /* if it has modifiers, none of these should "drastically" alter the curve */
00610         if (fcu->modifiers.first) {
00611                 FModifier *fcm;
00612                 
00613                 /* check modifiers from last to first, as last will be more influential */
00614                 // TODO: optionally, only check modifier if it is the active one...
00615                 for (fcm = fcu->modifiers.last; fcm; fcm = fcm->prev) {
00616                         /* ignore if muted/disabled */
00617                         if (fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED))
00618                                 continue;
00619                                 
00620                         /* type checks */
00621                         switch (fcm->type) {
00622                                 /* clearly harmless - do nothing */
00623                                 case FMODIFIER_TYPE_CYCLES:
00624                                 case FMODIFIER_TYPE_STEPPED:
00625                                 case FMODIFIER_TYPE_NOISE:
00626                                         break;
00627                                         
00628                                 /* sometimes harmful - depending on whether they're "additive" or not */
00629                                 case FMODIFIER_TYPE_GENERATOR:
00630                                 {
00631                                         FMod_Generator *data = (FMod_Generator *)fcm->data;
00632                                         
00633                                         if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
00634                                                 return 0;
00635                                 }
00636                                         break;
00637                                 case FMODIFIER_TYPE_FN_GENERATOR:
00638                                 {
00639                                         FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)fcm->data;
00640                                         
00641                                         if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
00642                                                 return 0;
00643                                 }
00644                                         break;
00645                                         
00646                                 /* always harmful - cannot allow */
00647                                 default:
00648                                         return 0;
00649                         }
00650                 }
00651         }
00652         
00653         /* keyframes are usable */
00654         return 1;
00655 }
00656 
00657 /* Can keyframes be added to F-Curve? 
00658  * Keyframes can only be added if they are already visible
00659  */
00660 short fcurve_is_keyframable (FCurve *fcu)
00661 {
00662         /* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
00663         if (fcurve_are_keyframes_usable(fcu) == 0)
00664                 return 0;
00665                 
00666         /* F-Curve must currently be editable too */
00667         if ( (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) )
00668                 return 0;
00669         
00670         /* F-Curve is keyframable */
00671         return 1;
00672 }
00673 
00674 /* ***************************** Keyframe Column Tools ********************************* */
00675 
00676 /* add a BezTriple to a column */
00677 void bezt_add_to_cfra_elem (ListBase *lb, BezTriple *bezt)
00678 {
00679         CfraElem *ce, *cen;
00680         
00681         for (ce= lb->first; ce; ce= ce->next) {
00682                 /* double key? */
00683                 if (ce->cfra == bezt->vec[1][0]) {
00684                         if (bezt->f2 & SELECT) ce->sel= bezt->f2;
00685                         return;
00686                 }
00687                 /* should key be inserted before this column? */
00688                 else if (ce->cfra > bezt->vec[1][0]) break;
00689         }
00690         
00691         /* create a new column */
00692         cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); 
00693         if (ce) BLI_insertlinkbefore(lb, ce, cen);
00694         else BLI_addtail(lb, cen);
00695 
00696         cen->cfra= bezt->vec[1][0];
00697         cen->sel= bezt->f2;
00698 }
00699 
00700 /* ***************************** Samples Utilities ******************************* */
00701 /* Some utilities for working with FPoints (i.e. 'sampled' animation curve data, such as
00702  * data imported from BVH/Mocap files), which are specialised for use with high density datasets,
00703  * which BezTriples/Keyframe data are ill equipped to do.
00704  */
00705  
00706  
00707 /* Basic sampling callback which acts as a wrapper for evaluate_fcurve() 
00708  *      'data' arg here is unneeded here...
00709  */
00710 float fcurve_samplingcb_evalcurve (FCurve *fcu, void *UNUSED(data), float evaltime)
00711 {
00712         /* assume any interference from drivers on the curve is intended... */
00713         return evaluate_fcurve(fcu, evaltime);
00714 } 
00715 
00716  
00717 /* Main API function for creating a set of sampled curve data, given some callback function 
00718  * used to retrieve the values to store.
00719  */
00720 void fcurve_store_samples (FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
00721 {
00722         FPoint *fpt, *new_fpt;
00723         int cfra;
00724         
00725         /* sanity checks */
00726         // TODO: make these tests report errors using reports not printf's
00727         if ELEM(NULL, fcu, sample_cb) {
00728                 printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
00729                 return;
00730         }
00731         if (start >= end) {
00732                 printf("Error: Frame range for Sampled F-Curve creation is inappropriate \n");
00733                 return;
00734         }
00735         
00736         /* set up sample data */
00737         fpt= new_fpt= MEM_callocN(sizeof(FPoint)*(end-start+1), "FPoint Samples");
00738         
00739         /* use the sampling callback at 1-frame intervals from start to end frames */
00740         for (cfra= start; cfra <= end; cfra++, fpt++) {
00741                 fpt->vec[0]= (float)cfra;
00742                 fpt->vec[1]= sample_cb(fcu, data, (float)cfra);
00743         }
00744         
00745         /* free any existing sample/keyframe data on curve  */
00746         if (fcu->bezt) MEM_freeN(fcu->bezt);
00747         if (fcu->fpt) MEM_freeN(fcu->fpt);
00748         
00749         /* store the samples */
00750         fcu->bezt= NULL;
00751         fcu->fpt= new_fpt;
00752         fcu->totvert= end - start + 1;
00753 }
00754 
00755 /* ***************************** F-Curve Sanity ********************************* */
00756 /* The functions here are used in various parts of Blender, usually after some editing
00757  * of keyframe data has occurred. They ensure that keyframe data is properly ordered and
00758  * that the handles are correctly 
00759  */
00760 
00761 /* This function recalculates the handles of an F-Curve 
00762  * If the BezTriples have been rearranged, sort them first before using this.
00763  */
00764 void calchandles_fcurve (FCurve *fcu)
00765 {
00766         BezTriple *bezt, *prev, *next;
00767         int a= fcu->totvert;
00768 
00769         /* Error checking:
00770          *      - need at least two points
00771          *      - need bezier keys
00772          *      - only bezier-interpolation has handles (for now)
00773          */
00774         if (ELEM(NULL, fcu, fcu->bezt) || (a < 2) /*|| ELEM(fcu->ipo, BEZT_IPO_CONST, BEZT_IPO_LIN)*/) 
00775                 return;
00776         
00777         /* get initial pointers */
00778         bezt= fcu->bezt;
00779         prev= NULL;
00780         next= (bezt + 1);
00781         
00782         /* loop over all beztriples, adjusting handles */
00783         while (a--) {
00784                 /* clamp timing of handles to be on either side of beztriple */
00785                 if (bezt->vec[0][0] > bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0];
00786                 if (bezt->vec[2][0] < bezt->vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0];
00787                 
00788                 /* calculate auto-handles */
00789                 if (fcu->flag & FCURVE_AUTO_HANDLES) 
00790                         calchandleNurb(bezt, prev, next, 2);    /* 2==special autohandle && keep extrema horizontal */
00791                 else
00792                         calchandleNurb(bezt, prev, next, 1);    /* 1==special autohandle */
00793                 
00794                 /* for automatic ease in and out */
00795                 if ((bezt->h1==HD_AUTO) && (bezt->h2==HD_AUTO)) {
00796                         /* only do this on first or last beztriple */
00797                         if ((a == 0) || (a == fcu->totvert-1)) {
00798                                 /* set both handles to have same horizontal value as keyframe */
00799                                 if (fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) {
00800                                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
00801                                 }
00802                         }
00803                 }
00804                 
00805                 /* advance pointers for next iteration */
00806                 prev= bezt;
00807                 if (a == 1) next= NULL;
00808                 else next++;
00809                 bezt++;
00810         }
00811 }
00812 
00813 /* Use when F-Curve with handles has changed
00814  * It treats all BezTriples with the following rules:
00815  *  - PHASE 1: do types have to be altered?
00816  *              -> Auto handles: become aligned when selection status is NOT(000 || 111)
00817  *              -> Vector handles: become 'nothing' when (one half selected AND other not)
00818  *  - PHASE 2: recalculate handles
00819 */
00820 void testhandles_fcurve (FCurve *fcu)
00821 {
00822         BezTriple *bezt;
00823         unsigned int a;
00824 
00825         /* only beztriples have handles (bpoints don't though) */
00826         if ELEM(NULL, fcu, fcu->bezt)
00827                 return;
00828         
00829         /* loop over beztriples */
00830         for (a=0, bezt=fcu->bezt; a < fcu->totvert; a++, bezt++) {
00831                 short flag= 0;
00832                 
00833                 /* flag is initialised as selection status
00834                  * of beztriple control-points (labelled 0,1,2)
00835                  */
00836                 if (bezt->f1 & SELECT) flag |= (1<<0); // == 1
00837                 if (bezt->f2 & SELECT) flag |= (1<<1); // == 2
00838                 if (bezt->f3 & SELECT) flag |= (1<<2); // == 4
00839                 
00840                 /* one or two handles selected only */
00841                 if (ELEM(flag, 0, 7)==0) {
00842                         /* auto handles become aligned */
00843                         if (bezt->h1==HD_AUTO)
00844                                 bezt->h1= HD_ALIGN;
00845                         if (bezt->h2==HD_AUTO)
00846                                 bezt->h2= HD_ALIGN;
00847                         
00848                         /* vector handles become 'free' when only one half selected */
00849                         if (bezt->h1==HD_VECT) {
00850                                 /* only left half (1 or 2 or 1+2) */
00851                                 if (flag < 4) 
00852                                         bezt->h1= 0;
00853                         }
00854                         if (bezt->h2==HD_VECT) {
00855                                 /* only right half (4 or 2+4) */
00856                                 if (flag > 3) 
00857                                         bezt->h2= 0;
00858                         }
00859                 }
00860         }
00861 
00862         /* recalculate handles */
00863         calchandles_fcurve(fcu);
00864 }
00865 
00866 /* This function sorts BezTriples so that they are arranged in chronological order,
00867  * as tools working on F-Curves expect that the BezTriples are in order.
00868  */
00869 void sort_time_fcurve (FCurve *fcu)
00870 {
00871         short ok= 1;
00872         
00873         /* keep adjusting order of beztriples until nothing moves (bubble-sort) */
00874         while (ok) {
00875                 ok= 0;
00876                 
00877                 /* currently, will only be needed when there are beztriples */
00878                 if (fcu->bezt) {
00879                         BezTriple *bezt;
00880                         unsigned int a;
00881                         
00882                         /* loop over ALL points to adjust position in array and recalculate handles */
00883                         for (a=0, bezt=fcu->bezt; a < fcu->totvert; a++, bezt++) {
00884                                 /* check if thee's a next beztriple which we could try to swap with current */
00885                                 if (a < (fcu->totvert-1)) {
00886                                         /* swap if one is after the other (and indicate that order has changed) */
00887                                         if (bezt->vec[1][0] > (bezt+1)->vec[1][0]) {
00888                                                 SWAP(BezTriple, *bezt, *(bezt+1));
00889                                                 ok= 1;
00890                                         }
00891                                         
00892                                         /* if either one of both of the points exceeds crosses over the keyframe time... */
00893                                         if ( (bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0]) ) {
00894                                                 /* swap handles if they have switched sides for some reason */
00895                                                 SWAP(float, bezt->vec[0][0], bezt->vec[2][0]);
00896                                                 SWAP(float, bezt->vec[0][1], bezt->vec[2][1]);
00897                                         }
00898                                         else {
00899                                                 /* clamp handles */
00900                                                 if (bezt->vec[0][0] > bezt->vec[1][0]) 
00901                                                         bezt->vec[0][0]= bezt->vec[1][0];
00902                                                 if (bezt->vec[2][0] < bezt->vec[1][0]) 
00903                                                         bezt->vec[2][0]= bezt->vec[1][0];
00904                                         }
00905                                 }
00906                         }
00907                 }
00908         }
00909 }
00910 
00911 /* This function tests if any BezTriples are out of order, thus requiring a sort */
00912 short test_time_fcurve (FCurve *fcu)
00913 {
00914         unsigned int a;
00915         
00916         /* sanity checks */
00917         if (fcu == NULL)
00918                 return 0;
00919         
00920         /* currently, only need to test beztriples */
00921         if (fcu->bezt) {
00922                 BezTriple *bezt;
00923                 
00924                 /* loop through all BezTriples, stopping when one exceeds the one after it */
00925                 for (a=0, bezt= fcu->bezt; a < (fcu->totvert - 1); a++, bezt++) {
00926                         if (bezt->vec[1][0] > (bezt+1)->vec[1][0])
00927                                 return 1;
00928                 }
00929         }
00930         else if (fcu->fpt) {
00931                 FPoint *fpt;
00932                 
00933                 /* loop through all FPoints, stopping when one exceeds the one after it */
00934                 for (a=0, fpt= fcu->fpt; a < (fcu->totvert - 1); a++, fpt++) {
00935                         if (fpt->vec[0] > (fpt+1)->vec[0])
00936                                 return 1;
00937                 }
00938         }
00939         
00940         /* none need any swapping */
00941         return 0;
00942 }
00943 
00944 /* ***************************** Drivers ********************************* */
00945 
00946 /* Driver Variables --------------------------- */
00947 
00948 /* TypeInfo for Driver Variables (dvti) */
00949 typedef struct DriverVarTypeInfo {
00950         /* evaluation callback */
00951         float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
00952         
00953         /* allocation of target slots */
00954         int num_targets;                                                /* number of target slots required */
00955         const char *target_names[MAX_DRIVER_TARGETS];   /* UI names that should be given to the slots */
00956         int target_flags[MAX_DRIVER_TARGETS];   /* flags defining the requirements for each slot */
00957 } DriverVarTypeInfo;
00958 
00959 /* Macro to begin definitions */
00960 #define BEGIN_DVAR_TYPEDEF(type) \
00961         {
00962         
00963 /* Macro to end definitions */
00964 #define END_DVAR_TYPEDEF \
00965         }
00966 
00967 /* ......... */
00968 
00969 static ID *dtar_id_ensure_proxy_from(ID *id)
00970 {
00971         if (id && GS(id->name)==ID_OB && ((Object *)id)->proxy_from)
00972                 return (ID *)(((Object *)id)->proxy_from);
00973         return id;
00974 }
00975 
00976 /* Helper function to obtain a value using RNA from the specified source (for evaluating drivers) */
00977 static float dtar_get_prop_val (ChannelDriver *driver, DriverTarget *dtar)
00978 {
00979         PointerRNA id_ptr, ptr;
00980         PropertyRNA *prop;
00981         ID *id;
00982         int index;
00983         float value= 0.0f;
00984         
00985         /* sanity check */
00986         if ELEM(NULL, driver, dtar)
00987                 return 0.0f;
00988         
00989         id= dtar_id_ensure_proxy_from(dtar->id);
00990         
00991         /* error check for missing pointer... */
00992         // TODO: tag the specific target too as having issues
00993         if (id == NULL) {
00994                 printf("Error: driver has an invalid target to use \n");
00995                 if (G.f & G_DEBUG) printf("\tpath = %s\n", dtar->rna_path);
00996                 driver->flag |= DRIVER_FLAG_INVALID;
00997                 return 0.0f;
00998         }
00999         
01000         /* get RNA-pointer for the ID-block given in target */
01001         RNA_id_pointer_create(id, &id_ptr);
01002         
01003         /* get property to read from, and get value as appropriate */
01004         if (RNA_path_resolve_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
01005                 if(RNA_property_array_check(&ptr, prop)) {
01006                         /* array */
01007                         if (index < RNA_property_array_length(&ptr, prop)) {    
01008                                 switch (RNA_property_type(prop)) {
01009                                 case PROP_BOOLEAN:
01010                                         value= (float)RNA_property_boolean_get_index(&ptr, prop, index);
01011                                         break;
01012                                 case PROP_INT:
01013                                         value= (float)RNA_property_int_get_index(&ptr, prop, index);
01014                                         break;
01015                                 case PROP_FLOAT:
01016                                         value= RNA_property_float_get_index(&ptr, prop, index);
01017                                         break;
01018                                 default:
01019                                         break;
01020                                 }
01021                         }
01022                 }
01023                 else {
01024                         /* not an array */
01025                         switch (RNA_property_type(prop)) {
01026                         case PROP_BOOLEAN:
01027                                 value= (float)RNA_property_boolean_get(&ptr, prop);
01028                                 break;
01029                         case PROP_INT:
01030                                 value= (float)RNA_property_int_get(&ptr, prop);
01031                                 break;
01032                         case PROP_FLOAT:
01033                                 value= RNA_property_float_get(&ptr, prop);
01034                                 break;
01035                         case PROP_ENUM:
01036                                 value= (float)RNA_property_enum_get(&ptr, prop);
01037                                 break;
01038                         default:
01039                                 break;
01040                         }
01041                 }
01042 
01043         }
01044         else {
01045                 if (G.f & G_DEBUG)
01046                         printf("Driver Evaluation Error: cannot resolve target for %s -> %s \n", id->name, dtar->rna_path);
01047                 
01048                 driver->flag |= DRIVER_FLAG_INVALID;
01049                 return 0.0f;
01050         }
01051         
01052         return value;
01053 }
01054 
01055 /* Helper function to obtain a pointer to a Pose Channel (for evaluating drivers) */
01056 static bPoseChannel *dtar_get_pchan_ptr (ChannelDriver *driver, DriverTarget *dtar)
01057 {
01058         ID *id;
01059         /* sanity check */
01060         if ELEM(NULL, driver, dtar)
01061                 return NULL;
01062 
01063         id= dtar_id_ensure_proxy_from(dtar->id);
01064 
01065         /* check if the ID here is a valid object */
01066         if (id && GS(id->name)) {
01067                 Object *ob= (Object *)id;
01068                 
01069                 /* get pose, and subsequently, posechannel */
01070                 return get_pose_channel(ob->pose, dtar->pchan_name);
01071         }
01072         else {
01073                 /* cannot find a posechannel this way */
01074                 return NULL;
01075         }
01076 }
01077 
01078 /* ......... */
01079 
01080 /* evaluate 'single prop' driver variable */
01081 static float dvar_eval_singleProp (ChannelDriver *driver, DriverVar *dvar)
01082 {
01083         /* just evaluate the first target slot */
01084         return dtar_get_prop_val(driver, &dvar->targets[0]);
01085 }
01086 
01087 /* evaluate 'rotation difference' driver variable */
01088 static float dvar_eval_rotDiff (ChannelDriver *driver, DriverVar *dvar)
01089 {
01090         bPoseChannel *pchan, *pchan2;
01091         float q1[4], q2[4], quat[4], angle;
01092         
01093         /* get pose channels, and check if we've got two */
01094         pchan= dtar_get_pchan_ptr(driver, &dvar->targets[0]);
01095         pchan2= dtar_get_pchan_ptr(driver, &dvar->targets[1]);
01096         
01097         if (ELEM(NULL, pchan, pchan2)) {
01098                 /* disable this driver, since it doesn't work correctly... */
01099                 driver->flag |= DRIVER_FLAG_INVALID;
01100                 
01101                 /* check what the error was */
01102                 if ((pchan == NULL) && (pchan2 == NULL))
01103                         printf("Driver Evaluation Error: Rotational difference failed - first 2 targets invalid \n");
01104                 else if (pchan == NULL)
01105                         printf("Driver Evaluation Error: Rotational difference failed - first target not valid PoseChannel \n");
01106                 else if (pchan2 == NULL)
01107                         printf("Driver Evaluation Error: Rotational difference failed - second target not valid PoseChannel \n");
01108                         
01109                 /* stop here... */
01110                 return 0.0f;
01111         }                       
01112         
01113         /* use the final posed locations */
01114         mat4_to_quat(q1, pchan->pose_mat);
01115         mat4_to_quat(q2, pchan2->pose_mat);
01116         
01117         invert_qt(q1);
01118         mul_qt_qtqt(quat, q1, q2);
01119         angle = 2.0f * (saacos(quat[0]));
01120         angle= ABS(angle);
01121         
01122         return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
01123 }
01124 
01125 /* evaluate 'location difference' driver variable */
01126 // TODO: this needs to take into account space conversions...
01127 static float dvar_eval_locDiff (ChannelDriver *driver, DriverVar *dvar)
01128 {
01129         float loc1[3] = {0.0f,0.0f,0.0f};
01130         float loc2[3] = {0.0f,0.0f,0.0f};
01131         
01132         /* get two location values */
01133         // NOTE: for now, these are all just worldspace
01134         DRIVER_TARGETS_USED_LOOPER(dvar)
01135         {
01136                 /* get pointer to loc values to store in */
01137                 Object *ob= (Object *)dtar_id_ensure_proxy_from(dtar->id);
01138                 bPoseChannel *pchan;
01139                 float tmp_loc[3];
01140                 
01141                 /* check if this target has valid data */
01142                 if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
01143                         /* invalid target, so will not have enough targets */
01144                         driver->flag |= DRIVER_FLAG_INVALID;
01145                         return 0.0f;
01146                 }
01147                 
01148                 /* try to get posechannel */
01149                 pchan= get_pose_channel(ob->pose, dtar->pchan_name);
01150                 
01151                 /* check if object or bone */
01152                 if (pchan) {
01153                         /* bone */
01154                         if ((dtar->flag & DTAR_FLAG_LOCALSPACE) == 0) {
01155                                 /* convert to worldspace */
01156                                 VECCOPY(tmp_loc, pchan->pose_head);
01157                                 mul_m4_v3(ob->obmat, tmp_loc);
01158                         }
01159                         else {
01160                                 /* local (use transform values directly) */
01161                                 VECCOPY(tmp_loc, pchan->loc);
01162                         }
01163                 }
01164                 else {
01165                         /* object */
01166                         if ((dtar->flag & DTAR_FLAG_LOCALSPACE) == 0) {
01167                                 /* worldspace */
01168                                 VECCOPY(tmp_loc, ob->obmat[3]); 
01169                         }
01170                         else {
01171                                 /* local (use transform values directly) */
01172                                 VECCOPY(tmp_loc, ob->loc);
01173                         }
01174                 }
01175                 
01176                 /* copy the location to the right place */
01177                 if (tarIndex) {
01178                         VECCOPY(loc2, tmp_loc);
01179                 }
01180                 else {
01181                         VECCOPY(loc1, tmp_loc);
01182                 }
01183         }
01184         DRIVER_TARGETS_LOOPER_END
01185         
01186         
01187         /* if we're still here, there should now be two targets to use,
01188          * so just take the length of the vector between these points 
01189          */
01190         return len_v3v3(loc1, loc2);
01191 }
01192 
01193 /* evaluate 'transform channel' driver variable */
01194 static float dvar_eval_transChan (ChannelDriver *driver, DriverVar *dvar)
01195 {
01196         DriverTarget *dtar= &dvar->targets[0];
01197         Object *ob= (Object *)dtar_id_ensure_proxy_from(dtar->id);
01198         bPoseChannel *pchan;
01199         float mat[4][4];
01200         float eul[3] = {0.0f,0.0f,0.0f};
01201         short useEulers=0, rotOrder=ROT_MODE_EUL;
01202         
01203         /* check if this target has valid data */
01204         if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
01205                 /* invalid target, so will not have enough targets */
01206                 driver->flag |= DRIVER_FLAG_INVALID;
01207                 return 0.0f;
01208         }
01209         
01210         /* try to get posechannel */
01211         pchan= get_pose_channel(ob->pose, dtar->pchan_name);
01212         
01213         /* check if object or bone, and get transform matrix accordingly */
01214         if (pchan) {
01215                 /* bone */
01216                 if (pchan->rotmode > 0) {
01217                         VECCOPY(eul, pchan->eul);
01218                         rotOrder= pchan->rotmode;
01219                         useEulers = 1;
01220                 }
01221                 
01222                 if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
01223                         /* specially calculate local matrix, since chan_mat is not valid 
01224                          * since it stores delta transform of pose_mat so that deforms work
01225                          */
01226                         pchan_to_mat4(pchan, mat);
01227                 }
01228                 else
01229                         mul_m4_m4m4(mat, pchan->pose_mat, ob->obmat);
01230         }
01231         else {
01232                 /* object */
01233                 if (ob->rotmode > 0) {
01234                         VECCOPY(eul, ob->rot);
01235                         rotOrder= ob->rotmode;
01236                         useEulers = 1;
01237                 }
01238                 
01239                 if (dtar->flag & DTAR_FLAG_LOCALSPACE)
01240                         object_to_mat4(ob, mat);
01241                 else
01242                         copy_m4_m4(mat, ob->obmat);
01243         }
01244         
01245         /* check which transform */
01246         if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) {
01247                 /* not valid channel */
01248                 return 0.0f;
01249         }
01250         else if (dtar->transChan >= DTAR_TRANSCHAN_SCALEX) {
01251                 /* extract scale, and choose the right axis */
01252                 float scale[3];
01253                 
01254                 mat4_to_size(scale, mat);
01255                 return scale[dtar->transChan - DTAR_TRANSCHAN_SCALEX];
01256         }
01257         else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
01258                 /* extract euler rotation (if needed), and choose the right axis */
01259                 if ((dtar->flag & DTAR_FLAG_LOCALSPACE)==0 || (useEulers == 0))
01260                         mat4_to_eulO(eul, rotOrder, mat);
01261                 
01262                 return eul[dtar->transChan - DTAR_TRANSCHAN_ROTX];
01263         }
01264         else {
01265                 /* extract location and choose right axis */
01266                 return mat[3][dtar->transChan];
01267         }
01268 }
01269 
01270 /* ......... */
01271 
01272 /* Table of Driver Varaiable Type Info Data */
01273 static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
01274         BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP)
01275                 dvar_eval_singleProp, /* eval callback */
01276                 1, /* number of targets used */
01277                 {"Property"}, /* UI names for targets */
01278                 {0} /* flags */
01279         END_DVAR_TYPEDEF,
01280         
01281         BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF)
01282                 dvar_eval_rotDiff, /* eval callback */
01283                 2, /* number of targets used */
01284                 {"Bone 1", "Bone 2"}, /* UI names for targets */
01285                 {DTAR_FLAG_STRUCT_REF|DTAR_FLAG_ID_OB_ONLY, DTAR_FLAG_STRUCT_REF|DTAR_FLAG_ID_OB_ONLY} /* flags */
01286         END_DVAR_TYPEDEF,
01287         
01288         BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF)
01289                 dvar_eval_locDiff, /* eval callback */
01290                 2, /* number of targets used */
01291                 {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
01292                 {DTAR_FLAG_STRUCT_REF|DTAR_FLAG_ID_OB_ONLY, DTAR_FLAG_STRUCT_REF|DTAR_FLAG_ID_OB_ONLY} /* flags */
01293         END_DVAR_TYPEDEF,
01294         
01295         BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN)
01296                 dvar_eval_transChan, /* eval callback */
01297                 1, /* number of targets used */
01298                 {"Object/Bone"}, /* UI names for targets */
01299                 {DTAR_FLAG_STRUCT_REF|DTAR_FLAG_ID_OB_ONLY} /* flags */
01300         END_DVAR_TYPEDEF,
01301 };
01302 
01303 /* Get driver variable typeinfo */
01304 static DriverVarTypeInfo *get_dvar_typeinfo (int type)
01305 {
01306         /* check if valid type */
01307         if ((type >= 0) && (type < MAX_DVAR_TYPES))
01308                 return &dvar_types[type];
01309         else
01310                 return NULL;
01311 }
01312 
01313 /* Driver API --------------------------------- */
01314 
01315 /* This frees the driver variable itself */
01316 void driver_free_variable (ChannelDriver *driver, DriverVar *dvar)
01317 {
01318         /* sanity checks */
01319         if (dvar == NULL)
01320                 return;
01321                 
01322         /* free target vars 
01323          *      - need to go over all of them, not just up to the ones that are used
01324          *        currently, since there may be some lingering RNA paths from 
01325          *        previous users needing freeing
01326          */
01327         DRIVER_TARGETS_LOOPER(dvar) 
01328         {
01329                 /* free RNA path if applicable */
01330                 if (dtar->rna_path)
01331                         MEM_freeN(dtar->rna_path);
01332         }
01333         DRIVER_TARGETS_LOOPER_END
01334         
01335         /* remove the variable from the driver */
01336         if (driver)
01337                 BLI_freelinkN(&driver->variables, dvar);
01338         else
01339                 MEM_freeN(dvar);
01340 
01341 #ifdef WITH_PYTHON
01342         /* since driver variables are cached, the expression needs re-compiling too */
01343         if(driver->type==DRIVER_TYPE_PYTHON)
01344                 driver->flag |= DRIVER_FLAG_RENAMEVAR;
01345 #endif
01346 }
01347 
01348 /* Change the type of driver variable */
01349 void driver_change_variable_type (DriverVar *dvar, int type)
01350 {
01351         DriverVarTypeInfo *dvti= get_dvar_typeinfo(type);
01352         
01353         /* sanity check */
01354         if (ELEM(NULL, dvar, dvti))
01355                 return;
01356                 
01357         /* set the new settings */
01358         dvar->type= type;
01359         dvar->num_targets= dvti->num_targets;
01360         
01361         /* make changes to the targets based on the defines for these types 
01362          * NOTE: only need to make sure the ones we're using here are valid...
01363          */
01364         DRIVER_TARGETS_USED_LOOPER(dvar)
01365         {
01366                 int flags = dvti->target_flags[tarIndex];
01367                 
01368                 /* store the flags */
01369                 dtar->flag = flags;
01370                 
01371                 /* object ID types only, or idtype not yet initialised*/
01372                 if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0))
01373                         dtar->idtype= ID_OB;
01374         }
01375         DRIVER_TARGETS_LOOPER_END
01376 }
01377 
01378 /* Add a new driver variable */
01379 DriverVar *driver_add_new_variable (ChannelDriver *driver)
01380 {
01381         DriverVar *dvar;
01382         
01383         /* sanity checks */
01384         if (driver == NULL)
01385                 return NULL;
01386                 
01387         /* make a new variable */
01388         dvar= MEM_callocN(sizeof(DriverVar), "DriverVar");
01389         BLI_addtail(&driver->variables, dvar);
01390         
01391         /* give the variable a 'unique' name */
01392         strcpy(dvar->name, "var");
01393         BLI_uniquename(&driver->variables, dvar, "var", '_', offsetof(DriverVar, name), sizeof(dvar->name));
01394         
01395         /* set the default type to 'single prop' */
01396         driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
01397         
01398 #ifdef WITH_PYTHON
01399         /* since driver variables are cached, the expression needs re-compiling too */
01400         if (driver->type==DRIVER_TYPE_PYTHON)
01401                 driver->flag |= DRIVER_FLAG_RENAMEVAR;
01402 #endif
01403 
01404         /* return the target */
01405         return dvar;
01406 }
01407 
01408 /* This frees the driver itself */
01409 void fcurve_free_driver(FCurve *fcu)
01410 {
01411         ChannelDriver *driver;
01412         DriverVar *dvar, *dvarn;
01413         
01414         /* sanity checks */
01415         if ELEM(NULL, fcu, fcu->driver)
01416                 return;
01417         driver= fcu->driver;
01418         
01419         /* free driver targets */
01420         for (dvar= driver->variables.first; dvar; dvar= dvarn) {
01421                 dvarn= dvar->next;
01422                 driver_free_variable(driver, dvar);
01423         }
01424 
01425 #ifdef WITH_PYTHON
01426         /* free compiled driver expression */
01427         if (driver->expr_comp)
01428                 BPY_DECREF(driver->expr_comp);
01429 #endif
01430 
01431         /* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */
01432         MEM_freeN(driver);
01433         fcu->driver= NULL;
01434 }
01435 
01436 /* This makes a copy of the given driver */
01437 ChannelDriver *fcurve_copy_driver (ChannelDriver *driver)
01438 {
01439         ChannelDriver *ndriver;
01440         DriverVar *dvar;
01441         
01442         /* sanity checks */
01443         if (driver == NULL)
01444                 return NULL;
01445                 
01446         /* copy all data */
01447         ndriver= MEM_dupallocN(driver);
01448         ndriver->expr_comp= NULL;
01449         
01450         /* copy variables */
01451         ndriver->variables.first= ndriver->variables.last= NULL;
01452         BLI_duplicatelist(&ndriver->variables, &driver->variables);
01453         
01454         for (dvar= ndriver->variables.first; dvar; dvar= dvar->next) {  
01455                 /* need to go over all targets so that we don't leave any dangling paths */
01456                 DRIVER_TARGETS_LOOPER(dvar) 
01457                 {       
01458                         /* make a copy of target's rna path if available */
01459                         if (dtar->rna_path)
01460                                 dtar->rna_path = MEM_dupallocN(dtar->rna_path);
01461                 }
01462                 DRIVER_TARGETS_LOOPER_END
01463         }
01464         
01465         /* return the new driver */
01466         return ndriver;
01467 }
01468 
01469 /* Driver Evaluation -------------------------- */
01470 
01471 /* Evaluate a Driver Variable to get a value that contributes to the final */
01472 float driver_get_variable_value (ChannelDriver *driver, DriverVar *dvar)
01473 {
01474         DriverVarTypeInfo *dvti;
01475 
01476         /* sanity check */
01477         if (ELEM(NULL, driver, dvar))
01478                 return 0.0f;
01479         
01480         /* call the relevant callbacks to get the variable value 
01481          * using the variable type info, storing the obtained value
01482          * in dvar->curval so that drivers can be debugged
01483          */
01484         dvti= get_dvar_typeinfo(dvar->type);
01485         
01486         if (dvti && dvti->get_value)
01487                 dvar->curval= dvti->get_value(driver, dvar);
01488         else
01489                 dvar->curval= 0.0f;
01490         
01491         return dvar->curval;
01492 }
01493 
01494 /* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
01495  *      - "evaltime" is the frame at which F-Curve is being evaluated
01496  *      - has to return a float value 
01497  */
01498 static float evaluate_driver (ChannelDriver *driver, float UNUSED(evaltime))
01499 {
01500         DriverVar *dvar;
01501         
01502         /* check if driver can be evaluated */
01503         if (driver->flag & DRIVER_FLAG_INVALID)
01504                 return 0.0f;
01505         
01506         switch (driver->type) {
01507                 case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
01508                 case DRIVER_TYPE_SUM: /* sum values of driver targets */
01509                 {
01510                         /* check how many variables there are first (i.e. just one?) */
01511                         if (driver->variables.first == driver->variables.last) {
01512                                 /* just one target, so just use that */
01513                                 dvar= driver->variables.first;
01514                                 driver->curval= driver_get_variable_value(driver, dvar);
01515                         }
01516                         else {
01517                                 /* more than one target, so average the values of the targets */
01518                                 float value = 0.0f;
01519                                 int tot = 0;
01520                                 
01521                                 /* loop through targets, adding (hopefully we don't get any overflow!) */
01522                                 for (dvar= driver->variables.first; dvar; dvar=dvar->next) {
01523                                         value += driver_get_variable_value(driver, dvar);
01524                                         tot++;
01525                                 }
01526                                 
01527                                 /* perform operations on the total if appropriate */
01528                                 if (driver->type == DRIVER_TYPE_AVERAGE)
01529                                         driver->curval= (value / (float)tot);
01530                                 else
01531                                         driver->curval= value;
01532                         }
01533                 }
01534                         break;
01535                         
01536                 case DRIVER_TYPE_MIN: /* smallest value */
01537                 case DRIVER_TYPE_MAX: /* largest value */
01538                 {
01539                         float value = 0.0f;
01540                         
01541                         /* loop through the variables, getting the values and comparing them to existing ones */
01542                         for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
01543                                 /* get value */
01544                                 float tmp_val= driver_get_variable_value(driver, dvar);
01545                                 
01546                                 /* store this value if appropriate */
01547                                 if (dvar->prev) {
01548                                         /* check if greater/smaller than the baseline */
01549                                         if (driver->type == DRIVER_TYPE_MAX) {
01550                                                 /* max? */
01551                                                 if (tmp_val > value) 
01552                                                         value= tmp_val;
01553                                         }
01554                                         else {
01555                                                 /* min? */
01556                                                 if (tmp_val < value) 
01557                                                         value= tmp_val;
01558                                         }
01559                                 }
01560                                 else {
01561                                         /* first item - make this the baseline for comparisons */
01562                                         value= tmp_val;
01563                                 }
01564                         }
01565                         
01566                         /* store value in driver */
01567                         driver->curval= value;
01568                 }
01569                         break;
01570                         
01571                 case DRIVER_TYPE_PYTHON: /* expression */
01572                 {
01573 #ifdef WITH_PYTHON
01574                         /* check for empty or invalid expression */
01575                         if ( (driver->expression[0] == '\0') ||
01576                                  (driver->flag & DRIVER_FLAG_INVALID) )
01577                         {
01578                                 driver->curval= 0.0f;
01579                         }
01580                         else
01581                         {
01582                                 /* this evaluates the expression using Python,and returns its result:
01583                                  *      - on errors it reports, then returns 0.0f
01584                                  */
01585                                 driver->curval= BPY_driver_exec(driver);
01586                         }
01587 #endif /* WITH_PYTHON*/
01588                 }
01589                         break;
01590                 
01591                 default:
01592                 {
01593                         /* special 'hack' - just use stored value 
01594                          *      This is currently used as the mechanism which allows animated settings to be able
01595                          *      to be changed via the UI.
01596                          */
01597                 }
01598         }
01599         
01600         /* return value for driver */
01601         return driver->curval;
01602 }
01603 
01604 /* ***************************** Curve Calculations ********************************* */
01605 
01606 /* The total length of the handles is not allowed to be more
01607  * than the horizontal distance between (v1-v4).
01608  * This is to prevent curve loops.
01609 */
01610 void correct_bezpart (float *v1, float *v2, float *v3, float *v4)
01611 {
01612         float h1[2], h2[2], len1, len2, len, fac;
01613         
01614         /* calculate handle deltas */
01615         h1[0]= v1[0] - v2[0];
01616         h1[1]= v1[1] - v2[1];
01617         
01618         h2[0]= v4[0] - v3[0];
01619         h2[1]= v4[1] - v3[1];
01620         
01621         /* calculate distances: 
01622          *      - len   = span of time between keyframes 
01623          *      - len1  = length of handle of start key
01624          *      - len2  = length of handle of end key
01625          */
01626         len= v4[0]- v1[0];
01627         len1= (float)fabs(h1[0]);
01628         len2= (float)fabs(h2[0]);
01629         
01630         /* if the handles have no length, no need to do any corrections */
01631         if ((len1+len2) == 0.0f) 
01632                 return;
01633                 
01634         /* the two handles cross over each other, so force them
01635          * apart using the proportion they overlap 
01636          */
01637         if ((len1+len2) > len) {
01638                 fac= len / (len1+len2);
01639                 
01640                 v2[0]= (v1[0] - fac*h1[0]);
01641                 v2[1]= (v1[1] - fac*h1[1]);
01642                 
01643                 v3[0]= (v4[0] - fac*h2[0]);
01644                 v3[1]= (v4[1] - fac*h2[1]);
01645         }
01646 }
01647 
01648 /* find root ('zero') */
01649 static int findzero (float x, float q0, float q1, float q2, float q3, float *o)
01650 {
01651         double c0, c1, c2, c3, a, b, c, p, q, d, t, phi;
01652         int nr= 0;
01653 
01654         c0= q0 - x;
01655         c1= 3.0f * (q1 - q0);
01656         c2= 3.0f * (q0 - 2.0f*q1 + q2);
01657         c3= q3 - q0 + 3.0f * (q1 - q2);
01658         
01659         if (c3 != 0.0) {
01660                 a= c2/c3;
01661                 b= c1/c3;
01662                 c= c0/c3;
01663                 a= a/3;
01664                 
01665                 p= b/3 - a*a;
01666                 q= (2*a*a*a - a*b + c) / 2;
01667                 d= q*q + p*p*p;
01668                 
01669                 if (d > 0.0) {
01670                         t= sqrt(d);
01671                         o[0]= (float)(sqrt3d(-q+t) + sqrt3d(-q-t) - a);
01672                         
01673                         if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) return 1;
01674                         else return 0;
01675                 }
01676                 else if (d == 0.0) {
01677                         t= sqrt3d(-q);
01678                         o[0]= (float)(2*t - a);
01679                         
01680                         if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) nr++;
01681                         o[nr]= (float)(-t-a);
01682                         
01683                         if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f)) return nr+1;
01684                         else return nr;
01685                 }
01686                 else {
01687                         phi= acos(-q / sqrt(-(p*p*p)));
01688                         t= sqrt(-p);
01689                         p= cos(phi/3);
01690                         q= sqrt(3 - 3*p*p);
01691                         o[0]= (float)(2*t*p - a);
01692                         
01693                         if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) nr++;
01694                         o[nr]= (float)(-t * (p + q) - a);
01695                         
01696                         if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f)) nr++;
01697                         o[nr]= (float)(-t * (p - q) - a);
01698                         
01699                         if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f)) return nr+1;
01700                         else return nr;
01701                 }
01702         }
01703         else {
01704                 a=c2;
01705                 b=c1;
01706                 c=c0;
01707                 
01708                 if (a != 0.0) {
01709                         // discriminant
01710                         p= b*b - 4*a*c;
01711                         
01712                         if (p > 0) {
01713                                 p= sqrt(p);
01714                                 o[0]= (float)((-b-p) / (2 * a));
01715                                 
01716                                 if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) nr++;
01717                                 o[nr]= (float)((-b+p)/(2*a));
01718                                 
01719                                 if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f)) return nr+1;
01720                                 else return nr;
01721                         }
01722                         else if (p == 0) {
01723                                 o[0]= (float)(-b / (2 * a));
01724                                 if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) return 1;
01725                                 else return 0;
01726                         }
01727                 }
01728                 else if (b != 0.0) {
01729                         o[0]= (float)(-c/b);
01730                         
01731                         if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) return 1;
01732                         else return 0;
01733                 }
01734                 else if (c == 0.0) {
01735                         o[0]= 0.0;
01736                         return 1;
01737                 }
01738                 
01739                 return 0;       
01740         }
01741 }
01742 
01743 static void berekeny (float f1, float f2, float f3, float f4, float *o, int b)
01744 {
01745         float t, c0, c1, c2, c3;
01746         int a;
01747 
01748         c0= f1;
01749         c1= 3.0f * (f2 - f1);
01750         c2= 3.0f * (f1 - 2.0f*f2 + f3);
01751         c3= f4 - f1 + 3.0f * (f2 - f3);
01752         
01753         for (a=0; a < b; a++) {
01754                 t= o[a];
01755                 o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3;
01756         }
01757 }
01758 
01759 #if 0
01760 static void berekenx (float *f, float *o, int b)
01761 {
01762         float t, c0, c1, c2, c3;
01763         int a;
01764 
01765         c0= f[0];
01766         c1= 3.0f * (f[3] - f[0]);
01767         c2= 3.0f * (f[0] - 2.0f*f[3] + f[6]);
01768         c3= f[9] - f[0] + 3.0f * (f[3] - f[6]);
01769         
01770         for (a=0; a < b; a++) {
01771                 t= o[a];
01772                 o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3;
01773         }
01774 }
01775 #endif
01776 
01777 
01778 /* -------------------------- */
01779 
01780 /* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */
01781 static float fcurve_eval_keyframes (FCurve *fcu, BezTriple *bezts, float evaltime)
01782 {
01783         BezTriple *bezt, *prevbezt, *lastbezt;
01784         float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac;
01785         unsigned int a;
01786         int b;
01787         float cvalue = 0.0f;
01788         
01789         /* get pointers */
01790         a= fcu->totvert-1;
01791         prevbezt= bezts;
01792         bezt= prevbezt+1;
01793         lastbezt= prevbezt + a;
01794         
01795         /* evaluation time at or past endpoints? */
01796         if (prevbezt->vec[1][0] >= evaltime) 
01797         {
01798                 /* before or on first keyframe */
01799                 if ( (fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST) &&
01800                         !(fcu->flag & FCURVE_DISCRETE_VALUES) ) 
01801                 {
01802                         /* linear or bezier interpolation */
01803                         if (prevbezt->ipo==BEZT_IPO_LIN) 
01804                         {
01805                                 /* Use the next center point instead of our own handle for
01806                                  * linear interpolated extrapolate 
01807                                  */
01808                                 if (fcu->totvert == 1) 
01809                                         cvalue= prevbezt->vec[1][1];
01810                                 else 
01811                                 {
01812                                         bezt = prevbezt+1;
01813                                         dx= prevbezt->vec[1][0] - evaltime;
01814                                         fac= bezt->vec[1][0] - prevbezt->vec[1][0];
01815                                         
01816                                         /* prevent division by zero */
01817                                         if (fac) {
01818                                                 fac= (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
01819                                                 cvalue= prevbezt->vec[1][1] - (fac * dx);
01820                                         }
01821                                         else 
01822                                                 cvalue= prevbezt->vec[1][1];
01823                                 }
01824                         } 
01825                         else 
01826                         {
01827                                 /* Use the first handle (earlier) of first BezTriple to calculate the
01828                                  * gradient and thus the value of the curve at evaltime
01829                                  */
01830                                 dx= prevbezt->vec[1][0] - evaltime;
01831                                 fac= prevbezt->vec[1][0] - prevbezt->vec[0][0];
01832                                 
01833                                 /* prevent division by zero */
01834                                 if (fac) {
01835                                         fac= (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac;
01836                                         cvalue= prevbezt->vec[1][1] - (fac * dx);
01837                                 }
01838                                 else 
01839                                         cvalue= prevbezt->vec[1][1];
01840                         }
01841                 }
01842                 else 
01843                 {
01844                         /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, 
01845                          * so just extend first keyframe's value 
01846                          */
01847                         cvalue= prevbezt->vec[1][1];
01848                 }
01849         }
01850         else if (lastbezt->vec[1][0] <= evaltime) 
01851         {
01852                 /* after or on last keyframe */
01853                 if ( (fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST) &&
01854                         !(fcu->flag & FCURVE_DISCRETE_VALUES) ) 
01855                 {
01856                         /* linear or bezier interpolation */
01857                         if (lastbezt->ipo==BEZT_IPO_LIN) 
01858                         {
01859                                 /* Use the next center point instead of our own handle for
01860                                  * linear interpolated extrapolate 
01861                                  */
01862                                 if (fcu->totvert == 1) 
01863                                         cvalue= lastbezt->vec[1][1];
01864                                 else 
01865                                 {
01866                                         prevbezt = lastbezt - 1;
01867                                         dx= evaltime - lastbezt->vec[1][0];
01868                                         fac= lastbezt->vec[1][0] - prevbezt->vec[1][0];
01869                                         
01870                                         /* prevent division by zero */
01871                                         if (fac) {
01872                                                 fac= (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
01873                                                 cvalue= lastbezt->vec[1][1] + (fac * dx);
01874                                         }
01875                                         else 
01876                                                 cvalue= lastbezt->vec[1][1];
01877                                 }
01878                         } 
01879                         else 
01880                         {
01881                                 /* Use the gradient of the second handle (later) of last BezTriple to calculate the
01882                                  * gradient and thus the value of the curve at evaltime
01883                                  */
01884                                 dx= evaltime - lastbezt->vec[1][0];
01885                                 fac= lastbezt->vec[2][0] - lastbezt->vec[1][0];
01886                                 
01887                                 /* prevent division by zero */
01888                                 if (fac) {
01889                                         fac= (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac;
01890                                         cvalue= lastbezt->vec[1][1] + (fac * dx);
01891                                 }
01892                                 else 
01893                                         cvalue= lastbezt->vec[1][1];
01894                         }
01895                 }
01896                 else 
01897                 {
01898                         /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, 
01899                          * so just extend last keyframe's value 
01900                          */
01901                         cvalue= lastbezt->vec[1][1];
01902                 }
01903         }
01904         else 
01905         {
01906                 /* evaltime occurs somewhere in the middle of the curve */
01907                 for (a=0; prevbezt && bezt && (a < fcu->totvert-1); a++, prevbezt=bezt, bezt++) 
01908                 {
01909                         /* use if the key is directly on the frame, rare cases this is needed else we get 0.0 instead. */
01910                         if(fabs(bezt->vec[1][0] - evaltime) < SMALL_NUMBER) {
01911                                 cvalue= bezt->vec[1][1];
01912                         }
01913                         /* evaltime occurs within the interval defined by these two keyframes */
01914                         else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime))
01915                         {
01916                                 /* value depends on interpolation mode */
01917                                 if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES))
01918                                 {
01919                                         /* constant (evaltime not relevant, so no interpolation needed) */
01920                                         cvalue= prevbezt->vec[1][1];
01921                                 }
01922                                 else if (prevbezt->ipo == BEZT_IPO_LIN) 
01923                                 {
01924                                         /* linear - interpolate between values of the two keyframes */
01925                                         fac= bezt->vec[1][0] - prevbezt->vec[1][0];
01926                                         
01927                                         /* prevent division by zero */
01928                                         if (fac) {
01929                                                 fac= (evaltime - prevbezt->vec[1][0]) / fac;
01930                                                 cvalue= prevbezt->vec[1][1] + (fac * (bezt->vec[1][1] - prevbezt->vec[1][1]));
01931                                         }
01932                                         else
01933                                                 cvalue= prevbezt->vec[1][1];
01934                                 }
01935                                 else 
01936                                 {
01937                                         /* bezier interpolation */
01938                                                 /* v1,v2 are the first keyframe and its 2nd handle */
01939                                         v1[0]= prevbezt->vec[1][0];
01940                                         v1[1]= prevbezt->vec[1][1];
01941                                         v2[0]= prevbezt->vec[2][0];
01942                                         v2[1]= prevbezt->vec[2][1];
01943                                                 /* v3,v4 are the last keyframe's 1st handle + the last keyframe */
01944                                         v3[0]= bezt->vec[0][0];
01945                                         v3[1]= bezt->vec[0][1];
01946                                         v4[0]= bezt->vec[1][0];
01947                                         v4[1]= bezt->vec[1][1];
01948                                         
01949                                         /* adjust handles so that they don't overlap (forming a loop) */
01950                                         correct_bezpart(v1, v2, v3, v4);
01951                                         
01952                                         /* try to get a value for this position - if failure, try another set of points */
01953                                         b= findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl);
01954                                         if (b) {
01955                                                 berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
01956                                                 cvalue= opl[0];
01957                                                 break;
01958                                         }
01959                                 }
01960                         }
01961                 }
01962         }
01963         
01964         /* return value */
01965         return cvalue;
01966 }
01967 
01968 /* Calculate F-Curve value for 'evaltime' using FPoint samples */
01969 static float fcurve_eval_samples (FCurve *fcu, FPoint *fpts, float evaltime)
01970 {
01971         FPoint *prevfpt, *lastfpt, *fpt;
01972         float cvalue= 0.0f;
01973         
01974         /* get pointers */
01975         prevfpt= fpts;
01976         lastfpt= prevfpt + fcu->totvert-1;
01977         
01978         /* evaluation time at or past endpoints? */
01979         if (prevfpt->vec[0] >= evaltime) {
01980                 /* before or on first sample, so just extend value */
01981                 cvalue= prevfpt->vec[1];
01982         }
01983         else if (lastfpt->vec[0] <= evaltime) {
01984                 /* after or on last sample, so just extend value */
01985                 cvalue= lastfpt->vec[1];
01986         }
01987         else {
01988                 float t= (float)abs(evaltime - (int)evaltime);
01989                 
01990                 /* find the one on the right frame (assume that these are spaced on 1-frame intervals) */
01991                 fpt= prevfpt + (int)(evaltime - prevfpt->vec[0]);
01992                 
01993                 /* if not exactly on the frame, perform linear interpolation with the next one */
01994                 if (t != 0.0f) 
01995                         cvalue= interpf(fpt->vec[1], (fpt+1)->vec[1], t);
01996                 else
01997                         cvalue= fpt->vec[1];
01998         }
01999         
02000         /* return value */
02001         return cvalue;
02002 }
02003 
02004 /* ***************************** F-Curve - Evaluation ********************************* */
02005 
02006 /* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime") 
02007  * Note: this is also used for drivers
02008  */
02009 float evaluate_fcurve (FCurve *fcu, float evaltime) 
02010 {
02011         float cvalue= 0.0f;
02012         float devaltime;
02013         
02014         /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime" 
02015          * since drivers essentially act as alternative input (i.e. in place of 'time') for F-Curves
02016          *      - this value will also be returned as the value of the 'curve', if there are no keyframes
02017          */
02018         if (fcu->driver) {
02019                 /* evaltime now serves as input for the curve */
02020                 evaltime= cvalue= evaluate_driver(fcu->driver, evaltime);
02021         }
02022         
02023         /* evaluate modifiers which modify time to evaluate the base curve at */
02024         devaltime= evaluate_time_fmodifiers(&fcu->modifiers, fcu, cvalue, evaltime);
02025         
02026         /* evaluate curve-data 
02027          *      - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying 
02028          *        F-Curve modifier on the stack requested the curve to be evaluated at
02029          */
02030         if (fcu->bezt)
02031                 cvalue= fcurve_eval_keyframes(fcu, fcu->bezt, devaltime);
02032         else if (fcu->fpt)
02033                 cvalue= fcurve_eval_samples(fcu, fcu->fpt, devaltime);
02034         
02035         /* evaluate modifiers */
02036         evaluate_value_fmodifiers(&fcu->modifiers, fcu, &cvalue, evaltime);
02037         
02038         /* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
02039          * here so that the curve can be sampled correctly
02040          */
02041         if (fcu->flag & FCURVE_INT_VALUES)
02042                 cvalue= floorf(cvalue + 0.5f);
02043         
02044         /* return evaluated value */
02045         return cvalue;
02046 }
02047 
02048 /* Calculate the value of the given F-Curve at the given frame, and set its curval */
02049 void calculate_fcurve (FCurve *fcu, float ctime)
02050 {
02051         /* only calculate + set curval (overriding the existing value) if curve has 
02052          * any data which warrants this...
02053          */
02054         if ( (fcu->totvert) || (fcu->driver && !(fcu->driver->flag & DRIVER_FLAG_INVALID)) ||
02055                  list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) )
02056         {
02057                 /* calculate and set curval (evaluates driver too if necessary) */
02058                 fcu->curval= evaluate_fcurve(fcu, ctime);
02059         }
02060 }
02061