1 #include "daeReader.h"
2 #include "domSourceReader.h"
3 #include <dae.h>
4 #include <dae/domAny.h>
5 #include <dom/domCOLLADA.h>
6 #include <dom/domConstants.h>
7
8 #include <osgAnimation/Channel>
9 #include <osgAnimation/MorphGeometry>
10 #include <osgAnimation/StackedTransform>
11 #include <osgAnimation/StackedRotateAxisElement>
12 #include <osgAnimation/UpdateBone>
13 #include <osgAnimation/UpdateMatrixTransform>
14
15 using namespace osgDAE;
16
17
18 // Mapping Collada animations to Osg animations
19 // domAnimation -> osgAnimation::Animation
20 // domSampler -> osgAnimation::Channel
21 // domSource -> osgAnimation::Channel.Sampler
22 // domChannel -> osgAnimation::Channel.TargetName
processAnimationLibraries(domCOLLADA * document)23 osgAnimation::BasicAnimationManager* daeReader::processAnimationLibraries(domCOLLADA* document)
24 {
25 domLibrary_animation_clips_Array domAnimationClipsLibraries = document->getLibrary_animation_clips_array();
26
27 domLibrary_animations_Array domAnimationsLibraries = document->getLibrary_animations_array();
28 osgAnimation::BasicAnimationManager* pOsgAnimationManager = NULL;
29
30 // Only create an animationmanager if we have animation clip libraries or animation libraries
31 if ((domAnimationClipsLibraries.getCount() > 0) || (domAnimationsLibraries.getCount() > 0))
32 {
33 pOsgAnimationManager = new osgAnimation::BasicAnimationManager();
34
35 // Process all animation clip libraries
36 for (size_t i=0; i < domAnimationClipsLibraries.getCount(); i++)
37 {
38 domAnimation_clip_Array domAnimationClips = domAnimationClipsLibraries[i]->getAnimation_clip_array();
39 // Process all animation clips in this library
40 for (size_t j=0; j < domAnimationClips.getCount(); j++)
41 {
42 processAnimationClip(pOsgAnimationManager, domAnimationClips[j]);
43 }
44 }
45
46 // If there are no clips then all animations are part of the same clip
47 if (domAnimationClipsLibraries.getCount() == 0 && domAnimationsLibraries.getCount())
48 {
49 osgAnimation::Animation* pOsgAnimation = new osgAnimation::Animation;
50 pOsgAnimation->setName("Default");
51 pOsgAnimationManager->registerAnimation(pOsgAnimation);
52
53 // Process all animation libraries
54 for (size_t i=0; i < domAnimationsLibraries.getCount(); i++)
55 {
56 domAnimation_Array domAnimations = domAnimationsLibraries[i]->getAnimation_array();
57
58 TargetChannelPartMap tcm;
59
60 // Process all animations in this library
61 for (size_t j=0; j < domAnimations.getCount(); j++)
62 {
63 processAnimationChannels(domAnimations[j], tcm);
64 }
65
66 processAnimationMap(tcm, pOsgAnimation);
67 }
68 }
69 }
70 return pOsgAnimationManager;
71 }
72
73 // <animation_clip (id) (name) (start) (end)>
74 // 0..1 <asset>
75 // 1..* <instance_animation>
76 // 0..* <extra>
processAnimationClip(osgAnimation::BasicAnimationManager * pOsgAnimationManager,domAnimation_clip * pDomAnimationClip)77 void daeReader::processAnimationClip(osgAnimation::BasicAnimationManager* pOsgAnimationManager, domAnimation_clip* pDomAnimationClip)
78 {
79 // an <animation_clip> groups animations
80 osgAnimation::Animation* pOsgAnimation = new osgAnimation::Animation;
81 std::string name = pDomAnimationClip->getId() ? pDomAnimationClip->getId() : "AnimationClip";
82 pOsgAnimation->setName(name);
83
84 // We register the animation inside the scheduler
85 pOsgAnimationManager->registerAnimation(pOsgAnimation);
86
87 double start = pDomAnimationClip->getStart();
88 double end = pDomAnimationClip->getEnd();
89
90 pOsgAnimation->setStartTime(start);
91 double duration = end - start;
92 if (duration > 0)
93 {
94 pOsgAnimation->setDuration(duration);
95 }
96
97 TargetChannelPartMap tcm;
98
99 // 1..* <instance_animation>
100 domInstanceWithExtra_Array domInstanceArray = pDomAnimationClip->getInstance_animation_array();
101 for (size_t i=0; i < domInstanceArray.getCount(); i++)
102 {
103 domAnimation *pDomAnimation = daeSafeCast<domAnimation>(getElementFromURI(domInstanceArray[i]->getUrl()));
104 if (pDomAnimation)
105 {
106 processAnimationChannels(pDomAnimation, tcm);
107 }
108 else
109 {
110 OSG_WARN << "Failed to locate animation " << domInstanceArray[i]->getUrl().getURI() << std::endl;
111 }
112 }
113
114 processAnimationMap(tcm, pOsgAnimation);
115 }
116
117 struct KeyFrameComparator
118 {
operator ()KeyFrameComparator119 bool operator () (const osgAnimation::Keyframe& a, const osgAnimation::Keyframe& b) const
120 {
121 return a.getTime() < b.getTime();
122 }
operator ()KeyFrameComparator123 bool operator () (const osgAnimation::Keyframe& a, float t) const
124 {
125 return a.getTime() < t;
126 }
operator ()KeyFrameComparator127 bool operator () (float t, const osgAnimation::Keyframe& b) const
128 {
129 return t < b.getTime();
130 }
131 };
132
133 template <typename T>
deCasteljau(osgAnimation::TemplateCubicBezier<T> & l,osgAnimation::TemplateCubicBezier<T> & n,osgAnimation::TemplateCubicBezier<T> & r,float t)134 void deCasteljau(osgAnimation::TemplateCubicBezier<T>& l, osgAnimation::TemplateCubicBezier<T>& n, osgAnimation::TemplateCubicBezier<T>& r, float t)
135 {
136 T q1 = l.getPosition() + t * (l.getControlPointOut() - l.getPosition());
137 T q2 = l.getControlPointOut() + t * (r.getControlPointIn() - l.getControlPointOut());
138 T q3 = r.getControlPointIn() + t * (r.getPosition() - r.getControlPointIn());
139
140 T r1 = q1 + t * (q2 - q1);
141 T r2 = q2 + t * (q3 - q2);
142
143 T s = r1 + t * (r2 - r1);
144
145 n.setControlPointIn(r1);
146
147 n.setPosition(s);
148
149 n.setControlPointOut(r2);
150
151 l.setControlPointOut(q1);
152
153 r.setControlPointIn(q3);
154 }
155
mergeKeyframeContainers(osgAnimation::Vec3CubicBezierKeyframeContainer * to,osgAnimation::FloatCubicBezierKeyframeContainer ** from,daeReader::InterpolationType interpolationType,const osg::Vec3 & defaultValue)156 void mergeKeyframeContainers(osgAnimation::Vec3CubicBezierKeyframeContainer* to,
157 osgAnimation::FloatCubicBezierKeyframeContainer** from,
158 daeReader::InterpolationType interpolationType,
159 const osg::Vec3& defaultValue)
160 {
161 assert(to->empty());
162
163 typedef std::set<float> TimeSet;
164 TimeSet times;
165
166 for (int i = 0; i < 3; ++i)
167 {
168 if (!from[i] || from[i]->empty())
169 {
170 continue;
171 }
172
173 for (osgAnimation::FloatCubicBezierKeyframeContainer::const_iterator
174 it = from[i]->begin(), end = from[i]->end(); it != end; ++it)
175 {
176 times.insert(it->getTime());
177 }
178 }
179
180 for (TimeSet::const_iterator it = times.begin(), end = times.end(); it != end; ++it)
181 {
182 const float time = *it;
183
184 osgAnimation::Vec3CubicBezier value(defaultValue);
185
186 for (int i = 0; i < 3; ++i)
187 {
188 if (!from[i] || from[i]->empty())
189 {
190 continue;
191 }
192
193 osgAnimation::FloatCubicBezierKeyframeContainer::iterator next =
194 std::lower_bound(from[i]->begin(), from[i]->end(), time, KeyFrameComparator());
195 if (next == from[i]->end())
196 {
197 --next;
198 value.getPosition().ptr()[i] = next->getValue().getPosition();
199 value.getControlPointIn().ptr()[i] = next->getValue().getControlPointIn();
200 value.getControlPointOut().ptr()[i] = next->getValue().getControlPointOut();
201 }
202 else if (next == from[i]->begin() || next->getTime() == time)
203 {
204 value.getPosition().ptr()[i] = next->getValue().getPosition();
205 value.getControlPointIn().ptr()[i] = next->getValue().getControlPointIn();
206 value.getControlPointOut().ptr()[i] = next->getValue().getControlPointOut();
207 }
208 else
209 {
210 osgAnimation::FloatCubicBezierKeyframeContainer::iterator prev = next;
211 --prev;
212
213 switch (interpolationType)
214 {
215 case daeReader::INTERPOLATION_STEP:
216 value.getPosition().ptr()[i] = prev->getValue().getPosition();
217 break;
218 case daeReader::INTERPOLATION_LINEAR:
219 {
220 float xp = prev->getTime(), xn = next->getTime();
221 float yp = prev->getValue().getPosition(), yn = next->getValue().getPosition();
222 value.getPosition().ptr()[i] = yp + (yn - yp) * (time - xp) / (xn - xp);
223 }
224 break;
225 case daeReader::INTERPOLATION_BEZIER:
226 {
227 float xp = prev->getTime(), xn = next->getTime();
228
229 osgAnimation::FloatCubicBezier l(prev->getValue()), n, r(next->getValue());
230 deCasteljau(l, n, r, (time - xp) / (xn - xp));
231
232 value.getPosition().ptr()[i] = n.getPosition();
233 value.getControlPointIn().ptr()[i] = n.getControlPointIn();
234 value.getControlPointOut().ptr()[i] = n.getControlPointOut();
235
236 osgAnimation::Vec3CubicBezier prevValue = to->back().getValue();
237 prevValue.getControlPointOut().ptr()[i] = l.getControlPointOut();
238 to->back().setValue(prevValue);
239
240 prev->setValue(l);
241 next->setValue(r);
242 from[i]->insert(next, osgAnimation::FloatCubicBezierKeyframe(time, n));
243 }
244 break;
245 default:
246 OSG_WARN << "Unsupported interpolation type." << std::endl;
247 break;
248 }
249
250 //todo - different types of interpolation
251 }
252 }
253
254 to->push_back(osgAnimation::Vec3CubicBezierKeyframe(time, value));
255 }
256 }
257
processAnimationChannels(domAnimation * pDomAnimation,TargetChannelPartMap & tcm)258 void daeReader::processAnimationChannels(
259 domAnimation* pDomAnimation, TargetChannelPartMap& tcm)
260 {
261 // 1..* <source>
262 SourceMap sources;
263 domSource_Array domSources = pDomAnimation->getSource_array();
264 for (size_t i=0; i < domSources.getCount(); i++)
265 {
266 sources.insert(std::make_pair((daeElement*)domSources[i], domSourceReader(domSources[i])));
267 }
268
269 domChannel_Array domChannels = pDomAnimation->getChannel_array();
270 for (size_t i=0; i < domChannels.getCount(); i++)
271 {
272 processChannel(domChannels[i], sources, tcm);
273 }
274
275 domAnimation_Array domAnimations = pDomAnimation->getAnimation_array();
276 for (size_t i=0; i < domAnimations.getCount(); i++)
277 {
278 // recursively call
279 processAnimationChannels(domAnimations[i], tcm);
280 }
281 }
282
convertKeyframeContainerToLinear(osgAnimation::Vec3CubicBezierKeyframeContainer & from)283 osgAnimation::Vec3KeyframeContainer* convertKeyframeContainerToLinear(osgAnimation::Vec3CubicBezierKeyframeContainer& from)
284 {
285 osgAnimation::Vec3KeyframeContainer* linearKeyframes = new osgAnimation::Vec3KeyframeContainer;
286 for (size_t i = 0; i < from.size(); ++i)
287 {
288 linearKeyframes->push_back(osgAnimation::Vec3Keyframe(
289 from[i].getTime(), from[i].getValue().getPosition()));
290 }
291 return linearKeyframes;
292 }
293
294 template <typename T>
convertHermiteToBezier(osgAnimation::TemplateKeyframeContainer<T> & keyframes)295 void convertHermiteToBezier(osgAnimation::TemplateKeyframeContainer<T>& keyframes)
296 {
297 for (size_t i = 0; i < keyframes.size(); ++i)
298 {
299 T val = keyframes[i].getValue();
300 val.setControlPointIn(val.getControlPointIn() / 3.0f + val.getPosition());
301 val.setControlPointOut(val.getControlPointOut() / -3.0f + val.getPosition());
302 keyframes[i].setValue(val);
303 }
304 }
305
306 // osgAnimation requires control points to be in a weird order. This function
307 // reorders them from the conventional order to osgAnimation order.
308 template <typename T>
reorderControlPoints(osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<T>> & vkfCont)309 void reorderControlPoints(osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<T> >& vkfCont)
310 {
311 if (vkfCont.size() <= 1)
312 {
313 if (vkfCont.size() == 1)
314 {
315 osgAnimation::TemplateCubicBezier<T> tcb = vkfCont.front().getValue();
316 T inCP = tcb.getControlPointIn();
317 tcb.setControlPointIn(tcb.getControlPointOut());
318 tcb.setControlPointOut(inCP);
319 vkfCont.front().setValue(tcb);
320 }
321 return;
322 }
323
324 osgAnimation::TemplateCubicBezier<T> first = vkfCont.front().getValue();
325
326 for (unsigned i = 0; i < vkfCont.size() - 1; ++i)
327 {
328 osgAnimation::TemplateCubicBezier<T> tcb = vkfCont[i].getValue();
329 tcb.setControlPointIn(tcb.getControlPointOut());
330 tcb.setControlPointOut(vkfCont[i + 1].getValue().getControlPointIn());
331 vkfCont[i].setValue(tcb);
332 }
333
334 osgAnimation::TemplateCubicBezier<T> last = vkfCont.back().getValue();
335 last.setControlPointIn(last.getControlPointOut());
336 last.setControlPointOut(first.getControlPointIn());
337 vkfCont.back().setValue(last);
338 }
339
340 // <animation (id) (name)>
341 // 0..1 <asset>
342 // option 1
343 // 1..* <source>
344 // one of (<sampler>, <channel>, <animation>) or <animation> (see below)
345 // option 2
346 // 1..* <source>
347 // 1..* <sampler>
348 // 0..* <animation>
349 // option 3
350 // 1..* <animation>
351 // 0..* <extra>
processAnimationMap(const TargetChannelPartMap & tcm,osgAnimation::Animation * pOsgAnimation)352 void daeReader::processAnimationMap(const TargetChannelPartMap& tcm, osgAnimation::Animation* pOsgAnimation)
353 {
354 for (TargetChannelPartMap::const_iterator lb = tcm.begin(), end = tcm.end(); lb != end;)
355 {
356 TargetChannelPartMap::const_iterator ub = tcm.upper_bound(lb->first);
357
358 osgAnimation::Channel* pOsgAnimationChannel = NULL;
359 std::string channelName, targetName, componentName;
360
361 if (osgAnimation::Vec3Target* pTarget = dynamic_cast<osgAnimation::Vec3Target*>(lb->first))
362 {
363 osgAnimation::FloatCubicBezierKeyframeContainer* fkfConts[3] = {NULL, NULL, NULL};
364 osgAnimation::Vec3CubicBezierKeyframeContainer* vkfCont = NULL;
365 InterpolationType interpolationType = INTERPOLATION_DEFAULT;
366
367 for (TargetChannelPartMap::const_iterator it = lb; it != ub; ++it)
368 {
369 ChannelPart* channelPart = it->second.get();
370 extractTargetName(channelPart->name, channelName, targetName, componentName);
371 interpolationType = channelPart->interpolation;
372
373 if (osgAnimation::Vec3CubicBezierKeyframeContainer* v3cnt = dynamic_cast<osgAnimation::Vec3CubicBezierKeyframeContainer*>(channelPart->keyframes.get()))
374 {
375 vkfCont = v3cnt;
376 break;
377 }
378 else if (osgAnimation::FloatCubicBezierKeyframeContainer* fcnt = dynamic_cast<osgAnimation::FloatCubicBezierKeyframeContainer*>(channelPart->keyframes.get()))
379 {
380 if (strchr("xusr0", tolower(componentName[0])))
381 {
382 fkfConts[0] = fcnt;
383 }
384 else if (strchr("yvtg1", tolower(componentName[0])))
385 {
386 fkfConts[1] = fcnt;
387 }
388 else if (strchr("zpb2", tolower(componentName[0])))
389 {
390 fkfConts[2] = fcnt;
391 }
392 else
393 {
394 OSG_WARN << "Unrecognised vector component \"" << componentName << "\"" << std::endl;
395 }
396 }
397 else
398 {
399 OSG_WARN << "Unrecognised keyframe container \"" << channelPart->name << "\"" << std::endl;
400 }
401 }
402
403 if (!pOsgAnimationChannel && (fkfConts[0] || fkfConts[1] || fkfConts[2]))
404 {
405 vkfCont = new osgAnimation::Vec3CubicBezierKeyframeContainer;
406 mergeKeyframeContainers(vkfCont, fkfConts, interpolationType, pTarget->getValue());
407 }
408
409 if (vkfCont)
410 {
411 if (interpolationType == INTERPOLATION_STEP)
412 {
413 osgAnimation::Vec3StepChannel* channel = new osgAnimation::Vec3StepChannel;
414 pOsgAnimationChannel = channel;
415 channel->getOrCreateSampler()->setKeyframeContainer(convertKeyframeContainerToLinear(*vkfCont));
416 }
417 else if (interpolationType == INTERPOLATION_LINEAR)
418 {
419 osgAnimation::Vec3LinearChannel* channel = new osgAnimation::Vec3LinearChannel;
420 pOsgAnimationChannel = channel;
421 channel->getOrCreateSampler()->setKeyframeContainer(convertKeyframeContainerToLinear(*vkfCont));
422 }
423 else if (interpolationType == INTERPOLATION_BEZIER)
424 {
425 osgAnimation::Vec3CubicBezierChannel* channel = new osgAnimation::Vec3CubicBezierChannel;
426 pOsgAnimationChannel = channel;
427 reorderControlPoints(*vkfCont);
428 channel->getOrCreateSampler()->setKeyframeContainer(vkfCont);
429 }
430 else if (interpolationType == INTERPOLATION_HERMITE)
431 {
432 osgAnimation::Vec3CubicBezierChannel* channel = new osgAnimation::Vec3CubicBezierChannel;
433 pOsgAnimationChannel = channel;
434 convertHermiteToBezier(*vkfCont);
435 reorderControlPoints(*vkfCont);
436 channel->getOrCreateSampler()->setKeyframeContainer(vkfCont);
437 }
438 else
439 {
440 OSG_WARN << "Unsupported interpolation type" << std::endl;
441 }
442 }
443 }
444 else
445 {
446 ChannelPart* channelPart = lb->second.get();
447 extractTargetName(channelPart->name, channelName, targetName, componentName);
448
449 typedef osgAnimation::TemplateKeyframe<osgAnimation::TemplateCubicBezier<osg::Matrixf> > MatrixCubicBezierKeyframe;
450 typedef osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<osg::Matrixf> > MatrixCubicBezierKeyframeContainer;
451
452 if (osgAnimation::FloatCubicBezierKeyframeContainer* kfCntr =
453 dynamic_cast<osgAnimation::FloatCubicBezierKeyframeContainer*>(channelPart->keyframes.get()))
454 {
455 if (dynamic_cast<osgAnimation::MatrixTarget*>(lb->first))
456 {
457 OSG_WARN << "Animating elements of matrices not supported." << std::endl;
458 }
459 else
460 {
461 osgAnimation::FloatCubicBezierChannel* channel = new osgAnimation::FloatCubicBezierChannel;
462 reorderControlPoints(*kfCntr);
463 channel->getOrCreateSampler()->setKeyframeContainer(kfCntr);
464 pOsgAnimationChannel = channel;
465 }
466 }
467 else if (MatrixCubicBezierKeyframeContainer* cbkfCntr =
468 dynamic_cast<MatrixCubicBezierKeyframeContainer*>(channelPart->keyframes.get()))
469 {
470 osgAnimation::MatrixKeyframeContainer* kfCntr = new osgAnimation::MatrixKeyframeContainer;
471 for (size_t i = 0; i < cbkfCntr->size(); ++i)
472 {
473 const MatrixCubicBezierKeyframe& cbkf = cbkfCntr->at(i);
474 kfCntr->push_back(osgAnimation::MatrixKeyframe(cbkf.getTime(), cbkf.getValue().getPosition()));
475 }
476 osgAnimation::MatrixLinearChannel* channel = new osgAnimation::MatrixLinearChannel;
477 channel->getOrCreateSampler()->setKeyframeContainer(kfCntr);
478 pOsgAnimationChannel = channel;
479 }
480 }
481
482 if (pOsgAnimationChannel)
483 {
484 pOsgAnimationChannel->setTargetName(targetName);
485 pOsgAnimationChannel->setName(channelName);
486 pOsgAnimation->addChannel(pOsgAnimationChannel);
487 }
488 lb = ub;
489 }
490
491 pOsgAnimation->computeDuration();
492 }
493
494 template <typename T, typename TArray>
makeKeyframes(const osg::FloatArray * pOsgTimesArray,TArray * pOsgPointArray,TArray * pOsgInTanArray,TArray * pOsgOutTanArray,daeReader::InterpolationType & interpolationType)495 osgAnimation::KeyframeContainer* makeKeyframes(
496 const osg::FloatArray* pOsgTimesArray,
497 TArray* pOsgPointArray,
498 TArray* pOsgInTanArray,
499 TArray* pOsgOutTanArray,
500 daeReader::InterpolationType& interpolationType)
501 {
502 osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<T> >* keyframes =
503 new osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<T> >;
504
505 for (size_t i = 0; i < pOsgTimesArray->size(); i++)
506 {
507 T pt = (*pOsgPointArray)[i];
508 T cpIn = pt, cpOut = pt;
509 if (pOsgInTanArray)
510 {
511 if (interpolationType == daeReader::INTERPOLATION_HERMITE)
512 //convert from hermite to bezier
513 cpIn += (*pOsgInTanArray)[i] / 3;
514 else if (interpolationType == daeReader::INTERPOLATION_BEZIER)
515 cpIn = (*pOsgInTanArray)[i];
516 }
517 if (pOsgOutTanArray)
518 {
519 if (interpolationType == daeReader::INTERPOLATION_HERMITE)
520 //convert from hermite to bezier
521 cpOut += (*pOsgOutTanArray)[i] / 3;
522 else if (interpolationType == daeReader::INTERPOLATION_BEZIER)
523 cpOut = (*pOsgOutTanArray)[i];
524 }
525
526 keyframes->push_back(
527 osgAnimation::TemplateKeyframe<osgAnimation::TemplateCubicBezier<T> >(
528 (*pOsgTimesArray)[i],
529 osgAnimation::TemplateCubicBezier<T>(pt, cpIn, cpOut)));
530 }
531
532 if (interpolationType == daeReader::INTERPOLATION_HERMITE)
533 {
534 interpolationType = daeReader::INTERPOLATION_BEZIER;
535 }
536
537 return keyframes;
538 }
539
540 // Sampler tells how to use the sources to generate an animated value.
541 // <sampler (id)>
542 // 1..* <input>
543 // 1 semantic
544 // 1 source
processSampler(domChannel * pDomChannel,SourceMap & sources)545 daeReader::ChannelPart* daeReader::processSampler(domChannel* pDomChannel, SourceMap &sources)
546 {
547 // And we finally define our channel
548 // Note osg can only create time based animations
549
550 //from the channel you know the target, from the target you know the type
551 domSampler *pDomSampler = daeSafeCast<domSampler>(getElementFromURI(pDomChannel->getSource()));
552 if (!pDomSampler)
553 {
554 return NULL;
555 }
556
557 domInputLocal_Array domInputArray = pDomSampler->getInput_array();
558
559 daeElement* input_source = NULL;
560 daeElement* output_source = NULL;
561 daeElement* output_intangent_source = NULL;
562 daeElement* output_outtangent_source = NULL;
563 domInputLocal *tmp;
564
565 osg::FloatArray* pOsgTimesArray = NULL;
566 if (findInputSourceBySemantic(domInputArray, COMMON_PROFILE_INPUT_INPUT, input_source, &tmp))
567 {
568 domSource* pDomSource = daeSafeCast<domSource>(input_source);
569 if (pDomSource)
570 {
571 domSource::domTechnique_common* pDomTechnique = pDomSource->getTechnique_common();
572 if (pDomTechnique)
573 {
574 domAccessor* pDomAccessor = pDomTechnique->getAccessor();
575 domParam_Array domParams = pDomAccessor->getParam_array();
576 if (domParams.getCount() > 0)
577 {
578 if (!strcmp("TIME", domParams[0]->getName()))
579 {
580 pOsgTimesArray = sources[input_source].getArray<osg::FloatArray>();
581 }
582 else
583 {
584 OSG_WARN << "Only TIME based animations are supported" <<std::endl;
585 return NULL;
586 }
587 }
588 else
589 {
590 OSG_WARN << "No params in accessor" <<std::endl;
591 return NULL;
592 }
593 }
594 else
595 {
596 OSG_WARN << "Unable to find <technique_common> in <source> " << pDomSource->getName() <<std::endl;
597 return NULL;
598 }
599 }
600 else
601 {
602 OSG_WARN << "Could not get animation 'INPUT' source"<<std::endl;
603 return NULL;
604 }
605 }
606
607 //const bool readDoubleKeyframes = (_precisionHint & osgDB::Options::DOUBLE_PRECISION_KEYFRAMES) != 0;
608 static const bool readDoubleKeyframes = false;
609
610 findInputSourceBySemantic(domInputArray, COMMON_PROFILE_INPUT_OUTPUT, output_source, &tmp);
611 findInputSourceBySemantic(domInputArray, COMMON_PROFILE_INPUT_IN_TANGENT, output_intangent_source, &tmp);
612 findInputSourceBySemantic(domInputArray, COMMON_PROFILE_INPUT_OUT_TANGENT, output_outtangent_source, &tmp);
613 domSourceReader::ArrayType arrayType = sources[output_source].getArrayType(readDoubleKeyframes);
614
615 struct InterpTypeName
616 {
617 InterpolationType interp;
618 const char* str;
619 };
620
621 InterpTypeName interpTypeNames[] = {
622 {INTERPOLATION_STEP, "STEP"},
623 {INTERPOLATION_LINEAR, "LINEAR"},
624 {INTERPOLATION_BEZIER, "BEZIER"},
625 {INTERPOLATION_HERMITE, "HERMITE"},
626 {INTERPOLATION_CARDINAL, "CARDINAL"},
627 {INTERPOLATION_BSPLINE, "BSPLINE"}
628 };
629 const int interpTypeCount = sizeof(interpTypeNames) / sizeof(*interpTypeNames);
630
631 // TODO multiple outputs may be possible?
632
633 InterpolationType interpolationType = INTERPOLATION_DEFAULT;
634
635 if (findInputSourceBySemantic(domInputArray, COMMON_PROFILE_INPUT_INTERPOLATION, input_source, &tmp))
636 {
637 domSource* pDomSource = daeSafeCast<domSource>(input_source);
638 if (pDomSource)
639 {
640 domName_array* pDomNames = pDomSource->getName_array();
641 if (pDomNames)
642 {
643 daeStringArray* stringArray = &(pDomNames->getValue());
644
645 // Take a look at the first element in the array to see what kind of interpolation is needed
646 // multiple interpolation types inside an animation is not supported
647 if (stringArray->getCount() > 0)
648 {
649 // Collada interpolation types
650 for (int i = 0; i < interpTypeCount; ++i)
651 {
652 if (!strcmp(interpTypeNames[i].str, (*stringArray)[0]))
653 {
654 interpolationType = interpTypeNames[i].interp;
655 break;
656 }
657 }
658 }
659 else
660 {
661 OSG_WARN << "No names in <Name_array>" <<std::endl;
662 return NULL;
663 }
664 }
665 else
666 {
667 OSG_WARN << "Unable to find <Name_array> in <source> " << pDomSource->getName() <<std::endl;
668 return NULL;
669 }
670 }
671 else
672 {
673 OSG_WARN << "Could not get animation 'INPUT' source"<<std::endl;
674 return NULL;
675 }
676 }
677
678 //work around for files output by the Autodesk FBX converter.
679 if ((interpolationType == INTERPOLATION_BEZIER) &&
680 (_authoringTool == FBX_CONVERTER || _authoringTool == MAYA))
681 {
682 interpolationType = INTERPOLATION_HERMITE;
683 }
684
685 osgAnimation::KeyframeContainer* keyframes = NULL;
686
687 switch (arrayType)
688 {
689 case domSourceReader::Float:
690 keyframes = makeKeyframes<float>(pOsgTimesArray,
691 sources[output_source].getArray<osg::FloatArray>(),
692 sources[output_intangent_source].getArray<osg::FloatArray>(),
693 sources[output_outtangent_source].getArray<osg::FloatArray>(),
694 interpolationType);
695 break;
696 case domSourceReader::Vec2:
697 keyframes = makeKeyframes<osg::Vec2>(pOsgTimesArray,
698 sources[output_source].getArray<osg::Vec2Array>(),
699 sources[output_intangent_source].getArray<osg::Vec2Array>(),
700 sources[output_outtangent_source].getArray<osg::Vec2Array>(),
701 interpolationType);
702 break;
703 case domSourceReader::Vec3:
704 keyframes = makeKeyframes<osg::Vec3>(pOsgTimesArray,
705 sources[output_source].getArray<osg::Vec3Array>(),
706 sources[output_intangent_source].getArray<osg::Vec3Array>(),
707 sources[output_outtangent_source].getArray<osg::Vec3Array>(),
708 interpolationType);
709 break;
710 case domSourceReader::Vec4:
711 keyframes = makeKeyframes<osg::Vec4>(pOsgTimesArray,
712 sources[output_source].getArray<osg::Vec4Array>(),
713 sources[output_intangent_source].getArray<osg::Vec4Array>(),
714 sources[output_outtangent_source].getArray<osg::Vec4Array>(),
715 interpolationType);
716 break;
717 case domSourceReader::Vec2d:
718 keyframes = makeKeyframes<osg::Vec2d>(pOsgTimesArray,
719 sources[output_source].getArray<osg::Vec2dArray>(),
720 sources[output_intangent_source].getArray<osg::Vec2dArray>(),
721 sources[output_outtangent_source].getArray<osg::Vec2dArray>(),
722 interpolationType);
723 break;
724 case domSourceReader::Vec3d:
725 keyframes = makeKeyframes<osg::Vec3d>(pOsgTimesArray,
726 sources[output_source].getArray<osg::Vec3dArray>(),
727 sources[output_intangent_source].getArray<osg::Vec3dArray>(),
728 sources[output_outtangent_source].getArray<osg::Vec3dArray>(),
729 interpolationType);
730 break;
731 case domSourceReader::Vec4d:
732 keyframes = makeKeyframes<osg::Vec4d>(pOsgTimesArray,
733 sources[output_source].getArray<osg::Vec4dArray>(),
734 sources[output_intangent_source].getArray<osg::Vec4dArray>(),
735 sources[output_outtangent_source].getArray<osg::Vec4dArray>(),
736 interpolationType);
737 break;
738 case domSourceReader::Matrix:
739 keyframes = makeKeyframes<osg::Matrixf>(pOsgTimesArray,
740 sources[output_source].getArray<osg::MatrixfArray>(),
741 sources[output_intangent_source].getArray<osg::MatrixfArray>(),
742 sources[output_outtangent_source].getArray<osg::MatrixfArray>(),
743 interpolationType);
744 break;
745 default:
746 ;// Fall through
747 }
748
749 if (keyframes)
750 {
751 ChannelPart* chanPart = new ChannelPart;
752 chanPart->keyframes = keyframes;
753 chanPart->interpolation = interpolationType;
754 chanPart->name = pDomChannel->getTarget();
755 return chanPart;
756 }
757
758 return NULL;
759 }
760
findChannelTarget(osg::Callback * nc,const std::string & targetName,bool & rotation)761 osgAnimation::Target* findChannelTarget(osg::Callback* nc, const std::string& targetName, bool& rotation)
762 {
763 if (osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(nc))
764 {
765 for (osgAnimation::StackedTransform::const_iterator
766 it = umt->getStackedTransforms().begin(), end = umt->getStackedTransforms().end(); it != end; ++it)
767 {
768 osgAnimation::StackedTransformElement* te = it->get();
769 if (te->getName() == targetName)
770 {
771 rotation = dynamic_cast<osgAnimation::StackedRotateAxisElement*>(te) != NULL;
772 return te->getOrCreateTarget();
773 }
774 }
775 }
776 else if (!dynamic_cast<osgAnimation::UpdateMorph*>(nc))
777 {
778 OSG_WARN << "Unrecognised AnimationUpdateCallback" << std::endl;
779 }
780
781 return NULL;
782 }
783
convertDegreesToRadians(osgAnimation::KeyframeContainer * pKeyframeContainer)784 void convertDegreesToRadians(osgAnimation::KeyframeContainer* pKeyframeContainer)
785 {
786 if (osgAnimation::FloatKeyframeContainer* fkc =
787 dynamic_cast<osgAnimation::FloatKeyframeContainer*>(pKeyframeContainer))
788 {
789 for (size_t i = 0; i < fkc->size(); ++i)
790 {
791 osgAnimation::FloatKeyframe& fk = (*fkc)[i];
792 fk.setValue(osg::DegreesToRadians(fk.getValue()));
793 }
794 }
795 else if (osgAnimation::FloatCubicBezierKeyframeContainer* fcbkc =
796 dynamic_cast<osgAnimation::FloatCubicBezierKeyframeContainer*>(pKeyframeContainer))
797 {
798 for (size_t i = 0; i < fcbkc->size(); ++i)
799 {
800 osgAnimation::FloatCubicBezierKeyframe& fcbk = (*fcbkc)[i];
801 osgAnimation::FloatCubicBezier fcb = fcbk.getValue();
802 fcb.setPosition(osg::DegreesToRadians(fcb.getPosition()));
803 fcb.setControlPointIn(osg::DegreesToRadians(fcb.getControlPointIn()));
804 fcb.setControlPointOut(osg::DegreesToRadians(fcb.getControlPointOut()));
805 fcbk.setValue(fcb);
806 }
807 }
808 else
809 {
810 OSG_WARN << "Warning: rotation keyframes not converted to radians." << std::endl;
811 }
812 }
813
814 // Channel connects animation output to parameter to animate
815 // <channel>
816 // 1 source
817 // 1 target
processChannel(domChannel * pDomChannel,SourceMap & sources,TargetChannelPartMap & tcm)818 void daeReader::processChannel(domChannel* pDomChannel, SourceMap& sources, TargetChannelPartMap& tcm)
819 {
820 domSampler *pDomSampler = daeSafeCast<domSampler>(getElementFromURI(pDomChannel->getSource()));
821 if (pDomSampler)
822 {
823 ChannelPart* pChannelPart = processSampler(pDomChannel, sources);
824
825 if (pChannelPart)
826 {
827 domChannelOsgAnimationUpdateCallbackMap::iterator iter = _domChannelOsgAnimationUpdateCallbackMap.find(pDomChannel);
828 if (iter != _domChannelOsgAnimationUpdateCallbackMap.end())
829 {
830 osg::Callback* nc = iter->second.get();
831
832 std::string channelName, targetName, componentName;
833 extractTargetName(pDomChannel->getTarget(), channelName, targetName, componentName);
834 //assert(targetName == nc->getName());
835 bool bRotationChannel = false;
836 if (osgAnimation::Target* pTarget = findChannelTarget(nc, channelName, bRotationChannel))
837 {
838 if (bRotationChannel)
839 {
840 convertDegreesToRadians(pChannelPart->keyframes.get());
841 }
842 tcm.insert(TargetChannelPartMap::value_type(pTarget, pChannelPart));
843 }
844 else
845 {
846 OSG_WARN << "Target \"" << channelName << "\" not found." << std::endl;
847 }
848 }
849 else
850 {
851 OSG_WARN << "Could not locate UpdateCallback for <channel> target " << pDomChannel->getTarget()<< std::endl;
852 }
853 }
854 else
855 {
856 OSG_WARN << "<channel> source " << pDomChannel->getSource().getURI() << " has no corresponding osgAnimation::Channel" << std::endl;
857 }
858 }
859 else
860 {
861 OSG_WARN << "Could not locate <channel> source " << pDomChannel->getSource().getURI() << std::endl;
862 }
863 }
864
extractTargetName(const std::string & daeTarget,std::string & channelName,std::string & targetName,std::string & component)865 void daeReader::extractTargetName(const std::string& daeTarget, std::string& channelName, std::string& targetName, std::string& component)
866 {
867 size_t slash = daeTarget.find_last_of("/");
868 if (slash != std::string::npos)
869 {
870 // Handle /translation
871 targetName = daeTarget.substr(0, slash);
872 channelName = daeTarget.substr(slash+1, std::string::npos);
873 }
874 else
875 {
876 size_t parenthesis = daeTarget.find_last_of("(");
877 size_t endpos = daeTarget.find_last_of(")");
878 if (parenthesis != std::string::npos && endpos != std::string::npos)
879 {
880 // Handle (1)
881 targetName = daeTarget.substr(0, parenthesis);
882 channelName = daeTarget.substr(parenthesis+1, endpos - parenthesis - 1);
883 }
884 else
885 {
886 OSG_WARN << "Couldn't extract a proper name for <channel> target " << daeTarget << std::endl;
887 }
888 }
889
890 size_t period = channelName.find_last_of(".");
891 if (period != std::string::npos)
892 {
893 component = channelName.substr(period+1, std::string::npos);
894 channelName = channelName.substr(0, period);
895 }
896 else
897 {
898 component.clear();
899
900 size_t first_parenthesis = channelName.find_first_of("(");
901 if (first_parenthesis != std::string::npos)
902 {
903 size_t open_parenthesis = first_parenthesis;
904
905 do
906 {
907 if (open_parenthesis != first_parenthesis) component += ",";
908
909 size_t close_parenthesis = channelName.find_first_of(")", open_parenthesis);
910 component += channelName.substr(open_parenthesis+1, close_parenthesis-open_parenthesis-1);
911 open_parenthesis = channelName.find_first_of("(", close_parenthesis);
912 }
913 while (open_parenthesis != std::string::npos);
914
915 channelName = channelName.substr(0, first_parenthesis);
916 }
917 }
918 }
919