1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2020 by Blender Foundation.
17  */
18 #include "testing/testing.h"
19 
20 #include "MEM_guardedalloc.h"
21 
22 #include "BKE_fcurve.h"
23 
24 #include "ED_keyframing.h"
25 
26 #include "DNA_anim_types.h"
27 
28 namespace blender::bke::tests {
29 
30 /* Epsilon for floating point comparisons. */
31 static const float EPSILON = 1e-7f;
32 
TEST(evaluate_fcurve,EmptyFCurve)33 TEST(evaluate_fcurve, EmptyFCurve)
34 {
35   FCurve *fcu = BKE_fcurve_create();
36   EXPECT_EQ(evaluate_fcurve(fcu, 47.0f), 0.0f);
37   BKE_fcurve_free(fcu);
38 }
39 
TEST(evaluate_fcurve,OnKeys)40 TEST(evaluate_fcurve, OnKeys)
41 {
42   FCurve *fcu = BKE_fcurve_create();
43 
44   insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
45   insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
46   insert_vert_fcurve(fcu, 3.0f, 19.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF);
47 
48   EXPECT_NEAR(evaluate_fcurve(fcu, 1.0f), 7.0f, EPSILON);  /* hits 'on or before first' function */
49   EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f), 13.0f, EPSILON); /* hits 'between' function */
50   EXPECT_NEAR(evaluate_fcurve(fcu, 3.0f), 19.0f, EPSILON); /* hits 'on or after last' function */
51 
52   /* Also test within a specific time epsilon of the keys, as this was an issue in T39207.
53    * This epsilon is just slightly smaller than the epsilon given to
54    * BKE_fcurve_bezt_binarysearch_index_ex() in fcurve_eval_between_keyframes(), so it should hit
55    * the "exact" code path. */
56   float time_epsilon = 0.00008f;
57   EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f - time_epsilon), 13.0f, EPSILON);
58   EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f + time_epsilon), 13.0f, EPSILON);
59 
60   BKE_fcurve_free(fcu);
61 }
62 
TEST(evaluate_fcurve,InterpolationConstant)63 TEST(evaluate_fcurve, InterpolationConstant)
64 {
65   FCurve *fcu = BKE_fcurve_create();
66 
67   EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
68   EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
69 
70   fcu->bezt[0].ipo = BEZT_IPO_CONST;
71   fcu->bezt[1].ipo = BEZT_IPO_CONST;
72 
73   EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.0f, EPSILON);
74   EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 7.0f, EPSILON);
75 
76   BKE_fcurve_free(fcu);
77 }
78 
TEST(evaluate_fcurve,InterpolationLinear)79 TEST(evaluate_fcurve, InterpolationLinear)
80 {
81   FCurve *fcu = BKE_fcurve_create();
82 
83   EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
84   EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
85 
86   fcu->bezt[0].ipo = BEZT_IPO_LIN;
87   fcu->bezt[1].ipo = BEZT_IPO_LIN;
88 
89   EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 8.5f, EPSILON);
90   EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON);
91   EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.5f, EPSILON);
92 
93   BKE_fcurve_free(fcu);
94 }
95 
TEST(evaluate_fcurve,InterpolationBezier)96 TEST(evaluate_fcurve, InterpolationBezier)
97 {
98   FCurve *fcu = BKE_fcurve_create();
99 
100   EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
101   EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
102 
103   EXPECT_EQ(fcu->bezt[0].ipo, BEZT_IPO_BEZ);
104   EXPECT_EQ(fcu->bezt[1].ipo, BEZT_IPO_BEZ);
105 
106   /* Test with default handles. */
107   EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.8297067f, EPSILON);
108   EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON);
109   EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 12.170294f, EPSILON);
110 
111   /* Test with modified handles. */
112   fcu->bezt[0].vec[0][0] = 0.71855f; /* left handle X */
113   fcu->bezt[0].vec[0][1] = 6.22482f; /* left handle Y */
114   fcu->bezt[0].vec[2][0] = 1.35148f; /* right handle X */
115   fcu->bezt[0].vec[2][1] = 7.96806f; /* right handle Y */
116 
117   fcu->bezt[1].vec[0][0] = 1.66667f; /* left handle X */
118   fcu->bezt[1].vec[0][1] = 10.4136f; /* left handle Y */
119   fcu->bezt[1].vec[2][0] = 2.33333f; /* right handle X */
120   fcu->bezt[1].vec[2][1] = 15.5864f; /* right handle Y */
121 
122   EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.945497f, EPSILON);
123   EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 9.3495407f, EPSILON);
124   EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.088551f, EPSILON);
125 
126   BKE_fcurve_free(fcu);
127 }
128 
TEST(evaluate_fcurve,InterpolationBounce)129 TEST(evaluate_fcurve, InterpolationBounce)
130 {
131   FCurve *fcu = BKE_fcurve_create();
132 
133   EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
134   EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
135 
136   fcu->bezt[0].ipo = BEZT_IPO_BOUNCE;
137   fcu->bezt[1].ipo = BEZT_IPO_BOUNCE;
138 
139   fcu->bezt[0].easing = BEZT_IPO_EASE_IN;
140   fcu->bezt[1].easing = BEZT_IPO_EASE_AUTO;
141 
142   EXPECT_NEAR(evaluate_fcurve(fcu, 1.4f), 8.3649998f, EPSILON);
143   EXPECT_NEAR(evaluate_fcurve(fcu, 1.5f), 8.4062500f, EPSILON);
144   EXPECT_NEAR(evaluate_fcurve(fcu, 1.8f), 11.184999f, EPSILON);
145 
146   BKE_fcurve_free(fcu);
147 }
148 
TEST(evaluate_fcurve,ExtrapolationLinearKeys)149 TEST(evaluate_fcurve, ExtrapolationLinearKeys)
150 {
151   FCurve *fcu = BKE_fcurve_create();
152 
153   EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
154   EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
155   fcu->bezt[0].ipo = BEZT_IPO_LIN;
156   fcu->bezt[1].ipo = BEZT_IPO_LIN;
157 
158   fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
159   /* Before first keyframe. */
160   EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 5.5f, EPSILON);
161   EXPECT_NEAR(evaluate_fcurve(fcu, 0.50f), 4.0f, EPSILON);
162   EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), -8.0f, EPSILON);
163   /* After last keyframe. */
164   EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 17.5f, EPSILON);
165   EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 22.0f, EPSILON);
166 
167   fcu->extend = FCURVE_EXTRAPOLATE_CONSTANT;
168   /* Before first keyframe. */
169   EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON);
170   EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON);
171   /* After last keyframe. */
172   EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON);
173   EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON);
174 
175   BKE_fcurve_free(fcu);
176 }
177 
TEST(evaluate_fcurve,ExtrapolationBezierKeys)178 TEST(evaluate_fcurve, ExtrapolationBezierKeys)
179 {
180   FCurve *fcu = BKE_fcurve_create();
181 
182   EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
183   EXPECT_EQ(insert_vert_fcurve(fcu, 2.0f, 13.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
184 
185   fcu->bezt[0].vec[0][0] = 0.71855f; /* left handle X */
186   fcu->bezt[0].vec[0][1] = 6.22482f; /* left handle Y */
187   fcu->bezt[0].vec[2][0] = 1.35148f; /* right handle X */
188   fcu->bezt[0].vec[2][1] = 7.96806f; /* right handle Y */
189 
190   fcu->bezt[1].vec[0][0] = 1.66667f; /* left handle X */
191   fcu->bezt[1].vec[0][1] = 10.4136f; /* left handle Y */
192   fcu->bezt[1].vec[2][0] = 2.33333f; /* right handle X */
193   fcu->bezt[1].vec[2][1] = 15.5864f; /* right handle Y */
194 
195   fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
196   /* Before first keyframe. */
197   EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 6.3114409f, EPSILON);
198   EXPECT_NEAR(evaluate_fcurve(fcu, -0.50f), 2.8686447f, EPSILON);
199   /* After last keyframe. */
200   EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 18.81946f, EPSILON);
201   EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 24.63892f, EPSILON);
202 
203   fcu->extend = FCURVE_EXTRAPOLATE_CONSTANT;
204   /* Before first keyframe. */
205   EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON);
206   EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON);
207   /* After last keyframe. */
208   EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON);
209   EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON);
210 
211   BKE_fcurve_free(fcu);
212 }
213 
TEST(fcurve_subdivide,BKE_fcurve_bezt_subdivide_handles)214 TEST(fcurve_subdivide, BKE_fcurve_bezt_subdivide_handles)
215 {
216   FCurve *fcu = BKE_fcurve_create();
217 
218   /* Insert two keyframes and set handles to something non-default. */
219   EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
220   EXPECT_EQ(insert_vert_fcurve(fcu, 13.0f, 2.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
221 
222   fcu->bezt[0].h1 = fcu->bezt[0].h2 = HD_FREE;
223   fcu->bezt[0].vec[0][0] = -5.0f;
224   fcu->bezt[0].vec[0][1] = 0.0f;
225   fcu->bezt[0].vec[2][0] = 2.0f;
226   fcu->bezt[0].vec[2][1] = 4.0f;
227 
228   fcu->bezt[1].h1 = fcu->bezt[1].h2 = HD_FREE;
229   fcu->bezt[1].vec[0][0] = 13.0f;
230   fcu->bezt[1].vec[0][1] = -2.0f;
231   fcu->bezt[1].vec[2][0] = 16.0f;
232   fcu->bezt[1].vec[2][1] = -3.0f;
233 
234   /* Create new keyframe point with defaults from insert_vert_fcurve(). */
235   BezTriple beztr;
236   const float x = 7.375f; /* at this X-coord, the FCurve should evaluate to 1.000f. */
237   const float y = 1.000f;
238   beztr.vec[0][0] = x - 1.0f;
239   beztr.vec[0][1] = y;
240   beztr.vec[1][0] = x;
241   beztr.vec[1][1] = y;
242   beztr.vec[2][0] = x + 1.0f;
243   beztr.vec[2][1] = y;
244   beztr.h1 = beztr.h2 = HD_AUTO_ANIM;
245   beztr.ipo = BEZT_IPO_BEZ;
246 
247   /* This should update the existing handles as well as the new BezTriple. */
248   float y_delta;
249   BKE_fcurve_bezt_subdivide_handles(&beztr, &fcu->bezt[0], &fcu->bezt[1], &y_delta);
250 
251   EXPECT_FLOAT_EQ(y_delta, 0.0f);
252 
253   EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][0], -5.0f); /* Left handle should not be touched. */
254   EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][1], 0.0f);
255   EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][0], 1.0f); /* Coordinates should not be touched. */
256   EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][1], 0.0f);
257   EXPECT_FLOAT_EQ(fcu->bezt[0].vec[2][0], 1.5f); /* Right handle should be updated. */
258   EXPECT_FLOAT_EQ(fcu->bezt[0].vec[2][1], 2.0f);
259 
260   EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 13.0f); /* Left handle should be updated. */
261   EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 0.0f);
262   EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 13.0f); /* Coordinates should not be touched. */
263   EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 2.0f);
264   EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 16.0f); /* Right handle should not be touched */
265   EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], -3.0f);
266 
267   EXPECT_FLOAT_EQ(beztr.vec[0][0], 4.5f); /* Left handle should be updated. */
268   EXPECT_FLOAT_EQ(beztr.vec[0][1], 1.5f);
269   EXPECT_FLOAT_EQ(beztr.vec[1][0], 7.375f); /* Coordinates should not be touched. */
270   EXPECT_FLOAT_EQ(beztr.vec[1][1], 1.0f);
271   EXPECT_FLOAT_EQ(beztr.vec[2][0], 10.250); /* Right handle should be updated. */
272   EXPECT_FLOAT_EQ(beztr.vec[2][1], 0.5);
273 
274   BKE_fcurve_free(fcu);
275 }
276 
TEST(fcurve_active_keyframe,ActiveKeyframe)277 TEST(fcurve_active_keyframe, ActiveKeyframe)
278 {
279   FCurve *fcu = BKE_fcurve_create();
280 
281   /* There should be no active keyframe with no points. */
282   EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), FCURVE_ACTIVE_KEYFRAME_NONE);
283 
284   /* Check that adding new points sets the active index. */
285   EXPECT_EQ(insert_vert_fcurve(fcu, 1.0f, 7.5f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 0);
286   EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), 0);
287   EXPECT_EQ(insert_vert_fcurve(fcu, 8.0f, 15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 1);
288   EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), 1);
289   EXPECT_EQ(insert_vert_fcurve(fcu, 14.0f, 8.2f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF), 2);
290   EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), 2);
291 
292   /* Check clearing the index. */
293   BKE_fcurve_active_keyframe_set(fcu, NULL);
294   EXPECT_EQ(fcu->active_keyframe_index, FCURVE_ACTIVE_KEYFRAME_NONE);
295   EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), FCURVE_ACTIVE_KEYFRAME_NONE);
296 
297   /* Check a "normal" action. */
298   BKE_fcurve_active_keyframe_set(fcu, &fcu->bezt[2]);
299   EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), 2);
300 
301   /* Check out of bounds. */
302   BKE_fcurve_active_keyframe_set(fcu, fcu->bezt - 20);
303   EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), FCURVE_ACTIVE_KEYFRAME_NONE);
304 
305   /* Check out of bounds again. */
306   BKE_fcurve_active_keyframe_set(fcu, fcu->bezt + 4);
307   EXPECT_EQ(BKE_fcurve_active_keyframe_index(fcu), FCURVE_ACTIVE_KEYFRAME_NONE);
308 
309   BKE_fcurve_free(fcu);
310 }
311 
312 }  // namespace blender::bke::tests
313