|
Blender
V2.59
|
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