Blender V4.5
BCAnimationSampler.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 <map>
6#include <vector>
7
8#include "BCAnimationCurve.h"
10#include "BCMath.h"
11#include "ExportSettings.h"
12#include "collada_utils.h"
13
14#include "BKE_action.hh"
15#include "BKE_constraint.h"
16#include "BKE_material.hh"
17
18#include "BLI_listbase.h"
19#include "BLI_string.h"
20
21#include "DNA_anim_types.h"
23#include "DNA_scene_types.h"
24
25#include "ED_object.hh"
26
27#include "ANIM_action_legacy.hh"
28
29static std::string EMPTY_STRING;
31
32BCAnimationSampler::BCAnimationSampler(BCExportSettings &export_settings, BCObjectSet &object_set)
33 : export_settings(export_settings)
34{
35 BCObjectSet::iterator it;
36 for (it = object_set.begin(); it != object_set.end(); ++it) {
37 Object *ob = *it;
38 add_object(ob);
39 }
40}
41
43{
44 BCAnimationObjectMap::iterator it;
45 for (it = objects.begin(); it != objects.end(); ++it) {
46 BCAnimation *animation = it->second;
47 delete animation;
48 }
49}
50
52{
53 BlenderContext blender_context = export_settings.get_blender_context();
54 BCAnimation *animation = new BCAnimation(blender_context.get_context(), ob);
55 objects[ob] = animation;
56
57 initialize_keyframes(animation->frame_set, ob);
58 initialize_curves(animation->curve_map, ob);
59}
60
62{
63 BCAnimation &animation = *objects[ob];
64 if (animation.curve_map.empty()) {
65 initialize_curves(animation.curve_map, ob);
66 }
67 return &animation.curve_map;
68}
69
70static void get_sample_frames(BCFrameSet &sample_frames,
71 int sampling_rate,
72 bool keyframe_at_end,
73 Scene *scene)
74{
75 sample_frames.clear();
76
77 if (sampling_rate < 1) {
78 return; /* no sample frames in this case */
79 }
80
81 float sfra = scene->r.sfra;
82 float efra = scene->r.efra;
83
84 int frame_index;
85 for (frame_index = nearbyint(sfra); frame_index < efra; frame_index += sampling_rate) {
86 sample_frames.insert(frame_index);
87 }
88
89 if (frame_index >= efra && keyframe_at_end) {
90 sample_frames.insert(efra);
91 }
92}
93
94static bool is_object_keyframe(Object *ob, int frame_index)
95{
96 return false;
97}
98
99static void add_keyframes_from(AnimData *adt, BCFrameSet &frameset)
100{
102 BezTriple *bezt = fcu->bezt;
103 for (int i = 0; i < fcu->totvert; bezt++, i++) {
104 int frame_index = nearbyint(bezt->vec[1][0]);
105 frameset.insert(frame_index);
106 }
107 }
108}
109
110void BCAnimationSampler::check_property_is_animated(
111 BCAnimation &animation, float *ref, float *val, std::string data_path, int length)
112{
113 for (int array_index = 0; array_index < length; array_index++) {
114 if (!bc_in_range(ref[length], val[length], 0.00001)) {
115 BCCurveKey key(BC_ANIMATION_TYPE_OBJECT, data_path, array_index);
116 BCAnimationCurveMap::iterator it = animation.curve_map.find(key);
117 if (it == animation.curve_map.end()) {
118 animation.curve_map[key] = new BCAnimationCurve(key, animation.get_reference());
119 }
120 }
121 }
122}
123
124void BCAnimationSampler::update_animation_curves(BCAnimation &animation,
126 Object *ob,
127 int frame)
128{
129 BCAnimationCurveMap::iterator it;
130 for (it = animation.curve_map.begin(); it != animation.curve_map.end(); ++it) {
131 BCAnimationCurve *curve = it->second;
132 if (curve->is_transform_curve()) {
133 curve->add_value_from_matrix(sample, frame);
134 }
135 else {
136 curve->add_value_from_rna(frame);
137 }
138 }
139}
140
141BCSample &BCAnimationSampler::sample_object(Object *ob, int frame_index, bool for_opensim)
142{
143 BCSample &ob_sample = sample_data.add(ob, frame_index);
144#if 0
145 if (export_settings.get_apply_global_orientation()) {
146 const BCMatrix &global_transform = export_settings.get_global_transform();
147 ob_sample.get_matrix(global_transform);
148 }
149#endif
150
151 if (ob->type == OB_ARMATURE) {
152 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
153 Bone *bone = pchan->bone;
154 Matrix bmat;
155 if (bc_bone_matrix_local_get(ob, bone, bmat, for_opensim)) {
156
157 ob_sample.add_bone_matrix(bone, bmat);
158 }
159 }
160 }
161 return ob_sample;
162}
163
164void BCAnimationSampler::sample_scene(BCExportSettings &export_settings, bool keyframe_at_end)
165{
166 BlenderContext blender_context = export_settings.get_blender_context();
167 int sampling_rate = export_settings.get_sampling_rate();
168 bool for_opensim = export_settings.get_open_sim();
169 bool keep_keyframes = export_settings.get_keep_keyframes();
170 BC_export_animation_type export_animation_type = export_settings.get_export_animation_type();
171
172 Scene *scene = blender_context.get_scene();
173 BCFrameSet scene_sample_frames;
174 get_sample_frames(scene_sample_frames, sampling_rate, keyframe_at_end, scene);
175
176 int startframe = scene->r.sfra;
177 int endframe = scene->r.efra;
178
179 for (int frame_index = startframe; frame_index <= endframe; frame_index++) {
180 /* Loop over all frames and decide for each frame if sampling is necessary */
181 bool is_scene_sample_frame = false;
182 bool needs_update = true;
183 if (scene_sample_frames.find(frame_index) != scene_sample_frames.end()) {
184 bc_update_scene(blender_context, frame_index);
185 needs_update = false;
186 is_scene_sample_frame = true;
187 }
188
189 bool needs_sampling = is_scene_sample_frame || keep_keyframes ||
190 export_animation_type == BC_ANIMATION_EXPORT_KEYS;
191 if (!needs_sampling) {
192 continue;
193 }
194
195 BCAnimationObjectMap::iterator obit;
196 for (obit = objects.begin(); obit != objects.end(); ++obit) {
197 Object *ob = obit->first;
198 BCAnimation *animation = obit->second;
199 BCFrameSet &object_keyframes = animation->frame_set;
200 if (is_scene_sample_frame || object_keyframes.find(frame_index) != object_keyframes.end()) {
201
202 if (needs_update) {
203 bc_update_scene(blender_context, frame_index);
204 needs_update = false;
205 }
206
207 BCSample &sample = sample_object(ob, frame_index, for_opensim);
208 update_animation_curves(*animation, sample, ob, frame_index);
209 }
210 }
211 }
212}
213
215 ListBase *conlist,
216 std::set<Object *> &animated_objects)
217{
218 LISTBASE_FOREACH (bConstraint *, con, conlist) {
219 ListBase targets = {nullptr, nullptr};
220
221 if (!bc_validateConstraints(con)) {
222 continue;
223 }
224
225 if (BKE_constraint_targets_get(con, &targets)) {
226 Object *obtar;
227 bool found = false;
228
229 LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
230 obtar = ct->tar;
231 if (obtar) {
232 if (animated_objects.find(obtar) != animated_objects.end()) {
233 found = true;
234 break;
235 }
236 }
237 }
238 BKE_constraint_targets_flush(con, &targets, true);
239 return found;
240 }
241 }
242 return false;
243}
244
245void BCAnimationSampler::find_depending_animated(std::set<Object *> &animated_objects,
246 std::set<Object *> &candidates)
247{
248 bool found_more;
249 do {
250 found_more = false;
251 std::set<Object *>::iterator it;
252 for (it = candidates.begin(); it != candidates.end(); ++it) {
253 Object *cob = *it;
255 if (is_animated_by_constraint(cob, conlist, animated_objects)) {
256 animated_objects.insert(cob);
257 candidates.erase(cob);
258 found_more = true;
259 break;
260 }
261 }
262 } while (found_more && !candidates.empty());
263}
264
265void BCAnimationSampler::get_animated_from_export_set(std::set<Object *> &animated_objects,
266 LinkNode &export_set)
267{
268 /* Check if this object is animated. That is: Check if it has its own action, or:
269 *
270 * - Check if it has constraints to other objects.
271 * - at least one of the other objects is animated as well.
272 */
273
274 animated_objects.clear();
275 std::set<Object *> candidates;
276
277 LinkNode *node;
278 for (node = &export_set; node; node = node->next) {
279 Object *cob = (Object *)node->link;
280 if (bc_has_animations(cob)) {
281 animated_objects.insert(cob);
282 }
283 else {
284 ListBase conlist = cob->constraints;
285 if (conlist.first) {
286 candidates.insert(cob);
287 }
288 }
289 }
290 find_depending_animated(animated_objects, candidates);
291}
292
294{
295 sample_data.get_frames(ob, frames);
296}
297
299{
300 sample_data.get_frames(ob, bone, frames);
301}
302
304{
305 sample_data.get_matrices(ob, bone, samples);
306 return bc_is_animated(samples);
307}
308
310{
311 sample_data.get_matrices(ob, samples);
312 return bc_is_animated(samples);
313}
314
315#if 0
328void BCAnimationSampler::add_value_set(BCAnimationCurve &curve,
329 BCFrameSampleMap &samples,
330 BC_export_animation_type animation_type)
331{
332 int array_index = curve.get_array_index();
333 const BC_animation_transform_type tm_type = curve.get_transform_type();
334
335 BCFrameSampleMap::iterator it;
336 for (it = samples.begin(); it != samples.end(); ++it) {
337 const int frame_index = nearbyint(it->first);
338 if (animation_type == BC_ANIMATION_EXPORT_SAMPLES || curve.is_keyframe(frame_index)) {
339
340 const BCSample *sample = it->second;
341 float val = 0;
342
343 int subindex = curve.get_subindex();
344 bool good;
345 if (subindex == -1) {
346 good = sample->get_value(tm_type, array_index, &val);
347 }
348 else {
349 good = sample->get_value(tm_type, array_index, &val, subindex);
350 }
351
352 if (good) {
353 curve.add_value(val, frame_index);
354 }
355 }
356 }
357 curve.remove_unused_keyframes();
358 curve.calchandles();
359}
360#endif
361
362void BCAnimationSampler::generate_transform(Object *ob,
363 const BCCurveKey &key,
364 BCAnimationCurveMap &curves)
365{
366 BCAnimationCurveMap::const_iterator it = curves.find(key);
367 if (it == curves.end()) {
368 curves[key] = new BCAnimationCurve(key, ob);
369 }
370}
371
372void BCAnimationSampler::generate_transforms(Object *ob,
373 const std::string prep,
374 const BC_animation_type type,
375 BCAnimationCurveMap &curves)
376{
377 generate_transform(ob, BCCurveKey(type, prep + "location", 0), curves);
378 generate_transform(ob, BCCurveKey(type, prep + "location", 1), curves);
379 generate_transform(ob, BCCurveKey(type, prep + "location", 2), curves);
380 generate_transform(ob, BCCurveKey(type, prep + "rotation_euler", 0), curves);
381 generate_transform(ob, BCCurveKey(type, prep + "rotation_euler", 1), curves);
382 generate_transform(ob, BCCurveKey(type, prep + "rotation_euler", 2), curves);
383 generate_transform(ob, BCCurveKey(type, prep + "scale", 0), curves);
384 generate_transform(ob, BCCurveKey(type, prep + "scale", 1), curves);
385 generate_transform(ob, BCCurveKey(type, prep + "scale", 2), curves);
386}
387
388void BCAnimationSampler::generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves)
389{
390 std::string prep = "pose.bones[\"" + std::string(bone->name) + "\"].";
391 generate_transforms(ob, prep, BC_ANIMATION_TYPE_BONE, curves);
392
393 LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
394 generate_transforms(ob, child, curves);
395 }
396}
397
398void BCAnimationSampler::initialize_keyframes(BCFrameSet &frameset, Object *ob)
399{
400 frameset.clear();
401 add_keyframes_from(ob->adt, frameset);
404
405 for (int a = 0; a < ob->totcol; a++) {
406 Material *ma = BKE_object_material_get(ob, a + 1);
408 }
409}
410
411void BCAnimationSampler::initialize_curves(BCAnimationCurveMap &curves, Object *ob)
412{
414
416 object_type = BC_ANIMATION_TYPE_OBJECT;
417 if (ob->type == OB_ARMATURE) {
418 char boneName[MAXBONENAME];
419 if (BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", boneName, sizeof(boneName))) {
420 object_type = BC_ANIMATION_TYPE_BONE;
421 }
422 }
423
424 /* Adding action curves on object */
425 BCCurveKey key(object_type, fcu->rna_path, fcu->array_index);
426 curves[key] = new BCAnimationCurve(key, ob, fcu);
427 }
428
429 /* Add missing curves */
430 object_type = BC_ANIMATION_TYPE_OBJECT;
431 generate_transforms(ob, EMPTY_STRING, object_type, curves);
432 if (ob->type == OB_ARMATURE) {
433 bArmature *arm = (bArmature *)ob->data;
434 LISTBASE_FOREACH (Bone *, root_bone, &arm->bonebase) {
435 generate_transforms(ob, root_bone, curves);
436 }
437 }
438
439 /* Add curves on Object->data actions */
440 AnimData *adt = nullptr;
441 if (ob->type == OB_CAMERA) {
443 object_type = BC_ANIMATION_TYPE_CAMERA;
444 }
445 else if (ob->type == OB_LAMP) {
446 adt = bc_getSceneLightAnimData(ob);
447 object_type = BC_ANIMATION_TYPE_LIGHT;
448 }
449
450 /* Add light action or Camera action */
452 BCCurveKey key(object_type, fcu->rna_path, fcu->array_index);
453 curves[key] = new BCAnimationCurve(key, ob, fcu);
454 }
455
456 /* Add curves on Object->material actions. */
457 object_type = BC_ANIMATION_TYPE_MATERIAL;
458 for (int a = 0; a < ob->totcol; a++) {
459 /* Export Material parameter animations. */
460 Material *ma = BKE_object_material_get(ob, a + 1);
461 if (ma) {
463 // isMatAnim = true;
465 BCCurveKey key(object_type, fcu->rna_path, fcu->array_index, a);
466 curves[key] = new BCAnimationCurve(key, ob, fcu);
467 }
468 }
469 }
470}
471
472/* ==================================================================== */
473
475{
476 BCSample *sample = new BCSample(ob);
477 sampleMap[ob] = sample;
478 return *sample;
479}
480
482{
483 BCSampleMap::const_iterator it = sampleMap.find(ob);
484 if (it == sampleMap.end()) {
485 return nullptr;
486 }
487 return it->second;
488}
489
491{
492 BCSampleMap::const_iterator it = sampleMap.find(ob);
493 if (it == sampleMap.end()) {
494 return nullptr;
495 }
496 BCSample *sample = it->second;
497 return &sample->get_matrix();
498}
499
501{
502 BCSampleMap::const_iterator it = sampleMap.find(ob);
503 if (it == sampleMap.end()) {
504 return nullptr;
505 }
506
507 BCSample *sample = it->second;
508 const BCMatrix *bc_bone = sample->get_matrix(bone);
509 return bc_bone;
510}
511
513{
514 return sampleMap.find(ob) != sampleMap.end();
515}
516
518{
519 const BCMatrix *bc_bone = get_sample_matrix(ob, bone);
520 return bc_bone;
521}
522
523/* ==================================================================== */
524
526{
527 BCSampleFrame &frame = sample_frames[frame_index];
528 return frame.add(ob);
529}
530
531/* ====================================================== */
532/* Below are the getters which we need to export the data */
533/* ====================================================== */
534
536{
537 BCSampleFrameMap::iterator it = sample_frames.find(frame_index);
538 BCSampleFrame *frame = (it == sample_frames.end()) ? nullptr : &it->second;
539 return frame;
540}
541
542int BCSampleFrameContainer::get_frames(std::vector<int> &frames) const
543{
544 frames.clear(); /* safety; */
545 BCSampleFrameMap::const_iterator it;
546 for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
547 frames.push_back(it->first);
548 }
549 return frames.size();
550}
551
553{
554 frames.clear(); /* safety; */
555 BCSampleFrameMap::const_iterator it;
556 for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
557 const BCSampleFrame &frame = it->second;
558 if (frame.has_sample_for(ob)) {
559 frames.push_back(it->first);
560 }
561 }
562 return frames.size();
563}
564
566{
567 frames.clear(); /* safety; */
568 BCSampleFrameMap::const_iterator it;
569 for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
570 const BCSampleFrame &frame = it->second;
571 if (frame.has_sample_for(ob, bone)) {
572 frames.push_back(it->first);
573 }
574 }
575 return frames.size();
576}
577
579{
580 samples.clear(); /* safety; */
581 BCSampleFrameMap::const_iterator it;
582 for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
583 const BCSampleFrame &frame = it->second;
584 const BCSample *sample = frame.get_sample(ob);
585 if (sample) {
586 samples[it->first] = sample;
587 }
588 }
589 return samples.size();
590}
591
593{
594 samples.clear(); /* safety; */
595 BCSampleFrameMap::const_iterator it;
596 for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
597 const BCSampleFrame &frame = it->second;
598 const BCMatrix *matrix = frame.get_sample_matrix(ob);
599 if (matrix) {
600 samples[it->first] = matrix;
601 }
602 }
603 return samples.size();
604}
605
607{
608 samples.clear(); /* safety; */
609 BCSampleFrameMap::const_iterator it;
610 for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
611 const BCSampleFrame &frame = it->second;
612 const BCMatrix *sample = frame.get_sample_matrix(ob, bone);
613 if (sample) {
614 samples[it->first] = sample;
615 }
616 }
617 return samples.size();
618}
Functions for backward compatibility with the legacy Action API.
std::string EMPTY_STRING
std::set< float > BCFrameSet
std::map< BCCurveKey, BCAnimationCurve * > BCAnimationCurveMap
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
static BCAnimationCurveMap BCEmptyAnimationCurves
static void add_keyframes_from(AnimData *adt, BCFrameSet &frameset)
static bool is_object_keyframe(Object *ob, int frame_index)
static void get_sample_frames(BCFrameSet &sample_frames, int sampling_rate, bool keyframe_at_end, Scene *scene)
std::map< int, const BCMatrix * > BCMatrixSampleMap
std::map< int, const BCSample * > BCFrameSampleMap
Blender kernel action and pose functionality.
void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy)
int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets)
General operations, lookup, etc. for materials.
Material * BKE_object_material_get(Object *ob, short act)
#define LISTBASE_FOREACH(type, var, list)
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
Definition string.cc:531
float[4][4] Matrix
struct bPoseChannel bPoseChannel
struct FCurve FCurve
struct AnimData AnimData
struct Bone Bone
#define MAXBONENAME
struct bArmature bArmature
struct Material Material
@ OB_CAMERA
@ OB_ARMATURE
@ OB_LAMP
BC_export_animation_type
@ BC_ANIMATION_EXPORT_KEYS
@ BC_ANIMATION_EXPORT_SAMPLES
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
void add_value(float val, int frame)
bool add_value_from_matrix(const BCSample &sample, int frame)
bool is_keyframe(int frame)
bool is_transform_curve() const
bool add_value_from_rna(int frame)
void get_object_frames(BCFrames &frames, Object *ob)
static void find_depending_animated(std::set< Object * > &animated_objects, std::set< Object * > &candidates)
bool get_bone_samples(BCMatrixSampleMap &samples, Object *ob, Bone *bone)
static void get_animated_from_export_set(std::set< Object * > &animated_objects, LinkNode &export_set)
void get_bone_frames(BCFrames &frames, Object *ob, Bone *bone)
BCAnimationSampler(BCExportSettings &export_settings, BCObjectSet &object_set)
void add_object(Object *ob)
void sample_scene(BCExportSettings &export_settings, bool keyframe_at_end)
static bool is_animated_by_constraint(Object *ob, ListBase *conlist, std::set< Object * > &animated_objects)
bool get_object_samples(BCMatrixSampleMap &samples, Object *ob)
BCAnimationCurveMap * get_curves(Object *ob)
Object * get_reference()
BCFrameSet frame_set
BCAnimationCurveMap curve_map
BCSample & add(Object *ob, int frame_index)
int get_frames(std::vector< int > &frames) const
BCSampleFrame * get_frame(int frame_index)
int get_samples(Object *ob, BCFrameSampleMap &samples) const
int get_matrices(Object *ob, BCMatrixSampleMap &samples) const
const BCMatrix * get_sample_matrix(Object *ob) const
bool has_sample_for(Object *ob) const
const BCSample * get_sample(Object *ob) const
BCSample & add(Object *ob)
const BCMatrix & get_matrix() const
void add_bone_matrix(Bone *bone, Matrix &mat)
bContext * get_context()
bool bc_has_animations(Object *ob)
bool bc_is_animated(BCMatrixSampleMap &values)
bool bc_validateConstraints(bConstraint *con)
void bc_update_scene(BlenderContext &blender_context, float ctime)
bool bc_bone_matrix_local_get(Object *ob, Bone *bone, Matrix &mat, bool for_opensim)
AnimData * bc_getSceneLightAnimData(Object *ob)
AnimData * bc_getSceneCameraAnimData(Object *ob)
bool bc_in_range(float a, float b, float range)
AnimData * bc_getSceneMaterialAnimData(Material *ma)
std::set< Object * > BCObjectSet
float length(VecOp< float, D >) RET
Vector< FCurve * > fcurves_for_assigned_action(AnimData *adt)
ListBase * constraint_active_list(Object *ob)
float vec[3][3]
char name[64]
ListBase childbase
void * link
struct LinkNode * next
void * first
ListBase constraints
struct bPose * pose
struct AnimData * adt
struct RenderData r
ListBase chanbase
i
Definition text_draw.cc:230