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