From 5b6ee803516a2ccb9f43e4d6ee0b6f77c22745cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 1 May 2020 15:49:59 +0200 Subject: Cleanup: Animation, split FCurve interpolation into separate function --- source/blender/blenkernel/intern/fcurve.c | 616 +++++++++++++++--------------- 1 file changed, 309 insertions(+), 307 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 2506c937dc5..8f2726b147a 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1462,11 +1462,10 @@ static float fcurve_eval_keyframes_extrapolate( return endpoint_bezt->vec[1][1] - (fac * dx); } -/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ -static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime) +static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, float evaltime) { const float eps = 1.e-8f; - BezTriple *bezt, *prevbezt, *lastbezt; + BezTriple *bezt, *prevbezt; float v1[2], v2[2], v3[2], v4[2], opl[32]; unsigned int a; int b; @@ -1476,329 +1475,332 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime a = fcu->totvert - 1; prevbezt = bezts; bezt = prevbezt + 1; - lastbezt = prevbezt + a; - /* evaluation time at or past endpoints? */ - if (prevbezt->vec[1][0] >= evaltime) { - cvalue = fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1); - } - else if (lastbezt->vec[1][0] <= evaltime) { - cvalue = fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1); + /* evaltime occurs somewhere in the middle of the curve */ + bool exact = false; + + /* Use binary search to find appropriate keyframes... + * + * The threshold here has the following constraints: + * - 0.001 is too coarse: + * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332) + * + * - 0.00001 is too fine: + * Weird errors, like selecting the wrong keyframe range (see T39207), occur. + * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd. + */ + a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact); + + if (exact) { + /* index returned must be interpreted differently when it sits on top of an existing keyframe + * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207) + */ + prevbezt = bezts + a; + bezt = (a < fcu->totvert - 1) ? (prevbezt + 1) : prevbezt; } else { - /* evaltime occurs somewhere in the middle of the curve */ - bool exact = false; - - /* Use binary search to find appropriate keyframes... - * - * The threshold here has the following constraints: - * - 0.001 is too coarse: - * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332) - * - * - 0.00001 is too fine: - * Weird errors, like selecting the wrong keyframe range (see T39207), occur. - * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd. + /* index returned refers to the keyframe that the eval-time occurs *before* + * - hence, that keyframe marks the start of the segment we're dealing with */ - a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact); - - if (exact) { - /* index returned must be interpreted differently when it sits on top of an existing keyframe - * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207) - */ - prevbezt = bezts + a; - bezt = (a < fcu->totvert - 1) ? (prevbezt + 1) : prevbezt; - } - else { - /* index returned refers to the keyframe that the eval-time occurs *before* - * - hence, that keyframe marks the start of the segment we're dealing with - */ - bezt = bezts + a; - prevbezt = (a > 0) ? (bezt - 1) : bezt; - } - - /* use if the key is directly on the frame, - * rare cases this is needed else we get 0.0 instead. */ - /* XXX: consult T39207 for examples of files where failure of these checks can cause issues */ - if (exact) { + bezt = bezts + a; + prevbezt = (a > 0) ? (bezt - 1) : bezt; + } + + /* use if the key is directly on the frame, + * rare cases this is needed else we get 0.0 instead. */ + /* XXX: consult T39207 for examples of files where failure of these checks can cause issues */ + if (exact) { + cvalue = prevbezt->vec[1][1]; + } + else if (fabsf(bezt->vec[1][0] - evaltime) < eps) { + cvalue = bezt->vec[1][1]; + } + /* evaltime occurs within the interval defined by these two keyframes */ + else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) { + const float begin = prevbezt->vec[1][1]; + const float change = bezt->vec[1][1] - prevbezt->vec[1][1]; + const float duration = bezt->vec[1][0] - prevbezt->vec[1][0]; + const float time = evaltime - prevbezt->vec[1][0]; + const float amplitude = prevbezt->amplitude; + const float period = prevbezt->period; + + /* value depends on interpolation mode */ + if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || + (duration == 0)) { + /* constant (evaltime not relevant, so no interpolation needed) */ cvalue = prevbezt->vec[1][1]; } - else if (fabsf(bezt->vec[1][0] - evaltime) < eps) { - cvalue = bezt->vec[1][1]; - } - /* evaltime occurs within the interval defined by these two keyframes */ - else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) { - const float begin = prevbezt->vec[1][1]; - const float change = bezt->vec[1][1] - prevbezt->vec[1][1]; - const float duration = bezt->vec[1][0] - prevbezt->vec[1][0]; - const float time = evaltime - prevbezt->vec[1][0]; - const float amplitude = prevbezt->amplitude; - const float period = prevbezt->period; - - /* value depends on interpolation mode */ - if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || - (duration == 0)) { - /* constant (evaltime not relevant, so no interpolation needed) */ - cvalue = prevbezt->vec[1][1]; - } - else { - switch (prevbezt->ipo) { - /* interpolation ...................................... */ - case BEZT_IPO_BEZ: - /* bezier interpolation */ - /* (v1, v2) are the first keyframe and its 2nd handle */ - v1[0] = prevbezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - v2[0] = prevbezt->vec[2][0]; - v2[1] = prevbezt->vec[2][1]; - /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ - v3[0] = bezt->vec[0][0]; - v3[1] = bezt->vec[0][1]; - v4[0] = bezt->vec[1][0]; - v4[1] = bezt->vec[1][1]; - - if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON && - fabsf(v3[1] - v4[1]) < FLT_EPSILON) { - /* Optimization: If all the handles are flat/at the same values, - * the value is simply the shared value (see T40372 -> F91346) - */ - cvalue = v1[1]; + else { + switch (prevbezt->ipo) { + /* interpolation ...................................... */ + case BEZT_IPO_BEZ: + /* bezier interpolation */ + /* (v1, v2) are the first keyframe and its 2nd handle */ + v1[0] = prevbezt->vec[1][0]; + v1[1] = prevbezt->vec[1][1]; + v2[0] = prevbezt->vec[2][0]; + v2[1] = prevbezt->vec[2][1]; + /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ + v3[0] = bezt->vec[0][0]; + v3[1] = bezt->vec[0][1]; + v4[0] = bezt->vec[1][0]; + v4[1] = bezt->vec[1][1]; + + if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON && + fabsf(v3[1] - v4[1]) < FLT_EPSILON) { + /* Optimization: If all the handles are flat/at the same values, + * the value is simply the shared value (see T40372 -> F91346) + */ + cvalue = v1[1]; + } + else { + /* adjust handles so that they don't overlap (forming a loop) */ + correct_bezpart(v1, v2, v3, v4); + + /* try to get a value for this position - if failure, try another set of points */ + b = findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl); + if (b) { + berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); + cvalue = opl[0]; + /* break; */ } else { - /* adjust handles so that they don't overlap (forming a loop) */ - correct_bezpart(v1, v2, v3, v4); - - /* try to get a value for this position - if failure, try another set of points */ - b = findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl); - if (b) { - berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); - cvalue = opl[0]; - /* break; */ + if (G.debug & G_DEBUG) { + printf(" ERROR: findzero() failed at %f with %f %f %f %f\n", + evaltime, + v1[0], + v2[0], + v3[0], + v4[0]); } - else { - if (G.debug & G_DEBUG) { - printf(" ERROR: findzero() failed at %f with %f %f %f %f\n", - evaltime, - v1[0], - v2[0], - v3[0], - v4[0]); - } - } - } - break; - - case BEZT_IPO_LIN: - /* linear - simply linearly interpolate between values of the two keyframes */ - cvalue = BLI_easing_linear_ease(time, begin, change, duration); - break; - - /* easing ............................................ */ - case BEZT_IPO_BACK: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_back_ease_in_out( - time, begin, change, duration, prevbezt->back); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); - break; } - break; - - case BEZT_IPO_BOUNCE: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_bounce_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_bounce_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_CIRC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_circ_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_circ_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_CUBIC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_cubic_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_cubic_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_ELASTIC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_elastic_ease_in( - time, begin, change, duration, amplitude, period); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_elastic_ease_out( - time, begin, change, duration, amplitude, period); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_elastic_ease_in_out( - time, begin, change, duration, amplitude, period); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_elastic_ease_out( - time, begin, change, duration, amplitude, period); - break; - } - break; - - case BEZT_IPO_EXPO: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_expo_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_expo_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_QUAD: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quad_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quad_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_QUART: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quart_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quart_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_QUINT: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quint_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quint_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_SINE: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_sine_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_sine_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); - break; - } - break; + } + break; - default: - cvalue = prevbezt->vec[1][1]; - break; - } + case BEZT_IPO_LIN: + /* linear - simply linearly interpolate between values of the two keyframes */ + cvalue = BLI_easing_linear_ease(time, begin, change, duration); + break; + + /* easing ............................................ */ + case BEZT_IPO_BACK: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back); + break; + + default: /* default/auto: same as ease out */ + cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); + break; + } + break; + + case BEZT_IPO_BOUNCE: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_bounce_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_bounce_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease out */ + cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_CIRC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_circ_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_circ_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_CUBIC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_cubic_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_cubic_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_ELASTIC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_elastic_ease_in( + time, begin, change, duration, amplitude, period); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_elastic_ease_out( + time, begin, change, duration, amplitude, period); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_elastic_ease_in_out( + time, begin, change, duration, amplitude, period); + break; + + default: /* default/auto: same as ease out */ + cvalue = BLI_easing_elastic_ease_out( + time, begin, change, duration, amplitude, period); + break; + } + break; + + case BEZT_IPO_EXPO: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_expo_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_expo_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_QUAD: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_quad_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_quad_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_QUART: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_quart_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_quart_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_QUINT: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_quint_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_quint_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_SINE: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + cvalue = BLI_easing_sine_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + cvalue = BLI_easing_sine_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); + break; + } + break; + + default: + cvalue = prevbezt->vec[1][1]; + break; } } - else { - if (G.debug & G_DEBUG) { - printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n", - prevbezt->vec[1][0], - bezt->vec[1][0], - evaltime, - fabsf(bezt->vec[1][0] - evaltime)); - } + } + else { + if (G.debug & G_DEBUG) { + printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n", + prevbezt->vec[1][0], + bezt->vec[1][0], + evaltime, + fabsf(bezt->vec[1][0] - evaltime)); } } - /* return value */ return cvalue; } +/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ +static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime) +{ + if (evaltime <= bezts->vec[1][0]) { + return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1); + } + + BezTriple *lastbezt = bezts + fcu->totvert - 1; + if (lastbezt->vec[1][0] <= evaltime) { + return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1); + } + + return fcurve_eval_keyframes_interpolate(fcu, bezts, evaltime); +} + /* Calculate F-Curve value for 'evaltime' using FPoint samples */ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime) { -- cgit v1.2.3