Blender V4.3
fcurve_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4#include "testing/testing.h"
5
6#include "MEM_guardedalloc.h"
7
8#include "BKE_fcurve.hh"
9
10#include "ANIM_fcurve.hh"
11
12#include "ED_keyframing.hh"
13
14#include "DNA_anim_types.h"
15
17
18namespace blender::bke::tests {
19using namespace blender::animrig;
20
21/* Epsilon for floating point comparisons. */
22static const float EPSILON = 1e-7f;
23
24TEST(evaluate_fcurve, EmptyFCurve)
25{
27 EXPECT_EQ(evaluate_fcurve(fcu, 47.0f), 0.0f);
28 BKE_fcurve_free(fcu);
29}
30
32{
34
35 const KeyframeSettings settings = get_keyframe_settings(false);
36 insert_vert_fcurve(fcu, {1.0f, 7.0f}, settings, INSERTKEY_NOFLAGS);
37 insert_vert_fcurve(fcu, {2.0f, 13.0f}, settings, INSERTKEY_NOFLAGS);
38 insert_vert_fcurve(fcu, {3.0f, 19.0f}, settings, INSERTKEY_NOFLAGS);
39
40 EXPECT_NEAR(evaluate_fcurve(fcu, 1.0f), 7.0f, EPSILON); /* hits 'on or before first' function */
41 EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f), 13.0f, EPSILON); /* hits 'between' function */
42 EXPECT_NEAR(evaluate_fcurve(fcu, 3.0f), 19.0f, EPSILON); /* hits 'on or after last' function */
43
44 /* Also test within a specific time epsilon of the keys, as this was an issue in #39207.
45 * This epsilon is just slightly smaller than the epsilon given to
46 * BKE_fcurve_bezt_binarysearch_index_ex() in fcurve_eval_between_keyframes(), so it should hit
47 * the "exact" code path. */
48 float time_epsilon = 0.00008f;
49 EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f - time_epsilon), 13.0f, EPSILON);
50 EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f + time_epsilon), 13.0f, EPSILON);
51
52 BKE_fcurve_free(fcu);
53}
54
55TEST(evaluate_fcurve, InterpolationConstant)
56{
58
59 const KeyframeSettings settings = get_keyframe_settings(false);
60 insert_vert_fcurve(fcu, {1.0f, 7.0f}, settings, INSERTKEY_NOFLAGS);
61 insert_vert_fcurve(fcu, {2.0f, 13.0f}, settings, INSERTKEY_NOFLAGS);
62 EXPECT_EQ(fcu->bezt[0].vec[1][0], 1.0f);
63 EXPECT_EQ(fcu->bezt[0].vec[1][1], 7.0f);
64 EXPECT_EQ(fcu->bezt[1].vec[1][0], 2.0f);
65 EXPECT_EQ(fcu->bezt[1].vec[1][1], 13.0f);
66
67 fcu->bezt[0].ipo = BEZT_IPO_CONST;
68 fcu->bezt[1].ipo = BEZT_IPO_CONST;
69
70 EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.0f, EPSILON);
71 EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 7.0f, EPSILON);
72
73 BKE_fcurve_free(fcu);
74}
75
76TEST(evaluate_fcurve, InterpolationLinear)
77{
79
80 const KeyframeSettings settings = get_keyframe_settings(false);
81 insert_vert_fcurve(fcu, {1.0f, 7.0f}, settings, INSERTKEY_NOFLAGS);
82 insert_vert_fcurve(fcu, {2.0f, 13.0f}, settings, INSERTKEY_NOFLAGS);
83 EXPECT_EQ(fcu->bezt[0].vec[1][0], 1.0f);
84 EXPECT_EQ(fcu->bezt[0].vec[1][1], 7.0f);
85 EXPECT_EQ(fcu->bezt[1].vec[1][0], 2.0f);
86 EXPECT_EQ(fcu->bezt[1].vec[1][1], 13.0f);
87
88 fcu->bezt[0].ipo = BEZT_IPO_LIN;
89 fcu->bezt[1].ipo = BEZT_IPO_LIN;
90
91 EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 8.5f, EPSILON);
92 EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON);
93 EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.5f, EPSILON);
94
95 BKE_fcurve_free(fcu);
96}
97
98TEST(evaluate_fcurve, InterpolationBezier)
99{
100 FCurve *fcu = BKE_fcurve_create();
101
102 const KeyframeSettings settings = get_keyframe_settings(false);
103 insert_vert_fcurve(fcu, {1.0f, 7.0f}, settings, INSERTKEY_NOFLAGS);
104 insert_vert_fcurve(fcu, {2.0f, 13.0f}, settings, INSERTKEY_NOFLAGS);
105 EXPECT_EQ(fcu->bezt[0].vec[1][0], 1.0f);
106 EXPECT_EQ(fcu->bezt[0].vec[1][1], 7.0f);
107 EXPECT_EQ(fcu->bezt[1].vec[1][0], 2.0f);
108 EXPECT_EQ(fcu->bezt[1].vec[1][1], 13.0f);
109
110 EXPECT_EQ(fcu->bezt[0].ipo, BEZT_IPO_BEZ);
111 EXPECT_EQ(fcu->bezt[1].ipo, BEZT_IPO_BEZ);
112
113 /* Test with default handles. */
114 EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.8297067f, EPSILON);
115 EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON);
116 EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 12.170294f, EPSILON);
117
118 /* Test with modified handles. */
119 fcu->bezt[0].vec[0][0] = 0.71855f; /* left handle X */
120 fcu->bezt[0].vec[0][1] = 6.22482f; /* left handle Y */
121 fcu->bezt[0].vec[2][0] = 1.35148f; /* right handle X */
122 fcu->bezt[0].vec[2][1] = 7.96806f; /* right handle Y */
123
124 fcu->bezt[1].vec[0][0] = 1.66667f; /* left handle X */
125 fcu->bezt[1].vec[0][1] = 10.4136f; /* left handle Y */
126 fcu->bezt[1].vec[2][0] = 2.33333f; /* right handle X */
127 fcu->bezt[1].vec[2][1] = 15.5864f; /* right handle Y */
128
129 EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.945497f, EPSILON);
130 EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 9.3495407f, EPSILON);
131 EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.088551f, EPSILON);
132
133 BKE_fcurve_free(fcu);
134}
135
136TEST(evaluate_fcurve, InterpolationBounce)
137{
138 FCurve *fcu = BKE_fcurve_create();
139
140 const KeyframeSettings settings = get_keyframe_settings(false);
141 insert_vert_fcurve(fcu, {1.0f, 7.0f}, settings, INSERTKEY_NOFLAGS);
142 insert_vert_fcurve(fcu, {2.0f, 13.0f}, settings, INSERTKEY_NOFLAGS);
143 EXPECT_EQ(fcu->bezt[0].vec[1][0], 1.0f);
144 EXPECT_EQ(fcu->bezt[0].vec[1][1], 7.0f);
145 EXPECT_EQ(fcu->bezt[1].vec[1][0], 2.0f);
146 EXPECT_EQ(fcu->bezt[1].vec[1][1], 13.0f);
147
148 fcu->bezt[0].ipo = BEZT_IPO_BOUNCE;
149 fcu->bezt[1].ipo = BEZT_IPO_BOUNCE;
150
151 fcu->bezt[0].easing = BEZT_IPO_EASE_IN;
153
154 EXPECT_NEAR(evaluate_fcurve(fcu, 1.4f), 8.3649998f, EPSILON);
155 EXPECT_NEAR(evaluate_fcurve(fcu, 1.5f), 8.4062500f, EPSILON);
156 EXPECT_NEAR(evaluate_fcurve(fcu, 1.8f), 11.184999f, EPSILON);
157
158 BKE_fcurve_free(fcu);
159}
160
161TEST(evaluate_fcurve, ExtrapolationLinearKeys)
162{
163 FCurve *fcu = BKE_fcurve_create();
164
165 const KeyframeSettings settings = get_keyframe_settings(false);
166 insert_vert_fcurve(fcu, {1.0f, 7.0f}, settings, INSERTKEY_NOFLAGS);
167 insert_vert_fcurve(fcu, {2.0f, 13.0f}, settings, INSERTKEY_NOFLAGS);
168 EXPECT_EQ(fcu->bezt[0].vec[1][0], 1.0f);
169 EXPECT_EQ(fcu->bezt[0].vec[1][1], 7.0f);
170 EXPECT_EQ(fcu->bezt[1].vec[1][0], 2.0f);
171 EXPECT_EQ(fcu->bezt[1].vec[1][1], 13.0f);
172
173 fcu->bezt[0].ipo = BEZT_IPO_LIN;
174 fcu->bezt[1].ipo = BEZT_IPO_LIN;
175
177 /* Before first keyframe. */
178 EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 5.5f, EPSILON);
179 EXPECT_NEAR(evaluate_fcurve(fcu, 0.50f), 4.0f, EPSILON);
180 EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), -8.0f, EPSILON);
181 /* After last keyframe. */
182 EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 17.5f, EPSILON);
183 EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 22.0f, EPSILON);
184
186 /* Before first keyframe. */
187 EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON);
188 EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON);
189 /* After last keyframe. */
190 EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON);
191 EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON);
192
193 BKE_fcurve_free(fcu);
194}
195
196TEST(evaluate_fcurve, ExtrapolationBezierKeys)
197{
198 FCurve *fcu = BKE_fcurve_create();
199
200 const KeyframeSettings settings = get_keyframe_settings(false);
201 insert_vert_fcurve(fcu, {1.0f, 7.0f}, settings, INSERTKEY_NOFLAGS);
202 insert_vert_fcurve(fcu, {2.0f, 13.0f}, settings, INSERTKEY_NOFLAGS);
203 EXPECT_EQ(fcu->bezt[0].vec[1][0], 1.0f);
204 EXPECT_EQ(fcu->bezt[0].vec[1][1], 7.0f);
205 EXPECT_EQ(fcu->bezt[1].vec[1][0], 2.0f);
206 EXPECT_EQ(fcu->bezt[1].vec[1][1], 13.0f);
207
208 fcu->bezt[0].vec[0][0] = 0.71855f; /* left handle X */
209 fcu->bezt[0].vec[0][1] = 6.22482f; /* left handle Y */
210 fcu->bezt[0].vec[2][0] = 1.35148f; /* right handle X */
211 fcu->bezt[0].vec[2][1] = 7.96806f; /* right handle Y */
212
213 fcu->bezt[1].vec[0][0] = 1.66667f; /* left handle X */
214 fcu->bezt[1].vec[0][1] = 10.4136f; /* left handle Y */
215 fcu->bezt[1].vec[2][0] = 2.33333f; /* right handle X */
216 fcu->bezt[1].vec[2][1] = 15.5864f; /* right handle Y */
217
219 /* Before first keyframe. */
220 EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 6.3114409f, EPSILON);
221 EXPECT_NEAR(evaluate_fcurve(fcu, -0.50f), 2.8686447f, EPSILON);
222 /* After last keyframe. */
223 EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 18.81946f, EPSILON);
224 EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 24.63892f, EPSILON);
225
227 /* Before first keyframe. */
228 EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON);
229 EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON);
230 /* After last keyframe. */
231 EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON);
232 EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON);
233
234 BKE_fcurve_free(fcu);
235}
236
238{
239 FCurve *fcu = BKE_fcurve_create();
240
241 const KeyframeSettings settings = get_keyframe_settings(false);
242 /* Insert two keyframes and set handles to something non-default. */
243 insert_vert_fcurve(fcu, {1.0f, 0.0f}, settings, INSERTKEY_NOFLAGS);
244 insert_vert_fcurve(fcu, {13.0f, 2.0f}, settings, INSERTKEY_NOFLAGS);
245 EXPECT_EQ(fcu->bezt[0].vec[1][0], 1.0f);
246 EXPECT_EQ(fcu->bezt[0].vec[1][1], 0.0f);
247 EXPECT_EQ(fcu->bezt[1].vec[1][0], 13.0f);
248 EXPECT_EQ(fcu->bezt[1].vec[1][1], 2.0f);
249
250 fcu->bezt[0].h1 = fcu->bezt[0].h2 = HD_FREE;
251 fcu->bezt[0].vec[0][0] = -5.0f;
252 fcu->bezt[0].vec[0][1] = 0.0f;
253 fcu->bezt[0].vec[2][0] = 2.0f;
254 fcu->bezt[0].vec[2][1] = 4.0f;
255
256 fcu->bezt[1].h1 = fcu->bezt[1].h2 = HD_FREE;
257 fcu->bezt[1].vec[0][0] = 13.0f;
258 fcu->bezt[1].vec[0][1] = -2.0f;
259 fcu->bezt[1].vec[2][0] = 16.0f;
260 fcu->bezt[1].vec[2][1] = -3.0f;
261
262 /* Create new keyframe point with defaults from insert_vert_fcurve(). */
263 BezTriple beztr;
264 const float x = 7.375f; /* at this X-coord, the FCurve should evaluate to 1.000f. */
265 const float y = 1.000f;
266 beztr.vec[0][0] = x - 1.0f;
267 beztr.vec[0][1] = y;
268 beztr.vec[1][0] = x;
269 beztr.vec[1][1] = y;
270 beztr.vec[2][0] = x + 1.0f;
271 beztr.vec[2][1] = y;
272 beztr.h1 = beztr.h2 = HD_AUTO_ANIM;
273 beztr.ipo = BEZT_IPO_BEZ;
274
275 /* This should update the existing handles as well as the new BezTriple. */
276 float y_delta;
277 BKE_fcurve_bezt_subdivide_handles(&beztr, &fcu->bezt[0], &fcu->bezt[1], &y_delta);
278
279 EXPECT_FLOAT_EQ(y_delta, 0.0f);
280
281 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][0], -5.0f); /* Left handle should not be touched. */
282 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][1], 0.0f);
283 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][0], 1.0f); /* Coordinates should not be touched. */
284 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][1], 0.0f);
285 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[2][0], 1.5f); /* Right handle should be updated. */
286 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[2][1], 2.0f);
287
288 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 13.0f); /* Left handle should be updated. */
289 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 0.0f);
290 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 13.0f); /* Coordinates should not be touched. */
291 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 2.0f);
292 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 16.0f); /* Right handle should not be touched */
293 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], -3.0f);
294
295 EXPECT_FLOAT_EQ(beztr.vec[0][0], 4.5f); /* Left handle should be updated. */
296 EXPECT_FLOAT_EQ(beztr.vec[0][1], 1.5f);
297 EXPECT_FLOAT_EQ(beztr.vec[1][0], 7.375f); /* Coordinates should not be touched. */
298 EXPECT_FLOAT_EQ(beztr.vec[1][1], 1.0f);
299 EXPECT_FLOAT_EQ(beztr.vec[2][0], 10.250); /* Right handle should be updated. */
300 EXPECT_FLOAT_EQ(beztr.vec[2][1], 0.5);
301
302 BKE_fcurve_free(fcu);
303}
304
305TEST(fcurve_active_keyframe, ActiveKeyframe)
306{
307 FCurve *fcu = BKE_fcurve_create();
308
309 /* There should be no active keyframe with no points. */
311
312 const KeyframeSettings settings = get_keyframe_settings(false);
313 /* Check that adding new points sets the active index. */
314 insert_vert_fcurve(fcu, {1.0f, 7.5f}, settings, INSERTKEY_NOFLAGS);
315 EXPECT_EQ(fcu->bezt[0].vec[1][0], 1.0f);
316 EXPECT_EQ(fcu->bezt[0].vec[1][1], 7.5f);
318 insert_vert_fcurve(fcu, {8.0f, 15.0f}, settings, INSERTKEY_NOFLAGS);
319 EXPECT_EQ(fcu->bezt[1].vec[1][0], 8.0f);
320 EXPECT_EQ(fcu->bezt[1].vec[1][1], 15.0f);
322 insert_vert_fcurve(fcu, {14.0f, 8.2f}, settings, INSERTKEY_NOFLAGS);
323 EXPECT_EQ(fcu->bezt[2].vec[1][0], 14.0f);
324 EXPECT_EQ(fcu->bezt[2].vec[1][1], 8.2f);
326
327 /* Check clearing the index. */
328 BKE_fcurve_active_keyframe_set(fcu, nullptr);
331
332 /* Check a "normal" action. */
333 fcu->bezt[2].f2 |= SELECT;
336
337 /* Check setting an unselected keyframe as active. */
338 fcu->bezt[2].f1 = fcu->bezt[2].f2 = fcu->bezt[2].f3 = 0;
339 EXPECT_BLI_ASSERT(BKE_fcurve_active_keyframe_set(fcu, &fcu->bezt[2]),
340 "active keyframe must be selected");
342
343 /* Check out of bounds (lower). */
344 BKE_fcurve_active_keyframe_set(fcu, fcu->bezt - 20);
346 << "Setting out-of-bounds value via the API should result in valid active_keyframe_index";
348
349 fcu->active_keyframe_index = -20;
351 << "Even with active_keyframe_index out of bounds, getting it via the API should produce a "
352 "valid value";
353
354 /* Check out of bounds (higher). */
357 << "Setting out-of-bounds value via the API should result in valid active_keyframe_index";
359
360 fcu->active_keyframe_index = fcu->totvert;
362 << "Even with active_keyframe_index out of bounds, getting it via the API should produce a "
363 "valid value";
364
365 BKE_fcurve_free(fcu);
366}
367
369{
370 FCurve *fcu = BKE_fcurve_create();
371
372 const KeyframeSettings settings = get_keyframe_settings(false);
373 insert_vert_fcurve(fcu, {1.0f, 7.5f}, settings, INSERTKEY_NOFLAGS);
374 insert_vert_fcurve(fcu, {8.0f, 15.0f}, settings, INSERTKEY_NOFLAGS);
375 insert_vert_fcurve(fcu, {14.0f, 8.2f}, settings, INSERTKEY_NOFLAGS);
376
377 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f);
378 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 15.0f);
379
380 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 8.0f);
381 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 15.0f);
382
383 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 10.342469f);
384 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], 15.0f);
385
387
388 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f) << "Left handle should not move in time";
389 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 47.0f) << "Left handle value should have been updated";
390
391 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 8.0f) << "Frame should not move in time";
392 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 47.0f) << "Frame value should have been updated";
393
394 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 10.342469f) << "Right handle should not move in time";
395 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], 47.0f) << "Right handle value should have been updated";
396
397 BKE_fcurve_free(fcu);
398}
399
401{
402 FCurve *fcu = BKE_fcurve_create();
403
404 const KeyframeSettings settings = get_keyframe_settings(false);
405 insert_vert_fcurve(fcu, {1.0f, 7.5f}, settings, INSERTKEY_NOFLAGS);
406 insert_vert_fcurve(fcu, {8.0f, 15.0f}, settings, INSERTKEY_NOFLAGS);
407 insert_vert_fcurve(fcu, {14.0f, 8.2f}, settings, INSERTKEY_NOFLAGS);
408
409 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f);
410 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 15.0f);
411
412 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 8.0f);
413 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 15.0f);
414
415 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 10.342469f);
416 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], 15.0f);
417
419
420 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 44.2671194f) << "Left handle time should be updated";
421 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 15.0f) << "Left handle should not move in value";
422
423 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 47.0f) << "Frame time should have been updated";
424 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 15.0f) << "Frame should not move in value";
425
426 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 49.342469f) << "Right handle time should be updated";
427 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], 15.0f) << "Right handle should not move in value";
428
429 BKE_fcurve_free(fcu);
430}
431
433{
434 FCurve *fcu = BKE_fcurve_create();
435
436 const KeyframeSettings settings = get_keyframe_settings(false);
437 insert_vert_fcurve(fcu, {1.0f, 7.5f}, settings, INSERTKEY_NOFLAGS);
438 insert_vert_fcurve(fcu, {4.0f, -15.0f}, settings, INSERTKEY_NOFLAGS);
439 insert_vert_fcurve(fcu, {8.0f, 15.0f}, settings, INSERTKEY_NOFLAGS);
440 insert_vert_fcurve(fcu, {14.0f, 8.2f}, settings, INSERTKEY_NOFLAGS);
441 insert_vert_fcurve(fcu, {18.2f, -20.0f}, settings, INSERTKEY_NOFLAGS);
442
443 for (int i = 0; i < fcu->totvert; i++) {
444 fcu->bezt[i].f1 &= ~SELECT;
445 fcu->bezt[i].f2 &= ~SELECT;
446 fcu->bezt[i].f3 &= ~SELECT;
447 }
448
449 float min, max;
450 bool success;
451
452 /* All keys. */
453 success = BKE_fcurve_calc_range(fcu, &min, &max, false);
454 EXPECT_TRUE(success) << "A non-empty FCurve should have a range.";
455 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][0], min);
456 EXPECT_FLOAT_EQ(fcu->bezt[4].vec[1][0], max);
457
458 /* Only selected. */
459 success = BKE_fcurve_calc_range(fcu, &min, &max, true);
460 EXPECT_FALSE(success)
461 << "Using selected keyframes only should not find a range if nothing is selected.";
462
463 fcu->bezt[1].f2 |= SELECT;
464 fcu->bezt[3].f2 |= SELECT;
465
466 success = BKE_fcurve_calc_range(fcu, &min, &max, true);
467 EXPECT_TRUE(success) << "Range of selected keyframes should have been found.";
468 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], min);
469 EXPECT_FLOAT_EQ(fcu->bezt[3].vec[1][0], max);
470
471 /* Curve samples. */
472 const int sample_start = 1;
473 const int sample_end = 20;
474 fcurve_store_samples(fcu, nullptr, sample_start, sample_end, fcurve_samplingcb_evalcurve);
475
476 success = BKE_fcurve_calc_range(fcu, &min, &max, true);
477 EXPECT_TRUE(success) << "FCurve samples should have a range.";
478
479 EXPECT_FLOAT_EQ(sample_start, min);
480 EXPECT_FLOAT_EQ(sample_end, max);
481
482 BKE_fcurve_free(fcu);
483}
484
486{
487 FCurve *fcu = BKE_fcurve_create();
488
489 const KeyframeSettings settings = get_keyframe_settings(false);
490 insert_vert_fcurve(fcu, {1.0f, 7.5f}, settings, INSERTKEY_NOFLAGS);
491 insert_vert_fcurve(fcu, {4.0f, -15.0f}, settings, INSERTKEY_NOFLAGS);
492 insert_vert_fcurve(fcu, {8.0f, 15.0f}, settings, INSERTKEY_NOFLAGS);
493 insert_vert_fcurve(fcu, {14.0f, 8.2f}, settings, INSERTKEY_NOFLAGS);
494 insert_vert_fcurve(fcu, {18.2f, -20.0f}, settings, INSERTKEY_NOFLAGS);
495
496 for (int i = 0; i < fcu->totvert; i++) {
497 fcu->bezt[i].f1 &= ~SELECT;
498 fcu->bezt[i].f2 &= ~SELECT;
499 fcu->bezt[i].f3 &= ~SELECT;
500 }
501
502 fcu->bezt[0].vec[0][0] = -5.0f;
503 fcu->bezt[4].vec[2][0] = 25.0f;
504
505 rctf bounds;
506 bool success;
507
508 /* All keys. */
509 success = BKE_fcurve_calc_bounds(fcu,
510 false /* select only */,
511 false /* include handles */,
512 nullptr /* frame range */,
513 &bounds);
514 EXPECT_TRUE(success) << "A non-empty FCurve should have bounds.";
515 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][0], bounds.xmin);
516 EXPECT_FLOAT_EQ(fcu->bezt[4].vec[1][0], bounds.xmax);
517 EXPECT_FLOAT_EQ(fcu->bezt[4].vec[1][1], bounds.ymin);
518 EXPECT_FLOAT_EQ(fcu->bezt[2].vec[1][1], bounds.ymax);
519
520 /* Only selected. */
521 success = BKE_fcurve_calc_bounds(fcu,
522 true /* select only */,
523 false /* include handles */,
524 nullptr /* frame range */,
525 &bounds);
526 EXPECT_FALSE(success)
527 << "Using selected keyframes only should not find bounds if nothing is selected.";
528
529 fcu->bezt[1].f2 |= SELECT;
530 fcu->bezt[3].f2 |= SELECT;
531
532 success = BKE_fcurve_calc_bounds(fcu,
533 true /* select only */,
534 false /* include handles */,
535 nullptr /* frame range */,
536 &bounds);
537 EXPECT_TRUE(success) << "Selected keys should have been found.";
538 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], bounds.xmin);
539 EXPECT_FLOAT_EQ(fcu->bezt[3].vec[1][0], bounds.xmax);
540 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], bounds.ymin);
541 EXPECT_FLOAT_EQ(fcu->bezt[3].vec[1][1], bounds.ymax);
542
543 /* Including handles. */
544 success = BKE_fcurve_calc_bounds(fcu,
545 false /* select only */,
546 true /* include handles */,
547 nullptr /* frame range */,
548 &bounds);
549 EXPECT_TRUE(success) << "A non-empty FCurve should have bounds including handles.";
550 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][0], bounds.xmin);
551 EXPECT_FLOAT_EQ(fcu->bezt[4].vec[2][0], bounds.xmax);
552 EXPECT_FLOAT_EQ(fcu->bezt[4].vec[1][1], bounds.ymin);
553 EXPECT_FLOAT_EQ(fcu->bezt[2].vec[1][1], bounds.ymax);
554
555 /* Range. */
556 float range[2];
557
558 range[0] = 25;
559 range[1] = 30;
560 success = BKE_fcurve_calc_bounds(
561 fcu, false /* select only */, false /* include handles */, range /* frame range */, &bounds);
562 EXPECT_FALSE(success) << "A frame range outside the range of keyframes should not find bounds.";
563
564 range[0] = 0;
565 range[1] = 18.2f;
566 success = BKE_fcurve_calc_bounds(
567 fcu, false /* select only */, false /* include handles */, range /* frame range */, &bounds);
568 EXPECT_TRUE(success) << "A frame range within the range of keyframes should find bounds.";
569 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][0], bounds.xmin);
570 EXPECT_FLOAT_EQ(fcu->bezt[3].vec[1][0], bounds.xmax);
571 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], bounds.ymin);
572 EXPECT_FLOAT_EQ(fcu->bezt[2].vec[1][1], bounds.ymax);
573
574 /* Range and handles. */
575 success = BKE_fcurve_calc_bounds(
576 fcu, false /* select only */, true /* include handles */, range /* frame range */, &bounds);
577 EXPECT_TRUE(success)
578 << "A frame range within the range of keyframes should find bounds with handles.";
579 EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][0], bounds.xmin);
580 EXPECT_FLOAT_EQ(fcu->bezt[3].vec[2][0], bounds.xmax);
581 EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], bounds.ymin);
582 EXPECT_FLOAT_EQ(fcu->bezt[2].vec[1][1], bounds.ymax);
583
584 /* Range, handles and only selection. */
585 range[0] = 8.0f;
586 range[1] = 18.2f;
587 success = BKE_fcurve_calc_bounds(
588 fcu, true /* select only */, true /* include handles */, range /* frame range */, &bounds);
589 EXPECT_TRUE(success)
590 << "A frame range within the range of keyframes should find bounds of selected keyframes.";
591 EXPECT_FLOAT_EQ(fcu->bezt[3].vec[0][0], bounds.xmin);
592 EXPECT_FLOAT_EQ(fcu->bezt[3].vec[2][0], bounds.xmax);
593 EXPECT_FLOAT_EQ(fcu->bezt[3].vec[2][1], bounds.ymin);
594 EXPECT_FLOAT_EQ(fcu->bezt[3].vec[0][1], bounds.ymax);
595
596 /* Curve samples. */
597 const int sample_start = 1;
598 const int sample_end = 20;
599 fcurve_store_samples(fcu, nullptr, sample_start, sample_end, fcurve_samplingcb_evalcurve);
600
601 success = BKE_fcurve_calc_bounds(fcu,
602 false /* select only */,
603 false /* include handles */,
604 nullptr /* frame range */,
605 &bounds);
606 EXPECT_TRUE(success) << "FCurve samples should have a range.";
607
608 EXPECT_FLOAT_EQ(sample_start, bounds.xmin);
609 EXPECT_FLOAT_EQ(sample_end, bounds.xmax);
610 EXPECT_FLOAT_EQ(-20.0f, bounds.ymin);
611 EXPECT_FLOAT_EQ(15.0f, bounds.ymax);
612
613 range[0] = 8.0f;
614 range[1] = 20.0f;
615 success = BKE_fcurve_calc_bounds(
616 fcu, false /* select only */, false /* include handles */, range /* frame range */, &bounds);
617 EXPECT_TRUE(success) << "FCurve samples should have a range.";
618
619 EXPECT_FLOAT_EQ(range[0], bounds.xmin);
620 EXPECT_FLOAT_EQ(range[1], bounds.xmax);
621 EXPECT_FLOAT_EQ(-20.0f, bounds.ymin);
622 EXPECT_FLOAT_EQ(15.0f, bounds.ymax);
623
624 range[0] = 20.1f;
625 range[1] = 30.0f;
626 success = BKE_fcurve_calc_bounds(
627 fcu, false /* select only */, false /* include handles */, range /* frame range */, &bounds);
628 EXPECT_FALSE(success)
629 << "A frame range outside the range of keyframe samples should not have bounds.";
630
631 BKE_fcurve_free(fcu);
632}
633
634static void set_key(FCurve *fcu, const int index, const float x, const float y)
635{
636 fcu->bezt[index].vec[0][0] = x - 0.5f;
637 fcu->bezt[index].vec[1][0] = x;
638 fcu->bezt[index].vec[2][0] = x + 0.5f;
639
640 fcu->bezt[index].vec[0][1] = y;
641 fcu->bezt[index].vec[1][1] = y;
642 fcu->bezt[index].vec[2][1] = y;
643}
644
646{
647 /* Create a curve with some duplicate keys. The first ones are all with Y=1, the later repeats
648 * increase Y-coordinates on every repeat. */
649 FCurve *fcu = BKE_fcurve_create();
650 ED_keyframes_add(fcu, 10); /* Avoid `insert_vert_fcurve`, that de-duplicates the keys. */
651 set_key(fcu, 0, 1.0f, 1.0f);
652 set_key(fcu, 1, 327.16f, 1.0f);
653 set_key(fcu, 2, 7.0f, 1.0f);
654 set_key(fcu, 3, 47.0f, 1.0f);
655 set_key(fcu, 4, 7.0f, 2.0f);
656 set_key(fcu, 5, 47.0f, 2.0f);
657 set_key(fcu, 6, 47.0f + BEZT_BINARYSEARCH_THRESH, 3.0f);
658 set_key(fcu, 7, 7.0f, 3.0f);
659 set_key(fcu, 8, 3.0f, 1.0f);
660 set_key(fcu, 9, 2.0f, 1.0f);
661 return fcu;
662}
663
664TEST(BKE_fcurve, sort_time_fcurve_stability)
665{
667 ASSERT_EQ(fcu->totvert, 10);
668
669 sort_time_fcurve(fcu);
670
671 /* The sorting should be stable, i.e. retain the original order when the
672 * X-coordinates are identical. */
673 ASSERT_EQ(fcu->totvert, 10) << "sorting should not influence number of keys";
674 EXPECT_V2_NEAR(fcu->bezt[0].vec[1], float2(1.0f, 1.0f), 1e-3);
675 EXPECT_V2_NEAR(fcu->bezt[1].vec[1], float2(2.0f, 1.0f), 1e-3);
676 EXPECT_V2_NEAR(fcu->bezt[2].vec[1], float2(3.0f, 1.0f), 1e-3);
677 EXPECT_V2_NEAR(fcu->bezt[3].vec[1], float2(7.0f, 1.0f), 1e-3);
678 EXPECT_V2_NEAR(fcu->bezt[4].vec[1], float2(7.0f, 2.0f), 1e-3);
679 EXPECT_V2_NEAR(fcu->bezt[5].vec[1], float2(7.0f, 3.0f), 1e-3);
680 EXPECT_V2_NEAR(fcu->bezt[6].vec[1], float2(47.0f, 1.0f), 1e-3);
681 EXPECT_V2_NEAR(fcu->bezt[7].vec[1], float2(47.0f, 2.0f), 1e-3);
682 EXPECT_V2_NEAR(fcu->bezt[8].vec[1], float2(47.0f + BEZT_BINARYSEARCH_THRESH, 3.0f), 1e-3);
683 EXPECT_V2_NEAR(fcu->bezt[9].vec[1], float2(327.16f, 1.0f), 1e-3);
684
685 BKE_fcurve_free(fcu);
686}
687
689{
691 ASSERT_EQ(fcu->totvert, 10);
692 sort_time_fcurve(fcu);
693
695 ASSERT_GE(fcu->totvert, 6); /* Protect against out-of-bounds access. */
696 EXPECT_EQ(fcu->totvert, 6); /* The actual expected value. */
697 EXPECT_V2_NEAR(fcu->bezt[0].vec[1], float2(1.0f, 1.0f), 1e-3);
698 EXPECT_V2_NEAR(fcu->bezt[1].vec[1], float2(2.0f, 1.0f), 1e-3);
699 EXPECT_V2_NEAR(fcu->bezt[2].vec[1], float2(3.0f, 1.0f), 1e-3);
700 EXPECT_V2_NEAR(fcu->bezt[3].vec[1], float2(7.0f, 3.0f), 1e-3);
701 EXPECT_V2_NEAR(fcu->bezt[4].vec[1], float2(47.0f, 3.0f), 1e-3);
702 EXPECT_V2_NEAR(fcu->bezt[5].vec[1], float2(327.16f, 1.0f), 1e-3);
703
704 BKE_fcurve_free(fcu);
705}
706
707TEST(BKE_fcurve, BKE_fcurve_deduplicate_keys_edge_cases)
708{
710 ASSERT_EQ(fcu->totvert, 10);
711
712 /* Update the 2nd and 2nd-to-last keys to test the edge cases. */
713 set_key(fcu, 0, 1, 1);
714 set_key(fcu, 1, 1, 2);
715 set_key(fcu, 8, 327.16f, 1);
716 set_key(fcu, 9, 327.16f, 2);
717
718 sort_time_fcurve(fcu);
719
721 ASSERT_EQ(fcu->totvert, 4);
722 EXPECT_V2_NEAR(fcu->bezt[0].vec[1], float2(1.0f, 2.0f), 1e-3);
723 EXPECT_V2_NEAR(fcu->bezt[1].vec[1], float2(7.0f, 3.0f), 1e-3);
724 EXPECT_V2_NEAR(fcu->bezt[2].vec[1], float2(47.0f, 3.0f), 1e-3);
725 EXPECT_V2_NEAR(fcu->bezt[3].vec[1], float2(327.16f, 2.0f), 1e-3);
726
727 BKE_fcurve_free(fcu);
728}
729
730TEST(BKE_fcurve, BKE_fcurve_deduplicate_keys_prefer_whole_frames)
731{
733 ASSERT_EQ(fcu->totvert, 10);
734
735 /* Update the first key around 47.0 to be slightly before the frame. This gives us three keys on
736 * 47-epsilon, 47, and 47+epsilon. The keys at index 5 and 6 already have this value, so the
737 * `set_key` calls are unnecessary, but this way this test has a more local overview of the
738 * situation under test. */
739 set_key(fcu, 3, 47.0f - BEZT_BINARYSEARCH_THRESH, 1.0f);
740 set_key(fcu, 5, 47.0f, 2.0f);
741 set_key(fcu, 6, 47.0f + BEZT_BINARYSEARCH_THRESH, 3.0f);
742
743 sort_time_fcurve(fcu);
744
746 ASSERT_EQ(fcu->totvert, 6);
747 EXPECT_V2_NEAR(fcu->bezt[0].vec[1], float2(1.0f, 1.0f), 1e-3);
748 EXPECT_V2_NEAR(fcu->bezt[1].vec[1], float2(2.0f, 1.0f), 1e-3);
749 EXPECT_V2_NEAR(fcu->bezt[2].vec[1], float2(3.0f, 1.0f), 1e-3);
750 EXPECT_V2_NEAR(fcu->bezt[3].vec[1], float2(7.0f, 3.0f), 1e-3);
751 EXPECT_V2_NEAR(fcu->bezt[4].vec[1], float2(47.0f, 3.0f), 1e-3);
752 EXPECT_V2_NEAR(fcu->bezt[5].vec[1], float2(327.16f, 1.0f), 1e-3);
753
754 BKE_fcurve_free(fcu);
755}
756
757} // namespace blender::bke::tests
Functions to modify FCurves.
void BKE_fcurve_deduplicate_keys(FCurve *fcu)
void BKE_fcurve_keyframe_move_time_with_handles(BezTriple *keyframe, const float new_time)
int BKE_fcurve_active_keyframe_index(const FCurve *fcu)
FCurve * BKE_fcurve_create(void)
void BKE_fcurve_active_keyframe_set(FCurve *fcu, const BezTriple *active_bezt)
#define BEZT_BINARYSEARCH_THRESH
bool BKE_fcurve_bezt_subdivide_handles(BezTriple *bezt, BezTriple *prev, BezTriple *next, float *r_pdelta)
void BKE_fcurve_keyframe_move_value_with_handles(BezTriple *keyframe, float new_value)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
void BKE_fcurve_free(FCurve *fcu)
bool BKE_fcurve_calc_range(const FCurve *fcu, float *r_min, float *r_max, bool selected_keys_only)
void sort_time_fcurve(FCurve *fcu)
void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *data, float evaltime)
bool BKE_fcurve_calc_bounds(const FCurve *fcu, bool selected_keys_only, bool include_handles, const float frame_range[2], rctf *r_bounds)
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
@ INSERTKEY_NOFLAGS
#define FCURVE_ACTIVE_KEYFRAME_NONE
@ FCURVE_EXTRAPOLATE_CONSTANT
@ FCURVE_EXTRAPOLATE_LINEAR
@ HD_AUTO_ANIM
@ HD_FREE
@ BEZT_IPO_BOUNCE
@ BEZT_IPO_CONST
@ BEZT_IPO_BEZ
@ BEZT_IPO_LIN
@ BEZT_IPO_EASE_AUTO
@ BEZT_IPO_EASE_IN
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
#define SELECT
void ED_keyframes_add(FCurve *fcu, int num_keys_to_add)
KeyframeSettings get_keyframe_settings(bool from_userprefs)
SingleKeyingResult insert_vert_fcurve(FCurve *fcu, const float2 position, const KeyframeSettings &settings, eInsertKeyFlags flag)
Main Key-framing API call.
static const float EPSILON
static void set_key(FCurve *fcu, const int index, const float x, const float y)
TEST(action_groups, ReconstructGroupsWithReordering)
static FCurve * testcurve_with_duplicates()
#define min(a, b)
Definition sort.c:32
float vec[3][3]
BezTriple * bezt
short extend
unsigned int totvert
int active_keyframe_index
float xmax
float xmin
float ymax
float ymin
float max