Blender V4.3
anim_ipo_utils.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9/* This file contains code for presenting F-Curves and other animation data
10 * in the UI (especially for use in the Animation Editors).
11 *
12 * -- Joshua Leung, Dec 2008
13 */
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_blenlib.h"
18#include "BLI_math_color.h"
19#include "BLI_utildefines.h"
20
21#include "BLT_translation.hh"
22
23#include "DNA_anim_types.h"
24
25#include "RNA_access.hh"
26#include "RNA_path.hh"
27#include "RNA_prototypes.hh"
28
29#include "ED_anim_api.hh"
30
31#include "ANIM_action.hh"
32
33#include "fmt/format.h"
34
35#include <cstring>
36
37struct StructRNA;
38
39/* ----------------------- Getter functions ----------------------- */
40
41std::optional<int> getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
42{
43 /* Could make an argument, it's a documented limit at the moment. */
44 constexpr size_t name_maxncpy = 256;
45
46 /* Handle some nullptr cases. */
47 if (name == nullptr) {
48 /* A 'get name' function should be able to get the name, otherwise it's a bug. */
50 return {};
51 }
52 if (fcu == nullptr) {
53 BLI_strncpy(name, RPT_("<invalid>"), name_maxncpy);
54 return {};
55 }
56 if (fcu->rna_path == nullptr) {
57 BLI_strncpy(name, RPT_("<no path>"), name_maxncpy);
58 return {};
59 }
60 if (id == nullptr) {
61 BLI_snprintf(name, name_maxncpy, "%s[%d]", fcu->rna_path, fcu->array_index);
62 return {};
63 }
64
66
68 PropertyRNA *prop;
69
70 if (!RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
71 /* Could not resolve the path, so just use the path itself as 'name'. */
72 BLI_snprintf(name, name_maxncpy, "\"%s[%d]\"", fcu->rna_path, fcu->array_index);
73
74 /* Tag F-Curve as disabled - as not usable path. */
75 fcu->flag |= FCURVE_DISABLED;
76 return {};
77 }
78
79 const char *structname = nullptr, *propname = nullptr;
80 char arrayindbuf[16];
81 const char *arrayname = nullptr;
82 bool free_structname = false;
83
84 /* For now, name will consist of 3 parts: struct-name, property name, array index
85 * There are several options possible:
86 * 1) <struct-name>.<property-name>.<array-index>
87 * i.e. Bone1.Location.X, or Object.Location.X
88 * 2) <array-index> <property-name> (<struct name>)
89 * i.e. X Location (Bone1), or X Location (Object)
90 *
91 * Currently, option 2 is in use, to try and make it easier to quickly identify F-Curves
92 * (it does have problems with looking rather odd though).
93 * Option 1 is better in terms of revealing a consistent sense of hierarchy though,
94 * which isn't so clear with option 2.
95 */
96
97 /* For struct-name:
98 * - As base, we use a custom name from the structs if one is available
99 * - However, if we're showing sub-data of bones
100 * (probably there will be other exceptions later).
101 * need to include that info too since it gets confusing otherwise.
102 * - If a pointer just refers to the ID-block, then don't repeat this info
103 * since this just introduces clutter.
104 */
105
106 char pchanName[name_maxncpy], constName[name_maxncpy];
107 if (BLI_str_quoted_substr(fcu->rna_path, "bones[", pchanName, sizeof(pchanName)) &&
108 BLI_str_quoted_substr(fcu->rna_path, "constraints[", constName, sizeof(constName)))
109 {
110 structname = BLI_sprintfN("%s : %s", pchanName, constName);
111 free_structname = true;
112 }
113 else if (ptr.data != ptr.owner_id) {
115 if (nameprop) {
116 structname = RNA_property_string_get_alloc(&ptr, nameprop, nullptr, 0, nullptr);
117 free_structname = true;
118 }
119 else {
120 structname = RNA_struct_ui_name(ptr.type);
121 }
122
123 /* For the sequencer, a strip's 'Transform' or 'Crop' is a nested (under Sequence)
124 * struct, but displaying the struct name alone is no meaningful information
125 * (and also cannot be filtered well), same for modifiers.
126 * So display strip name alongside as well. */
127 if (GS(ptr.owner_id->name) == ID_SCE) {
128 char stripname[name_maxncpy];
130 fcu->rna_path, "sequence_editor.sequences_all[", stripname, sizeof(stripname)))
131 {
132 if (strstr(fcu->rna_path, ".transform.") || strstr(fcu->rna_path, ".crop.") ||
133 strstr(fcu->rna_path, ".modifiers["))
134 {
135 const char *structname_all = BLI_sprintfN("%s : %s", stripname, structname);
136 if (free_structname) {
137 MEM_freeN((void *)structname);
138 }
139 structname = structname_all;
140 free_structname = true;
141 }
142 }
143 }
144 /* For node sockets, it is useful to include the node name as well (multiple similar nodes
145 * are not distinguishable otherwise). Unfortunately, the node label cannot be retrieved
146 * from the rna path, for this to work access to the underlying node is needed (but finding
147 * the node iterates all nodes & sockets which would result in bad performance in some
148 * circumstances). */
149 if (RNA_struct_is_a(ptr.type, &RNA_NodeSocket)) {
150 char nodename[name_maxncpy];
151 if (BLI_str_quoted_substr(fcu->rna_path, "nodes[", nodename, sizeof(nodename))) {
152 const char *structname_all = BLI_sprintfN("%s : %s", nodename, structname);
153 if (free_structname) {
154 MEM_freeN((void *)structname);
155 }
156 structname = structname_all;
157 free_structname = true;
158 }
159 }
160 }
161
162 /* Property Name is straightforward */
163 propname = RNA_property_ui_name(prop);
164
165 /* Array Index - only if applicable */
166 if (RNA_property_array_check(prop)) {
167 char c = RNA_property_array_item_char(prop, fcu->array_index);
168
169 /* we need to write the index to a temp buffer (in py syntax) */
170 if (c) {
171 SNPRINTF(arrayindbuf, "%c ", c);
172 }
173 else {
174 SNPRINTF(arrayindbuf, "[%d]", fcu->array_index);
175 }
176
177 arrayname = &arrayindbuf[0];
178 }
179 else {
180 /* no array index */
181 arrayname = "";
182 }
183
184 /* putting this all together into the buffer */
185 /* XXX we need to check for invalid names...
186 * XXX the name length limit needs to be passed in or as some define */
187 if (structname) {
188 BLI_snprintf(name, name_maxncpy, "%s%s (%s)", arrayname, propname, structname);
189 }
190 else {
191 BLI_snprintf(name, name_maxncpy, "%s%s", arrayname, propname);
192 }
193
194 /* free temp name if nameprop is set */
195 if (free_structname) {
196 MEM_freeN((void *)structname);
197 }
198
199 /* Valid path - remove the invalid tag since we now know how to use it saving
200 * users manual effort to re-enable using "Revive Disabled FCurves" #29629. */
201 fcu->flag &= ~FCURVE_DISABLED;
202
203 /* Use the property's owner struct icon. */
205}
206
208 const blender::animrig::Slot &slot,
209 FCurve &fcurve)
210{
211 /* TODO: Refactor to avoid this variable. */
212 constexpr size_t name_maxncpy = 256;
213 char name_buffer[name_maxncpy];
214 name_buffer[0] = '\0';
215
216 /* Check the Slot's users to see if we can find an ID* that can resolve the F-Curve. */
217 for (ID *user : slot.users(bmain)) {
218 const std::optional<int> icon = getname_anim_fcurve(name_buffer, user, &fcurve);
219 if (icon.has_value()) {
220 /* Managed to find a name! */
221 return name_buffer;
222 }
223 }
224
225 if (!slot.users(bmain).is_empty()) {
226 /* This slot is assigned to at least one ID, and still the property it animates could not be
227 * found. There is no use in continuing. */
228 fcurve.flag |= FCURVE_DISABLED;
229 return fmt::format("\"{}[{}]\"", fcurve.rna_path, fcurve.array_index);
230 }
231
232 /* If this part of the code is hit, the slot is not assigned to anything. The remainder of
233 * this function is all a best-effort attempt. Because of that, it will not set the
234 * FCURVE_DISABLED flag on the F-Curve, as having unassigned animation data is not an error (and
235 * that flag indicates an error). */
236
237 /* Fall back to the ID type of the slot for simple properties. */
238 if (!slot.has_idtype()) {
239 /* The Slot has never been assigned to any ID, so we don't even know what type of ID it is
240 * meant for. */
241 return fmt::format("\"{}[{}]\"", fcurve.rna_path, fcurve.array_index);
242 }
243
245 /* Not a simple property, so bail out. This needs path resolution, which needs an ID*. */
246 return fmt::format("\"{}[{}]\"", fcurve.rna_path, fcurve.array_index);
247 }
248
249 /* Find the StructRNA for this Slot's ID type. */
251 if (!srna) {
252 return fmt::format("\"{}[{}]\"", fcurve.rna_path, fcurve.array_index);
253 }
254
255 /* Find the property. */
257 if (!prop) {
258 return fmt::format("\"{}[{}]\"", fcurve.rna_path, fcurve.array_index);
259 }
260
261 /* Property Name is straightforward */
262 const char *propname = RNA_property_ui_name(prop);
263
264 /* Array Index - only if applicable */
265 if (!RNA_property_array_check(prop)) {
266 return propname;
267 }
268
269 std::string arrayname = "";
270 char c = RNA_property_array_item_char(prop, fcurve.array_index);
271 if (c) {
272 arrayname = std::string(1, c);
273 }
274 else {
275 arrayname = fmt::format("[{}]", fcurve.array_index);
276 }
277 return arrayname + " " + propname;
278}
279
280/* ------------------------------- Color Codes for F-Curve Channels ---------------------------- */
281
282/* step between the major distinguishable color bands of the primary colors */
283#define HSV_BANDWIDTH 0.3f
284
285/* used to determine the color of F-Curves with FCURVE_COLOR_AUTO_RAINBOW set */
286// void fcurve_rainbow(uint cur, uint tot, float *out)
287void getcolor_fcurve_rainbow(int cur, int tot, float out[3])
288{
289 float hsv[3], fac;
290 int grouping;
291
292 /* we try to divide the color into groupings of n colors,
293 * where n is:
294 * 3 - for 'odd' numbers of curves - there should be a majority of triplets of curves
295 * 4 - for 'even' numbers of curves - there should be a majority of quartets of curves
296 * so the base color is simply one of the three primary colors
297 */
298 grouping = (4 - (tot % 2));
299 hsv[0] = HSV_BANDWIDTH * float(cur % grouping);
300
301 /* 'Value' (i.e. darkness) needs to vary so that larger sets of three will be
302 * 'darker' (i.e. smaller value), so that they don't look that similar to previous ones.
303 * However, only a range of 0.3 to 1.0 is really usable to avoid clashing
304 * with some other stuff
305 */
306 fac = (float(cur) / float(tot)) * 0.7f;
307
308 /* the base color can get offset a bit so that the colors aren't so identical */
309 hsv[0] += fac * HSV_BANDWIDTH;
310 if (hsv[0] > 1.0f) {
311 hsv[0] = fmod(hsv[0], 1.0f);
312 }
313
314 /* saturation adjustments for more visible range */
315 hsv[1] = ((hsv[0] > 0.5f) && (hsv[0] < 0.8f)) ? 0.5f : 0.6f;
316
317 /* value is fixed at 1.0f, otherwise we cannot clearly see the curves... */
318 hsv[2] = 1.0f;
319
320 /* finally, convert this to RGB colors */
321 hsv_to_rgb_v(hsv, out);
322}
Functions and classes to work with Actions.
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition math_color.cc:57
char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
Definition string.c:517
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define RPT_(msgid)
@ ID_SCE
@ FCURVE_DISABLED
Read Guarded memory(de)allocation.
StructRNA * ID_code_to_RNA_type(short idcode)
std::string getname_anim_fcurve_for_slot(Main &bmain, const blender::animrig::Slot &slot, FCurve &fcurve)
std::optional< int > getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
void getcolor_fcurve_rainbow(int cur, int tot, float out[3])
#define HSV_BANDWIDTH
constexpr bool is_empty() const
Definition BLI_span.hh:261
static constexpr int64_t not_found
constexpr int64_t find(char c, int64_t pos=0) const
Span< ID * > users(Main &bmain) const
draw_view in_light_buf[] float
#define GS(x)
Definition iris.cc:202
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float2 fmod(const float2 a, const float b)
PropertyRNA * RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
bool RNA_property_array_check(PropertyRNA *prop)
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
char * RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
char RNA_property_array_item_char(PropertyRNA *prop, int index)
int RNA_struct_ui_icon(const StructRNA *type)
const char * RNA_struct_ui_name(const StructRNA *type)
const char * RNA_property_ui_name(const PropertyRNA *prop)
PropertyRNA * RNA_struct_name_property(const StructRNA *type)
PointerRNA RNA_id_pointer_create(ID *id)
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:553
char * rna_path
int array_index
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
ID * owner_id
Definition RNA_types.hh:40
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
PointerRNA * ptr
Definition wm_files.cc:4126