Blender V4.3
BCAnimationCurve.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "RNA_path.hh"
6
7#include "BCAnimationCurve.h"
8
10{
12 this->fcurve = nullptr;
13 this->curve_is_local_copy = false;
14}
15
17{
18 this->min = other.min;
19 this->max = other.max;
20 this->fcurve = other.fcurve;
21 this->curve_key = other.curve_key;
22 this->curve_is_local_copy = false;
23 this->id_ptr = other.id_ptr;
24
25 /* The fcurve of the new instance is a copy and can be modified */
26
28}
29
31{
32 this->min = 0;
33 this->max = 0;
34 this->curve_key = key;
35 this->fcurve = fcu;
36 this->curve_is_local_copy = false;
37 init_pointer_rna(ob);
38}
39
41{
42 this->curve_key = key;
43 this->fcurve = nullptr;
44 this->curve_is_local_copy = false;
45 init_pointer_rna(ob);
46}
47
48void BCAnimationCurve::init_pointer_rna(Object *ob)
49{
50 switch (this->curve_key.get_animation_type()) {
52 bArmature *arm = (bArmature *)ob->data;
53 id_ptr = RNA_id_pointer_create(&arm->id);
54 break;
55 }
57 id_ptr = RNA_id_pointer_create(&ob->id);
58 break;
59 }
61 Material *ma = BKE_object_material_get(ob, curve_key.get_subindex() + 1);
62 id_ptr = RNA_id_pointer_create(&ma->id);
63 break;
64 }
66 Camera *camera = (Camera *)ob->data;
67 id_ptr = RNA_id_pointer_create(&camera->id);
68 break;
69 }
71 Light *lamp = (Light *)ob->data;
72 id_ptr = RNA_id_pointer_create(&lamp->id);
73 break;
74 }
75 default:
76 fprintf(
77 stderr, "BC_animation_curve_type %d not supported", this->curve_key.get_array_index());
78 break;
79 }
80}
81
82void BCAnimationCurve::delete_fcurve(FCurve *fcu)
83{
84 BKE_fcurve_free(fcu);
85}
86
87FCurve *BCAnimationCurve::create_fcurve(int array_index, const char *rna_path)
88{
91 fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
92 fcu->array_index = array_index;
93 return fcu;
94}
95
96void BCAnimationCurve::create_bezt(float frame, float output)
97{
98 FCurve *fcu = get_edit_fcurve();
99 BezTriple bez;
100 memset(&bez, 0, sizeof(BezTriple));
101 bez.vec[1][0] = frame;
102 bez.vec[1][1] = output;
103 bez.ipo = U.ipo_new; /* use default interpolation mode here... */
104 bez.f1 = bez.f2 = bez.f3 = SELECT;
105 bez.h1 = bez.h2 = HD_AUTO;
108}
109
111{
112 if (curve_is_local_copy && fcurve) {
113 // fprintf(stderr, "removed fcurve %s\n", fcurve->rna_path);
114 delete_fcurve(fcurve);
115 this->fcurve = nullptr;
116 }
117}
118
120{
121 return curve_key.get_animation_type() == type;
122}
123
125{
126 const std::string path = curve_key.get_path();
127
128 if (bc_startswith(path, "pose.bones")) {
129 return bc_string_after(path, "pose.bones");
130 }
131 return bc_string_after(path, ".");
132}
133
135{
136 const std::string channel = get_channel_target();
137 return bc_string_after(channel, ".");
138}
139
141{
142 const std::string channel = get_channel_target();
143 std::string pose_bone_name = bc_string_before(channel, ".");
144 if (pose_bone_name == channel) {
145 pose_bone_name = "";
146 }
147 else {
148 pose_bone_name = bc_string_after(pose_bone_name, "\"[");
149 pose_bone_name = bc_string_before(pose_bone_name, "]\"");
150 }
151 return pose_bone_name;
152}
153
155{
156 std::string name;
157
158 switch (curve_key.get_animation_type()) {
160 name = id_name(ob);
161 break;
162 }
164 if (fcurve == nullptr || fcurve->rna_path == nullptr) {
165 name = "";
166 }
167 else {
168 char boneName[MAXBONENAME];
169 if (BLI_str_quoted_substr(fcurve->rna_path, "pose.bones[", boneName, sizeof(boneName))) {
170 name = id_name(ob) + "_" + std::string(boneName);
171 }
172 else {
173 name = "";
174 }
175 }
176 break;
177 }
179 Camera *camera = (Camera *)ob->data;
180 name = id_name(ob) + "-" + id_name(camera) + "-camera";
181 break;
182 }
184 Light *lamp = (Light *)ob->data;
185 name = id_name(ob) + "-" + id_name(lamp) + "-light";
186 break;
187 }
189 Material *ma = BKE_object_material_get(ob, this->curve_key.get_subindex() + 1);
190 name = id_name(ob) + "-" + id_name(ma) + "-material";
191 break;
192 }
193 default: {
194 name = "";
195 }
196 }
197
198 return name;
199}
200
202{
203 return curve_key.get_array_index();
204}
205
207{
208 return curve_key.get_subindex();
209}
210
212{
213 return curve_key.get_path();
214}
215
217{
218 if (fcurve == nullptr) {
219 return 0;
220 }
221 return fcurve->totvert;
222}
223
224int BCAnimationCurve::closest_index_above(const float sample_frame, const int start_at) const
225{
226 if (fcurve == nullptr) {
227 return -1;
228 }
229
230 const int cframe = fcurve->bezt[start_at].vec[1][0]; /* inaccurate! */
231
232 if (fabs(cframe - sample_frame) < 0.00001) {
233 return start_at;
234 }
235 return (fcurve->totvert > start_at + 1) ? start_at + 1 : start_at;
236}
237
238int BCAnimationCurve::closest_index_below(const float sample_frame) const
239{
240 if (fcurve == nullptr) {
241 return -1;
242 }
243
244 float lower_frame = sample_frame;
245 float upper_frame = sample_frame;
246 int lower_index = 0;
247 int upper_index = 0;
248
249 for (int fcu_index = 0; fcu_index < fcurve->totvert; fcu_index++) {
250 upper_index = fcu_index;
251
252 const int cframe = fcurve->bezt[fcu_index].vec[1][0]; /* inaccurate! */
253 if (cframe <= sample_frame) {
254 lower_frame = cframe;
255 lower_index = fcu_index;
256 }
257 if (cframe >= sample_frame) {
258 upper_frame = cframe;
259 break;
260 }
261 }
262
263 if (lower_index == upper_index) {
264 return lower_index;
265 }
266
267 const float fraction = float(sample_frame - lower_frame) / (upper_frame - lower_frame);
268 return (fraction < 0.5) ? lower_index : upper_index;
269}
270
271int BCAnimationCurve::get_interpolation_type(float sample_frame) const
272{
273 const int index = closest_index_below(sample_frame);
274 if (index < 0) {
275 return BEZT_IPO_BEZ;
276 }
277 return fcurve->bezt[index].ipo;
278}
279
281{
282 return fcurve;
283}
284
286{
287 if (!curve_is_local_copy) {
288 const int index = curve_key.get_array_index();
289 const std::string &path = curve_key.get_path();
290 fcurve = create_fcurve(index, path.c_str());
291
292 /* Caution here:
293 * Replacing the pointer here is OK only because the original value
294 * of FCurve was a const pointer into Blender territory. We do not
295 * touch that! We use the local copy to prepare data for export. */
296
297 curve_is_local_copy = true;
298 }
299 return fcurve;
300}
301
303{
304 using namespace blender::animrig;
305 if (fcurve == nullptr) {
306 fcurve = get_edit_fcurve();
307 }
308
309 const KeyframeSettings settings = get_keyframe_settings(true);
310
311 /* Keep old bezt data for copy). */
312 BezTriple *old_bezts = fcurve->bezt;
313 int totvert = fcurve->totvert;
314 fcurve->bezt = nullptr;
315 fcurve->totvert = 0;
316
317 for (int i = 0; i < totvert; i++) {
318 BezTriple *bezt = &old_bezts[i];
319 float x = bezt->vec[1][0];
320 float y = bezt->vec[1][1];
321 insert_vert_fcurve(fcurve, {x, y}, settings, INSERTKEY_NOFLAGS);
322 BezTriple *lastb = fcurve->bezt + (fcurve->totvert - 1);
323 lastb->f1 = lastb->f2 = lastb->f3 = 0;
324 }
325
326 /* now free the memory used by the old BezTriples */
327 if (old_bezts) {
328 MEM_freeN(old_bezts);
329 }
330}
331
333{
334 std::string channel_type = this->get_channel_type();
335 return (is_rotation_curve() || channel_type == "scale" || channel_type == "location");
336}
337
339{
340 std::string channel_type = this->get_channel_type();
341 return ELEM(channel_type, "rotation", "rotation_euler", "rotation_quaternion");
342}
343
344float BCAnimationCurve::get_value(const float frame)
345{
346 if (fcurve) {
347 return evaluate_fcurve(fcurve, frame);
348 }
349 return 0; /* TODO: handle case where neither sample nor fcu exist */
350}
351
352void BCAnimationCurve::update_range(float val)
353{
354 if (val < min) {
355 min = val;
356 }
357 if (val > max) {
358 max = val;
359 }
360}
361
362void BCAnimationCurve::init_range(float val)
363{
364 min = max = val;
365}
366
367void BCAnimationCurve::adjust_range(const int frame_index)
368{
369 if (fcurve && fcurve->totvert > 1) {
370 const float eval = evaluate_fcurve(fcurve, frame_index);
371
372 int first_frame = fcurve->bezt[0].vec[1][0];
373 if (first_frame == frame_index) {
374 init_range(eval);
375 }
376 else {
377 update_range(eval);
378 }
379 }
380}
381
382void BCAnimationCurve::add_value(const float val, const int frame_index)
383{
384 using namespace blender::animrig;
385 const KeyframeSettings settings = get_keyframe_settings(true);
386 FCurve *fcu = get_edit_fcurve();
387 fcu->auto_smoothing = U.auto_smoothing_new;
388 insert_vert_fcurve(fcu, {float(frame_index), val}, settings, INSERTKEY_NOFLAGS);
389
390 if (fcu->totvert == 1) {
391 init_range(val);
392 }
393 else {
394 update_range(val);
395 }
396}
397
398bool BCAnimationCurve::add_value_from_matrix(const BCSample &sample, const int frame_index)
399{
400 int array_index = curve_key.get_array_index();
401
402 /* transformation curves are fed directly from the transformation matrix
403 * to resolve parent inverse matrix issues with object hierarchies.
404 * Maybe this can be unified with the
405 */
406 const std::string channel_target = get_channel_target();
407 float val = 0;
408 /* Pick the value from the sample according to the definition of the FCurve */
409 bool good = sample.get_value(channel_target, array_index, &val);
410 if (good) {
411 add_value(val, frame_index);
412 }
413 return good;
414}
415
416bool BCAnimationCurve::add_value_from_rna(const int frame_index)
417{
419 PropertyRNA *prop;
420 float value = 0.0f;
421 int array_index = curve_key.get_array_index();
422 const std::string full_path = curve_key.get_full_path();
423
424 /* get property to read from, and get value as appropriate */
425 bool path_resolved = RNA_path_resolve_full(
426 &id_ptr, full_path.c_str(), &ptr, &prop, &array_index);
427 if (!path_resolved && array_index == 0) {
428 const std::string rna_path = curve_key.get_path();
429 path_resolved = RNA_path_resolve_full(&id_ptr, rna_path.c_str(), &ptr, &prop, &array_index);
430 }
431
432 if (path_resolved) {
433 bool is_array = RNA_property_array_check(prop);
434 if (is_array) {
435 /* array */
436 if ((array_index >= 0) && (array_index < RNA_property_array_length(&ptr, prop))) {
437 switch (RNA_property_type(prop)) {
438 case PROP_BOOLEAN:
439 value = float(RNA_property_boolean_get_index(&ptr, prop, array_index));
440 break;
441 case PROP_INT:
442 value = float(RNA_property_int_get_index(&ptr, prop, array_index));
443 break;
444 case PROP_FLOAT:
445 value = RNA_property_float_get_index(&ptr, prop, array_index);
446 break;
447 default:
448 break;
449 }
450 }
451 else {
452 fprintf(stderr,
453 "Out of Bounds while reading data for Curve %s\n",
454 curve_key.get_full_path().c_str());
455 return false;
456 }
457 }
458 else {
459 /* not an array */
460 switch (RNA_property_type(prop)) {
461 case PROP_BOOLEAN:
462 value = float(RNA_property_boolean_get(&ptr, prop));
463 break;
464 case PROP_INT:
465 value = float(RNA_property_int_get(&ptr, prop));
466 break;
467 case PROP_FLOAT:
468 value = RNA_property_float_get(&ptr, prop);
469 break;
470 case PROP_ENUM:
471 value = float(RNA_property_enum_get(&ptr, prop));
472 break;
473 default:
474 fprintf(stderr,
475 "property type %d not supported for Curve %s\n",
476 RNA_property_type(prop),
477 curve_key.get_full_path().c_str());
478 return false;
479 break;
480 }
481 }
482 }
483 else {
484 /* path couldn't be resolved */
485 fprintf(stderr, "Path not recognized for Curve %s\n", curve_key.get_full_path().c_str());
486 return false;
487 }
488
489 add_value(value, frame_index);
490 return true;
491}
492
494{
495 value_map.clear();
496 if (fcurve == nullptr) {
497 return;
498 }
499
500 for (int i = 0; i < fcurve->totvert; i++) {
501 const float frame = fcurve->bezt[i].vec[1][0];
502 const float val = fcurve->bezt[i].vec[1][1];
503 value_map[frame] = val;
504 }
505}
506
508{
509 frames.clear();
510 if (fcurve) {
511 for (int i = 0; i < fcurve->totvert; i++) {
512 const float val = fcurve->bezt[i].vec[1][0];
513 frames.push_back(val);
514 }
515 }
516}
517
519{
520 values.clear();
521 if (fcurve) {
522 for (int i = 0; i < fcurve->totvert; i++) {
523 const float val = fcurve->bezt[i].vec[1][1];
524 values.push_back(val);
525 }
526 }
527}
528
530{
531 static float MIN_DISTANCE = 0.00001;
532 return fabs(max - min) > MIN_DISTANCE;
533}
534
536{
537 if (this->fcurve == nullptr) {
538 return false;
539 }
540
541 for (int i = 0; i < fcurve->totvert; i++) {
542 const int cframe = nearbyint(fcurve->bezt[i].vec[1][0]);
543 if (cframe == frame) {
544 return true;
545 }
546 if (cframe > frame) {
547 break;
548 }
549 }
550 return false;
551}
552
553/* Needed for adding a BCAnimationCurve into a BCAnimationCurveSet */
554inline bool operator<(const BCAnimationCurve &lhs, const BCAnimationCurve &rhs)
555{
556 std::string lhtgt = lhs.get_channel_target();
557 std::string rhtgt = rhs.get_channel_target();
558 if (lhtgt == rhtgt) {
559 const int lha = lhs.get_channel_index();
560 const int rha = rhs.get_channel_index();
561 return lha < rha;
562 }
563
564 return lhtgt < rhtgt;
565}
566
568{
569 this->key_type = BC_ANIMATION_TYPE_OBJECT;
570 this->rna_path = "";
571 this->curve_array_index = 0;
572 this->curve_subindex = -1;
573}
574
576 const std::string path,
577 const int array_index,
578 const int subindex)
579{
580 this->key_type = type;
581 this->rna_path = path;
582 this->curve_array_index = array_index;
583 this->curve_subindex = subindex;
584}
585
587{
588 this->key_type = other.key_type;
589 this->rna_path = other.rna_path;
590 this->curve_array_index = other.curve_array_index;
591 this->curve_subindex = other.curve_subindex;
592}
593
594std::string BCCurveKey::get_full_path() const
595{
596 return this->rna_path + '[' + std::to_string(this->curve_array_index) + ']';
597}
598
599std::string BCCurveKey::get_path() const
600{
601 return this->rna_path;
602}
603
605{
606 return this->curve_array_index;
607}
608
610{
611 return this->curve_subindex;
612}
613
615{
616 this->key_type = object_type;
617}
618
620{
621 return this->key_type;
622}
623
624bool BCCurveKey::operator<(const BCCurveKey &other) const
625{
626 /* needed for using this class as key in maps and sets */
627 if (this->key_type != other.key_type) {
628 return this->key_type < other.key_type;
629 }
630
631 if (this->curve_subindex != other.curve_subindex) {
632 return this->curve_subindex < other.curve_subindex;
633 }
634
635 if (this->rna_path != other.rna_path) {
636 return this->rna_path < other.rna_path;
637 }
638
639 return this->curve_array_index < other.curve_array_index;
640}
641
643
645{
646 return bezt.vec[1][0];
647}
648
649float BCBezTriple::get_time(Scene *scene) const
650{
651 return FRA2TIME(bezt.vec[1][0]);
652}
653
655{
656 return bezt.vec[1][1];
657}
658
660{
661 return RAD2DEGF(get_value());
662}
663
664void BCBezTriple::get_in_tangent(Scene *scene, float point[2], bool as_angle) const
665{
666 get_tangent(scene, point, as_angle, 0);
667}
668
669void BCBezTriple::get_out_tangent(Scene *scene, float point[2], bool as_angle) const
670{
671 get_tangent(scene, point, as_angle, 2);
672}
673
674void BCBezTriple::get_tangent(Scene *scene, float point[2], bool as_angle, int index) const
675{
676 point[0] = FRA2TIME(bezt.vec[index][0]);
677 if (bezt.ipo != BEZT_IPO_BEZ) {
678 /* We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain
679 * unused data */
680 point[0] = 0;
681 point[1] = 0;
682 }
683 else if (as_angle) {
684 point[1] = RAD2DEGF(bezt.vec[index][1]);
685 }
686 else {
687 point[1] = bezt.vec[index][1];
688 }
689}
bool operator<(const BCAnimationCurve &lhs, const BCAnimationCurve &rhs)
std::vector< float > BCValues
std::map< int, float > BCValueMap
BC_animation_type
@ BC_ANIMATION_TYPE_MATERIAL
@ BC_ANIMATION_TYPE_LIGHT
@ BC_ANIMATION_TYPE_OBJECT
@ BC_ANIMATION_TYPE_BONE
@ BC_ANIMATION_TYPE_CAMERA
std::vector< float > BCFrames
void BKE_fcurve_handles_recalc(FCurve *fcu)
FCurve * BKE_fcurve_create(void)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
void BKE_fcurve_free(FCurve *fcu)
struct Material * BKE_object_material_get(struct Object *ob, short act)
#define RAD2DEGF(_rad)
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.c:29
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
Definition string.c:517
#define ELEM(...)
@ INSERTKEY_NOFLAGS
@ FCURVE_SELECTED
@ FCURVE_VISIBLE
#define MAXBONENAME
@ HD_AUTO
@ BEZT_IPO_BEZ
#define FRA2TIME(a)
@ PROP_FLOAT
Definition RNA_types.hh:67
@ PROP_BOOLEAN
Definition RNA_types.hh:65
@ PROP_ENUM
Definition RNA_types.hh:69
@ PROP_INT
Definition RNA_types.hh:66
unsigned int U
Definition btGjkEpa3.h:78
#define output
std::string get_rna_path() const
FCurve * get_fcurve() const
float get_value(float frame)
void get_values(BCValues &values) const
void add_value(float val, int frame)
bool add_value_from_matrix(const BCSample &sample, int frame)
std::string get_channel_type() const
void adjust_range(int frame)
bool is_rotation_curve() const
void get_value_map(BCValueMap &value_map)
bool is_keyframe(int frame)
int get_interpolation_type(float sample_frame) const
bool is_of_animation_type(BC_animation_type type) const
int closest_index_below(float sample_frame) const
void get_frames(BCFrames &frames) const
int closest_index_above(float sample_frame, int start_at) const
bool is_transform_curve() const
std::string get_channel_posebone() const
bool add_value_from_rna(int frame)
std::string get_channel_target() const
int get_channel_index() const
std::string get_animation_name(Object *ob) const
void get_tangent(Scene *scene, float point[2], bool as_angle, int index) const
float get_frame() const
BezTriple & bezt
BCBezTriple(BezTriple &bezt)
float get_time(Scene *scene) const
void get_out_tangent(Scene *scene, float point[2], bool as_angle) const
void get_in_tangent(Scene *scene, float point[2], bool as_angle) const
float get_value() const
float get_angle() const
std::string get_path() const
int get_subindex() const
std::string get_full_path() const
void set_object_type(BC_animation_type object_type)
int get_array_index() const
void operator=(const BCCurveKey &other)
BC_animation_type get_animation_type() const
bool operator<(const BCCurveKey &other) const
std::string id_name(void *id)
std::string bc_string_after(const std::string &s, const std::string probe)
std::string bc_string_before(const std::string &s, const std::string probe)
bool bc_startswith(std::string const &value, std::string const &starting)
local_group_size(16, 16) .push_constant(Type rhs
#define SELECT
draw_view in_light_buf[] float
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float2 fabs(const float2 a)
int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
Lesser Key-framing API call.
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_array_check(PropertyRNA *prop)
int RNA_property_int_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
float RNA_property_float_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
PropertyType RNA_property_type(PropertyRNA *prop)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
PointerRNA RNA_id_pointer_create(ID *id)
bool RNA_path_resolve_full(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
Definition rna_path.cc:537
float vec[3][3]
char * rna_path
BezTriple * bezt
int array_index
unsigned int totvert
char auto_smoothing
PointerRNA * ptr
Definition wm_files.cc:4126