|
Blender
V2.59
|
00001 /* 00002 * $Id: fmodifier.c 35953 2011-04-02 02:08:33Z 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 * Contributor(s): Joshua Leung (full recode) 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00034 #include <math.h> 00035 #include <stdio.h> 00036 #include <stddef.h> 00037 #include <string.h> 00038 #include <float.h> 00039 00040 #include "MEM_guardedalloc.h" 00041 00042 #include "DNA_anim_types.h" 00043 00044 #include "BLI_blenlib.h" 00045 #include "BLI_math.h" /* windows needs for M_PI */ 00046 #include "BLI_utildefines.h" 00047 00048 #include "BKE_fcurve.h" 00049 #include "BKE_idprop.h" 00050 00051 00052 #define SMALL -1.0e-10 00053 #define SELECT 1 00054 00055 /* ******************************** F-Modifiers ********************************* */ 00056 00057 /* Info ------------------------------- */ 00058 00059 /* F-Modifiers are modifiers which operate on F-Curves. However, they can also be defined 00060 * on NLA-Strips to affect all of the F-Curves referenced by the NLA-Strip. 00061 */ 00062 00063 /* Template --------------------------- */ 00064 00065 /* Each modifier defines a set of functions, which will be called at the appropriate 00066 * times. In addition to this, each modifier should have a type-info struct, where 00067 * its functions are attached for use. 00068 */ 00069 00070 /* Template for type-info data: 00071 * - make a copy of this when creating new modifiers, and just change the functions 00072 * pointed to as necessary 00073 * - although the naming of functions doesn't matter, it would help for code 00074 * readability, to follow the same naming convention as is presented here 00075 * - any functions that a constraint doesn't need to define, don't define 00076 * for such cases, just use NULL 00077 * - these should be defined after all the functions have been defined, so that 00078 * forward-definitions/prototypes don't need to be used! 00079 * - keep this copy #if-def'd so that future constraints can get based off this 00080 */ 00081 #if 0 00082 static FModifierTypeInfo FMI_MODNAME = { 00083 FMODIFIER_TYPE_MODNAME, /* type */ 00084 sizeof(FMod_ModName), /* size */ 00085 FMI_TYPE_SOME_ACTION, /* action type */ 00086 FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */ 00087 "Modifier Name", /* name */ 00088 "FMod_ModName", /* struct name */ 00089 fcm_modname_free, /* free data */ 00090 fcm_modname_relink, /* relink data */ 00091 fcm_modname_copy, /* copy data */ 00092 fcm_modname_new_data, /* new data */ 00093 fcm_modname_verify, /* verify */ 00094 fcm_modname_time, /* evaluate time */ 00095 fcm_modname_evaluate /* evaluate */ 00096 }; 00097 #endif 00098 00099 /* Generator F-Curve Modifier --------------------------- */ 00100 00101 /* Generators available: 00102 * 1) simple polynomial generator: 00103 * - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n]) 00104 * - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1])) 00105 */ 00106 00107 static void fcm_generator_free (FModifier *fcm) 00108 { 00109 FMod_Generator *data= (FMod_Generator *)fcm->data; 00110 00111 /* free polynomial coefficients array */ 00112 if (data->coefficients) 00113 MEM_freeN(data->coefficients); 00114 } 00115 00116 static void fcm_generator_copy (FModifier *fcm, FModifier *src) 00117 { 00118 FMod_Generator *gen= (FMod_Generator *)fcm->data; 00119 FMod_Generator *ogen= (FMod_Generator *)src->data; 00120 00121 /* copy coefficients array? */ 00122 if (ogen->coefficients) 00123 gen->coefficients= MEM_dupallocN(ogen->coefficients); 00124 } 00125 00126 static void fcm_generator_new_data (void *mdata) 00127 { 00128 FMod_Generator *data= (FMod_Generator *)mdata; 00129 float *cp; 00130 00131 /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */ 00132 data->poly_order= 1; 00133 data->arraysize= 2; 00134 cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs"); 00135 cp[0] = 0; // y-offset 00136 cp[1] = 1; // gradient 00137 } 00138 00139 static void fcm_generator_verify (FModifier *fcm) 00140 { 00141 FMod_Generator *data= (FMod_Generator *)fcm->data; 00142 00143 /* requirements depend on mode */ 00144 switch (data->mode) { 00145 case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */ 00146 { 00147 /* arraysize needs to be order+1, so resize if not */ 00148 if (data->arraysize != (data->poly_order+1)) { 00149 float *nc; 00150 00151 /* make new coefficients array, and copy over as much data as can fit */ 00152 nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs"); 00153 00154 if (data->coefficients) { 00155 if ((int)data->arraysize > (data->poly_order+1)) 00156 memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order+1)); 00157 else 00158 memcpy(nc, data->coefficients, sizeof(float)*data->arraysize); 00159 00160 /* free the old data */ 00161 MEM_freeN(data->coefficients); 00162 } 00163 00164 /* set the new data */ 00165 data->coefficients= nc; 00166 data->arraysize= data->poly_order+1; 00167 } 00168 } 00169 break; 00170 00171 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */ 00172 { 00173 /* arraysize needs to be 2*order, so resize if not */ 00174 if (data->arraysize != (data->poly_order * 2)) { 00175 float *nc; 00176 00177 /* make new coefficients array, and copy over as much data as can fit */ 00178 nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs"); 00179 00180 if (data->coefficients) { 00181 if (data->arraysize > (unsigned int)(data->poly_order * 2)) 00182 memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2)); 00183 else 00184 memcpy(nc, data->coefficients, sizeof(float)*data->arraysize); 00185 00186 /* free the old data */ 00187 MEM_freeN(data->coefficients); 00188 } 00189 00190 /* set the new data */ 00191 data->coefficients= nc; 00192 data->arraysize= data->poly_order * 2; 00193 } 00194 } 00195 break; 00196 } 00197 } 00198 00199 static void fcm_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime) 00200 { 00201 FMod_Generator *data= (FMod_Generator *)fcm->data; 00202 00203 /* behaviour depends on mode 00204 * NOTE: the data in its default state is fine too 00205 */ 00206 switch (data->mode) { 00207 case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */ 00208 { 00209 /* we overwrite cvalue with the sum of the polynomial */ 00210 float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers"); 00211 float value= 0.0f; 00212 unsigned int i; 00213 00214 /* for each x^n, precalculate value based on previous one first... this should be 00215 * faster that calling pow() for each entry 00216 */ 00217 for (i=0; i < data->arraysize; i++) { 00218 /* first entry is x^0 = 1, otherwise, calculate based on previous */ 00219 if (i) 00220 powers[i]= powers[i-1] * evaltime; 00221 else 00222 powers[0]= 1; 00223 } 00224 00225 /* for each coefficient, add to value, which we'll write to *cvalue in one go */ 00226 for (i=0; i < data->arraysize; i++) 00227 value += data->coefficients[i] * powers[i]; 00228 00229 /* only if something changed, write *cvalue in one go */ 00230 if (data->poly_order) { 00231 if (data->flag & FCM_GENERATOR_ADDITIVE) 00232 *cvalue += value; 00233 else 00234 *cvalue= value; 00235 } 00236 00237 /* cleanup */ 00238 if (powers) 00239 MEM_freeN(powers); 00240 } 00241 break; 00242 00243 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */ 00244 { 00245 float value= 1.0f, *cp=NULL; 00246 unsigned int i; 00247 00248 /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */ 00249 for (cp=data->coefficients, i=0; (cp) && (i < (unsigned int)data->poly_order); cp+=2, i++) 00250 value *= (cp[0]*evaltime + cp[1]); 00251 00252 /* only if something changed, write *cvalue in one go */ 00253 if (data->poly_order) { 00254 if (data->flag & FCM_GENERATOR_ADDITIVE) 00255 *cvalue += value; 00256 else 00257 *cvalue= value; 00258 } 00259 } 00260 break; 00261 } 00262 } 00263 00264 static FModifierTypeInfo FMI_GENERATOR = { 00265 FMODIFIER_TYPE_GENERATOR, /* type */ 00266 sizeof(FMod_Generator), /* size */ 00267 FMI_TYPE_GENERATE_CURVE, /* action type */ 00268 FMI_REQUIRES_NOTHING, /* requirements */ 00269 "Generator", /* name */ 00270 "FMod_Generator", /* struct name */ 00271 fcm_generator_free, /* free data */ 00272 fcm_generator_copy, /* copy data */ 00273 fcm_generator_new_data, /* new data */ 00274 fcm_generator_verify, /* verify */ 00275 NULL, /* evaluate time */ 00276 fcm_generator_evaluate /* evaluate */ 00277 }; 00278 00279 /* Built-In Function Generator F-Curve Modifier --------------------------- */ 00280 00281 /* This uses the general equation for equations: 00282 * y = amplitude * fn(phase_multiplier*x + phase_offset) + y_offset 00283 * 00284 * where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients, 00285 * x is the evaluation 'time', and 'y' is the resultant value 00286 * 00287 * Functions available are 00288 * sin, cos, tan, sinc (normalised sin), natural log, square root 00289 */ 00290 00291 static void fcm_fn_generator_new_data (void *mdata) 00292 { 00293 FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)mdata; 00294 00295 /* set amplitude and phase multiplier to 1.0f so that something is generated */ 00296 data->amplitude= 1.0f; 00297 data->phase_multiplier= 1.0f; 00298 } 00299 00300 /* Unary 'normalised sine' function 00301 * y = sin(PI + x) / (PI * x), 00302 * except for x = 0 when y = 1. 00303 */ 00304 static double sinc (double x) 00305 { 00306 if (fabs(x) < 0.0001) 00307 return 1.0; 00308 else 00309 return sin(M_PI * x) / (M_PI * x); 00310 } 00311 00312 static void fcm_fn_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime) 00313 { 00314 FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data; 00315 double arg= data->phase_multiplier*evaltime + data->phase_offset; 00316 double (*fn)(double v) = NULL; 00317 00318 /* get function pointer to the func to use: 00319 * WARNING: must perform special argument validation hereto guard against crashes 00320 */ 00321 switch (data->type) 00322 { 00323 /* simple ones */ 00324 case FCM_GENERATOR_FN_SIN: /* sine wave */ 00325 fn= sin; 00326 break; 00327 case FCM_GENERATOR_FN_COS: /* cosine wave */ 00328 fn= cos; 00329 break; 00330 case FCM_GENERATOR_FN_SINC: /* normalised sine wave */ 00331 fn= sinc; 00332 break; 00333 00334 /* validation required */ 00335 case FCM_GENERATOR_FN_TAN: /* tangent wave */ 00336 { 00337 /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */ 00338 if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) { 00339 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) 00340 *cvalue = 0.0f; /* no value possible here */ 00341 } 00342 else 00343 fn= tan; 00344 } 00345 break; 00346 case FCM_GENERATOR_FN_LN: /* natural log */ 00347 { 00348 /* check that value is greater than 1? */ 00349 if (arg > 1.0) { 00350 fn= log; 00351 } 00352 else { 00353 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) 00354 *cvalue = 0.0f; /* no value possible here */ 00355 } 00356 } 00357 break; 00358 case FCM_GENERATOR_FN_SQRT: /* square root */ 00359 { 00360 /* no negative numbers */ 00361 if (arg > 0.0) { 00362 fn= sqrt; 00363 } 00364 else { 00365 if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) 00366 *cvalue = 0.0f; /* no value possible here */ 00367 } 00368 } 00369 break; 00370 00371 default: 00372 printf("Invalid Function-Generator for F-Modifier - %d \n", data->type); 00373 } 00374 00375 /* execute function callback to set value if appropriate */ 00376 if (fn) { 00377 float value= (float)(data->amplitude*(float)fn(arg) + data->value_offset); 00378 00379 if (data->flag & FCM_GENERATOR_ADDITIVE) 00380 *cvalue += value; 00381 else 00382 *cvalue= value; 00383 } 00384 } 00385 00386 static FModifierTypeInfo FMI_FN_GENERATOR = { 00387 FMODIFIER_TYPE_FN_GENERATOR, /* type */ 00388 sizeof(FMod_FunctionGenerator), /* size */ 00389 FMI_TYPE_GENERATE_CURVE, /* action type */ 00390 FMI_REQUIRES_NOTHING, /* requirements */ 00391 "Built-In Function", /* name */ 00392 "FMod_FunctionGenerator", /* struct name */ 00393 NULL, /* free data */ 00394 NULL, /* copy data */ 00395 fcm_fn_generator_new_data, /* new data */ 00396 NULL, /* verify */ 00397 NULL, /* evaluate time */ 00398 fcm_fn_generator_evaluate /* evaluate */ 00399 }; 00400 00401 /* Envelope F-Curve Modifier --------------------------- */ 00402 00403 static void fcm_envelope_free (FModifier *fcm) 00404 { 00405 FMod_Envelope *env= (FMod_Envelope *)fcm->data; 00406 00407 /* free envelope data array */ 00408 if (env->data) 00409 MEM_freeN(env->data); 00410 } 00411 00412 static void fcm_envelope_copy (FModifier *fcm, FModifier *src) 00413 { 00414 FMod_Envelope *env= (FMod_Envelope *)fcm->data; 00415 FMod_Envelope *oenv= (FMod_Envelope *)src->data; 00416 00417 /* copy envelope data array */ 00418 if (oenv->data) 00419 env->data= MEM_dupallocN(oenv->data); 00420 } 00421 00422 static void fcm_envelope_new_data (void *mdata) 00423 { 00424 FMod_Envelope *env= (FMod_Envelope *)mdata; 00425 00426 /* set default min/max ranges */ 00427 env->min= -1.0f; 00428 env->max= 1.0f; 00429 } 00430 00431 static void fcm_envelope_verify (FModifier *fcm) 00432 { 00433 FMod_Envelope *env= (FMod_Envelope *)fcm->data; 00434 00435 /* if the are points, perform bubble-sort on them, as user may have changed the order */ 00436 if (env->data) { 00437 // XXX todo... 00438 } 00439 } 00440 00441 static void fcm_envelope_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime) 00442 { 00443 FMod_Envelope *env= (FMod_Envelope *)fcm->data; 00444 FCM_EnvelopeData *fed, *prevfed, *lastfed; 00445 float min=0.0f, max=0.0f, fac=0.0f; 00446 int a; 00447 00448 /* get pointers */ 00449 if (env->data == NULL) return; 00450 prevfed= env->data; 00451 fed= prevfed + 1; 00452 lastfed= prevfed + (env->totvert-1); 00453 00454 /* get min/max values for envelope at evaluation time (relative to mid-value) */ 00455 if (prevfed->time >= evaltime) { 00456 /* before or on first sample, so just extend value */ 00457 min= prevfed->min; 00458 max= prevfed->max; 00459 } 00460 else if (lastfed->time <= evaltime) { 00461 /* after or on last sample, so just extend value */ 00462 min= lastfed->min; 00463 max= lastfed->max; 00464 } 00465 else { 00466 /* evaltime occurs somewhere between segments */ 00467 // TODO: implement binary search for this to make it faster? 00468 for (a=0; prevfed && fed && (a < env->totvert-1); a++, prevfed=fed, fed++) { 00469 /* evaltime occurs within the interval defined by these two envelope points */ 00470 if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) { 00471 float afac, bfac, diff; 00472 00473 diff= fed->time - prevfed->time; 00474 afac= (evaltime - prevfed->time) / diff; 00475 bfac= (fed->time - evaltime) / diff; 00476 00477 min= bfac*prevfed->min + afac*fed->min; 00478 max= bfac*prevfed->max + afac*fed->max; 00479 00480 break; 00481 } 00482 } 00483 } 00484 00485 /* adjust *cvalue 00486 * - fac is the ratio of how the current y-value corresponds to the reference range 00487 * - thus, the new value is found by mapping the old range to the new! 00488 */ 00489 fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min); 00490 *cvalue= min + fac*(max - min); 00491 } 00492 00493 static FModifierTypeInfo FMI_ENVELOPE = { 00494 FMODIFIER_TYPE_ENVELOPE, /* type */ 00495 sizeof(FMod_Envelope), /* size */ 00496 FMI_TYPE_REPLACE_VALUES, /* action type */ 00497 0, /* requirements */ 00498 "Envelope", /* name */ 00499 "FMod_Envelope", /* struct name */ 00500 fcm_envelope_free, /* free data */ 00501 fcm_envelope_copy, /* copy data */ 00502 fcm_envelope_new_data, /* new data */ 00503 fcm_envelope_verify, /* verify */ 00504 NULL, /* evaluate time */ 00505 fcm_envelope_evaluate /* evaluate */ 00506 }; 00507 00508 /* Cycles F-Curve Modifier --------------------------- */ 00509 00510 /* This modifier changes evaltime to something that exists within the curve's frame-range, 00511 * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour 00512 * is very likely to be more time-consuming than the original approach... (which was tighly integrated into 00513 * the calculation code...). 00514 * 00515 * NOTE: this needs to be at the start of the stack to be of use, as it needs to know the extents of the keyframes/sample-data 00516 * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted 00517 * as appropriate 00518 */ 00519 00520 /* temp data used during evaluation */ 00521 typedef struct tFCMED_Cycles { 00522 float cycyofs; /* y-offset to apply */ 00523 } tFCMED_Cycles; 00524 00525 static void fcm_cycles_new_data (void *mdata) 00526 { 00527 FMod_Cycles *data= (FMod_Cycles *)mdata; 00528 00529 /* turn on cycles by default */ 00530 data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC; 00531 } 00532 00533 static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float UNUSED(cvalue), float evaltime) 00534 { 00535 FMod_Cycles *data= (FMod_Cycles *)fcm->data; 00536 float prevkey[2], lastkey[2], cycyofs=0.0f; 00537 short side=0, mode=0; 00538 int cycles=0, ofs=0; 00539 00540 /* check if modifier is first in stack, otherwise disable ourself... */ 00541 // FIXME... 00542 if (fcm->prev) { 00543 fcm->flag |= FMODIFIER_FLAG_DISABLED; 00544 return evaltime; 00545 } 00546 00547 /* calculate new evaltime due to cyclic interpolation */ 00548 if (fcu && fcu->bezt) { 00549 BezTriple *prevbezt= fcu->bezt; 00550 BezTriple *lastbezt= prevbezt + fcu->totvert-1; 00551 00552 prevkey[0]= prevbezt->vec[1][0]; 00553 prevkey[1]= prevbezt->vec[1][1]; 00554 00555 lastkey[0]= lastbezt->vec[1][0]; 00556 lastkey[1]= lastbezt->vec[1][1]; 00557 } 00558 else if (fcu && fcu->fpt) { 00559 FPoint *prevfpt= fcu->fpt; 00560 FPoint *lastfpt= prevfpt + fcu->totvert-1; 00561 00562 prevkey[0]= prevfpt->vec[0]; 00563 prevkey[1]= prevfpt->vec[1]; 00564 00565 lastkey[0]= lastfpt->vec[0]; 00566 lastkey[1]= lastfpt->vec[1]; 00567 } 00568 else 00569 return evaltime; 00570 00571 /* check if modifier will do anything 00572 * 1) if in data range, definitely don't do anything 00573 * 2) if before first frame or after last frame, make sure some cycling is in use 00574 */ 00575 if (evaltime < prevkey[0]) { 00576 if (data->before_mode) { 00577 side= -1; 00578 mode= data->before_mode; 00579 cycles= data->before_cycles; 00580 ofs= prevkey[0]; 00581 } 00582 } 00583 else if (evaltime > lastkey[0]) { 00584 if (data->after_mode) { 00585 side= 1; 00586 mode= data->after_mode; 00587 cycles= data->after_cycles; 00588 ofs= lastkey[0]; 00589 } 00590 } 00591 if ELEM(0, side, mode) 00592 return evaltime; 00593 00594 /* find relative place within a cycle */ 00595 { 00596 float cycdx=0, cycdy=0; 00597 float cycle= 0, cyct=0; 00598 00599 /* calculate period and amplitude (total height) of a cycle */ 00600 cycdx= lastkey[0] - prevkey[0]; 00601 cycdy= lastkey[1] - prevkey[1]; 00602 00603 /* check if cycle is infinitely small, to be point of being impossible to use */ 00604 if (cycdx == 0) 00605 return evaltime; 00606 00607 /* calculate the 'number' of the cycle */ 00608 cycle= ((float)side * (evaltime - ofs) / cycdx); 00609 00610 /* calculate the time inside the cycle */ 00611 cyct= fmod(evaltime - ofs, cycdx); 00612 00613 /* check that cyclic is still enabled for the specified time */ 00614 if (cycles == 0) { 00615 /* catch this case so that we don't exit when we have cycles=0 00616 * as this indicates infinite cycles... 00617 */ 00618 } 00619 else if (cycle > cycles) { 00620 /* we are too far away from range to evaluate 00621 * TODO: but we should still hold last value... 00622 */ 00623 return evaltime; 00624 } 00625 00626 /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */ 00627 if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) { 00628 if(side < 0) 00629 cycyofs = (float)floor((evaltime - ofs) / cycdx); 00630 else 00631 cycyofs = (float)ceil((evaltime - ofs) / cycdx); 00632 cycyofs *= cycdy; 00633 } 00634 00635 /* special case for cycle start/end */ 00636 if(cyct == 0.0f) { 00637 evaltime = (side == 1 ? lastkey[0] : prevkey[0]); 00638 00639 if((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)cycle % 2)) 00640 evaltime = (side == 1 ? prevkey[0] : lastkey[0]); 00641 } 00642 /* calculate where in the cycle we are (overwrite evaltime to reflect this) */ 00643 else if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle+1) % 2)) { 00644 /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse 00645 * - for 'before' extrapolation, we need to flip in a different way, otherwise values past 00646 * then end of the curve get referenced (result of fmod will be negative, and with different phase) 00647 */ 00648 if (side < 0) 00649 evaltime= prevkey[0] - cyct; 00650 else 00651 evaltime= lastkey[0] - cyct; 00652 } 00653 else { 00654 /* the cycle is played normally... */ 00655 evaltime= prevkey[0] + cyct; 00656 } 00657 if (evaltime < prevkey[0]) evaltime += cycdx; 00658 } 00659 00660 /* store temp data if needed */ 00661 if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) { 00662 tFCMED_Cycles *edata; 00663 00664 /* for now, this is just a float, but we could get more stuff... */ 00665 fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles"); 00666 edata->cycyofs= cycyofs; 00667 } 00668 00669 /* return the new frame to evaluate */ 00670 return evaltime; 00671 } 00672 00673 static void fcm_cycles_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime)) 00674 { 00675 tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata; 00676 00677 /* use temp data */ 00678 if (edata) { 00679 /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */ 00680 *cvalue += edata->cycyofs; 00681 00682 /* free temp data */ 00683 MEM_freeN(edata); 00684 fcm->edata= NULL; 00685 } 00686 } 00687 00688 static FModifierTypeInfo FMI_CYCLES = { 00689 FMODIFIER_TYPE_CYCLES, /* type */ 00690 sizeof(FMod_Cycles), /* size */ 00691 FMI_TYPE_EXTRAPOLATION, /* action type */ 00692 FMI_REQUIRES_ORIGINAL_DATA, /* requirements */ 00693 "Cycles", /* name */ 00694 "FMod_Cycles", /* struct name */ 00695 NULL, /* free data */ 00696 NULL, /* copy data */ 00697 fcm_cycles_new_data, /* new data */ 00698 NULL /*fcm_cycles_verify*/, /* verify */ 00699 fcm_cycles_time, /* evaluate time */ 00700 fcm_cycles_evaluate /* evaluate */ 00701 }; 00702 00703 /* Noise F-Curve Modifier --------------------------- */ 00704 00705 static void fcm_noise_new_data (void *mdata) 00706 { 00707 FMod_Noise *data= (FMod_Noise *)mdata; 00708 00709 /* defaults */ 00710 data->size= 1.0f; 00711 data->strength= 1.0f; 00712 data->phase= 1.0f; 00713 data->depth = 0; 00714 data->modification = FCM_NOISE_MODIF_REPLACE; 00715 } 00716 00717 static void fcm_noise_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime) 00718 { 00719 FMod_Noise *data= (FMod_Noise *)fcm->data; 00720 float noise; 00721 00722 /* generate noise using good ol' Blender Noise 00723 * - 0.1 is passed as the 'z' value, otherwise evaluation fails for size = phase = 1 00724 * with evaltime being an integer (which happens when evaluating on frame by frame basis) 00725 */ 00726 noise = BLI_turbulence(data->size, evaltime, data->phase, 0.1f, data->depth); 00727 00728 /* combine the noise with existing motion data */ 00729 switch (data->modification) { 00730 case FCM_NOISE_MODIF_ADD: 00731 *cvalue= *cvalue + noise * data->strength; 00732 break; 00733 case FCM_NOISE_MODIF_SUBTRACT: 00734 *cvalue= *cvalue - noise * data->strength; 00735 break; 00736 case FCM_NOISE_MODIF_MULTIPLY: 00737 *cvalue= *cvalue * noise * data->strength; 00738 break; 00739 case FCM_NOISE_MODIF_REPLACE: 00740 default: 00741 *cvalue= *cvalue + (noise - 0.5f) * data->strength; 00742 break; 00743 } 00744 } 00745 00746 static FModifierTypeInfo FMI_NOISE = { 00747 FMODIFIER_TYPE_NOISE, /* type */ 00748 sizeof(FMod_Noise), /* size */ 00749 FMI_TYPE_REPLACE_VALUES, /* action type */ 00750 0, /* requirements */ 00751 "Noise", /* name */ 00752 "FMod_Noise", /* struct name */ 00753 NULL, /* free data */ 00754 NULL, /* copy data */ 00755 fcm_noise_new_data, /* new data */ 00756 NULL /*fcm_noise_verify*/, /* verify */ 00757 NULL, /* evaluate time */ 00758 fcm_noise_evaluate /* evaluate */ 00759 }; 00760 00761 /* Filter F-Curve Modifier --------------------------- */ 00762 00763 #if 0 // XXX not yet implemented 00764 static FModifierTypeInfo FMI_FILTER = { 00765 FMODIFIER_TYPE_FILTER, /* type */ 00766 sizeof(FMod_Filter), /* size */ 00767 FMI_TYPE_REPLACE_VALUES, /* action type */ 00768 0, /* requirements */ 00769 "Filter", /* name */ 00770 "FMod_Filter", /* struct name */ 00771 NULL, /* free data */ 00772 NULL, /* copy data */ 00773 NULL, /* new data */ 00774 NULL /*fcm_filter_verify*/, /* verify */ 00775 NULL, /* evlauate time */ 00776 fcm_filter_evaluate /* evaluate */ 00777 }; 00778 #endif // XXX not yet implemented 00779 00780 00781 /* Python F-Curve Modifier --------------------------- */ 00782 00783 static void fcm_python_free (FModifier *fcm) 00784 { 00785 FMod_Python *data= (FMod_Python *)fcm->data; 00786 00787 /* id-properties */ 00788 IDP_FreeProperty(data->prop); 00789 MEM_freeN(data->prop); 00790 } 00791 00792 static void fcm_python_new_data (void *mdata) 00793 { 00794 FMod_Python *data= (FMod_Python *)mdata; 00795 00796 /* everything should be set correctly by calloc, except for the prop->type constant.*/ 00797 data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps"); 00798 data->prop->type = IDP_GROUP; 00799 } 00800 00801 static void fcm_python_copy (FModifier *fcm, FModifier *src) 00802 { 00803 FMod_Python *pymod = (FMod_Python *)fcm->data; 00804 FMod_Python *opymod = (FMod_Python *)src->data; 00805 00806 pymod->prop = IDP_CopyProperty(opymod->prop); 00807 } 00808 00809 static void fcm_python_evaluate (FCurve *UNUSED(fcu), FModifier *UNUSED(fcm), float *UNUSED(cvalue), float UNUSED(evaltime)) 00810 { 00811 #ifdef WITH_PYTHON 00812 //FMod_Python *data= (FMod_Python *)fcm->data; 00813 00814 /* FIXME... need to implement this modifier... 00815 * It will need it execute a script using the custom properties 00816 */ 00817 #endif /* WITH_PYTHON */ 00818 } 00819 00820 static FModifierTypeInfo FMI_PYTHON = { 00821 FMODIFIER_TYPE_PYTHON, /* type */ 00822 sizeof(FMod_Python), /* size */ 00823 FMI_TYPE_GENERATE_CURVE, /* action type */ 00824 FMI_REQUIRES_RUNTIME_CHECK, /* requirements */ 00825 "Python", /* name */ 00826 "FMod_Python", /* struct name */ 00827 fcm_python_free, /* free data */ 00828 fcm_python_copy, /* copy data */ 00829 fcm_python_new_data, /* new data */ 00830 NULL /*fcm_python_verify*/, /* verify */ 00831 NULL /*fcm_python_time*/, /* evaluate time */ 00832 fcm_python_evaluate /* evaluate */ 00833 }; 00834 00835 00836 /* Limits F-Curve Modifier --------------------------- */ 00837 00838 static float fcm_limits_time (FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime) 00839 { 00840 FMod_Limits *data= (FMod_Limits *)fcm->data; 00841 00842 /* check for the time limits */ 00843 if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin)) 00844 return data->rect.xmin; 00845 if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax)) 00846 return data->rect.xmax; 00847 00848 /* modifier doesn't change time */ 00849 return evaltime; 00850 } 00851 00852 static void fcm_limits_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime)) 00853 { 00854 FMod_Limits *data= (FMod_Limits *)fcm->data; 00855 00856 /* value limits now */ 00857 if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin)) 00858 *cvalue= data->rect.ymin; 00859 if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax)) 00860 *cvalue= data->rect.ymax; 00861 } 00862 00863 static FModifierTypeInfo FMI_LIMITS = { 00864 FMODIFIER_TYPE_LIMITS, /* type */ 00865 sizeof(FMod_Limits), /* size */ 00866 FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */ 00867 FMI_REQUIRES_RUNTIME_CHECK, /* requirements */ 00868 "Limits", /* name */ 00869 "FMod_Limits", /* struct name */ 00870 NULL, /* free data */ 00871 NULL, /* copy data */ 00872 NULL, /* new data */ 00873 NULL, /* verify */ 00874 fcm_limits_time, /* evaluate time */ 00875 fcm_limits_evaluate /* evaluate */ 00876 }; 00877 00878 /* Stepped F-Curve Modifier --------------------------- */ 00879 00880 static void fcm_stepped_new_data (void *mdata) 00881 { 00882 FMod_Stepped *data= (FMod_Stepped *)mdata; 00883 00884 /* just need to set the step-size to 2-frames by default */ 00885 // XXX: or would 5 be more normal? 00886 data->step_size = 2.0f; 00887 } 00888 00889 static float fcm_stepped_time (FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime) 00890 { 00891 FMod_Stepped *data= (FMod_Stepped *)fcm->data; 00892 int snapblock; 00893 00894 /* check range clamping to see if we should alter the timing to achieve the desired results */ 00895 if (data->flag & FCM_STEPPED_NO_BEFORE) { 00896 if (evaltime < data->start_frame) 00897 return evaltime; 00898 } 00899 if (data->flag & FCM_STEPPED_NO_AFTER) { 00900 if (evaltime > data->end_frame) 00901 return evaltime; 00902 } 00903 00904 /* we snap to the start of the previous closest block of 'step_size' frames 00905 * after the start offset has been discarded 00906 * - i.e. round down 00907 */ 00908 snapblock = (int)((evaltime - data->offset) / data->step_size); 00909 00910 /* reapply the offset, and multiple the snapblock by the size of the steps to get 00911 * the new time to evaluate at 00912 */ 00913 return ((float)snapblock * data->step_size) + data->offset; 00914 } 00915 00916 static FModifierTypeInfo FMI_STEPPED = { 00917 FMODIFIER_TYPE_STEPPED, /* type */ 00918 sizeof(FMod_Limits), /* size */ 00919 FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */ 00920 FMI_REQUIRES_RUNTIME_CHECK, /* requirements */ 00921 "Stepped", /* name */ 00922 "FMod_Stepped", /* struct name */ 00923 NULL, /* free data */ 00924 NULL, /* copy data */ 00925 fcm_stepped_new_data, /* new data */ 00926 NULL, /* verify */ 00927 fcm_stepped_time, /* evaluate time */ 00928 NULL /* evaluate */ 00929 }; 00930 00931 /* F-Curve Modifier API --------------------------- */ 00932 /* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out 00933 * and operations that involve F-Curve modifier specific code. 00934 */ 00935 00936 /* These globals only ever get directly accessed in this file */ 00937 static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES]; 00938 static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */ 00939 00940 /* This function only gets called when FMI_INIT is non-zero */ 00941 static void fmods_init_typeinfo (void) 00942 { 00943 fmodifiersTypeInfo[0]= NULL; /* 'Null' F-Curve Modifier */ 00944 fmodifiersTypeInfo[1]= &FMI_GENERATOR; /* Generator F-Curve Modifier */ 00945 fmodifiersTypeInfo[2]= &FMI_FN_GENERATOR; /* Built-In Function Generator F-Curve Modifier */ 00946 fmodifiersTypeInfo[3]= &FMI_ENVELOPE; /* Envelope F-Curve Modifier */ 00947 fmodifiersTypeInfo[4]= &FMI_CYCLES; /* Cycles F-Curve Modifier */ 00948 fmodifiersTypeInfo[5]= &FMI_NOISE; /* Apply-Noise F-Curve Modifier */ 00949 fmodifiersTypeInfo[6]= NULL/*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented 00950 fmodifiersTypeInfo[7]= &FMI_PYTHON; /* Custom Python F-Curve Modifier */ 00951 fmodifiersTypeInfo[8]= &FMI_LIMITS; /* Limits F-Curve Modifier */ 00952 fmodifiersTypeInfo[9]= &FMI_STEPPED; /* Stepped F-Curve Modifier */ 00953 } 00954 00955 /* This function should be used for getting the appropriate type-info when only 00956 * a F-Curve modifier type is known 00957 */ 00958 FModifierTypeInfo *get_fmodifier_typeinfo (int type) 00959 { 00960 /* initialise the type-info list? */ 00961 if (FMI_INIT) { 00962 fmods_init_typeinfo(); 00963 FMI_INIT = 0; 00964 } 00965 00966 /* only return for valid types */ 00967 if ( (type >= FMODIFIER_TYPE_NULL) && 00968 (type <= FMODIFIER_NUM_TYPES ) ) 00969 { 00970 /* there shouldn't be any segfaults here... */ 00971 return fmodifiersTypeInfo[type]; 00972 } 00973 else { 00974 printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type); 00975 } 00976 00977 return NULL; 00978 } 00979 00980 /* This function should always be used to get the appropriate type-info, as it 00981 * has checks which prevent segfaults in some weird cases. 00982 */ 00983 FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm) 00984 { 00985 /* only return typeinfo for valid modifiers */ 00986 if (fcm) 00987 return get_fmodifier_typeinfo(fcm->type); 00988 else 00989 return NULL; 00990 } 00991 00992 /* API --------------------------- */ 00993 00994 /* Add a new F-Curve Modifier to the given F-Curve of a certain type */ 00995 FModifier *add_fmodifier (ListBase *modifiers, int type) 00996 { 00997 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type); 00998 FModifier *fcm; 00999 01000 /* sanity checks */ 01001 if ELEM(NULL, modifiers, fmi) 01002 return NULL; 01003 01004 /* special checks for whether modifier can be added */ 01005 if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) { 01006 /* cycles modifier must be first in stack, so for now, don't add if it can't be */ 01007 // TODO: perhaps there is some better way, but for now, 01008 printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n"); 01009 return NULL; 01010 } 01011 01012 /* add modifier itself */ 01013 fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier"); 01014 fcm->type = type; 01015 fcm->flag = FMODIFIER_FLAG_EXPANDED; 01016 BLI_addtail(modifiers, fcm); 01017 01018 /* tag modifier as "active" if no other modifiers exist in the stack yet */ 01019 if (modifiers->first == modifiers->last) 01020 fcm->flag |= FMODIFIER_FLAG_ACTIVE; 01021 01022 /* add modifier's data */ 01023 fcm->data= MEM_callocN(fmi->size, fmi->structName); 01024 01025 /* init custom settings if necessary */ 01026 if (fmi->new_data) 01027 fmi->new_data(fcm->data); 01028 01029 /* return modifier for further editing */ 01030 return fcm; 01031 } 01032 01033 /* Make a copy of the specified F-Modifier */ 01034 FModifier *copy_fmodifier (FModifier *src) 01035 { 01036 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(src); 01037 FModifier *dst; 01038 01039 /* sanity check */ 01040 if (src == NULL) 01041 return NULL; 01042 01043 /* copy the base data, clearing the links */ 01044 dst = MEM_dupallocN(src); 01045 dst->next = dst->prev = NULL; 01046 01047 /* make a new copy of the F-Modifier's data */ 01048 dst->data = MEM_dupallocN(src->data); 01049 01050 /* only do specific constraints if required */ 01051 if (fmi && fmi->copy_data) 01052 fmi->copy_data(dst, src); 01053 01054 /* return the new modifier */ 01055 return dst; 01056 } 01057 01058 /* Duplicate all of the F-Modifiers in the Modifier stacks */ 01059 void copy_fmodifiers (ListBase *dst, ListBase *src) 01060 { 01061 FModifier *fcm, *srcfcm; 01062 01063 if ELEM(NULL, dst, src) 01064 return; 01065 01066 dst->first= dst->last= NULL; 01067 BLI_duplicatelist(dst, src); 01068 01069 for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) { 01070 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); 01071 01072 /* make a new copy of the F-Modifier's data */ 01073 fcm->data = MEM_dupallocN(fcm->data); 01074 01075 /* only do specific constraints if required */ 01076 if (fmi && fmi->copy_data) 01077 fmi->copy_data(fcm, srcfcm); 01078 } 01079 } 01080 01081 /* Remove and free the given F-Modifier from the given stack */ 01082 int remove_fmodifier (ListBase *modifiers, FModifier *fcm) 01083 { 01084 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); 01085 01086 /* sanity check */ 01087 if (fcm == NULL) 01088 return 0; 01089 01090 /* free modifier's special data (stored inside fcm->data) */ 01091 if (fcm->data) { 01092 if (fmi && fmi->free_data) 01093 fmi->free_data(fcm); 01094 01095 /* free modifier's data (fcm->data) */ 01096 MEM_freeN(fcm->data); 01097 } 01098 01099 /* remove modifier from stack */ 01100 if (modifiers) { 01101 BLI_freelinkN(modifiers, fcm); 01102 return 1; 01103 } 01104 else { 01105 // XXX this case can probably be removed some day, as it shouldn't happen... 01106 printf("remove_fmodifier() - no modifier stack given \n"); 01107 MEM_freeN(fcm); 01108 return 0; 01109 } 01110 } 01111 01112 /* Remove all of a given F-Curve's modifiers */ 01113 void free_fmodifiers (ListBase *modifiers) 01114 { 01115 FModifier *fcm, *fmn; 01116 01117 /* sanity check */ 01118 if (modifiers == NULL) 01119 return; 01120 01121 /* free each modifier in order - modifier is unlinked from list and freed */ 01122 for (fcm= modifiers->first; fcm; fcm= fmn) { 01123 fmn= fcm->next; 01124 remove_fmodifier(modifiers, fcm); 01125 } 01126 } 01127 01128 /* Find the active F-Modifier */ 01129 FModifier *find_active_fmodifier (ListBase *modifiers) 01130 { 01131 FModifier *fcm; 01132 01133 /* sanity checks */ 01134 if ELEM(NULL, modifiers, modifiers->first) 01135 return NULL; 01136 01137 /* loop over modifiers until 'active' one is found */ 01138 for (fcm= modifiers->first; fcm; fcm= fcm->next) { 01139 if (fcm->flag & FMODIFIER_FLAG_ACTIVE) 01140 return fcm; 01141 } 01142 01143 /* no modifier is active */ 01144 return NULL; 01145 } 01146 01147 /* Set the active F-Modifier */ 01148 void set_active_fmodifier (ListBase *modifiers, FModifier *fcm) 01149 { 01150 FModifier *fm; 01151 01152 /* sanity checks */ 01153 if ELEM(NULL, modifiers, modifiers->first) 01154 return; 01155 01156 /* deactivate all, and set current one active */ 01157 for (fm= modifiers->first; fm; fm= fm->next) 01158 fm->flag &= ~FMODIFIER_FLAG_ACTIVE; 01159 01160 /* make given modifier active */ 01161 if (fcm) 01162 fcm->flag |= FMODIFIER_FLAG_ACTIVE; 01163 } 01164 01165 /* Do we have any modifiers which match certain criteria 01166 * - mtype - type of modifier (if 0, doesn't matter) 01167 * - acttype - type of action to perform (if -1, doesn't matter) 01168 */ 01169 short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype) 01170 { 01171 FModifier *fcm; 01172 01173 /* if there are no specific filtering criteria, just skip */ 01174 if ((mtype == 0) && (acttype == 0)) 01175 return (modifiers && modifiers->first); 01176 01177 /* sanity checks */ 01178 if ELEM(NULL, modifiers, modifiers->first) 01179 return 0; 01180 01181 /* find the first mdifier fitting these criteria */ 01182 for (fcm= modifiers->first; fcm; fcm= fcm->next) { 01183 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); 01184 short mOk=1, aOk=1; /* by default 1, so that when only one test, won't fail */ 01185 01186 /* check if applicable ones are fullfilled */ 01187 if (mtype) 01188 mOk= (fcm->type == mtype); 01189 if (acttype > -1) 01190 aOk= (fmi->acttype == acttype); 01191 01192 /* if both are ok, we've found a hit */ 01193 if (mOk && aOk) 01194 return 1; 01195 } 01196 01197 /* no matches */ 01198 return 0; 01199 } 01200 01201 /* Evaluation API --------------------------- */ 01202 01203 /* evaluate time modifications imposed by some F-Curve Modifiers 01204 * - this step acts as an optimisation to prevent the F-Curve stack being evaluated 01205 * several times by modifiers requesting the time be modified, as the final result 01206 * would have required using the modified time 01207 * - modifiers only ever receive the unmodified time, as subsequent modifiers should be 01208 * working on the 'global' result of the modified curve, not some localised segment, 01209 * so nevaltime gets set to whatever the last time-modifying modifier likes... 01210 * - we start from the end of the stack, as only the last one matters for now 01211 */ 01212 float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime) 01213 { 01214 FModifier *fcm; 01215 01216 /* sanity checks */ 01217 if ELEM(NULL, modifiers, modifiers->last) 01218 return evaltime; 01219 01220 /* Starting from the end of the stack, calculate the time effects of various stacked modifiers 01221 * on the time the F-Curve should be evaluated at. 01222 * 01223 * This is done in reverse order to standard evaluation, as when this is done in standard 01224 * order, each modifier would cause jumps to other points in the curve, forcing all 01225 * previous ones to be evaluated again for them to be correct. However, if we did in the 01226 * reverse order as we have here, we can consider them a macro to micro type of waterfall 01227 * effect, which should get us the desired effects when using layered time manipulations 01228 * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates) 01229 */ 01230 for (fcm= modifiers->last; fcm; fcm= fcm->prev) { 01231 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); 01232 01233 /* only evaluate if there's a callback for this */ 01234 // TODO: implement the 'influence' control feature... 01235 if (fmi && fmi->evaluate_modifier_time) { 01236 if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) 01237 evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime); 01238 } 01239 } 01240 01241 /* return the modified evaltime */ 01242 return evaltime; 01243 } 01244 01245 /* Evalautes the given set of F-Curve Modifiers using the given data 01246 * Should only be called after evaluate_time_fmodifiers() has been called... 01247 */ 01248 void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime) 01249 { 01250 FModifier *fcm; 01251 01252 /* sanity checks */ 01253 if ELEM(NULL, modifiers, modifiers->first) 01254 return; 01255 01256 /* evaluate modifiers */ 01257 for (fcm= modifiers->first; fcm; fcm= fcm->next) { 01258 FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); 01259 01260 /* only evaluate if there's a callback for this */ 01261 // TODO: implement the 'influence' control feature... 01262 if (fmi && fmi->evaluate_modifier) { 01263 if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) 01264 fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime); 01265 } 01266 } 01267 } 01268 01269 /* ---------- */ 01270 01271 /* Bake modifiers for given F-Curve to curve sample data, in the frame range defined 01272 * by start and end (inclusive). 01273 */ 01274 void fcurve_bake_modifiers (FCurve *fcu, int start, int end) 01275 { 01276 ChannelDriver *driver; 01277 01278 /* sanity checks */ 01279 // TODO: make these tests report errors using reports not printf's 01280 if ELEM(NULL, fcu, fcu->modifiers.first) { 01281 printf("Error: No F-Curve with F-Curve Modifiers to Bake\n"); 01282 return; 01283 } 01284 01285 /* temporarily, disable driver while we sample, so that they don't influence the outcome */ 01286 driver= fcu->driver; 01287 fcu->driver= NULL; 01288 01289 /* bake the modifiers, by sampling the curve at each frame */ 01290 fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve); 01291 01292 /* free the modifiers now */ 01293 free_fmodifiers(&fcu->modifiers); 01294 01295 /* restore driver */ 01296 fcu->driver= driver; 01297 }