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