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