Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2014-03-21 17:50:24 +0400
committerJoshua Leung <aligorith@gmail.com>2014-03-21 18:00:27 +0400
commitdaccaa713b6e66af4b958fa373b31d557a4caa33 (patch)
tree9e257e0b6d9e641ab3c9843304c9644ff9ca76ab
parent6e99fb04b6cccef4d5685184dfd0d1406fc6e624 (diff)
Patch T22084: Robert Penner Easing Equations for FCurves
This commit introduces support for a number of new interpolation types which are useful for motion-graphics work. These define a number of "easing equations" (basically, equations which define some preset ways that one keyframe transitions to another) which reduce the amount of manual work (inserting and tweaking keyframes) to achieve certain common effects. For example, snappy movements, and fake-physics such as bouncing/springing effects. The additional interpolation types introduced in this commit can be found in many packages and toolkits (notably Qt and all modern web browsers). For more info and a few live demos, see [1] and [2]. Credits: * Dan Eicher (dna) - Original patch * Thomas Beck (plasmasolutions) - Porting/updating patch to 2.70 codebase * Joshua Leung (aligorith) - Code review and a few polishing tweaks Additional Resources: [1] http://easings.net [2] http://www.robertpenner.com/easing/
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py1
-rw-r--r--source/blender/blenkernel/intern/fcurve.c227
-rw-r--r--source/blender/blenlib/BLI_math_easing.h78
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/math_easing.c312
-rw-r--r--source/blender/editors/animation/keyframes_edit.c133
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h1
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c21
-rw-r--r--source/blender/editors/space_graph/graph_draw.c7
-rw-r--r--source/blender/editors/space_graph/graph_edit.c66
-rw-r--r--source/blender/editors/space_graph/graph_intern.h1
-rw-r--r--source/blender/editors/space_graph/graph_ops.c2
-rw-r--r--source/blender/makesdna/DNA_curve_types.h31
-rw-r--r--source/blender/makesrna/RNA_enum_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_curve.c22
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c32
16 files changed, 895 insertions, 42 deletions
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index e4fb53805b6..67fc2867536 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -227,6 +227,7 @@ class GRAPH_MT_key(Menu):
layout.separator()
layout.operator_menu_enum("graph.handle_type", "type", text="Handle Type")
layout.operator_menu_enum("graph.interpolation_type", "type", text="Interpolation Mode")
+ layout.operator_menu_enum("graph.easing_type", "type", text="Easing Type")
layout.separator()
layout.operator("graph.clean")
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index c6b64a112c7..e496513131f 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -45,6 +45,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_math_easing.h"
#include "BLI_utildefines.h"
#include "BLF_translation.h"
@@ -2080,49 +2081,199 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime
}
/* 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)) {
+ 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 (prevbezt->ipo == BEZT_IPO_LIN) {
- /* linear - interpolate between values of the two keyframes */
- fac = bezt->vec[1][0] - prevbezt->vec[1][0];
-
- /* prevent division by zero */
- if (fac) {
- fac = (evaltime - prevbezt->vec[1][0]) / fac;
- cvalue = prevbezt->vec[1][1] + (fac * (bezt->vec[1][1] - prevbezt->vec[1][1]));
- }
- else {
- cvalue = prevbezt->vec[1][1];
- }
- }
else {
- /* 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];
-
- /* 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 {
- 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]);
+ 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];
+
+ /* 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 {
+ 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 = LinearEase(time, begin, change, duration);
+ break;
+
+ /* easing ............................................ */
+ case BEZT_IPO_BACK:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BackEaseIn(time, begin, change, duration, prevbezt->back);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BackEaseOut(time, begin, change, duration, prevbezt->back);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BackEaseInOut(time, begin, change, duration, prevbezt->back);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_BOUNCE:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BounceEaseIn(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BounceEaseOut(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BounceEaseInOut(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_CIRC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = CircEaseIn(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = CircEaseOut(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = CircEaseInOut(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_CUBIC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = CubicEaseIn(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = CubicEaseOut(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = CubicEaseInOut(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_ELASTIC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = ElasticEaseIn(time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = ElasticEaseOut(time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = ElasticEaseInOut(time, begin, change, duration, amplitude, period);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_EXPO:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = ExpoEaseIn(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = ExpoEaseOut(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = ExpoEaseInOut(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_QUAD:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = QuadEaseIn(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = QuadEaseOut(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = QuadEaseInOut(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_QUART:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = QuartEaseIn(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = QuartEaseOut(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = QuartEaseInOut(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_QUINT:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = QuintEaseIn(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = QuintEaseOut(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = QuintEaseInOut(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_SINE:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = SineEaseIn(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = SineEaseOut(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = SineEaseInOut(time, begin, change, duration);
+ break;
+ }
+ break;
+
+
+ default:
+ cvalue = prevbezt->vec[1][1];
+ break;
}
}
}
diff --git a/source/blender/blenlib/BLI_math_easing.h b/source/blender/blenlib/BLI_math_easing.h
new file mode 100644
index 00000000000..c6518491bb3
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_easing.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the author nor the names of contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BLI_MATH_EASING_H__
+#define __BLI_MATH_EASING_H__
+
+/** \file BLI_math_easing.h
+ * \ingroup bli
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+float BackEaseIn(float time, float begin, float change, float duration, float overshoot);
+float BackEaseOut(float time, float begin, float change, float duration, float overshoot);
+float BackEaseInOut(float time, float begin, float change, float duration, float overshoot);
+float BounceEaseOut(float time, float begin, float change, float duration);
+float BounceEaseIn(float time, float begin, float change, float duration);
+float BounceEaseInOut(float time, float begin, float change, float duration);
+float CircEaseIn(float time, float begin, float change, float duration);
+float CircEaseOut(float time, float begin, float change, float duration);
+float CircEaseInOut(float time, float begin, float change, float duration);
+float CubicEaseIn(float time, float begin, float change, float duration);
+float CubicEaseOut(float time, float begin, float change, float duration);
+float CubicEaseInOut(float time, float begin, float change, float duration);
+float ElasticEaseIn(float time, float begin, float change, float duration, float amplitude, float period);
+float ElasticEaseOut(float time, float begin, float change, float duration, float amplitude, float period);
+float ElasticEaseInOut(float time, float begin, float change, float duration, float amplitude, float period);
+float ExpoEaseIn(float time, float begin, float change, float duration);
+float ExpoEaseOut(float time, float begin, float change, float duration);
+float ExpoEaseInOut(float time, float begin, float change, float duration);
+float LinearEase(float time, float begin, float change, float duration);
+float QuadEaseIn(float time, float begin, float change, float duration);
+float QuadEaseOut(float time, float begin, float change, float duration);
+float QuadEaseInOut(float time, float begin, float change, float duration);
+float QuartEaseIn(float time, float begin, float change, float duration);
+float QuartEaseOut(float time, float begin, float change, float duration);
+float QuartEaseInOut(float time, float begin, float change, float duration);
+float QuintEaseIn(float time, float begin, float change, float duration);
+float QuintEaseOut(float time, float begin, float change, float duration);
+float QuintEaseInOut(float time, float begin, float change, float duration);
+float SineEaseIn(float time, float begin, float change, float duration);
+float SineEaseOut(float time, float begin, float change, float duration);
+float SineEaseInOut(float time, float begin, float change, float duration);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __BLI_MATH_EASING_H__
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 9194bb5a54c..24973cece91 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -72,6 +72,7 @@ set(SRC
intern/math_color.c
intern/math_color_blend_inline.c
intern/math_color_inline.c
+ intern/math_easing.c
intern/math_geom.c
intern/math_geom_inline.c
intern/math_interp.c
@@ -141,6 +142,7 @@ set(SRC
BLI_math_base.h
BLI_math_color.h
BLI_math_color_blend.h
+ BLI_math_easing.h
BLI_math_geom.h
BLI_math_inline.h
BLI_math_interp.h
diff --git a/source/blender/blenlib/intern/math_easing.c b/source/blender/blenlib/intern/math_easing.c
new file mode 100644
index 00000000000..bec4e0b228a
--- /dev/null
+++ b/source/blender/blenlib/intern/math_easing.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the author nor the names of contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file blender/blenlib/intern/math_easing.c
+ * \ingroup bli
+ */
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "BLI_math_easing.h"
+
+
+float BackEaseIn(float time, float begin, float change, float duration, float overshoot)
+{
+ if (overshoot == 0)
+ overshoot = 1.70158f;
+ time /= duration;
+ return change * time * time * ((overshoot + 1) * time - overshoot) + begin;
+}
+
+float BackEaseOut(float time, float begin, float change, float duration, float overshoot)
+{
+ if (overshoot == 0)
+ overshoot = 1.70158f;
+ time = time / duration - 1;
+ return change * (time * time * ((overshoot + 1) * time + overshoot) + 1) + begin;
+}
+
+float BackEaseInOut(float time, float begin, float change, float duration, float overshoot)
+{
+ if (overshoot == 0)
+ overshoot = 1.70158f;
+ overshoot *= 1.525f;
+ if ((time /= duration / 2) < 1) {
+ return change / 2 * (time * time * ((overshoot + 1) * time - overshoot)) + begin;
+ }
+ time -= 2;
+ return change / 2 * (time * time * ((overshoot + 1) * time + overshoot) + 2) + begin;
+
+}
+
+float BounceEaseOut(float time, float begin, float change, float duration)
+{
+ time /= duration;
+ if (time < (1 / 2.75f)) {
+ return change * (7.5625f * time * time) + begin;
+ }
+ else if (time < (2 / 2.75f)) {
+ time -= (1.5f / 2.75f);
+ return change * ((7.5625f * time) * time + 0.75f) + begin;
+ }
+ else if (time < (2.5f / 2.75f)) {
+ time -= (2.25f / 2.75f);
+ return change * ((7.5625f * time) * time + 0.9375f) + begin;
+ }
+ else {
+ time -= (2.625f / 2.75f);
+ return change * ((7.5625f * time) * time + .984375f) + begin;
+ }
+}
+
+float BounceEaseIn(float time, float begin, float change, float duration)
+{
+ return change - BounceEaseOut(duration - time, 0, change, duration) + begin;
+}
+
+float BounceEaseInOut(float time, float begin, float change, float duration)
+{
+ if (time < duration / 2)
+ return BounceEaseIn(time * 2, 0, change, duration) * 0.5f + begin;
+ else
+ return BounceEaseOut(time * 2 - duration, 0, change, duration) * 0.5f + change * 0.5f + begin;
+}
+
+float CircEaseIn(float time, float begin, float change, float duration)
+{
+ time /= duration;
+ return -change * (sqrt(1 - time * time) - 1) + begin;
+}
+
+float CircEaseOut(float time, float begin, float change, float duration)
+{
+ time = time / duration - 1;
+ return change * sqrt(1 - time * time) + begin;
+}
+
+float CircEaseInOut(float time, float begin, float change, float duration)
+{
+ if ((time /= duration / 2) < 1)
+ return -change / 2 * (sqrt(1 - time * time) - 1) + begin;
+ time -= 2;
+ return change / 2 * (sqrt(1 - time * time) + 1) + begin;
+}
+
+float CubicEaseIn(float time, float begin, float change, float duration)
+{
+ time /= duration;
+ return change * time * time * time + begin;
+}
+
+float CubicEaseOut(float time, float begin, float change, float duration)
+{
+ time = time / duration - 1;
+ return change * (time * time * time + 1) + begin;
+}
+
+float CubicEaseInOut(float time, float begin, float change, float duration)
+{
+ if ((time /= duration / 2) < 1)
+ return change / 2 * time * time * time + begin;
+ time -= 2;
+ return change / 2 * (time * time * time + 2) + begin;
+}
+
+float ElasticEaseIn(float time, float begin, float change, float duration, float amplitude, float period)
+{
+ float s;
+
+ if (time == 0)
+ return begin;
+
+ if ((time /= duration) == 1)
+ return begin + change;
+
+ if (!period)
+ period = duration * 0.3f;
+
+ if (!amplitude || amplitude < abs(change)) {
+ amplitude = change;
+ s = period / 4;
+ }
+ else
+ s = period / (2 * M_PI) * asin(change / amplitude);
+
+ time -= 1;
+ return -(amplitude * pow(2, 10 * time) * sin((time * duration - s) * (2 * M_PI) / period)) + begin;
+}
+
+float ElasticEaseOut(float time, float begin, float change, float duration, float amplitude, float period)
+{
+ float s;
+
+ if (time == 0)
+ return begin;
+ if ((time /= duration) == 1)
+ return begin + change;
+ if (!period)
+ period = duration * 0.3f;
+ if (!amplitude || amplitude < abs(change)) {
+ amplitude = change;
+ s = period / 4;
+ }
+ else
+ s = period / (2 * M_PI) * asin(change / amplitude);
+
+ return (amplitude * pow(2, -10 * time) * sin((time * duration - s) * (2 * M_PI) / period ) + change + begin);
+}
+
+float ElasticEaseInOut(float time, float begin, float change, float duration, float amplitude, float period)
+{
+ float s;
+
+ if (time == 0)
+ return begin;
+ if ((time /= duration / 2) == 2)
+ return begin + change;
+ if (!period)
+ period = duration * (0.3f * 1.5f);
+ if (!amplitude || amplitude < abs(change)) {
+ amplitude = change;
+ s = period / 4;
+ }
+ else
+ s = period / ( 2 * M_PI) * asin(change / amplitude);
+ if (time < 1) {
+ time -= 1;
+ return -0.5f * (amplitude * pow(2, 10 * time) * sin((time * duration - s) * (2 * M_PI) / period)) + begin;
+ }
+
+ time -= 1;
+ return amplitude * pow(2, -10 * time) * sin((time * duration - s) * (2 * M_PI) / period) * 0.5f + change + begin;
+}
+
+float ExpoEaseIn(float time, float begin, float change, float duration)
+{
+ return (time == 0) ? begin : change * pow(2, 10 * (time / duration - 1)) + begin;
+}
+
+float ExpoEaseOut(float time, float begin, float change, float duration)
+{
+ return (time == duration) ? begin + change : change * (-pow(2, -10 * time / duration) + 1) + begin;
+}
+
+float ExpoEaseInOut(float time, float begin, float change, float duration)
+{
+ if (time == 0)
+ return begin;
+ if (time == duration)
+ return begin + change;
+ if ((time /= duration / 2) < 1)
+ return change/2 * pow(2, 10 * (time - 1)) + begin;
+ --time;
+ return change / 2 * (-pow(2, -10 * time) + 2) + begin;
+}
+
+float LinearEase(float time, float begin, float change, float duration)
+{
+ return change * time / duration + begin;
+}
+
+float QuadEaseIn(float time, float begin, float change, float duration)
+{
+ time /= duration;
+ return change * time * time + begin;
+}
+
+float QuadEaseOut(float time, float begin, float change, float duration)
+{
+ time /= duration;
+ return -change * time * (time - 2) + begin;
+}
+
+float QuadEaseInOut(float time, float begin, float change, float duration)
+{
+ if ((time /= duration / 2) < 1)
+ return change / 2 * time * time + begin;
+ --time;
+ return -change / 2 * (time * (time - 2) - 1) + begin;
+}
+
+
+float QuartEaseIn(float time, float begin, float change, float duration)
+{
+ time /= duration;
+ return change * time * time * time * time + begin;
+}
+
+float QuartEaseOut(float time, float begin, float change, float duration)
+{
+ time = time / duration - 1;
+ return -change * (time * time * time * time - 1) + begin;
+}
+
+float QuartEaseInOut(float time, float begin, float change, float duration)
+{
+ if ((time /= duration / 2) < 1)
+ return change / 2 * time * time * time * time + begin;
+ time -= 2;
+ return -change/2 * ( time * time * time * time - 2) + begin;
+}
+
+float QuintEaseIn(float time, float begin, float change, float duration)
+{
+ time /= duration;
+ return change * time * time * time * time * time + begin;
+}
+float QuintEaseOut(float time, float begin, float change, float duration)
+{
+ time = time / duration - 1;
+ return change * (time * time * time * time * time + 1) + begin;
+}
+float QuintEaseInOut(float time, float begin, float change, float duration)
+{
+ if ((time /= duration / 2) < 1)
+ return change/2 * time * time * time * time * time + begin;
+ time -= 2;
+ return change / 2 * (time * time * time * time * time + 2) + begin;
+}
+
+float SineEaseIn(float time, float begin, float change, float duration)
+{
+ return -change * cos(time / duration * M_PI_2) + change + begin;
+}
+
+float SineEaseOut(float time, float begin, float change, float duration)
+{
+ return change * sin(time / duration * M_PI_2) + begin;
+}
+
+float SineEaseInOut(float time, float begin, float change, float duration)
+{
+ return -change / 2 * (cos(M_PI * time / duration) - 1) + begin;
+}
+
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 6b294c93b42..b14bbe821e8 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -922,15 +922,109 @@ static short set_bezt_bezier(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
+static short set_bezt_back(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo = BEZT_IPO_BACK;
+ return 0;
+}
+
+static short set_bezt_bounce(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo = BEZT_IPO_BOUNCE;
+ return 0;
+}
+
+static short set_bezt_circle(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo = BEZT_IPO_CIRC;
+ return 0;
+}
+
+static short set_bezt_cubic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo = BEZT_IPO_CUBIC;
+ return 0;
+}
+
+static short set_bezt_elastic(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo = BEZT_IPO_ELASTIC;
+ return 0;
+}
+
+static short set_bezt_expo(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo = BEZT_IPO_EXPO;
+ return 0;
+}
+
+static short set_bezt_quad(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo = BEZT_IPO_QUAD;
+ return 0;
+}
+
+static short set_bezt_quart(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo = BEZT_IPO_QUART;
+ return 0;
+}
+
+static short set_bezt_quint(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo = BEZT_IPO_QUINT;
+ return 0;
+}
+
+static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo= BEZT_IPO_SINE;
+ return 0;
+}
+
/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
// ANIM_editkeyframes_ipocurve_ipotype() !
KeyframeEditFunc ANIM_editkeyframes_ipo(short code)
{
switch (code) {
+ /* interpolation */
case BEZT_IPO_CONST: /* constant */
return set_bezt_constant;
case BEZT_IPO_LIN: /* linear */
return set_bezt_linear;
+
+ /* easing */
+ case BEZT_IPO_BACK:
+ return set_bezt_back;
+ case BEZT_IPO_BOUNCE:
+ return set_bezt_bounce;
+ case BEZT_IPO_CIRC:
+ return set_bezt_circle;
+ case BEZT_IPO_CUBIC:
+ return set_bezt_cubic;
+ case BEZT_IPO_ELASTIC:
+ return set_bezt_elastic;
+ case BEZT_IPO_EXPO:
+ return set_bezt_expo;
+ case BEZT_IPO_QUAD:
+ return set_bezt_quad;
+ case BEZT_IPO_QUART:
+ return set_bezt_quart;
+ case BEZT_IPO_QUINT:
+ return set_bezt_quint;
+ case BEZT_IPO_SINE:
+ return set_bezt_sine;
+
default: /* bezier */
return set_bezt_bezier;
}
@@ -985,6 +1079,45 @@ KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
}
}
+/* ------- */
+
+static short set_easingtype_easein(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->easing = BEZT_IPO_EASE_IN;
+ return 0;
+}
+
+static short set_easingtype_easeout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->easing = BEZT_IPO_EASE_OUT;
+ return 0;
+}
+
+static short set_easingtype_easeinout(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->easing = BEZT_IPO_EASE_IN_OUT;
+ return 0;
+}
+
+/* Set the easing type of the selected BezTriples in each F-Curve to the specified one */
+KeyframeEditFunc ANIM_editkeyframes_easing(short mode)
+{
+ switch (mode) {
+ case BEZT_IPO_EASE_IN: /* ease in */
+ return set_easingtype_easein;
+
+ case BEZT_IPO_EASE_OUT: /* ease out */
+ return set_easingtype_easeout;
+
+ case BEZT_IPO_EASE_IN_OUT: /* both */
+ default:
+ return set_easingtype_easeinout;
+ }
+}
+
/* ******************************************* */
/* Selection */
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index 4e68b6a9494..c8365689803 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -217,6 +217,7 @@ KeyframeEditFunc ANIM_editkeyframes_select(short mode);
KeyframeEditFunc ANIM_editkeyframes_handles(short mode);
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode);
KeyframeEditFunc ANIM_editkeyframes_keytype(short mode);
+KeyframeEditFunc ANIM_editkeyframes_easing(short mode);
/* -------- BezTriple Callbacks (Selection Map) ---------- */
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 42aa9935251..671a4c3afd3 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -291,7 +291,26 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
/* interpolation */
col = uiLayoutColumn(layout, FALSE);
uiItemR(col, &bezt_ptr, "interpolation", 0, NULL, ICON_NONE);
-
+
+ /* easing type */
+ if (bezt->ipo > BEZT_IPO_BEZ)
+ uiItemR(col, &bezt_ptr, "easing", 0, NULL, 0);
+
+ /* easing extra */
+ switch (bezt->ipo) {
+ case BEZT_IPO_BACK:
+ col = uiLayoutColumn(layout, 1);
+ uiItemR(col, &bezt_ptr, "back", 0, NULL, 0);
+ break;
+ case BEZT_IPO_ELASTIC:
+ col = uiLayoutColumn(layout, 1);
+ uiItemR(col, &bezt_ptr, "amplitude", 0, NULL, 0);
+ uiItemR(col, &bezt_ptr, "period", 0, NULL, 0);
+ break;
+ default:
+ break;
+ }
+
/* numerical coordinate editing
* - we use the button-versions of the calls so that we can attach special update handlers
* and unit conversion magic that cannot be achieved using a purely RNA-approach
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index ab69dc9e7b9..eb36abe6eef 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -623,6 +623,7 @@ static void draw_fcurve_curve_samples(bAnimContext *ac, ID *id, FCurve *fcu, Vie
glPopMatrix();
}
+#if 0
/* helper func - draw one repeat of an F-Curve */
static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d)
{
@@ -778,7 +779,8 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
glEnd();
glPopMatrix();
-}
+}
+#endif
/* Debugging -------------------------------- */
@@ -995,7 +997,8 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
/* just draw curve based on defined data (i.e. no modifiers) */
if (fcu->bezt)
- draw_fcurve_curve_bezts(ac, ale->id, fcu, &ar->v2d);
+ //draw_fcurve_curve_bezts(ac, ale->id, fcu, &ar->v2d);
+ draw_fcurve_curve(ac, ale->id, fcu, &ar->v2d, grid); // XXX: better to do an optimised integration here instead, but for now, this works
else if (fcu->fpt)
draw_fcurve_curve_samples(ac, ale->id, fcu, &ar->v2d);
}
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 93d103e11a6..0fa6edd0011 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -1502,6 +1502,72 @@ void GRAPH_OT_interpolation_type(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", beztriple_interpolation_mode_items, 0, "Type", "");
}
+/* ******************** Set Easing Operator *********************** */
+
+static void seteasing_graph_keys(bAnimContext *ac, short mode)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+ KeyframeEditFunc set_cb = ANIM_editkeyframes_easing(mode);
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* loop through setting BezTriple easing
+ * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
+ */
+ for (ale = anim_data.first; ale; ale = ale->next)
+ ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
+
+ /* cleanup */
+ BLI_freelistN(&anim_data);
+}
+
+static int graphkeys_easing_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ short mode;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* get handle setting mode */
+ mode = RNA_enum_get(op->ptr, "type");
+
+ /* set handle type */
+ seteasing_graph_keys(&ac, mode);
+
+ /* validate keyframes after editing */
+ ANIM_editkeyframes_refresh(&ac);
+
+ /* set notifier that keyframe properties have changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_easing_type(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Keyframe Easing Type";
+ ot->idname = "GRAPH_OT_easing_type";
+ ot->description = "Set easing type for the F-Curve segments starting from the selected keyframes";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = graphkeys_easing_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* id-props */
+ ot->prop = RNA_def_enum(ot->srna, "type", beztriple_interpolation_easing_items, 0, "Type", "");
+}
+
/* ******************** Set Handle-Type Operator *********************** */
/* this function is responsible for setting handle-type of selected keyframes */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 567b0a60bb0..fe1378679d8 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -112,6 +112,7 @@ void GRAPH_OT_euler_filter(struct wmOperatorType *ot);
void GRAPH_OT_handle_type(struct wmOperatorType *ot);
void GRAPH_OT_interpolation_type(struct wmOperatorType *ot);
void GRAPH_OT_extrapolation_type(struct wmOperatorType *ot);
+void GRAPH_OT_easing_type(struct wmOperatorType *ot);
void GRAPH_OT_frame_jump(struct wmOperatorType *ot);
void GRAPH_OT_snap(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 0b9936ff14e..1041c885697 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -227,6 +227,7 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_handle_type);
WM_operatortype_append(GRAPH_OT_interpolation_type);
WM_operatortype_append(GRAPH_OT_extrapolation_type);
+ WM_operatortype_append(GRAPH_OT_easing_type);
WM_operatortype_append(GRAPH_OT_sample);
WM_operatortype_append(GRAPH_OT_bake);
WM_operatortype_append(GRAPH_OT_sound_bake);
@@ -376,6 +377,7 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "GRAPH_OT_handle_type", VKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_interpolation_type", TKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "GRAPH_OT_easing_type", EKEY, KM_PRESS, KM_CTRL, 0);
/* destructive */
WM_keymap_add_item(keymap, "GRAPH_OT_clean", OKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index f0c555792fc..ebba59ec785 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -108,10 +108,19 @@ typedef struct BevPoint {
typedef struct BezTriple {
float vec[3][3];
float alfa, weight, radius; /* alfa: tilt in 3D View, weight: used for softbody goal weight, radius: for bevel tapering */
+
short ipo; /* ipo: interpolation mode for segment from this BezTriple to the next */
+
char h1, h2; /* h1, h2: the handle type of the two handles */
char f1, f2, f3; /* f1, f2, f3: used for selection status */
+
char hide; /* hide: used to indicate whether BezTriple is hidden (3D), type of keyframe (eBezTriple_KeyframeTypes) */
+
+ float back; /* BEZT_IPO_BACK */
+ float amplitude, period; /* BEZT_IPO_ELASTIC */
+ char easing; /* easing: easing type for interpolation mode (eBezTriple_Easing) */
+
+ char pad[3];
} BezTriple;
/* note; alfa location in struct is abused by Key system */
@@ -341,11 +350,31 @@ typedef enum eBezTriple_Handle {
/* interpolation modes (used only for BezTriple->ipo) */
typedef enum eBezTriple_Interpolation {
+ /* traditional interpolation */
BEZT_IPO_CONST = 0, /* constant interpolation */
BEZT_IPO_LIN = 1, /* linear interpolation */
- BEZT_IPO_BEZ = 2 /* bezier interpolation */
+ BEZT_IPO_BEZ = 2, /* bezier interpolation */
+
+ /* easing equations */
+ BEZT_IPO_BACK = 3,
+ BEZT_IPO_BOUNCE = 4,
+ BEZT_IPO_CIRC = 5,
+ BEZT_IPO_CUBIC = 6,
+ BEZT_IPO_ELASTIC = 7,
+ BEZT_IPO_EXPO = 8,
+ BEZT_IPO_QUAD = 9,
+ BEZT_IPO_QUART = 10,
+ BEZT_IPO_QUINT = 11,
+ BEZT_IPO_SINE = 12
} eBezTriple_Interpolation;
+/* easing modes (used only for Keyframes - BezTriple->easing) */
+typedef enum eBezTriple_Easing {
+ BEZT_IPO_EASE_IN = 0,
+ BEZT_IPO_EASE_OUT = 1,
+ BEZT_IPO_EASE_IN_OUT = 2
+} eBezTriple_Easing;
+
/* types of keyframe (used only for BezTriple->hide when BezTriple is used in F-Curves) */
typedef enum eBezTriple_KeyframeType {
BEZT_KEYTYPE_KEYFRAME = 0, /* default - 'proper' Keyframe */
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 49ff04192b8..0b73fc932a9 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -72,6 +72,7 @@ extern EnumPropertyItem color_sets_items[];
extern EnumPropertyItem beztriple_keyframe_type_items[];
extern EnumPropertyItem beztriple_interpolation_mode_items[];
+extern EnumPropertyItem beztriple_interpolation_easing_items[];
extern EnumPropertyItem keyframe_handle_type_items[];
extern EnumPropertyItem keyblock_type_items[];
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 0c17b55d2c6..a4d099c69c7 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -34,6 +34,8 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLF_translation.h"
+
#include "BKE_font.h"
#include "RNA_access.h"
@@ -67,9 +69,29 @@ EnumPropertyItem keyframe_handle_type_items[] = {
};
EnumPropertyItem beztriple_interpolation_mode_items[] = {
+ /* interpolation */
+ {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"},
{BEZT_IPO_CONST, "CONSTANT", 0, "Constant", "No interpolation, value of A gets held until B is encountered"},
{BEZT_IPO_LIN, "LINEAR", 0, "Linear", "Straight-line interpolation between A and B (i.e. no ease in/out)"},
{BEZT_IPO_BEZ, "BEZIER", 0, "Bezier", "Smooth interpolation between A and B, with some control over curve shape"},
+
+ /* easing */
+ {0, "", 0, N_("Easing (by strength)"), "Predefined inertial transitions, useful for motion graphics (from least to most ''dramatic'')"},
+ {BEZT_IPO_QUAD, "QUAD", 0, "Quadratic", "Quadratic easing (weakest)"},
+ {BEZT_IPO_CUBIC, "CUBIC", 0, "Cubic", "Cubic easing"},
+ {BEZT_IPO_QUART, "QUART", 0, "Quartic", "Quartic easing"},
+ {BEZT_IPO_QUINT, "QUINT", 0, "Quintic", "Quintic easing"},
+ {BEZT_IPO_EXPO, "EXPO", 0, "Exponential", "Exponential easing (strongest)"},
+
+ {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"},
+ {BEZT_IPO_BACK, "BACK", 0, "Back", "Cubic easing with overshoot and settle"},
+ {BEZT_IPO_BOUNCE, "BOUNCE", 0, "Bounce", "Exponentially decaying parabolic bounce, like when objects collide"},
+ {BEZT_IPO_ELASTIC, "ELASTIC", 0, "Elastic", "Exponentially decaying sine wave, like an elastic band"},
+
+ {0, "", 0, N_("Other"), "Other easing equations"},
+ {BEZT_IPO_SINE, "SINE", 0, "Sinusoidal", "Sinusoidal easing"},
+ {BEZT_IPO_CIRC, "CIRC", 0, "Circular", "Circular easing"},
+
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index aad8d6057ed..81fa2ad62a4 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include "DNA_anim_types.h"
+#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -76,6 +77,13 @@ EnumPropertyItem beztriple_keyframe_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem beztriple_interpolation_easing_items[] = {
+ {BEZT_IPO_EASE_IN, "EASE_IN", 0, "Ease In", "Only on the end closest to the next keyframe"},
+ {BEZT_IPO_EASE_OUT, "EASE_OUT", 0, "Ease Out", "Only on the end closest to the first keyframe"},
+ {BEZT_IPO_EASE_IN_OUT, "EASE_IN_OUT", 0, "Ease In and Out", "Segment between both keyframes"},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "WM_api.h"
@@ -1652,6 +1660,30 @@ static void rna_def_fkeyframe(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Type", "Type of keyframe (for visual purposes only)");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
+
+ prop = RNA_def_property(srna, "easing", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "easing");
+ RNA_def_property_enum_items(prop, beztriple_interpolation_easing_items);
+ RNA_def_property_ui_text(prop, "Easing",
+ "Which ends of the segment between this and the next keyframe easing "
+ "interpolation is applied to");
+ RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
+
+ prop = RNA_def_property(srna, "back", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "back");
+ RNA_def_property_ui_text(prop, "Back", "Amount of overshoot for 'back' easing");
+ RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of bounces for elastic easing");
+ RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
+
+ prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "period");
+ RNA_def_property_ui_text(prop, "Period", "Time between bounces for elastic easing");
+ RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
+
/* Vector values */
prop = RNA_def_property(srna, "handle_left", PROP_FLOAT, PROP_COORDS); /* keyframes are dimensionless */
RNA_def_property_array(prop, 2);