Blender V4.3
blenkernel/intern/action_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_string.h"
6
7#include "BKE_action.hh"
8
9#include "ANIM_action.hh"
10
11#include "DNA_action_types.h"
12#include "DNA_anim_types.h"
13
14#include "BLI_listbase.h"
15
16#include "MEM_guardedalloc.h"
17
18#include "testing/testing.h"
19
21
22TEST(action_groups, ReconstructGroupsWithReordering)
23{
24 /* Construct an Action with three groups. */
25 bAction action = {{nullptr}};
26 FCurve groupAcurve1 = {nullptr};
27 FCurve groupAcurve2 = {nullptr};
28 FCurve groupBcurve1 = {nullptr};
29 FCurve groupBcurve2 = {nullptr};
30 FCurve groupBcurve3 = {nullptr};
31 /* Group C has no curves intentionally. */
32 FCurve groupDcurve1 = {nullptr};
33 FCurve groupDcurve2 = {nullptr};
34
35 groupAcurve1.rna_path = (char *)"groupAcurve1";
36 groupAcurve2.rna_path = (char *)"groupAcurve2";
37 groupBcurve1.rna_path = (char *)"groupBcurve1";
38 groupBcurve2.rna_path = (char *)"groupBcurve2";
39 groupDcurve1.rna_path = (char *)"groupDcurve1";
40 groupBcurve3.rna_path = (char *)"groupBcurve3";
41 groupDcurve2.rna_path = (char *)"groupDcurve2";
42
43 BLI_addtail(&action.curves, &groupAcurve1);
44 BLI_addtail(&action.curves, &groupAcurve2);
45 BLI_addtail(&action.curves, &groupBcurve1);
46 BLI_addtail(&action.curves, &groupBcurve2);
47 BLI_addtail(&action.curves, &groupDcurve1);
48 BLI_addtail(&action.curves, &groupBcurve3); /* <-- The error that should be corrected. */
49 BLI_addtail(&action.curves, &groupDcurve2);
50
51 /* Introduce another error type, by changing some `prev` pointers. */
52 groupBcurve1.prev = nullptr;
53 groupBcurve3.prev = &groupBcurve2;
54 groupDcurve1.prev = &groupBcurve3;
55
56 bActionGroup groupA = {nullptr};
57 bActionGroup groupB = {nullptr};
58 bActionGroup groupC = {nullptr};
59 bActionGroup groupD = {nullptr};
60 STRNCPY(groupA.name, "groupA");
61 STRNCPY(groupB.name, "groupB");
62 STRNCPY(groupC.name, "groupC");
63 STRNCPY(groupD.name, "groupD");
64
65 BLI_addtail(&action.groups, &groupA);
66 BLI_addtail(&action.groups, &groupB);
67 BLI_addtail(&action.groups, &groupC);
68 BLI_addtail(&action.groups, &groupD);
69
70 groupAcurve1.grp = &groupA;
71 groupAcurve2.grp = &groupA;
72 groupBcurve1.grp = &groupB;
73 groupBcurve2.grp = &groupB;
74 groupBcurve3.grp = &groupB;
75 groupDcurve1.grp = &groupD;
76 groupDcurve2.grp = &groupD;
77
78 groupA.channels.first = &groupAcurve1;
79 groupA.channels.last = &groupAcurve2;
80 groupB.channels.first = &groupBcurve1;
81 groupB.channels.last = &groupBcurve3; /* The last channel in group B, after group C curve 1. */
82 groupD.channels.first = &groupDcurve1;
83 groupD.channels.last = &groupDcurve2;
84
85 EXPECT_EQ(groupA.channels.first, &groupAcurve1);
86 EXPECT_EQ(groupA.channels.last, &groupAcurve2);
87 EXPECT_EQ(groupB.channels.first, &groupBcurve1);
88 EXPECT_EQ(groupB.channels.last, &groupBcurve3);
89 EXPECT_EQ(groupC.channels.first, nullptr);
90 EXPECT_EQ(groupC.channels.last, nullptr);
91 EXPECT_EQ(groupD.channels.first, &groupDcurve1);
92 EXPECT_EQ(groupD.channels.last, &groupDcurve2);
93
95
96 EXPECT_EQ(action.curves.first, &groupAcurve1);
97 EXPECT_EQ(action.curves.last, &groupDcurve2);
98
99 EXPECT_EQ(groupA.prev, nullptr);
100 EXPECT_EQ(groupB.prev, &groupA);
101 EXPECT_EQ(groupC.prev, &groupB);
102 EXPECT_EQ(groupD.prev, &groupC);
103
104 EXPECT_EQ(groupA.next, &groupB);
105 EXPECT_EQ(groupB.next, &groupC);
106 EXPECT_EQ(groupC.next, &groupD);
107 EXPECT_EQ(groupD.next, nullptr);
108
109 EXPECT_EQ(groupA.channels.first, &groupAcurve1);
110 EXPECT_EQ(groupA.channels.last, &groupAcurve2);
111 EXPECT_EQ(groupB.channels.first, &groupBcurve1);
112 EXPECT_EQ(groupB.channels.last, &groupBcurve3);
113 EXPECT_EQ(groupC.channels.first, nullptr);
114 EXPECT_EQ(groupC.channels.last, nullptr);
115 EXPECT_EQ(groupD.channels.first, &groupDcurve1);
116 EXPECT_EQ(groupD.channels.last, &groupDcurve2);
117
118 EXPECT_EQ(groupAcurve1.prev, nullptr);
119 EXPECT_EQ(groupAcurve2.prev, &groupAcurve1);
120 EXPECT_EQ(groupBcurve1.prev, &groupAcurve2);
121 EXPECT_EQ(groupBcurve2.prev, &groupBcurve1);
122 EXPECT_EQ(groupBcurve3.prev, &groupBcurve2);
123 EXPECT_EQ(groupDcurve1.prev, &groupBcurve3);
124 EXPECT_EQ(groupDcurve2.prev, &groupDcurve1);
125
126 EXPECT_EQ(groupAcurve1.next, &groupAcurve2);
127 EXPECT_EQ(groupAcurve2.next, &groupBcurve1);
128 EXPECT_EQ(groupBcurve1.next, &groupBcurve2);
129 EXPECT_EQ(groupBcurve2.next, &groupBcurve3);
130 EXPECT_EQ(groupBcurve3.next, &groupDcurve1);
131 EXPECT_EQ(groupDcurve1.next, &groupDcurve2);
132 EXPECT_EQ(groupDcurve2.next, nullptr);
133}
134
135namespace {
136
137/* Allocate fcu->bezt, and also return a unique_ptr to it for easily freeing the memory. */
138std::unique_ptr<BezTriple[]> allocate_keyframes(FCurve *fcu, const size_t num_keyframes)
139{
140 auto bezt_uptr = std::make_unique<BezTriple[]>(num_keyframes);
141 fcu->bezt = bezt_uptr.get();
142 return bezt_uptr;
143}
144
145/* Append keyframe, assumes that fcu->bezt is allocated and has enough space. */
146void add_keyframe(FCurve *fcu, float x, float y)
147{
148 /* The insert_keyframe functions are in the editors, so we cannot link to those here. */
149 BezTriple the_keyframe;
150 memset(&the_keyframe, 0, sizeof(the_keyframe));
151
152 /* Copied from insert_vert_fcurve() in `keyframing.cc`. */
153 the_keyframe.vec[0][0] = x - 1.0f;
154 the_keyframe.vec[0][1] = y;
155 the_keyframe.vec[1][0] = x;
156 the_keyframe.vec[1][1] = y;
157 the_keyframe.vec[2][0] = x + 1.0f;
158 the_keyframe.vec[2][1] = y;
159
160 memcpy(&fcu->bezt[fcu->totvert], &the_keyframe, sizeof(the_keyframe));
161 fcu->totvert++;
162}
163
164} // namespace
165
166TEST(action_assets, BKE_action_has_single_frame)
167{
168 /* No FCurves. */
169 {
170 const bAction empty = {{nullptr}};
171 EXPECT_FALSE(empty.wrap().has_single_frame())
172 << "Action without FCurves cannot have a single frame.";
173 }
174
175 /* One curve with one key. */
176 {
177 FCurve fcu = {nullptr};
178 std::unique_ptr<BezTriple[]> bezt = allocate_keyframes(&fcu, 1);
179 add_keyframe(&fcu, 1.0f, 2.0f);
180
181 bAction action = {{nullptr}};
182 BLI_addtail(&action.curves, &fcu);
183
184 EXPECT_TRUE(action.wrap().has_single_frame())
185 << "Action with one FCurve and one key should have single frame.";
186 }
187
188 /* Two curves with one key each. */
189 {
190 FCurve fcu1 = {nullptr};
191 FCurve fcu2 = {nullptr};
192 std::unique_ptr<BezTriple[]> bezt1 = allocate_keyframes(&fcu1, 1);
193 std::unique_ptr<BezTriple[]> bezt2 = allocate_keyframes(&fcu2, 1);
194 add_keyframe(&fcu1, 1.0f, 327.0f);
195 add_keyframe(&fcu2, 1.0f, 47.0f); /* Same X-coordinate as the other one. */
196
197 bAction action = {{nullptr}};
198 BLI_addtail(&action.curves, &fcu1);
199 BLI_addtail(&action.curves, &fcu2);
200
201 EXPECT_TRUE(action.wrap().has_single_frame())
202 << "Two FCurves with keys on the same frame should have single frame.";
203
204 /* Modify the 2nd curve so it's keyed on a different frame. */
205 fcu2.bezt[0].vec[1][0] = 2.0f;
206 EXPECT_FALSE(action.wrap().has_single_frame())
207 << "Two FCurves with keys on different frames should have animation.";
208 }
209
210 /* One curve with two keys. */
211 {
212 FCurve fcu = {nullptr};
213 std::unique_ptr<BezTriple[]> bezt = allocate_keyframes(&fcu, 2);
214 add_keyframe(&fcu, 1.0f, 2.0f);
215 add_keyframe(&fcu, 2.0f, 2.5f);
216
217 bAction action = {{nullptr}};
218 BLI_addtail(&action.curves, &fcu);
219
220 EXPECT_FALSE(action.wrap().has_single_frame())
221 << "Action with one FCurve and two keys must have animation.";
222 }
223}
224
225} // namespace blender::bke::tests
Functions and classes to work with Actions.
Blender kernel action and pose functionality.
void BKE_action_groups_reconstruct(bAction *act)
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
#define STRNCPY(dst, src)
Definition BLI_string.h:593
Read Guarded memory(de)allocation.
TEST(action_groups, ReconstructGroupsWithReordering)
float vec[3][3]
struct FCurve * next
bActionGroup * grp
char * rna_path
BezTriple * bezt
struct FCurve * prev
unsigned int totvert
void * last
void * first
struct bActionGroup * prev
struct bActionGroup * next
ListBase curves
ListBase groups