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