Blender  V3.3
fcurve_test.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. */
3 #include "testing/testing.h"
4 
5 #include "MEM_guardedalloc.h"
6 
7 #include "BKE_fcurve.h"
8 
9 #include "ED_keyframing.h"
10 #include "ED_types.h" /* For SELECT. */
11 
12 #include "DNA_anim_types.h"
13 
14 namespace blender::bke::tests {
15 
16 /* Epsilon for floating point comparisons. */
17 static const float EPSILON = 1e-7f;
18 
19 TEST(evaluate_fcurve, EmptyFCurve)
20 {
21  FCurve *fcu = BKE_fcurve_create();
22  EXPECT_EQ(evaluate_fcurve(fcu, 47.0f), 0.0f);
23  BKE_fcurve_free(fcu);
24 }
25 
27 {
28  FCurve *fcu = BKE_fcurve_create();
29 
33 
34  EXPECT_NEAR(evaluate_fcurve(fcu, 1.0f), 7.0f, EPSILON); /* hits 'on or before first' function */
35  EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f), 13.0f, EPSILON); /* hits 'between' function */
36  EXPECT_NEAR(evaluate_fcurve(fcu, 3.0f), 19.0f, EPSILON); /* hits 'on or after last' function */
37 
38  /* Also test within a specific time epsilon of the keys, as this was an issue in T39207.
39  * This epsilon is just slightly smaller than the epsilon given to
40  * BKE_fcurve_bezt_binarysearch_index_ex() in fcurve_eval_between_keyframes(), so it should hit
41  * the "exact" code path. */
42  float time_epsilon = 0.00008f;
43  EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f - time_epsilon), 13.0f, EPSILON);
44  EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f + time_epsilon), 13.0f, EPSILON);
45 
46  BKE_fcurve_free(fcu);
47 }
48 
49 TEST(evaluate_fcurve, InterpolationConstant)
50 {
51  FCurve *fcu = BKE_fcurve_create();
52 
55 
56  fcu->bezt[0].ipo = BEZT_IPO_CONST;
57  fcu->bezt[1].ipo = BEZT_IPO_CONST;
58 
59  EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.0f, EPSILON);
60  EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 7.0f, EPSILON);
61 
62  BKE_fcurve_free(fcu);
63 }
64 
65 TEST(evaluate_fcurve, InterpolationLinear)
66 {
67  FCurve *fcu = BKE_fcurve_create();
68 
71 
72  fcu->bezt[0].ipo = BEZT_IPO_LIN;
73  fcu->bezt[1].ipo = BEZT_IPO_LIN;
74 
75  EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 8.5f, EPSILON);
76  EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON);
77  EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.5f, EPSILON);
78 
79  BKE_fcurve_free(fcu);
80 }
81 
82 TEST(evaluate_fcurve, InterpolationBezier)
83 {
84  FCurve *fcu = BKE_fcurve_create();
85 
88 
89  EXPECT_EQ(fcu->bezt[0].ipo, BEZT_IPO_BEZ);
90  EXPECT_EQ(fcu->bezt[1].ipo, BEZT_IPO_BEZ);
91 
92  /* Test with default handles. */
93  EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.8297067f, EPSILON);
94  EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON);
95  EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 12.170294f, EPSILON);
96 
97  /* Test with modified handles. */
98  fcu->bezt[0].vec[0][0] = 0.71855f; /* left handle X */
99  fcu->bezt[0].vec[0][1] = 6.22482f; /* left handle Y */
100  fcu->bezt[0].vec[2][0] = 1.35148f; /* right handle X */
101  fcu->bezt[0].vec[2][1] = 7.96806f; /* right handle Y */
102 
103  fcu->bezt[1].vec[0][0] = 1.66667f; /* left handle X */
104  fcu->bezt[1].vec[0][1] = 10.4136f; /* left handle Y */
105  fcu->bezt[1].vec[2][0] = 2.33333f; /* right handle X */
106  fcu->bezt[1].vec[2][1] = 15.5864f; /* right handle Y */
107 
108  EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.945497f, EPSILON);
109  EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 9.3495407f, EPSILON);
110  EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.088551f, EPSILON);
111 
112  BKE_fcurve_free(fcu);
113 }
114 
115 TEST(evaluate_fcurve, InterpolationBounce)
116 {
117  FCurve *fcu = BKE_fcurve_create();
118 
121 
122  fcu->bezt[0].ipo = BEZT_IPO_BOUNCE;
123  fcu->bezt[1].ipo = BEZT_IPO_BOUNCE;
124 
125  fcu->bezt[0].easing = BEZT_IPO_EASE_IN;
126  fcu->bezt[1].easing = BEZT_IPO_EASE_AUTO;
127 
128  EXPECT_NEAR(evaluate_fcurve(fcu, 1.4f), 8.3649998f, EPSILON);
129  EXPECT_NEAR(evaluate_fcurve(fcu, 1.5f), 8.4062500f, EPSILON);
130  EXPECT_NEAR(evaluate_fcurve(fcu, 1.8f), 11.184999f, EPSILON);
131 
132  BKE_fcurve_free(fcu);
133 }
134 
135 TEST(evaluate_fcurve, ExtrapolationLinearKeys)
136 {
137  FCurve *fcu = BKE_fcurve_create();
138 
141  fcu->bezt[0].ipo = BEZT_IPO_LIN;
142  fcu->bezt[1].ipo = BEZT_IPO_LIN;
143 
145  /* Before first keyframe. */
146  EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 5.5f, EPSILON);
147  EXPECT_NEAR(evaluate_fcurve(fcu, 0.50f), 4.0f, EPSILON);
148  EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), -8.0f, EPSILON);
149  /* After last keyframe. */
150  EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 17.5f, EPSILON);
151  EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 22.0f, EPSILON);
152 
154  /* Before first keyframe. */
155  EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON);
156  EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON);
157  /* After last keyframe. */
158  EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON);
159  EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON);
160 
161  BKE_fcurve_free(fcu);
162 }
163 
164 TEST(evaluate_fcurve, ExtrapolationBezierKeys)
165 {
166  FCurve *fcu = BKE_fcurve_create();
167 
170 
171  fcu->bezt[0].vec[0][0] = 0.71855f; /* left handle X */
172  fcu->bezt[0].vec[0][1] = 6.22482f; /* left handle Y */
173  fcu->bezt[0].vec[2][0] = 1.35148f; /* right handle X */
174  fcu->bezt[0].vec[2][1] = 7.96806f; /* right handle Y */
175 
176  fcu->bezt[1].vec[0][0] = 1.66667f; /* left handle X */
177  fcu->bezt[1].vec[0][1] = 10.4136f; /* left handle Y */
178  fcu->bezt[1].vec[2][0] = 2.33333f; /* right handle X */
179  fcu->bezt[1].vec[2][1] = 15.5864f; /* right handle Y */
180 
182  /* Before first keyframe. */
183  EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 6.3114409f, EPSILON);
184  EXPECT_NEAR(evaluate_fcurve(fcu, -0.50f), 2.8686447f, EPSILON);
185  /* After last keyframe. */
186  EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 18.81946f, EPSILON);
187  EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 24.63892f, EPSILON);
188 
190  /* Before first keyframe. */
191  EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON);
192  EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON);
193  /* After last keyframe. */
194  EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON);
195  EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON);
196 
197  BKE_fcurve_free(fcu);
198 }
199 
201 {
202  FCurve *fcu = BKE_fcurve_create();
203 
204  /* Insert two keyframes and set handles to something non-default. */
207 
208  fcu->bezt[0].h1 = fcu->bezt[0].h2 = HD_FREE;
209  fcu->bezt[0].vec[0][0] = -5.0f;
210  fcu->bezt[0].vec[0][1] = 0.0f;
211  fcu->bezt[0].vec[2][0] = 2.0f;
212  fcu->bezt[0].vec[2][1] = 4.0f;
213 
214  fcu->bezt[1].h1 = fcu->bezt[1].h2 = HD_FREE;
215  fcu->bezt[1].vec[0][0] = 13.0f;
216  fcu->bezt[1].vec[0][1] = -2.0f;
217  fcu->bezt[1].vec[2][0] = 16.0f;
218  fcu->bezt[1].vec[2][1] = -3.0f;
219 
220  /* Create new keyframe point with defaults from insert_vert_fcurve(). */
221  BezTriple beztr;
222  const float x = 7.375f; /* at this X-coord, the FCurve should evaluate to 1.000f. */
223  const float y = 1.000f;
224  beztr.vec[0][0] = x - 1.0f;
225  beztr.vec[0][1] = y;
226  beztr.vec[1][0] = x;
227  beztr.vec[1][1] = y;
228  beztr.vec[2][0] = x + 1.0f;
229  beztr.vec[2][1] = y;
230  beztr.h1 = beztr.h2 = HD_AUTO_ANIM;
231  beztr.ipo = BEZT_IPO_BEZ;
232 
233  /* This should update the existing handles as well as the new BezTriple. */
234  float y_delta;
235  BKE_fcurve_bezt_subdivide_handles(&beztr, &fcu->bezt[0], &fcu->bezt[1], &y_delta);
236 
237  EXPECT_FLOAT_EQ(y_delta, 0.0f);
238 
239  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][0], -5.0f); /* Left handle should not be touched. */
240  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][1], 0.0f);
241  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][0], 1.0f); /* Coordinates should not be touched. */
242  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][1], 0.0f);
243  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[2][0], 1.5f); /* Right handle should be updated. */
244  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[2][1], 2.0f);
245 
246  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 13.0f); /* Left handle should be updated. */
247  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 0.0f);
248  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 13.0f); /* Coordinates should not be touched. */
249  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 2.0f);
250  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 16.0f); /* Right handle should not be touched */
251  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], -3.0f);
252 
253  EXPECT_FLOAT_EQ(beztr.vec[0][0], 4.5f); /* Left handle should be updated. */
254  EXPECT_FLOAT_EQ(beztr.vec[0][1], 1.5f);
255  EXPECT_FLOAT_EQ(beztr.vec[1][0], 7.375f); /* Coordinates should not be touched. */
256  EXPECT_FLOAT_EQ(beztr.vec[1][1], 1.0f);
257  EXPECT_FLOAT_EQ(beztr.vec[2][0], 10.250); /* Right handle should be updated. */
258  EXPECT_FLOAT_EQ(beztr.vec[2][1], 0.5);
259 
260  BKE_fcurve_free(fcu);
261 }
262 
263 TEST(fcurve_active_keyframe, ActiveKeyframe)
264 {
265  FCurve *fcu = BKE_fcurve_create();
266 
267  /* There should be no active keyframe with no points. */
269 
270  /* Check that adding new points sets the active index. */
277 
278  /* Check clearing the index. */
279  BKE_fcurve_active_keyframe_set(fcu, nullptr);
282 
283  /* Check a "normal" action. */
284  fcu->bezt[2].f2 |= SELECT;
285  BKE_fcurve_active_keyframe_set(fcu, &fcu->bezt[2]);
287 
288  /* Check setting an unselected keyframe as active. */
289  fcu->bezt[2].f1 = fcu->bezt[2].f2 = fcu->bezt[2].f3 = 0;
290  EXPECT_BLI_ASSERT(BKE_fcurve_active_keyframe_set(fcu, &fcu->bezt[2]),
291  "active keyframe must be selected");
293 
294  /* Check out of bounds (lower). */
295  BKE_fcurve_active_keyframe_set(fcu, fcu->bezt - 20);
297  << "Setting out-of-bounds value via the API should result in valid active_keyframe_index";
299 
300  fcu->active_keyframe_index = -20;
302  << "Even with active_keyframe_index out of bounds, getting it via the API should produce a "
303  "valid value";
304 
305  /* Check out of bounds (higher). */
306  BKE_fcurve_active_keyframe_set(fcu, fcu->bezt + 4);
308  << "Setting out-of-bounds value via the API should result in valid active_keyframe_index";
310 
311  fcu->active_keyframe_index = fcu->totvert;
313  << "Even with active_keyframe_index out of bounds, getting it via the API should produce a "
314  "valid value";
315 
316  BKE_fcurve_free(fcu);
317 }
318 
320 {
321  FCurve *fcu = BKE_fcurve_create();
322 
326 
327  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f);
328  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 15.0f);
329 
330  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 8.0f);
331  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 15.0f);
332 
333  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 10.342469f);
334  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], 15.0f);
335 
337 
338  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f) << "Left handle should not move in time";
339  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 47.0f) << "Left handle value should have been updated";
340 
341  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 8.0f) << "Frame should not move in time";
342  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 47.0f) << "Frame value should have been updated";
343 
344  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 10.342469f) << "Right handle should not move in time";
345  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], 47.0f) << "Right handle value should have been updated";
346 
347  BKE_fcurve_free(fcu);
348 }
349 
350 } // namespace blender::bke::tests
void BKE_fcurve_active_keyframe_set(struct FCurve *fcu, const struct BezTriple *active_bezt)
float evaluate_fcurve(struct FCurve *fcu, float evaltime)
Definition: fcurve.c:2135
bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, float *r_pdelta)
Definition: fcurve.c:1600
void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, float new_value)
Definition: fcurve.c:891
void BKE_fcurve_free(struct FCurve *fcu)
Definition: fcurve.c:65
int BKE_fcurve_active_keyframe_index(const struct FCurve *fcu)
struct FCurve * BKE_fcurve_create(void)
Definition: fcurve.c:53
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
@ INSERTKEY_NO_USERPREF
#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
@ BEZT_KEYTYPE_KEYFRAME
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
Read Guarded memory(de)allocation.
#define SELECT
int insert_vert_fcurve(FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
Main Key-framing API call.
Definition: keyframing.c:545
static const float EPSILON
Definition: fcurve_test.cc:17
TEST(action_groups, ReconstructGroupsWithReordering)
Definition: action_test.cc:17
uint8_t h1
uint8_t f3
float vec[3][3]
uint8_t f1
uint8_t f2
uint8_t h2
BezTriple * bezt
short extend
unsigned int totvert
int active_keyframe_index