Blender  V2.93
fcurve_test.cc
Go to the documentation of this file.
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 #include "ED_types.h" /* For SELECT. */
26 
27 #include "DNA_anim_types.h"
28 
29 namespace blender::bke::tests {
30 
31 /* Epsilon for floating point comparisons. */
32 static const float EPSILON = 1e-7f;
33 
34 TEST(evaluate_fcurve, EmptyFCurve)
35 {
36  FCurve *fcu = BKE_fcurve_create();
37  EXPECT_EQ(evaluate_fcurve(fcu, 47.0f), 0.0f);
38  BKE_fcurve_free(fcu);
39 }
40 
42 {
43  FCurve *fcu = BKE_fcurve_create();
44 
48 
49  EXPECT_NEAR(evaluate_fcurve(fcu, 1.0f), 7.0f, EPSILON); /* hits 'on or before first' function */
50  EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f), 13.0f, EPSILON); /* hits 'between' function */
51  EXPECT_NEAR(evaluate_fcurve(fcu, 3.0f), 19.0f, EPSILON); /* hits 'on or after last' function */
52 
53  /* Also test within a specific time epsilon of the keys, as this was an issue in T39207.
54  * This epsilon is just slightly smaller than the epsilon given to
55  * BKE_fcurve_bezt_binarysearch_index_ex() in fcurve_eval_between_keyframes(), so it should hit
56  * the "exact" code path. */
57  float time_epsilon = 0.00008f;
58  EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f - time_epsilon), 13.0f, EPSILON);
59  EXPECT_NEAR(evaluate_fcurve(fcu, 2.0f + time_epsilon), 13.0f, EPSILON);
60 
61  BKE_fcurve_free(fcu);
62 }
63 
64 TEST(evaluate_fcurve, InterpolationConstant)
65 {
66  FCurve *fcu = BKE_fcurve_create();
67 
70 
71  fcu->bezt[0].ipo = BEZT_IPO_CONST;
72  fcu->bezt[1].ipo = BEZT_IPO_CONST;
73 
74  EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.0f, EPSILON);
75  EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 7.0f, EPSILON);
76 
77  BKE_fcurve_free(fcu);
78 }
79 
80 TEST(evaluate_fcurve, InterpolationLinear)
81 {
82  FCurve *fcu = BKE_fcurve_create();
83 
86 
87  fcu->bezt[0].ipo = BEZT_IPO_LIN;
88  fcu->bezt[1].ipo = BEZT_IPO_LIN;
89 
90  EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 8.5f, EPSILON);
91  EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON);
92  EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.5f, EPSILON);
93 
94  BKE_fcurve_free(fcu);
95 }
96 
97 TEST(evaluate_fcurve, InterpolationBezier)
98 {
99  FCurve *fcu = BKE_fcurve_create();
100 
103 
104  EXPECT_EQ(fcu->bezt[0].ipo, BEZT_IPO_BEZ);
105  EXPECT_EQ(fcu->bezt[1].ipo, BEZT_IPO_BEZ);
106 
107  /* Test with default handles. */
108  EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.8297067f, EPSILON);
109  EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 10.0f, EPSILON);
110  EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 12.170294f, EPSILON);
111 
112  /* Test with modified handles. */
113  fcu->bezt[0].vec[0][0] = 0.71855f; /* left handle X */
114  fcu->bezt[0].vec[0][1] = 6.22482f; /* left handle Y */
115  fcu->bezt[0].vec[2][0] = 1.35148f; /* right handle X */
116  fcu->bezt[0].vec[2][1] = 7.96806f; /* right handle Y */
117 
118  fcu->bezt[1].vec[0][0] = 1.66667f; /* left handle X */
119  fcu->bezt[1].vec[0][1] = 10.4136f; /* left handle Y */
120  fcu->bezt[1].vec[2][0] = 2.33333f; /* right handle X */
121  fcu->bezt[1].vec[2][1] = 15.5864f; /* right handle Y */
122 
123  EXPECT_NEAR(evaluate_fcurve(fcu, 1.25f), 7.945497f, EPSILON);
124  EXPECT_NEAR(evaluate_fcurve(fcu, 1.50f), 9.3495407f, EPSILON);
125  EXPECT_NEAR(evaluate_fcurve(fcu, 1.75f), 11.088551f, EPSILON);
126 
127  BKE_fcurve_free(fcu);
128 }
129 
130 TEST(evaluate_fcurve, InterpolationBounce)
131 {
132  FCurve *fcu = BKE_fcurve_create();
133 
136 
137  fcu->bezt[0].ipo = BEZT_IPO_BOUNCE;
138  fcu->bezt[1].ipo = BEZT_IPO_BOUNCE;
139 
140  fcu->bezt[0].easing = BEZT_IPO_EASE_IN;
141  fcu->bezt[1].easing = BEZT_IPO_EASE_AUTO;
142 
143  EXPECT_NEAR(evaluate_fcurve(fcu, 1.4f), 8.3649998f, EPSILON);
144  EXPECT_NEAR(evaluate_fcurve(fcu, 1.5f), 8.4062500f, EPSILON);
145  EXPECT_NEAR(evaluate_fcurve(fcu, 1.8f), 11.184999f, EPSILON);
146 
147  BKE_fcurve_free(fcu);
148 }
149 
150 TEST(evaluate_fcurve, ExtrapolationLinearKeys)
151 {
152  FCurve *fcu = BKE_fcurve_create();
153 
156  fcu->bezt[0].ipo = BEZT_IPO_LIN;
157  fcu->bezt[1].ipo = BEZT_IPO_LIN;
158 
160  /* Before first keyframe. */
161  EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 5.5f, EPSILON);
162  EXPECT_NEAR(evaluate_fcurve(fcu, 0.50f), 4.0f, EPSILON);
163  EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), -8.0f, EPSILON);
164  /* After last keyframe. */
165  EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 17.5f, EPSILON);
166  EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 22.0f, EPSILON);
167 
169  /* Before first keyframe. */
170  EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON);
171  EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON);
172  /* After last keyframe. */
173  EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON);
174  EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON);
175 
176  BKE_fcurve_free(fcu);
177 }
178 
179 TEST(evaluate_fcurve, ExtrapolationBezierKeys)
180 {
181  FCurve *fcu = BKE_fcurve_create();
182 
185 
186  fcu->bezt[0].vec[0][0] = 0.71855f; /* left handle X */
187  fcu->bezt[0].vec[0][1] = 6.22482f; /* left handle Y */
188  fcu->bezt[0].vec[2][0] = 1.35148f; /* right handle X */
189  fcu->bezt[0].vec[2][1] = 7.96806f; /* right handle Y */
190 
191  fcu->bezt[1].vec[0][0] = 1.66667f; /* left handle X */
192  fcu->bezt[1].vec[0][1] = 10.4136f; /* left handle Y */
193  fcu->bezt[1].vec[2][0] = 2.33333f; /* right handle X */
194  fcu->bezt[1].vec[2][1] = 15.5864f; /* right handle Y */
195 
197  /* Before first keyframe. */
198  EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 6.3114409f, EPSILON);
199  EXPECT_NEAR(evaluate_fcurve(fcu, -0.50f), 2.8686447f, EPSILON);
200  /* After last keyframe. */
201  EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 18.81946f, EPSILON);
202  EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 24.63892f, EPSILON);
203 
205  /* Before first keyframe. */
206  EXPECT_NEAR(evaluate_fcurve(fcu, 0.75f), 7.0f, EPSILON);
207  EXPECT_NEAR(evaluate_fcurve(fcu, -1.50f), 7.0f, EPSILON);
208  /* After last keyframe. */
209  EXPECT_NEAR(evaluate_fcurve(fcu, 2.75f), 13.0f, EPSILON);
210  EXPECT_NEAR(evaluate_fcurve(fcu, 3.50f), 13.0f, EPSILON);
211 
212  BKE_fcurve_free(fcu);
213 }
214 
216 {
217  FCurve *fcu = BKE_fcurve_create();
218 
219  /* Insert two keyframes and set handles to something non-default. */
222 
223  fcu->bezt[0].h1 = fcu->bezt[0].h2 = HD_FREE;
224  fcu->bezt[0].vec[0][0] = -5.0f;
225  fcu->bezt[0].vec[0][1] = 0.0f;
226  fcu->bezt[0].vec[2][0] = 2.0f;
227  fcu->bezt[0].vec[2][1] = 4.0f;
228 
229  fcu->bezt[1].h1 = fcu->bezt[1].h2 = HD_FREE;
230  fcu->bezt[1].vec[0][0] = 13.0f;
231  fcu->bezt[1].vec[0][1] = -2.0f;
232  fcu->bezt[1].vec[2][0] = 16.0f;
233  fcu->bezt[1].vec[2][1] = -3.0f;
234 
235  /* Create new keyframe point with defaults from insert_vert_fcurve(). */
236  BezTriple beztr;
237  const float x = 7.375f; /* at this X-coord, the FCurve should evaluate to 1.000f. */
238  const float y = 1.000f;
239  beztr.vec[0][0] = x - 1.0f;
240  beztr.vec[0][1] = y;
241  beztr.vec[1][0] = x;
242  beztr.vec[1][1] = y;
243  beztr.vec[2][0] = x + 1.0f;
244  beztr.vec[2][1] = y;
245  beztr.h1 = beztr.h2 = HD_AUTO_ANIM;
246  beztr.ipo = BEZT_IPO_BEZ;
247 
248  /* This should update the existing handles as well as the new BezTriple. */
249  float y_delta;
250  BKE_fcurve_bezt_subdivide_handles(&beztr, &fcu->bezt[0], &fcu->bezt[1], &y_delta);
251 
252  EXPECT_FLOAT_EQ(y_delta, 0.0f);
253 
254  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][0], -5.0f); /* Left handle should not be touched. */
255  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][1], 0.0f);
256  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][0], 1.0f); /* Coordinates should not be touched. */
257  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][1], 0.0f);
258  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[2][0], 1.5f); /* Right handle should be updated. */
259  EXPECT_FLOAT_EQ(fcu->bezt[0].vec[2][1], 2.0f);
260 
261  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 13.0f); /* Left handle should be updated. */
262  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 0.0f);
263  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 13.0f); /* Coordinates should not be touched. */
264  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 2.0f);
265  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 16.0f); /* Right handle should not be touched */
266  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], -3.0f);
267 
268  EXPECT_FLOAT_EQ(beztr.vec[0][0], 4.5f); /* Left handle should be updated. */
269  EXPECT_FLOAT_EQ(beztr.vec[0][1], 1.5f);
270  EXPECT_FLOAT_EQ(beztr.vec[1][0], 7.375f); /* Coordinates should not be touched. */
271  EXPECT_FLOAT_EQ(beztr.vec[1][1], 1.0f);
272  EXPECT_FLOAT_EQ(beztr.vec[2][0], 10.250); /* Right handle should be updated. */
273  EXPECT_FLOAT_EQ(beztr.vec[2][1], 0.5);
274 
275  BKE_fcurve_free(fcu);
276 }
277 
278 TEST(fcurve_active_keyframe, ActiveKeyframe)
279 {
280  FCurve *fcu = BKE_fcurve_create();
281 
282  /* There should be no active keyframe with no points. */
284 
285  /* Check that adding new points sets the active index. */
292 
293  /* Check clearing the index. */
294  BKE_fcurve_active_keyframe_set(fcu, nullptr);
297 
298  /* Check a "normal" action. */
299  fcu->bezt[2].f2 |= SELECT;
300  BKE_fcurve_active_keyframe_set(fcu, &fcu->bezt[2]);
302 
303  /* Check setting an unselected keyframe as active. */
304  fcu->bezt[2].f1 = fcu->bezt[2].f2 = fcu->bezt[2].f3 = 0;
305  EXPECT_BLI_ASSERT(BKE_fcurve_active_keyframe_set(fcu, &fcu->bezt[2]),
306  "active keyframe must be selected");
308 
309  /* Check out of bounds (lower). */
310  BKE_fcurve_active_keyframe_set(fcu, fcu->bezt - 20);
312  << "Setting out-of-bounds value via the API should result in valid active_keyframe_index";
314 
315  fcu->active_keyframe_index = -20;
317  << "Even with active_keyframe_index out of bounds, getting it via the API should produce a "
318  "valid value";
319 
320  /* Check out of bounds (higher). */
321  BKE_fcurve_active_keyframe_set(fcu, fcu->bezt + 4);
323  << "Setting out-of-bounds value via the API should result in valid active_keyframe_index";
325 
326  fcu->active_keyframe_index = fcu->totvert;
328  << "Even with active_keyframe_index out of bounds, getting it via the API should produce a "
329  "valid value";
330 
331  BKE_fcurve_free(fcu);
332 }
333 
335 {
336  FCurve *fcu = BKE_fcurve_create();
337 
341 
342  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f);
343  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 15.0f);
344 
345  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 8.0f);
346  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 15.0f);
347 
348  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 10.342469f);
349  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], 15.0f);
350 
352 
353  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][0], 5.2671194f) << "Left handle should not move in time";
354  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[0][1], 47.0f) << "Left handle value should have been updated";
355 
356  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], 8.0f) << "Frame should not move in time";
357  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], 47.0f) << "Frame value should have been updated";
358 
359  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][0], 10.342469f) << "Right handle should not move in time";
360  EXPECT_FLOAT_EQ(fcu->bezt[1].vec[2][1], 47.0f) << "Right handle value should have been updated";
361 
362  BKE_fcurve_free(fcu);
363 }
364 
365 } // 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:2186
bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, float *r_pdelta)
Definition: fcurve.c:1714
void BKE_fcurve_keyframe_move_value_with_handles(struct BezTriple *keyframe, float new_value)
Definition: fcurve.c:947
void BKE_fcurve_free(struct FCurve *fcu)
Definition: fcurve.c:81
int BKE_fcurve_active_keyframe_index(const struct FCurve *fcu)
struct FCurve * BKE_fcurve_create(void)
Definition: fcurve.c:68
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)
Definition: keyframing.c:547
static const float EPSILON
Definition: fcurve_test.cc:32
TEST(mat3_vec_to_roll, UnitMatrix)
float vec[3][3]
BezTriple * bezt
short extend
unsigned int totvert
int active_keyframe_index