Blender  V2.93
AnimationExporter.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include "AnimationExporter.h"
22 #include "AnimationClipExporter.h"
23 #include "BCAnimationSampler.h"
24 #include "GeometryExporter.h"
25 #include "MaterialExporter.h"
26 #include "collada_utils.h"
27 
28 std::string EMPTY_STRING;
29 
30 std::string AnimationExporter::get_axis_name(std::string channel_type, int id)
31 {
32 
33  static std::map<std::string, std::vector<std::string>> BC_COLLADA_AXIS_FROM_TYPE = {
34  {"color", {"R", "G", "B"}},
35  {"specular_color", {"R", "G", "B"}},
36  {"diffuse_color", {"R", "G", "B"}},
37  {"alpha", {"R", "G", "B"}},
38  {"scale", {"X", "Y", "Z"}},
39  {"location", {"X", "Y", "Z"}},
40  {"rotation_euler", {"X", "Y", "Z"}}};
41 
42  std::map<std::string, std::vector<std::string>>::const_iterator it;
43 
44  it = BC_COLLADA_AXIS_FROM_TYPE.find(channel_type);
45  if (it == BC_COLLADA_AXIS_FROM_TYPE.end()) {
46  return "";
47  }
48 
49  const std::vector<std::string> &subchannel = it->second;
50  if (id >= subchannel.size()) {
51  return "";
52  }
53  return subchannel[id];
54 }
55 
57 {
58  if (!has_container) {
59  char anim_id[200];
60  sprintf(anim_id, "action_container-%s", translate_id(id_name(ob)).c_str());
61  openAnimation(anim_id, encode_xml(id_name(ob)));
62  }
63  return true;
64 }
65 
66 void AnimationExporter::openAnimationWithClip(std::string action_id, std::string action_name)
67 {
68  std::vector<std::string> anim_meta_entry;
69  anim_meta_entry.push_back(translate_id(action_id));
70  anim_meta_entry.push_back(action_name);
71  anim_meta.push_back(anim_meta_entry);
72 
73  openAnimation(translate_id(action_id), action_name);
74 }
75 
77 {
78  if (has_container) {
79  closeAnimation();
80  }
81 }
82 
84 {
85  Scene *sce = export_settings.get_scene();
86 
87  LinkNode *export_set = this->export_settings.get_export_set();
88  bool has_anim_data = bc_has_animations(sce, export_set);
89  int animation_count = 0;
90  if (has_anim_data) {
91 
92  BCObjectSet animated_subset;
93  BCAnimationSampler::get_animated_from_export_set(animated_subset, *export_set);
94  animation_count = animated_subset.size();
95  BCAnimationSampler animation_sampler(export_settings, animated_subset);
96 
97  try {
98  animation_sampler.sample_scene(export_settings, /*keyframe_at_end = */ true);
99 
100  openLibrary();
101 
102  BCObjectSet::iterator it;
103  for (it = animated_subset.begin(); it != animated_subset.end(); ++it) {
104  Object *ob = *it;
105  exportAnimation(ob, animation_sampler);
106  }
107  }
108  catch (std::invalid_argument &iae) {
109  fprintf(stderr, "Animation export interrupted");
110  fprintf(stderr, "Exception was: %s", iae.what());
111  }
112 
113  closeLibrary();
114 
115 #if 0
116  /* TODO: If all actions shall be exported, we need to call the
117  * AnimationClipExporter which will figure out which actions
118  * need to be exported for which objects
119  */
120  if (this->export_settings->include_all_actions) {
121  AnimationClipExporter ace(eval_ctx, sw, export_settings, anim_meta);
122  ace.exportAnimationClips(sce);
123  }
124 #endif
125  }
126  return animation_count;
127 }
128 
129 /* called for each exported object */
131 {
132  bool container_is_open = false;
133 
134  /* Transform animations (trans, rot, scale). */
135  container_is_open = open_animation_container(container_is_open, ob);
136 
137  /* Now take care of the Object Animations
138  * Note: For Armatures the skeletal animation has already been exported (see above)
139  * However Armatures also can have Object animation.
140  */
141  bool export_as_matrix = this->export_settings.get_animation_transformation_type() ==
143 
144  if (export_as_matrix) {
145  /* export all transform_curves as one single matrix animation */
146  export_matrix_animation(ob, sampler);
147  }
148 
149  export_curve_animation_set(ob, sampler, export_as_matrix);
150 
151  if (ob->type == OB_ARMATURE && export_as_matrix) {
152 
153 #ifdef WITH_MORPH_ANIMATION
154  /* TODO: This needs to be handled by extra profiles, postponed for now */
156 #endif
157 
158  /* Export skeletal animation (if any) */
159  bArmature *arm = (bArmature *)ob->data;
160  for (Bone *root_bone = (Bone *)arm->bonebase.first; root_bone; root_bone = root_bone->next) {
161  export_bone_animations_recursive(ob, root_bone, sampler);
162  }
163  }
164 
165  close_animation_container(container_is_open);
166 }
167 
168 /*
169  * Export all animation FCurves of an Object.
170  *
171  * Note: This uses the keyframes as sample points,
172  * and exports "baked keyframes" while keeping the tangent information
173  * of the FCurves intact. This works for simple cases, but breaks
174  * especially when negative scales are involved in the animation.
175  * And when parent inverse matrices are involved (when exporting
176  * object hierarchies)
177  */
179  BCAnimationSampler &sampler,
180  bool export_as_matrix)
181 {
182  BCAnimationCurveMap *curves = sampler.get_curves(ob);
183  bool keep_flat_curves = this->export_settings.get_keep_flat_curves();
184 
185  BCAnimationCurveMap::iterator it;
186  for (it = curves->begin(); it != curves->end(); ++it) {
187  BCAnimationCurve &curve = *it->second;
188  std::string channel_type = curve.get_channel_type();
189  if (channel_type == "rotation_quaternion") {
190  /* Can not export Quaternion animation in Collada as far as i know)
191  * Maybe automatically convert to euler rotation?
192  * Discard for now. */
193  continue;
194  }
195 
196  if (export_as_matrix && curve.is_transform_curve()) {
197  /* All Transform curves will be exported within a single matrix animation,
198  * see export_matrix_animation()
199  * No need to export the curves here again.
200  */
201  continue;
202  }
203 
204  if (!keep_flat_curves && !curve.is_animated()) {
205  continue;
206  }
207 
208  BCAnimationCurve *mcurve = get_modified_export_curve(ob, curve, *curves);
209  if (mcurve) {
210  export_curve_animation(ob, *mcurve);
211  delete mcurve;
212  }
213  else {
215  }
216  }
217 }
218 
220 {
221  bool keep_flat_curves = this->export_settings.get_keep_flat_curves();
222 
223  std::vector<float> frames;
224  sampler.get_object_frames(frames, ob);
225  if (!frames.empty()) {
226  BCMatrixSampleMap samples;
227  bool is_animated = sampler.get_object_samples(samples, ob);
228  if (keep_flat_curves || is_animated) {
229  bAction *action = bc_getSceneObjectAction(ob);
230  std::string name = encode_xml(id_name(ob));
231  std::string action_name = (action == nullptr) ? name + "-action" : id_name(action);
232  std::string channel_type = "transform";
233  std::string axis;
234  std::string id = bc_get_action_id(action_name, name, channel_type, axis);
235 
236  std::string target = translate_id(name) + '/' + channel_type;
237 
238  BC_global_rotation_type global_rotation_type = get_global_rotation_type(ob);
240  id, name, target, frames, samples, global_rotation_type, ob->parentinv);
241  }
242  }
243 }
244 
245 BC_global_rotation_type AnimationExporter::get_global_rotation_type(Object *ob)
246 {
247  bool is_export_root = this->export_settings.is_export_root(ob);
248  if (!is_export_root) {
249  return BC_NO_ROTATION;
250  }
251 
252  bool apply_global_rotation = this->export_settings.get_apply_global_orientation();
253 
254  return (apply_global_rotation) ? BC_DATA_ROTATION : BC_OBJECT_ROTATION;
255 }
256 
257 /* Write bone animations in transform matrix sources. */
259  Bone *bone,
260  BCAnimationSampler &sampler)
261 {
262  bool keep_flat_curves = this->export_settings.get_keep_flat_curves();
263 
264  std::vector<float> frames;
265  sampler.get_bone_frames(frames, ob, bone);
266 
267  if (!frames.empty()) {
268  BCMatrixSampleMap samples;
269  bool is_animated = sampler.get_bone_samples(samples, ob, bone);
270  if (keep_flat_curves || is_animated) {
271  export_bone_animation(ob, bone, frames, samples);
272  }
273  }
274 
275  for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
276  export_bone_animations_recursive(ob, child, sampler);
277  }
278 }
279 
290  BCAnimationCurveMap &curves)
291 {
292  std::string channel_type = curve.get_channel_type();
293  BCAnimationCurve *mcurve = nullptr;
294  if (channel_type == "lens") {
295 
296  /* Create an xfov curve */
297 
298  BCCurveKey key(BC_ANIMATION_TYPE_CAMERA, "xfov", 0);
299  mcurve = new BCAnimationCurve(key, ob);
300 
301  /* now tricky part: transform the fcurve */
302  BCValueMap lens_values;
303  curve.get_value_map(lens_values);
304 
305  BCAnimationCurve *sensor_curve = nullptr;
306  BCCurveKey sensor_key(BC_ANIMATION_TYPE_CAMERA, "sensor_width", 0);
307  BCAnimationCurveMap::iterator cit = curves.find(sensor_key);
308  if (cit != curves.end()) {
309  sensor_curve = cit->second;
310  }
311 
312  BCValueMap::const_iterator vit;
313  for (vit = lens_values.begin(); vit != lens_values.end(); ++vit) {
314  int frame = vit->first;
315  float lens_value = vit->second;
316 
317  float sensor_value;
318  if (sensor_curve) {
319  sensor_value = sensor_curve->get_value(frame);
320  }
321  else {
322  sensor_value = ((Camera *)ob->data)->sensor_x;
323  }
324  float value = RAD2DEGF(focallength_to_fov(lens_value, sensor_value));
325  mcurve->add_value(value, frame);
326  }
327  /* to reset the handles */
328  mcurve->clean_handles();
329  }
330  return mcurve;
331 }
332 
334 {
335  std::string channel_target = curve.get_channel_target();
336 
337  /*
338  * Some curves can not be exported as is and need some conversion
339  * For more information see implementation of get_modified_export_curve()
340  * note: if mcurve is not NULL then it must be deleted at end of this method;
341  */
342 
343  int channel_index = curve.get_channel_index();
344  /* RGB or XYZ or "" */
345  std::string channel_type = curve.get_channel_type();
346  std::string axis = get_axis_name(channel_type, channel_index);
347 
348  std::string action_name;
349  bAction *action = bc_getSceneObjectAction(ob);
350  action_name = (action) ? id_name(action) : "constraint_anim";
351 
352  const std::string curve_name = encode_xml(curve.get_animation_name(ob));
353  std::string id = bc_get_action_id(action_name, curve_name, channel_target, axis, ".");
354 
355  std::string collada_target = translate_id(curve_name);
356 
357  if (curve.is_of_animation_type(BC_ANIMATION_TYPE_MATERIAL)) {
358  int material_index = curve.get_subindex();
359  Material *ma = BKE_object_material_get(ob, material_index + 1);
360  if (ma) {
361  collada_target = translate_id(id_name(ma)) + "-effect/common/" +
362  get_collada_sid(curve, axis);
363  }
364  }
365  else {
366  collada_target += "/" + get_collada_sid(curve, axis);
367  }
368 
369  BC_global_rotation_type global_rotation_type = get_global_rotation_type(ob);
371  id, curve_name, collada_target, axis, curve, global_rotation_type);
372 }
373 
375  Bone *bone,
376  BCFrames &frames,
377  BCMatrixSampleMap &samples)
378 {
379  bAction *action = bc_getSceneObjectAction(ob);
380  std::string bone_name(bone->name);
381  std::string name = encode_xml(id_name(ob));
382  std::string id = bc_get_action_id(id_name(action), name, bone_name, "pose_matrix");
383  std::string target = translate_id(id_name(ob) + "_" + bone_name) + "/transform";
384 
385  BC_global_rotation_type global_rotation_type = get_global_rotation_type(ob);
387  id, name, target, frames, samples, global_rotation_type, ob->parentinv);
388 }
389 
391 {
392  bool is_def;
393  /* Check if current bone is deform */
394  if ((bone->flag & BONE_NO_DEFORM) == 0) {
395  return true;
396  }
397  /* Check child bones */
398 
399  for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
400  /* loop through all the children until deform bone is found, and then return */
401  is_def = is_bone_deform_group(child);
402  if (is_def) {
403  return true;
404  }
405  }
406 
407  /* no deform bone found in children also */
408  return false;
409 }
410 
412  std::string id,
413  std::string name,
414  std::string collada_target,
415  std::string axis,
417  BC_global_rotation_type global_rotation_type)
418 {
419  BCFrames frames;
420  BCValues values;
421  curve.get_frames(frames);
422  curve.get_values(values);
423  std::string channel_target = curve.get_channel_target();
424 
425  fprintf(
426  stdout, "Export animation curve %s (%d control points)\n", id.c_str(), int(frames.size()));
427  openAnimation(id, name);
428  BC_animation_source_type source_type = (curve.is_rotation_curve()) ? BC_SOURCE_TYPE_ANGLE :
430 
431  std::string input_id = collada_source_from_values(
432  BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, axis);
433  std::string output_id = collada_source_from_values(
434  source_type, COLLADASW::InputSemantic::OUTPUT, values, id, axis);
435 
436  bool has_tangents = false;
437  std::string interpolation_id;
438  if (this->export_settings.get_keep_smooth_curves()) {
439  interpolation_id = collada_interpolation_source(curve, id, axis, &has_tangents);
440  }
441  else {
442  interpolation_id = collada_linear_interpolation_source(frames.size(), id);
443  }
444 
445  std::string intangent_id;
446  std::string outtangent_id;
447  if (has_tangents) {
448  intangent_id = collada_tangent_from_curve(
449  COLLADASW::InputSemantic::IN_TANGENT, curve, id, axis);
450  outtangent_id = collada_tangent_from_curve(
451  COLLADASW::InputSemantic::OUT_TANGENT, curve, id, axis);
452  }
453 
454  std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
455 
456  COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
457 
458  sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
459  sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
460  sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION,
461  COLLADABU::URI(EMPTY_STRING, interpolation_id));
462 
463  if (has_tangents) {
464  sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT,
465  COLLADABU::URI(EMPTY_STRING, intangent_id));
466  sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT,
467  COLLADABU::URI(EMPTY_STRING, outtangent_id));
468  }
469 
470  addSampler(sampler);
471  addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), collada_target);
472 
473  closeAnimation();
474 }
475 
477  std::string id,
478  std::string name,
479  std::string target,
480  BCFrames &frames,
481  BCMatrixSampleMap &samples,
482  BC_global_rotation_type global_rotation_type,
483  Matrix &parentinv)
484 {
485  fprintf(
486  stdout, "Export animation matrix %s (%d control points)\n", id.c_str(), int(frames.size()));
487 
488  openAnimationWithClip(id, name);
489 
490  std::string input_id = collada_source_from_values(
491  BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, "");
492  std::string output_id = collada_source_from_values(samples, id, global_rotation_type, parentinv);
493  std::string interpolation_id = collada_linear_interpolation_source(frames.size(), id);
494 
495  std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
496  COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
497 
498  sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
499  sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
500  sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION,
501  COLLADABU::URI(EMPTY_STRING, interpolation_id));
502 
503  /* Matrix animation has no tangents */
504 
505  addSampler(sampler);
506  addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), target);
507 
508  closeAnimation();
509 }
510 
511 std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
512 {
513  switch (semantic) {
514  case COLLADASW::InputSemantic::INPUT:
515  return INPUT_SOURCE_ID_SUFFIX;
516  case COLLADASW::InputSemantic::OUTPUT:
517  return OUTPUT_SOURCE_ID_SUFFIX;
518  case COLLADASW::InputSemantic::INTERPOLATION:
519  return INTERPOLATION_SOURCE_ID_SUFFIX;
520  case COLLADASW::InputSemantic::IN_TANGENT:
521  return INTANGENT_SOURCE_ID_SUFFIX;
522  case COLLADASW::InputSemantic::OUT_TANGENT:
523  return OUTTANGENT_SOURCE_ID_SUFFIX;
524  default:
525  break;
526  }
527  return "";
528 }
529 
530 void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList &param,
531  COLLADASW::InputSemantic::Semantics semantic,
532  bool is_rot,
533  const std::string axis,
534  bool transform)
535 {
536  switch (semantic) {
537  case COLLADASW::InputSemantic::INPUT:
538  param.push_back("TIME");
539  break;
540  case COLLADASW::InputSemantic::OUTPUT:
541  if (is_rot) {
542  param.push_back("ANGLE");
543  }
544  else {
545  if (!axis.empty()) {
546  param.push_back(axis);
547  }
548  else if (transform) {
549  param.push_back("TRANSFORM");
550  }
551  else {
552  /* assumes if axis isn't specified all axises are added */
553  param.push_back("X");
554  param.push_back("Y");
555  param.push_back("Z");
556  }
557  }
558  break;
559  case COLLADASW::InputSemantic::IN_TANGENT:
560  case COLLADASW::InputSemantic::OUT_TANGENT:
561  param.push_back("X");
562  param.push_back("Y");
563  break;
564  default:
565  break;
566  }
567 }
568 
570  COLLADASW::InputSemantic::Semantics semantic,
572  const std::string &anim_id,
573  std::string axis_name)
574 {
575  Scene *scene = this->export_settings.get_scene();
576 
577  std::string channel = curve.get_channel_target();
578 
579  const std::string source_id = anim_id + get_semantic_suffix(semantic);
580 
581  bool is_angle = (bc_startswith(channel, "rotation") || channel == "spot_size");
582 
583  COLLADASW::FloatSourceF source(mSW);
584  source.setId(source_id);
585  source.setArrayId(source_id + ARRAY_ID_SUFFIX);
586  source.setAccessorCount(curve.sample_count());
587  source.setAccessorStride(2);
588 
589  COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
590  add_source_parameters(param, semantic, is_angle, axis_name, false);
591 
592  source.prepareToAppendValues();
593 
594  const FCurve *fcu = curve.get_fcurve();
595  int tangent = (semantic == COLLADASW::InputSemantic::IN_TANGENT) ? 0 : 2;
596 
597  for (int i = 0; i < fcu->totvert; i++) {
598  BezTriple &bezt = fcu->bezt[i];
599 
600  float sampled_time = bezt.vec[tangent][0];
601  float sampled_val = bezt.vec[tangent][1];
602 
603  if (is_angle) {
604  sampled_val = RAD2DEGF(sampled_val);
605  }
606 
607  source.appendValues(FRA2TIME(sampled_time));
608  source.appendValues(sampled_val);
609  }
610  source.finish();
611  return source_id;
612 }
613 
615  BC_animation_source_type source_type,
616  COLLADASW::InputSemantic::Semantics semantic,
617  std::vector<float> &values,
618  const std::string &anim_id,
619  const std::string axis_name)
620 {
621  BlenderContext &blender_context = this->export_settings.get_blender_context();
622  Scene *scene = blender_context.get_scene();
623  /* T can be float, int or double */
624 
625  int stride = 1;
626  int entry_count = values.size() / stride;
627  std::string source_id = anim_id + get_semantic_suffix(semantic);
628 
629  COLLADASW::FloatSourceF source(mSW);
630  source.setId(source_id);
631  source.setArrayId(source_id + ARRAY_ID_SUFFIX);
632  source.setAccessorCount(entry_count);
633  source.setAccessorStride(stride);
634 
635  COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
636  add_source_parameters(param, semantic, source_type == BC_SOURCE_TYPE_ANGLE, axis_name, false);
637 
638  source.prepareToAppendValues();
639 
640  for (int i = 0; i < entry_count; i++) {
641  float val = values[i];
642  switch (source_type) {
644  val = FRA2TIME(val);
645  break;
647  val = RAD2DEGF(val);
648  break;
649  default:
650  break;
651  }
652  source.appendValues(val);
653  }
654 
655  source.finish();
656 
657  return source_id;
658 }
659 
660 /*
661  * Create a collada matrix source for a set of samples
662  */
664  BCMatrixSampleMap &samples,
665  const std::string &anim_id,
666  BC_global_rotation_type global_rotation_type,
667  Matrix &parentinv)
668 {
669  COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
670  std::string source_id = anim_id + get_semantic_suffix(semantic);
671 
672  COLLADASW::Float4x4Source source(mSW);
673  source.setId(source_id);
674  source.setArrayId(source_id + ARRAY_ID_SUFFIX);
675  source.setAccessorCount(samples.size());
676  source.setAccessorStride(16);
677 
678  COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
679  add_source_parameters(param, semantic, false, "", true);
680 
681  source.prepareToAppendValues();
682 
683  BCMatrixSampleMap::iterator it;
684  /* could be made configurable */
685  int precision = (this->export_settings.get_limit_precision()) ? 6 : -1;
686  for (it = samples.begin(); it != samples.end(); it++) {
687  BCMatrix sample = BCMatrix(*it->second);
688  BCMatrix global_transform = this->export_settings.get_global_transform();
689  DMatrix daemat;
690  if (this->export_settings.get_apply_global_orientation()) {
691  sample.apply_transform(global_transform);
692  }
693  else {
694  sample.add_transform(global_transform);
695  }
696  sample.get_matrix(daemat, true, precision);
697  source.appendValues(daemat);
698  }
699 
700  source.finish();
701  return source_id;
702 }
703 
705  const std::string &anim_id,
706  const std::string axis,
707  bool *has_tangents)
708 {
709  std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
710 
711  COLLADASW::NameSource source(mSW);
712  source.setId(source_id);
713  source.setArrayId(source_id + ARRAY_ID_SUFFIX);
714  source.setAccessorCount(curve.sample_count());
715  source.setAccessorStride(1);
716 
717  COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
718  param.push_back("INTERPOLATION");
719 
720  source.prepareToAppendValues();
721 
722  *has_tangents = false;
723 
724  std::vector<float> frames;
725  curve.get_frames(frames);
726 
727  for (unsigned int i = 0; i < curve.sample_count(); i++) {
728  float frame = frames[i];
729  int ipo = curve.get_interpolation_type(frame);
730  if (ipo == BEZT_IPO_BEZ) {
731  source.appendValues(BEZIER_NAME);
732  *has_tangents = true;
733  }
734  else if (ipo == BEZT_IPO_CONST) {
735  source.appendValues(STEP_NAME);
736  }
737  else {
738  /* BEZT_IPO_LIN */
739  source.appendValues(LINEAR_NAME);
740  }
741  }
742  /* unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS */
743 
744  source.finish();
745 
746  return source_id;
747 }
748 
750  const std::string &anim_id)
751 {
752  std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
753 
754  COLLADASW::NameSource source(mSW);
755  source.setId(source_id);
756  source.setArrayId(source_id + ARRAY_ID_SUFFIX);
757  source.setAccessorCount(tot);
758  source.setAccessorStride(1);
759 
760  COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
761  param.push_back("INTERPOLATION");
762 
763  source.prepareToAppendValues();
764 
765  for (int i = 0; i < tot; i++) {
766  source.appendValues(LINEAR_NAME);
767  }
768 
769  source.finish();
770 
771  return source_id;
772 }
773 
774 std::string AnimationExporter::get_collada_name(std::string channel_type) const
775 {
776  /*
777  * Translation table to map FCurve animation types to Collada animation.
778  * Todo: Maybe we can keep the names from the fcurves here instead of
779  * mapping. However this is what i found in the old code. So keep
780  * this map for now.
781  */
782  static std::map<std::string, std::string> BC_CHANNEL_BLENDER_TO_COLLADA = {
783  {"rotation", "rotation"},
784  {"rotation_euler", "rotation"},
785  {"rotation_quaternion", "rotation"},
786  {"scale", "scale"},
787  {"location", "location"},
788 
789  /* Materials */
790  {"specular_color", "specular"},
791  {"diffuse_color", "diffuse"},
792  {"ior", "index_of_refraction"},
793  {"specular_hardness", "specular_hardness"},
794  {"alpha", "alpha"},
795 
796  /* Lights */
797  {"color", "color"},
798  {"fall_off_angle", "falloff_angle"},
799  {"spot_size", "falloff_angle"},
800  {"fall_off_exponent", "falloff_exponent"},
801  {"spot_blend", "falloff_exponent"},
802  /* Special blender profile (todo: make this more elegant). */
803  {"blender/blender_dist", "blender/blender_dist"},
804  /* Special blender profile (todo: make this more elegant). */
805  {"distance", "blender/blender_dist"},
806 
807  /* Cameras */
808  {"lens", "xfov"},
809  {"xfov", "xfov"},
810  {"xmag", "xmag"},
811  {"zfar", "zfar"},
812  {"znear", "znear"},
813  {"ortho_scale", "xmag"},
814  {"clip_end", "zfar"},
815  {"clip_start", "znear"}};
816 
817  std::map<std::string, std::string>::iterator name_it = BC_CHANNEL_BLENDER_TO_COLLADA.find(
818  channel_type);
819  if (name_it == BC_CHANNEL_BLENDER_TO_COLLADA.end()) {
820  return "";
821  }
822  std::string tm_name = name_it->second;
823  return tm_name;
824 }
825 
826 /*
827  * Assign sid of the animated parameter or transform for rotation,
828  * axis name is always appended and the value of append_axis is ignored
829  */
831  const std::string axis_name)
832 {
833  std::string channel_target = curve.get_channel_target();
834  std::string channel_type = curve.get_channel_type();
835  std::string tm_name = get_collada_name(channel_type);
836 
837  bool is_angle = curve.is_rotation_curve();
838 
839  if (!tm_name.empty()) {
840  if (is_angle) {
841  return tm_name + std::string(axis_name) + ".ANGLE";
842  }
843  if (!axis_name.empty()) {
844  return tm_name + "." + std::string(axis_name);
845  }
846 
847  return tm_name;
848  }
849 
850  return tm_name;
851 }
852 
853 #ifdef WITH_MORPH_ANIMATION
854 /* TODO: This function needs to be implemented similar to the material animation export
855  * So we have to update BCSample for this to work. */
857 {
858  FCurve *fcu;
859  Key *key = BKE_key_from_object(ob);
860  if (!key) {
861  return;
862  }
863 
864  if (key->adt && key->adt->action) {
865  fcu = (FCurve *)key->adt->action->curves.first;
866 
867  while (fcu) {
868  BC_animation_transform_type tm_type = get_transform_type(fcu->rna_path);
869 
870  create_keyframed_animation(ob, fcu, tm_type, true, sampler);
871 
872  fcu = fcu->next;
873  }
874  }
875 }
876 #endif
std::string EMPTY_STRING
BC_animation_source_type
@ BC_SOURCE_TYPE_TIMEFRAME
@ BC_SOURCE_TYPE_VALUE
@ BC_SOURCE_TYPE_ANGLE
BC_global_rotation_type
@ BC_DATA_ROTATION
@ BC_OBJECT_ROTATION
@ BC_NO_ROTATION
std::vector< float > BCValues
std::map< int, float > BCValueMap
@ BC_ANIMATION_TYPE_MATERIAL
@ BC_ANIMATION_TYPE_CAMERA
std::map< BCCurveKey, BCAnimationCurve * > BCAnimationCurveMap
std::vector< float > BCFrames
std::map< int, const BCMatrix * > BCMatrixSampleMap
Definition: BCSampleData.h:63
struct Key * BKE_key_from_object(const struct Object *ob)
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:697
#define RAD2DEGF(_rad)
float focallength_to_fov(float focal_length, float sensor)
@ BONE_NO_DEFORM
@ BEZT_IPO_CONST
@ BEZT_IPO_BEZ
@ OB_ARMATURE
#define FRA2TIME(a)
@ BC_TRANSFORMATION_TYPE_MATRIX
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei stride
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
void exportAnimationClips(Scene *sce)
void export_collada_matrix_animation(std::string id, std::string name, std::string target, BCFrames &frames, BCMatrixSampleMap &samples, BC_global_rotation_type global_rotation_type, Matrix &parentinv)
std::string get_axis_name(std::string channel, int id)
std::string collada_interpolation_source(const BCAnimationCurve &curve, const std::string &anim_id, std::string axis_name, bool *has_tangents)
void add_source_parameters(COLLADASW::SourceBase::ParameterNameList &param, COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const std::string axis, bool transform)
void close_animation_container(bool has_container)
void openAnimationWithClip(std::string id, std::string name)
bool open_animation_container(bool has_container, Object *ob)
void export_collada_curve_animation(std::string id, std::string name, std::string target, std::string axis, BCAnimationCurve &curve, BC_global_rotation_type global_rotation_type)
void exportAnimation(Object *ob, BCAnimationSampler &sampler)
void export_matrix_animation(Object *ob, BCAnimationSampler &sampler)
void export_curve_animation_set(Object *ob, BCAnimationSampler &sampler, bool export_as_matrix)
bool is_bone_deform_group(Bone *bone)
void export_bone_animations_recursive(Object *ob_arm, Bone *bone, BCAnimationSampler &sampler)
void export_bone_animation(Object *ob, Bone *bone, BCFrames &frames, BCMatrixSampleMap &samples)
BCAnimationCurve * get_modified_export_curve(Object *ob, BCAnimationCurve &curve, BCAnimationCurveMap &curves)
void export_curve_animation(Object *ob, BCAnimationCurve &curve)
void export_morph_animation(Object *ob)
std::string get_collada_name(std::string channel_type) const
std::string collada_linear_interpolation_source(int tot, const std::string &anim_id)
std::string get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name)
std::vector< std::vector< std::string > > anim_meta
std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
std::string collada_tangent_from_curve(COLLADASW::InputSemantic::Semantics semantic, BCAnimationCurve &curve, const std::string &anim_id, const std::string axis_name)
std::string collada_source_from_values(BC_animation_source_type source_type, COLLADASW::InputSemantic::Semantics semantic, std::vector< float > &values, const std::string &anim_id, const std::string axis_name)
float get_value(const float frame)
void add_value(const float val, const int frame)
void get_object_frames(BCFrames &frames, Object *ob)
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)
void sample_scene(BCExportSettings &export_settings, bool keyframe_at_end)
bool get_object_samples(BCMatrixSampleMap &samples, Object *ob)
BCAnimationCurveMap * get_curves(Object *ob)
std::string translate_id(const char *idString)
std::string encode_xml(std::string xml)
std::string id_name(void *id)
bool bc_has_animations(Object *ob)
std::string bc_get_action_id(std::string action_name, std::string ob_name, std::string channel_type, std::string axis_name, std::string axis_separator)
std::set< Object * > BCObjectSet
Definition: collada_utils.h:72
bAction * bc_getSceneObjectAction(Object *ob)
Definition: collada_utils.h:82
bool bc_startswith(std::string const &value, std::string const &starting)
Scene scene
Curve curve
static void sample(SocketReader *reader, int x, int y, float color[4])
bAction * action
float vec[3][3]
char name[64]
ListBase childbase
struct FCurve * next
char * rna_path
BezTriple * bezt
unsigned int totvert
struct AnimData * adt
Definition: DNA_key_types.h:81
void * first
Definition: DNA_listBase.h:47
float parentinv[4][4]
void * data
ListBase curves
ListBase bonebase