1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2009 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 #if __GNUC__ >= 4 || __GNUC_MINOR__ >=3
40 #pragma GCC diagnostic ignored "-Wold-style-cast"
43 #include "OSGColladaAnimation.h"
45 #ifdef OSG_WITH_COLLADA
47 #include "OSGColladaAnimationClip.h"
48 #include "OSGColladaGlobal.h"
49 #include "OSGColladaInstanceAnimation.h"
50 #include "OSGColladaLog.h"
51 #include "OSGColladaNode.h"
52 #include "OSGColladaSource.h"
54 #include "OSGAnimMatrixDataSource.h"
55 #include "OSGAnimQuaternionDataSource.h"
56 #include "OSGAnimVec3fDataSource.h"
57 #include "OSGAnimTargetAttachment.h"
59 #include "OSGNameAttachment.h"
61 #include <dom/domAnimation.h>
65 ColladaInstInfoTransitPtr
66 ColladaAnimation::ColladaAnimationInstInfo::create(
67 ColladaAnimationClip
*colInstParent
,
68 ColladaInstanceAnimation
*colInst
,
69 ColladaAnimation
*colInstTarget
,
70 AnimKeyFrameTemplate
*animTmpl
)
72 return ColladaInstInfoTransitPtr(
73 new ColladaAnimationInstInfo(colInstParent
, colInst
,
74 colInstTarget
, animTmpl
));
78 ColladaAnimation::ColladaAnimationInstInfo::getAnim(void) const
80 return _colInstTarget
;
83 AnimKeyFrameTemplate
*
84 ColladaAnimation::ColladaAnimationInstInfo::getTemplate(void) const
90 ColladaAnimation::ColladaAnimationInstInfo::process(void)
92 #if !defined(OSG_USE_COLLADA_ANIMCLIP_INSTANCE_HACK)
93 ColladaAnimation
*colAnim
=
94 dynamic_cast<ColladaAnimation
*>(getColInst()->getTargetElem());
95 OSG_ASSERT(colAnim
!= NULL
);
97 colAnim
->createInstance(this);
99 OSG_ASSERT(getAnim() != NULL
);
101 getAnim()->createInstance(this);
105 ColladaAnimation::ColladaAnimationInstInfo::ColladaAnimationInstInfo(
106 ColladaAnimationClip
*colInstParent
,
107 ColladaInstanceAnimation
*colInst
,
108 ColladaAnimation
*colInstTarget
,
109 AnimKeyFrameTemplate
*animTmpl
)
111 : Inherited (colInstParent
, colInst
)
112 , _colInstTarget(colInstTarget
)
113 , _animTmpl (animTmpl
)
117 ColladaAnimation::ColladaAnimationInstInfo::~ColladaAnimationInstInfo(void)
121 // ===========================================================================
123 ColladaElementRegistrationHelper
ColladaAnimation::_regHelper(
124 &ColladaAnimation::create
, "animation");
127 ColladaElementTransitPtr
128 ColladaAnimation::create(daeElement
*elem
, ColladaGlobal
*global
)
130 return ColladaElementTransitPtr(new ColladaAnimation(elem
, global
));
134 ColladaAnimation::read(ColladaElement
*colElemParent
)
136 domAnimationRef anim
= getDOMElementAs
<domAnimation
>();
138 OSG_COLLADA_LOG(("ColladaAnimation::read id [%s]\n", anim
->getId()));
142 const domAnimation_Array
&subAnims
= anim
->getAnimation_array();
144 for(UInt32 i
= 0; i
< subAnims
.getCount(); ++i
)
146 readAnim(subAnims
[i
]);
150 AnimKeyFrameTemplate
*
151 ColladaAnimation::createInstance(ColladaInstInfo
*colInstInfo
)
153 domAnimationRef anim
= getDOMElementAs
<domAnimation
>();
155 OSG_COLLADA_LOG(("ColladaAnimation::createInstance id [%s]\n",
158 ColladaAnimationInstInfo
*colAnimInstInfo
=
159 dynamic_cast<ColladaAnimationInstInfo
*>(colInstInfo
);
161 ColladaAnimationClip
*colAnimClip
=
162 dynamic_cast<ColladaAnimationClip
*>(colInstInfo
->getColInstParent());
164 AnimKeyFrameTemplate
*animTmpl
=
165 colAnimInstInfo
->getTemplate();
167 OSG_ASSERT(animTmpl
!= NULL
);
169 createInstanceAnim(anim
,
170 colInstInfo
->getColInstParent(),
171 colInstInfo
->getColInst (),
174 const domAnimation_Array
&subAnims
= anim
->getAnimation_array();
176 for(UInt32 i
= 0; i
< subAnims
.getCount(); ++i
)
178 createInstanceAnim(subAnims
[i
],
179 colInstInfo
->getColInstParent(),
180 colInstInfo
->getColInst (),
184 editInstStore().push_back(animTmpl
);
189 ColladaAnimation::ColladaAnimation(daeElement
*elem
, ColladaGlobal
*global
)
190 : Inherited (elem
, global
)
195 ColladaAnimation::~ColladaAnimation(void)
200 ColladaAnimation::readAnim(domAnimation
*anim
)
202 OSG_COLLADA_LOG(("ColladaAnimation::readAnim id [%s]\n",
203 (anim
->getId() != NULL
? anim
->getId() : "") ));
205 const domSource_Array
&sources
= anim
->getSource_array();
207 for(UInt32 i
= 0; i
< sources
.getCount(); ++i
)
209 ColladaSourceRefPtr colSource
=
210 getUserDataAs
<ColladaSource
>(sources
[i
]);
212 if(colSource
== NULL
)
214 colSource
= dynamic_pointer_cast
<ColladaSource
>(
215 ColladaElementFactory::the()->create(sources
[i
], getGlobal()));
217 colSource
->read(this);
221 SourceMap::value_type(sources
[i
]->getId(), colSource
));
224 const domAnimation_Array
&subAnims
= anim
->getAnimation_array();
226 for(UInt32 i
= 0; i
< subAnims
.getCount(); ++i
)
228 readAnim(subAnims
[i
]);
233 ColladaAnimation::createInstanceAnim(
234 domAnimation
*anim
, ColladaElement
*colInstParent
,
235 ColladaInstanceElement
*colInst
, AnimKeyFrameTemplate
*animTmpl
)
237 ColladaAnimationClip
*colAnimClip
=
238 dynamic_cast<ColladaAnimationClip
*>(colInstParent
);
239 const domChannel_Array
&channels
= anim
->getChannel_array();
241 for(UInt32 i
= 0; i
< channels
.getCount(); ++i
)
243 daeURI samplerURI
= channels
[i
]->getSource();
244 domSamplerRef sampler
=
245 daeSafeCast
<domSampler
>(samplerURI
.getElement());
249 SWARNING
<< "ColladaAnimation::createInstanceAnim: Could not "
250 << "find <sampler> [" << samplerURI
.str()
251 << "] for <channel> [" << i
<< "] in animation id ["
252 << (anim
->getId() != NULL
? anim
->getId() : "")
257 DataSourceInfo dsInfo
;
259 createDataSource(channels
[i
], sampler
, dsInfo
);
261 handleInput (channels
[i
], sampler
, colAnimClip
, animTmpl
, dsInfo
);
262 handleOutput (channels
[i
], sampler
, animTmpl
, dsInfo
);
263 handleInterpolation(channels
[i
], sampler
, animTmpl
, dsInfo
);
265 if(dsInfo
._dataSource
== NULL
)
267 SWARNING
<< "ColladaAnimation::createInstanceAnim: Failed to "
268 << "create a data source for <channel> [" << i
269 << "]. Ignoring." << std::endl
;
273 OSG_COLLADA_LOG(("ColladaAnimation::createInstanceAnim: Filled "
274 "data source for channel [%d] target [%s]\n",
275 i
, channels
[i
]->getTarget()));
277 animTmpl
->editMFSources ()->push_back(dsInfo
._dataSource
);
278 animTmpl
->editMFTargetIds()->push_back(dsInfo
._target
);
281 domAnimation_clipRef animClip
=
282 colAnimClip
->getDOMElementAs
<domAnimation_clip
>();
284 animTmpl
->setName(animClip
->getName());
288 ColladaAnimation::createDataSource(
289 domChannel
*channel
, domSampler
*sampler
, DataSourceInfo
&dsInfo
)
291 domInputLocalRef input
= findInput(sampler
, "OUTPUT");
295 SWARNING
<< "ColladaAnimation::createDataSource: No <input> "
296 << "with semantic OUTPUT in <sampler> ["
297 << (sampler
->getId() != NULL
? sampler
->getId() : "")
298 << "]." << std::endl
;
302 std::string sourceId
= input
->getSource().id();
303 SourceMapConstIt smIt
= _sourceMap
.find(sourceId
);
305 if(smIt
== _sourceMap
.end())
307 SWARNING
<< "ColladaAnimation::createDataSource: No <source> "
308 << "with id [" << sourceId
<< "] found." << std::endl
;
312 std::string fieldSuffix
;
313 std::string
target (channel
->getTarget() );
314 daeSidRef
targetRef(target
, getGlobal()->getDocRoot());
315 daeElement
*targetElem
= targetRef
.resolve().elt
;
317 if(targetElem
== NULL
)
319 SWARNING
<< "ColladaAnimation::createDataSource: Could not resolve ["
320 << target
<< "]. Ignoring" << std::endl
;
324 if(targetElem
->typeID() == domMatrix::ID())
326 dsInfo
._target
= channel
->getTarget() + std::string(".matrix");
327 dsInfo
._dataSource
= AnimMatrixDataSource::create();
329 else if(targetElem
->typeID() == domTranslate::ID())
331 dsInfo
._target
= channel
->getTarget() + std::string(".translate");
332 dsInfo
._dataSource
= AnimVec3fDataSource::create();
334 else if(targetElem
->typeID() == domRotate::ID())
336 dsInfo
._target
= channel
->getTarget() + std::string(".rotate");
337 dsInfo
._dataSource
= AnimQuaternionDataSource::create();
341 dsInfo
._dataSource
= NULL
;
343 SWARNING
<< "ColladaAnimation::createDataSource: Target [" << target
344 << "] has unhandled type [" << targetElem
->typeID()
345 << "]. Ignoring" << std::endl
;
349 // make sure the target has a AnimTargetAttachment on it
350 daeElement
*targetParentElem
= targetElem
->getParentElement();
351 domNode
*parentNode
= daeSafeCast
<domNode
>(targetParentElem
);
353 if(parentNode
== NULL
)
355 SWARNING
<< "ColladaAnimation::createDataSource: Target [" << target
356 << "] does not have a parent <node>.\n" << std::endl
;
360 ColladaNodeRefPtr colNode
= getUserDataAs
<ColladaNode
>(parentNode
);
364 SWARNING
<< "ColladaAnimation::createDataSource: Parent <node> for "
365 << "target [" << target
<< "] has no ColladaNode structure."
370 std::string::size_type slashPos
= target
.find('/');
371 std::string targetSID
= target
.substr(slashPos
+ 1);
373 Node
*targetNode
= colNode
->getNodeBySid(0, targetSID
);
375 if(targetNode
== NULL
)
377 SWARNING
<< "ColladaAnimation::createDataSource: Could not find "
378 << "node for sid [" << targetSID
<< "]." << std::endl
;
382 NodeCore
*targetCore
= targetNode
->getCore();
383 setTargetId(targetCore
, target
);
385 OSG_COLLADA_LOG(("ColladaAnimation::createDataSource: Setting "
386 "AnimTargetAttachment targetId [%s] for core [%p] node [%p] [%s]\n",
387 target
.c_str(), targetCore
, targetNode
,
388 (getName(targetNode
) != NULL
? getName(targetNode
) : "")));
392 ColladaAnimation::handleInput(
393 domChannel
*channel
, domSampler
*sampler
,
394 ColladaAnimationClip
*colAnimClip
, AnimKeyFrameTemplate
*animTmpl
,
395 DataSourceInfo
&dsInfo
)
397 if(dsInfo
._dataSource
== NULL
)
400 domInputLocalRef input
= findInput(sampler
, "INPUT");
404 SWARNING
<< "ColladaAnimation::handleInput: No <input> "
405 << "with semantic INPUT in sampler ["
406 << (sampler
->getId() != NULL
? sampler
->getId() : "")
407 << "]. Ignoring." << std::endl
;
412 colAnimClip
->getDOMElementAs
<domAnimation_clip
>()->getStart();
414 colAnimClip
->getDOMElementAs
<domAnimation_clip
>()->getEnd ();
416 std::string sourceId
= input
->getSource().id();
417 SourceMapConstIt smIt
= _sourceMap
.find(sourceId
);
419 if(smIt
== _sourceMap
.end())
421 SWARNING
<< "ColladaAnimation::handleInput: No <source> "
422 << "with id [" << sourceId
<< "] found." << std::endl
;
426 const ColladaSource::FloatStore
&inputStore
= smIt
->second
->getFloatStore();
428 ColladaSource::FloatStoreConstIt startIt
=
429 std::lower_bound(inputStore
.begin(), inputStore
.end(), startT
);
430 ColladaSource::FloatStoreConstIt endIt
=
431 std::upper_bound(inputStore
.begin(), inputStore
.end(), endT
);
433 dsInfo
._firstKey
= std::distance(inputStore
.begin(), startIt
);
434 dsInfo
._lastKey
= std::distance(inputStore
.begin(), endIt
);
436 OSG_COLLADA_LOG(("ColladaAnimation::handleInput: "
437 "Using key range [%d %d] [%f %f] [%f %f] of [0 %"
439 dsInfo
._firstKey
, dsInfo
._lastKey
,
440 inputStore
[dsInfo
._firstKey
],
441 inputStore
[dsInfo
._lastKey
- 1],
442 startT
, endT
, inputStore
.size()));
444 for(UInt32 i
= dsInfo
._firstKey
; i
< dsInfo
._lastKey
; ++i
)
446 dsInfo
._dataSource
->editMFInValues()->push_back(inputStore
[i
]);
452 ColladaAnimation::handleOutput(
453 domChannel
*channel
, domSampler
*sampler
,
454 AnimKeyFrameTemplate
*animTmpl
, DataSourceInfo
&dsInfo
)
456 if(dsInfo
._dataSource
== NULL
)
459 domInputLocalRef input
= findInput(sampler
, "OUTPUT");
463 SWARNING
<< "ColladaAnimation::handleOutput: No <input> "
464 << "with semantic OUTPUT in <sampler> ["
465 << (sampler
->getId() != NULL
? sampler
->getId() : "")
466 << "]." << std::endl
;
470 std::string sourceId
= input
->getSource().id();
471 SourceMapConstIt smIt
= _sourceMap
.find(sourceId
);
473 if(smIt
== _sourceMap
.end())
475 SWARNING
<< "ColladaAnimation::handleOutput: No <source> "
476 << "with id [" << sourceId
<< "] found." << std::endl
;
480 AnimMatrixDataSourceRefPtr matrixDS
=
481 dynamic_pointer_cast
<AnimMatrixDataSource
>(dsInfo
._dataSource
);
482 AnimVec3fDataSourceRefPtr vec3fDS
=
483 dynamic_pointer_cast
<AnimVec3fDataSource
>(dsInfo
._dataSource
);
484 AnimQuaternionDataSourceRefPtr quatDS
=
485 dynamic_pointer_cast
<AnimQuaternionDataSource
>(dsInfo
._dataSource
);
489 #if defined(OSG_USE_COLLADA_ANIMCLIP_INSTANCE_HACK)
493 ColladaSource::MatrixStoreConstIt matIt
=
494 smIt
->second
->getMatrixStore().begin() + dsInfo
._firstKey
;
495 ColladaSource::MatrixStoreConstIt matEnd
=
496 smIt
->second
->getMatrixStore().begin() + dsInfo
._lastKey
;
498 #if defined(OSG_USE_COLLADA_ANIMCLIP_INSTANCE_HACK)
499 // remove animations that do not change during the clip we instantiate
502 for(; matIt
!= matEnd
; ++matIt
)
504 if(*matIt
!= smIt
->second
->getMatrixStore()[dsInfo
._firstKey
])
514 OSG_COLLADA_LOG(("ColladaAnimation::handleOutput: No anim for "
515 "current clip - skipping animation\n"));
517 dsInfo
._dataSource
= NULL
;
521 matIt
= smIt
->second
->getMatrixStore().begin() + dsInfo
._firstKey
;
522 matEnd
= smIt
->second
->getMatrixStore().begin() + dsInfo
._lastKey
;
525 for(; matIt
!= matEnd
; ++matIt
)
527 matrixDS
->editMFValues()->push_back(*matIt
);
531 else if(vec3fDS
!= NULL
)
533 SWARNING
<< "ColladaAnimation::handleOutput: Vec3fDataSource NIY"
536 else if(quatDS
!= NULL
)
538 SWARNING
<< "ColladaAnimation::handleOutput: QuaternionDataSource NIY"
543 SWARNING
<< "ColladaAnimation::handleOutput: Unknown DataSource type."
549 ColladaAnimation::handleInterpolation(
550 domChannel
*channel
, domSampler
*sampler
,
551 AnimKeyFrameTemplate
*animTmpl
, DataSourceInfo
&dsInfo
)
553 if(dsInfo
._dataSource
== NULL
)
556 domInputLocalRef input
= findInput(sampler
, "INTERPOLATION");
560 SWARNING
<< "ColladaAnimation::handleInterpolation: No <input> "
561 << "with semantic INTERPOLATION in <sampler> ["
562 << (sampler
->getId() != NULL
? sampler
->getId() : "")
563 << "]." << std::endl
;
567 std::string sourceId
= input
->getSource().id();
568 SourceMapConstIt smIt
= _sourceMap
.find(sourceId
);
570 if(smIt
== _sourceMap
.end())
572 SWARNING
<< "ColladaAnimation::handleInterpolation: No <source> "
573 << "with id [" << sourceId
<< "] found." << std::endl
;
577 // check if all values are the same
578 bool singleVal
= true;
579 const ColladaSource::NameStore
&interpol
=
580 smIt
->second
->getNameStore();
581 ColladaSource::NameStoreConstIt iIt
= interpol
.begin() + dsInfo
._firstKey
;
582 ColladaSource::NameStoreConstIt iEnd
= interpol
.begin() + dsInfo
._lastKey
;
584 for(; iIt
!= iEnd
; ++iIt
)
586 if(interpol
[dsInfo
._firstKey
] != *iIt
)
593 iIt
= interpol
.begin() + dsInfo
._firstKey
;
594 iEnd
= interpol
.begin() + dsInfo
._lastKey
;
596 for(; iIt
!= iEnd
; ++iIt
)
600 dsInfo
._dataSource
->editMFInterpolationModes()->push_back(
601 AnimKeyFrameDataSource::IM_Step
);
603 else if(*iIt
== "LINEAR")
605 dsInfo
._dataSource
->editMFInterpolationModes()->push_back(
606 AnimKeyFrameDataSource::IM_Linear
);
608 else if(*iIt
== "BEZIER")
610 dsInfo
._dataSource
->editMFInterpolationModes()->push_back(
611 AnimKeyFrameDataSource::IM_Bezier
);
613 else if(*iIt
== "HERMITE")
615 dsInfo
._dataSource
->editMFInterpolationModes()->push_back(
616 AnimKeyFrameDataSource::IM_Hermite
);
620 SWARNING
<< "ColladdaAnimation::handleInterpolation: "
621 << "unknown interpolation mode [" << *iIt
622 << "]. Using LINEAR instead." << std::endl
;
624 dsInfo
._dataSource
->editMFInterpolationModes()->push_back(
625 AnimKeyFrameDataSource::IM_Linear
);
628 // stop after one value if they are all the same
629 if(singleVal
== true)
634 /*! Find an <input> with the given semantic in the given sampler.
637 ColladaAnimation::findInput(domSampler
*sampler
, const std::string
&semantic
)
639 domInputLocal
*retVal
= NULL
;
640 const domInputLocal_Array
&inputs
= sampler
->getInput_array();
642 for(UInt32 i
= 0; i
< inputs
.getCount(); ++i
)
644 std::string inputSem
= inputs
[i
]->getSemantic();
646 if(semantic
== inputSem
)
658 #endif // OSG_WITH_COLLADA