Files
OpenSceneGraph/src/osgPlugins/dae/daeRAnimations.cpp

919 lines
35 KiB
C++

#include "daeReader.h"
#include "domSourceReader.h"
#include <dae.h>
#include <dae/domAny.h>
#include <dom/domCOLLADA.h>
#include <dom/domConstants.h>
#include <osgAnimation/Channel>
#include <osgAnimation/MorphGeometry>
#include <osgAnimation/StackedTransform>
#include <osgAnimation/StackedRotateAxisElement>
#include <osgAnimation/UpdateBone>
#include <osgAnimation/UpdateMatrixTransform>
using namespace osgDAE;
// Mapping Collada animations to Osg animations
// domAnimation -> osgAnimation::Animation
// domSampler -> osgAnimation::Channel
// domSource -> osgAnimation::Channel.Sampler
// domChannel -> osgAnimation::Channel.TargetName
osgAnimation::BasicAnimationManager* daeReader::processAnimationLibraries(domCOLLADA* document)
{
domLibrary_animation_clips_Array domAnimationClipsLibraries = document->getLibrary_animation_clips_array();
domLibrary_animations_Array domAnimationsLibraries = document->getLibrary_animations_array();
osgAnimation::BasicAnimationManager* pOsgAnimationManager = NULL;
// Only create an animationmanager if we have animation clip libraries or animation libraries
if ((domAnimationClipsLibraries.getCount() > 0) || (domAnimationsLibraries.getCount() > 0))
{
pOsgAnimationManager = new osgAnimation::BasicAnimationManager();
// Process all animation clip libraries
for (size_t i=0; i < domAnimationClipsLibraries.getCount(); i++)
{
domAnimation_clip_Array domAnimationClips = domAnimationClipsLibraries[i]->getAnimation_clip_array();
// Process all animation clips in this library
for (size_t j=0; j < domAnimationClips.getCount(); j++)
{
processAnimationClip(pOsgAnimationManager, domAnimationClips[j]);
}
}
// If there are no clips then all animations are part of the same clip
if (domAnimationClipsLibraries.getCount() == 0 && domAnimationsLibraries.getCount())
{
osgAnimation::Animation* pOsgAnimation = new osgAnimation::Animation;
pOsgAnimation->setName("Default");
pOsgAnimationManager->registerAnimation(pOsgAnimation);
// Process all animation libraries
for (size_t i=0; i < domAnimationsLibraries.getCount(); i++)
{
domAnimation_Array domAnimations = domAnimationsLibraries[i]->getAnimation_array();
TargetChannelPartMap tcm;
// Process all animations in this library
for (size_t j=0; j < domAnimations.getCount(); j++)
{
processAnimationChannels(domAnimations[j], tcm);
}
processAnimationMap(tcm, pOsgAnimation);
}
}
}
return pOsgAnimationManager;
}
// <animation_clip (id) (name) (start) (end)>
// 0..1 <asset>
// 1..* <instance_animation>
// 0..* <extra>
void daeReader::processAnimationClip(osgAnimation::BasicAnimationManager* pOsgAnimationManager, domAnimation_clip* pDomAnimationClip)
{
// an <animation_clip> groups animations
osgAnimation::Animation* pOsgAnimation = new osgAnimation::Animation;
std::string name = pDomAnimationClip->getId() ? pDomAnimationClip->getId() : "AnimationClip";
pOsgAnimation->setName(name);
// We register the animation inside the scheduler
pOsgAnimationManager->registerAnimation(pOsgAnimation);
double start = pDomAnimationClip->getStart();
double end = pDomAnimationClip->getEnd();
pOsgAnimation->setStartTime(start);
double duration = end - start;
if (duration > 0)
{
pOsgAnimation->setDuration(duration);
}
TargetChannelPartMap tcm;
// 1..* <instance_animation>
domInstanceWithExtra_Array domInstanceArray = pDomAnimationClip->getInstance_animation_array();
for (size_t i=0; i < domInstanceArray.getCount(); i++)
{
domAnimation *pDomAnimation = daeSafeCast<domAnimation>(getElementFromURI(domInstanceArray[i]->getUrl()));
if (pDomAnimation)
{
processAnimationChannels(pDomAnimation, tcm);
}
else
{
OSG_WARN << "Failed to locate animation " << domInstanceArray[i]->getUrl().getURI() << std::endl;
}
}
processAnimationMap(tcm, pOsgAnimation);
}
struct KeyFrameComparator
{
bool operator () (const osgAnimation::Keyframe& a, const osgAnimation::Keyframe& b) const
{
return a.getTime() < b.getTime();
}
bool operator () (const osgAnimation::Keyframe& a, float t) const
{
return a.getTime() < t;
}
bool operator () (float t, const osgAnimation::Keyframe& b) const
{
return t < b.getTime();
}
};
template <typename T>
void deCasteljau(osgAnimation::TemplateCubicBezier<T>& l, osgAnimation::TemplateCubicBezier<T>& n, osgAnimation::TemplateCubicBezier<T>& r, float t)
{
T q1 = l.getPosition() + t * (l.getControlPointOut() - l.getPosition());
T q2 = l.getControlPointOut() + t * (r.getControlPointIn() - l.getControlPointOut());
T q3 = r.getControlPointIn() + t * (r.getPosition() - r.getControlPointIn());
T r1 = q1 + t * (q2 - q1);
T r2 = q2 + t * (q3 - q2);
T s = r1 + t * (r2 - r1);
n.setControlPointIn(r1);
n.setPosition(s);
n.setControlPointOut(r2);
l.setControlPointOut(q1);
r.setControlPointIn(q3);
}
void mergeKeyframeContainers(osgAnimation::Vec3CubicBezierKeyframeContainer* to,
osgAnimation::FloatCubicBezierKeyframeContainer** from,
daeReader::InterpolationType interpolationType,
const osg::Vec3& defaultValue)
{
assert(to->empty());
typedef std::set<float> TimeSet;
TimeSet times;
for (int i = 0; i < 3; ++i)
{
if (!from[i] || from[i]->empty())
{
continue;
}
for (osgAnimation::FloatCubicBezierKeyframeContainer::const_iterator
it = from[i]->begin(), end = from[i]->end(); it != end; ++it)
{
times.insert(it->getTime());
}
}
for (TimeSet::const_iterator it = times.begin(), end = times.end(); it != end; ++it)
{
const float time = *it;
osgAnimation::Vec3CubicBezier value(defaultValue);
for (int i = 0; i < 3; ++i)
{
if (!from[i] || from[i]->empty())
{
continue;
}
osgAnimation::FloatCubicBezierKeyframeContainer::iterator next =
std::lower_bound(from[i]->begin(), from[i]->end(), time, KeyFrameComparator());
if (next == from[i]->end())
{
--next;
value.getPosition().ptr()[i] = next->getValue().getPosition();
value.getControlPointIn().ptr()[i] = next->getValue().getControlPointIn();
value.getControlPointOut().ptr()[i] = next->getValue().getControlPointOut();
}
else if (next == from[i]->begin() || next->getTime() == time)
{
value.getPosition().ptr()[i] = next->getValue().getPosition();
value.getControlPointIn().ptr()[i] = next->getValue().getControlPointIn();
value.getControlPointOut().ptr()[i] = next->getValue().getControlPointOut();
}
else
{
osgAnimation::FloatCubicBezierKeyframeContainer::iterator prev = next;
--prev;
switch (interpolationType)
{
case daeReader::INTERPOLATION_STEP:
value.getPosition().ptr()[i] = prev->getValue().getPosition();
break;
case daeReader::INTERPOLATION_LINEAR:
{
float xp = prev->getTime(), xn = next->getTime();
float yp = prev->getValue().getPosition(), yn = next->getValue().getPosition();
value.getPosition().ptr()[i] = yp + (yn - yp) * (time - xp) / (xn - xp);
}
break;
case daeReader::INTERPOLATION_BEZIER:
{
float xp = prev->getTime(), xn = next->getTime();
osgAnimation::FloatCubicBezier l(prev->getValue()), n, r(next->getValue());
deCasteljau(l, n, r, (time - xp) / (xn - xp));
value.getPosition().ptr()[i] = n.getPosition();
value.getControlPointIn().ptr()[i] = n.getControlPointIn();
value.getControlPointOut().ptr()[i] = n.getControlPointOut();
osgAnimation::Vec3CubicBezier prevValue = to->back().getValue();
prevValue.getControlPointOut().ptr()[i] = l.getControlPointOut();
to->back().setValue(prevValue);
prev->setValue(l);
next->setValue(r);
from[i]->insert(next, osgAnimation::FloatCubicBezierKeyframe(time, n));
}
break;
default:
OSG_WARN << "Unsupported interpolation type." << std::endl;
break;
}
//todo - different types of interpolation
}
}
to->push_back(osgAnimation::Vec3CubicBezierKeyframe(time, value));
}
}
void daeReader::processAnimationChannels(
domAnimation* pDomAnimation, TargetChannelPartMap& tcm)
{
// 1..* <source>
SourceMap sources;
domSource_Array domSources = pDomAnimation->getSource_array();
for (size_t i=0; i < domSources.getCount(); i++)
{
sources.insert(std::make_pair((daeElement*)domSources[i], domSourceReader(domSources[i])));
}
domChannel_Array domChannels = pDomAnimation->getChannel_array();
for (size_t i=0; i < domChannels.getCount(); i++)
{
processChannel(domChannels[i], sources, tcm);
}
domAnimation_Array domAnimations = pDomAnimation->getAnimation_array();
for (size_t i=0; i < domAnimations.getCount(); i++)
{
// recursively call
processAnimationChannels(domAnimations[i], tcm);
}
}
osgAnimation::Vec3KeyframeContainer* convertKeyframeContainerToLinear(osgAnimation::Vec3CubicBezierKeyframeContainer& from)
{
osgAnimation::Vec3KeyframeContainer* linearKeyframes = new osgAnimation::Vec3KeyframeContainer;
for (size_t i = 0; i < from.size(); ++i)
{
linearKeyframes->push_back(osgAnimation::Vec3Keyframe(
from[i].getTime(), from[i].getValue().getPosition()));
}
return linearKeyframes;
}
template <typename T>
void convertHermiteToBezier(osgAnimation::TemplateKeyframeContainer<T>& keyframes)
{
for (size_t i = 0; i < keyframes.size(); ++i)
{
T val = keyframes[i].getValue();
val.setControlPointIn(val.getControlPointIn() / 3.0f + val.getPosition());
val.setControlPointOut(val.getControlPointOut() / -3.0f + val.getPosition());
keyframes[i].setValue(val);
}
}
// osgAnimation requires control points to be in a weird order. This function
// reorders them from the conventional order to osgAnimation order.
template <typename T>
void reorderControlPoints(osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<T> >& vkfCont)
{
if (vkfCont.size() <= 1)
{
if (vkfCont.size() == 1)
{
osgAnimation::TemplateCubicBezier<T> tcb = vkfCont.front().getValue();
T inCP = tcb.getControlPointIn();
tcb.setControlPointIn(tcb.getControlPointOut());
tcb.setControlPointOut(inCP);
vkfCont.front().setValue(tcb);
}
return;
}
osgAnimation::TemplateCubicBezier<T> first = vkfCont.front().getValue();
for (unsigned i = 0; i < vkfCont.size() - 1; ++i)
{
osgAnimation::TemplateCubicBezier<T> tcb = vkfCont[i].getValue();
tcb.setControlPointIn(tcb.getControlPointOut());
tcb.setControlPointOut(vkfCont[i + 1].getValue().getControlPointIn());
vkfCont[i].setValue(tcb);
}
osgAnimation::TemplateCubicBezier<T> last = vkfCont.back().getValue();
last.setControlPointIn(last.getControlPointOut());
last.setControlPointOut(first.getControlPointIn());
vkfCont.back().setValue(last);
}
// <animation (id) (name)>
// 0..1 <asset>
// option 1
// 1..* <source>
// one of (<sampler>, <channel>, <animation>) or <animation> (see below)
// option 2
// 1..* <source>
// 1..* <sampler>
// 0..* <animation>
// option 3
// 1..* <animation>
// 0..* <extra>
void daeReader::processAnimationMap(const TargetChannelPartMap& tcm, osgAnimation::Animation* pOsgAnimation)
{
for (TargetChannelPartMap::const_iterator lb = tcm.begin(), end = tcm.end(); lb != end;)
{
TargetChannelPartMap::const_iterator ub = tcm.upper_bound(lb->first);
osgAnimation::Channel* pOsgAnimationChannel = NULL;
std::string channelName, targetName, componentName;
if (osgAnimation::Vec3Target* pTarget = dynamic_cast<osgAnimation::Vec3Target*>(lb->first))
{
osgAnimation::FloatCubicBezierKeyframeContainer* fkfConts[3] = {NULL, NULL, NULL};
osgAnimation::Vec3CubicBezierKeyframeContainer* vkfCont = NULL;
InterpolationType interpolationType = INTERPOLATION_DEFAULT;
for (TargetChannelPartMap::const_iterator it = lb; it != ub; ++it)
{
ChannelPart* channelPart = it->second.get();
extractTargetName(channelPart->name, channelName, targetName, componentName);
interpolationType = channelPart->interpolation;
if (osgAnimation::Vec3CubicBezierKeyframeContainer* v3cnt = dynamic_cast<osgAnimation::Vec3CubicBezierKeyframeContainer*>(channelPart->keyframes.get()))
{
vkfCont = v3cnt;
break;
}
else if (osgAnimation::FloatCubicBezierKeyframeContainer* fcnt = dynamic_cast<osgAnimation::FloatCubicBezierKeyframeContainer*>(channelPart->keyframes.get()))
{
if (strchr("xusr0", tolower(componentName[0])))
{
fkfConts[0] = fcnt;
}
else if (strchr("yvtg1", tolower(componentName[0])))
{
fkfConts[1] = fcnt;
}
else if (strchr("zpb2", tolower(componentName[0])))
{
fkfConts[2] = fcnt;
}
else
{
OSG_WARN << "Unrecognised vector component \"" << componentName << "\"" << std::endl;
}
}
else
{
OSG_WARN << "Unrecognised keyframe container \"" << channelPart->name << "\"" << std::endl;
}
}
if (!pOsgAnimationChannel && (fkfConts[0] || fkfConts[1] || fkfConts[2]))
{
vkfCont = new osgAnimation::Vec3CubicBezierKeyframeContainer;
mergeKeyframeContainers(vkfCont, fkfConts, interpolationType, pTarget->getValue());
}
if (vkfCont)
{
if (interpolationType == INTERPOLATION_STEP)
{
osgAnimation::Vec3StepChannel* channel = new osgAnimation::Vec3StepChannel;
pOsgAnimationChannel = channel;
channel->getOrCreateSampler()->setKeyframeContainer(convertKeyframeContainerToLinear(*vkfCont));
}
else if (interpolationType == INTERPOLATION_LINEAR)
{
osgAnimation::Vec3LinearChannel* channel = new osgAnimation::Vec3LinearChannel;
pOsgAnimationChannel = channel;
channel->getOrCreateSampler()->setKeyframeContainer(convertKeyframeContainerToLinear(*vkfCont));
}
else if (interpolationType == INTERPOLATION_BEZIER)
{
osgAnimation::Vec3CubicBezierChannel* channel = new osgAnimation::Vec3CubicBezierChannel;
pOsgAnimationChannel = channel;
reorderControlPoints(*vkfCont);
channel->getOrCreateSampler()->setKeyframeContainer(vkfCont);
}
else if (interpolationType == INTERPOLATION_HERMITE)
{
osgAnimation::Vec3CubicBezierChannel* channel = new osgAnimation::Vec3CubicBezierChannel;
pOsgAnimationChannel = channel;
convertHermiteToBezier(*vkfCont);
reorderControlPoints(*vkfCont);
channel->getOrCreateSampler()->setKeyframeContainer(vkfCont);
}
else
{
OSG_WARN << "Unsupported interpolation type" << std::endl;
}
}
}
else
{
ChannelPart* channelPart = lb->second.get();
extractTargetName(channelPart->name, channelName, targetName, componentName);
typedef osgAnimation::TemplateKeyframe<osgAnimation::TemplateCubicBezier<osg::Matrixf> > MatrixCubicBezierKeyframe;
typedef osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<osg::Matrixf> > MatrixCubicBezierKeyframeContainer;
if (osgAnimation::FloatCubicBezierKeyframeContainer* kfCntr =
dynamic_cast<osgAnimation::FloatCubicBezierKeyframeContainer*>(channelPart->keyframes.get()))
{
if (dynamic_cast<osgAnimation::MatrixTarget*>(lb->first))
{
OSG_WARN << "Animating elements of matrices not supported." << std::endl;
}
else
{
osgAnimation::FloatCubicBezierChannel* channel = new osgAnimation::FloatCubicBezierChannel;
reorderControlPoints(*kfCntr);
channel->getOrCreateSampler()->setKeyframeContainer(kfCntr);
pOsgAnimationChannel = channel;
}
}
else if (MatrixCubicBezierKeyframeContainer* cbkfCntr =
dynamic_cast<MatrixCubicBezierKeyframeContainer*>(channelPart->keyframes.get()))
{
osgAnimation::MatrixKeyframeContainer* kfCntr = new osgAnimation::MatrixKeyframeContainer;
for (size_t i = 0; i < cbkfCntr->size(); ++i)
{
const MatrixCubicBezierKeyframe& cbkf = cbkfCntr->at(i);
kfCntr->push_back(osgAnimation::MatrixKeyframe(cbkf.getTime(), cbkf.getValue().getPosition()));
}
osgAnimation::MatrixLinearChannel* channel = new osgAnimation::MatrixLinearChannel;
channel->getOrCreateSampler()->setKeyframeContainer(kfCntr);
pOsgAnimationChannel = channel;
}
}
if (pOsgAnimationChannel)
{
pOsgAnimationChannel->setTargetName(targetName);
pOsgAnimationChannel->setName(channelName);
pOsgAnimation->addChannel(pOsgAnimationChannel);
}
lb = ub;
}
pOsgAnimation->computeDuration();
}
template <typename T, typename TArray>
osgAnimation::KeyframeContainer* makeKeyframes(
const osg::FloatArray* pOsgTimesArray,
TArray* pOsgPointArray,
TArray* pOsgInTanArray,
TArray* pOsgOutTanArray,
daeReader::InterpolationType& interpolationType)
{
osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<T> >* keyframes =
new osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<T> >;
for (size_t i = 0; i < pOsgTimesArray->size(); i++)
{
T pt = (*pOsgPointArray)[i];
T cpIn = pt, cpOut = pt;
if (pOsgInTanArray)
{
if (interpolationType == daeReader::INTERPOLATION_HERMITE)
//convert from hermite to bezier
cpIn += (*pOsgInTanArray)[i] / 3;
else if (interpolationType == daeReader::INTERPOLATION_BEZIER)
cpIn = (*pOsgInTanArray)[i];
}
if (pOsgOutTanArray)
{
if (interpolationType == daeReader::INTERPOLATION_HERMITE)
//convert from hermite to bezier
cpOut += (*pOsgOutTanArray)[i] / 3;
else if (interpolationType == daeReader::INTERPOLATION_BEZIER)
cpOut = (*pOsgOutTanArray)[i];
}
keyframes->push_back(
osgAnimation::TemplateKeyframe<osgAnimation::TemplateCubicBezier<T> >(
(*pOsgTimesArray)[i],
osgAnimation::TemplateCubicBezier<T>(pt, cpIn, cpOut)));
}
if (interpolationType == daeReader::INTERPOLATION_HERMITE)
{
interpolationType = daeReader::INTERPOLATION_BEZIER;
}
return keyframes;
}
// Sampler tells how to use the sources to generate an animated value.
// <sampler (id)>
// 1..* <input>
// 1 semantic
// 1 source
daeReader::ChannelPart* daeReader::processSampler(domChannel* pDomChannel, SourceMap &sources)
{
// And we finally define our channel
// Note osg can only create time based animations
//from the channel you know the target, from the target you know the type
domSampler *pDomSampler = daeSafeCast<domSampler>(getElementFromURI(pDomChannel->getSource()));
if (!pDomSampler)
{
return NULL;
}
domInputLocal_Array domInputArray = pDomSampler->getInput_array();
daeElement* input_source = NULL;
daeElement* output_source = NULL;
daeElement* output_intangent_source = NULL;
daeElement* output_outtangent_source = NULL;
domInputLocal *tmp;
osg::FloatArray* pOsgTimesArray = NULL;
if (findInputSourceBySemantic(domInputArray, COMMON_PROFILE_INPUT_INPUT, input_source, &tmp))
{
domSource* pDomSource = daeSafeCast<domSource>(input_source);
if (pDomSource)
{
domSource::domTechnique_common* pDomTechnique = pDomSource->getTechnique_common();
if (pDomTechnique)
{
domAccessor* pDomAccessor = pDomTechnique->getAccessor();
domParam_Array domParams = pDomAccessor->getParam_array();
if (domParams.getCount() > 0)
{
if (!strcmp("TIME", domParams[0]->getName()))
{
pOsgTimesArray = sources[input_source].getFloatArray();
}
else
{
OSG_WARN << "Only TIME based animations are supported" <<std::endl;
return NULL;
}
}
else
{
OSG_WARN << "No params in accessor" <<std::endl;
return NULL;
}
}
else
{
OSG_WARN << "Unable to find <technique_common> in <source> " << pDomSource->getName() <<std::endl;
return NULL;
}
}
else
{
OSG_WARN << "Could not get animation 'INPUT' source"<<std::endl;
return NULL;
}
}
//const bool readDoubleKeyframes = (_precisionHint & osgDB::Options::DOUBLE_PRECISION_KEYFRAMES) != 0;
static const bool readDoubleKeyframes = false;
findInputSourceBySemantic(domInputArray, COMMON_PROFILE_INPUT_OUTPUT, output_source, &tmp);
findInputSourceBySemantic(domInputArray, COMMON_PROFILE_INPUT_IN_TANGENT, output_intangent_source, &tmp);
findInputSourceBySemantic(domInputArray, COMMON_PROFILE_INPUT_OUT_TANGENT, output_outtangent_source, &tmp);
domSourceReader::ArrayType arrayType = sources[output_source].getArrayType(readDoubleKeyframes);
struct InterpTypeName
{
InterpolationType interp;
const char* str;
};
InterpTypeName interpTypeNames[] = {
{INTERPOLATION_STEP, "STEP"},
{INTERPOLATION_LINEAR, "LINEAR"},
{INTERPOLATION_BEZIER, "BEZIER"},
{INTERPOLATION_HERMITE, "HERMITE"},
{INTERPOLATION_CARDINAL, "CARDINAL"},
{INTERPOLATION_BSPLINE, "BSPLINE"}
};
const int interpTypeCount = sizeof(interpTypeNames) / sizeof(*interpTypeNames);
// TODO multiple outputs may be possible?
InterpolationType interpolationType = INTERPOLATION_DEFAULT;
if (findInputSourceBySemantic(domInputArray, COMMON_PROFILE_INPUT_INTERPOLATION, input_source, &tmp))
{
domSource* pDomSource = daeSafeCast<domSource>(input_source);
if (pDomSource)
{
domName_array* pDomNames = pDomSource->getName_array();
if (pDomNames)
{
daeStringArray* stringArray = &(pDomNames->getValue());
// Take a look at the first element in the array to see what kind of interpolation is needed
// multiple interpolation types inside an animation is not supported
if (stringArray->getCount() > 0)
{
// Collada interpolation types
for (int i = 0; i < interpTypeCount; ++i)
{
if (!strcmp(interpTypeNames[i].str, (*stringArray)[0]))
{
interpolationType = interpTypeNames[i].interp;
break;
}
}
}
else
{
OSG_WARN << "No names in <Name_array>" <<std::endl;
return NULL;
}
}
else
{
OSG_WARN << "Unable to find <Name_array> in <source> " << pDomSource->getName() <<std::endl;
return NULL;
}
}
else
{
OSG_WARN << "Could not get animation 'INPUT' source"<<std::endl;
return NULL;
}
}
//work around for files output by the Autodesk FBX converter.
if ((interpolationType == INTERPOLATION_BEZIER) &&
(_authoringTool == FBX_CONVERTER || _authoringTool == MAYA))
{
interpolationType = INTERPOLATION_HERMITE;
}
osgAnimation::KeyframeContainer* keyframes = NULL;
switch (arrayType)
{
case domSourceReader::Float:
keyframes = makeKeyframes<float>(pOsgTimesArray,
sources[output_source].getFloatArray(),
sources[output_intangent_source].getFloatArray(),
sources[output_outtangent_source].getFloatArray(),
interpolationType);
break;
case domSourceReader::Vec2:
keyframes = makeKeyframes<osg::Vec2>(pOsgTimesArray,
sources[output_source].getVec2Array(),
sources[output_intangent_source].getVec2Array(),
sources[output_outtangent_source].getVec2Array(),
interpolationType);
break;
case domSourceReader::Vec3:
keyframes = makeKeyframes<osg::Vec3>(pOsgTimesArray,
sources[output_source].getVec3Array(),
sources[output_intangent_source].getVec3Array(),
sources[output_outtangent_source].getVec3Array(),
interpolationType);
break;
case domSourceReader::Vec4:
keyframes = makeKeyframes<osg::Vec4>(pOsgTimesArray,
sources[output_source].getVec4Array(),
sources[output_intangent_source].getVec4Array(),
sources[output_outtangent_source].getVec4Array(),
interpolationType);
break;
case domSourceReader::Vec2d:
keyframes = makeKeyframes<osg::Vec2d>(pOsgTimesArray,
sources[output_source].getVec2dArray(),
sources[output_intangent_source].getVec2dArray(),
sources[output_outtangent_source].getVec2dArray(),
interpolationType);
break;
case domSourceReader::Vec3d:
keyframes = makeKeyframes<osg::Vec3d>(pOsgTimesArray,
sources[output_source].getVec3dArray(),
sources[output_intangent_source].getVec3dArray(),
sources[output_outtangent_source].getVec3dArray(),
interpolationType);
break;
case domSourceReader::Vec4d:
keyframes = makeKeyframes<osg::Vec4d>(pOsgTimesArray,
sources[output_source].getVec4dArray(),
sources[output_intangent_source].getVec4dArray(),
sources[output_outtangent_source].getVec4dArray(),
interpolationType);
break;
case domSourceReader::Matrix:
keyframes = makeKeyframes<osg::Matrixf>(pOsgTimesArray,
sources[output_source].getMatrixArray(),
sources[output_intangent_source].getMatrixArray(),
sources[output_outtangent_source].getMatrixArray(),
interpolationType);
break;
default:
;// Fall through
}
if (keyframes)
{
ChannelPart* chanPart = new ChannelPart;
chanPart->keyframes = keyframes;
chanPart->interpolation = interpolationType;
chanPart->name = pDomChannel->getTarget();
return chanPart;
}
return NULL;
}
osgAnimation::Target* findChannelTarget(osg::NodeCallback* nc, const std::string& targetName, bool& rotation)
{
if (osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(nc))
{
for (osgAnimation::StackedTransform::const_iterator
it = umt->getStackedTransforms().begin(), end = umt->getStackedTransforms().end(); it != end; ++it)
{
osgAnimation::StackedTransformElement* te = it->get();
if (te->getName() == targetName)
{
rotation = dynamic_cast<osgAnimation::StackedRotateAxisElement*>(te) != NULL;
return te->getOrCreateTarget();
}
}
}
else if (!dynamic_cast<osgAnimation::UpdateMorph*>(nc))
{
OSG_WARN << "Unrecognised AnimationUpdateCallback" << std::endl;
}
return NULL;
}
void convertDegreesToRadians(osgAnimation::KeyframeContainer* pKeyframeContainer)
{
if (osgAnimation::FloatKeyframeContainer* fkc =
dynamic_cast<osgAnimation::FloatKeyframeContainer*>(pKeyframeContainer))
{
for (size_t i = 0; i < fkc->size(); ++i)
{
osgAnimation::FloatKeyframe& fk = (*fkc)[i];
fk.setValue(osg::DegreesToRadians(fk.getValue()));
}
}
else if (osgAnimation::FloatCubicBezierKeyframeContainer* fcbkc =
dynamic_cast<osgAnimation::FloatCubicBezierKeyframeContainer*>(pKeyframeContainer))
{
for (size_t i = 0; i < fcbkc->size(); ++i)
{
osgAnimation::FloatCubicBezierKeyframe& fcbk = (*fcbkc)[i];
osgAnimation::FloatCubicBezier fcb = fcbk.getValue();
fcb.setPosition(osg::DegreesToRadians(fcb.getPosition()));
fcb.setControlPointIn(osg::DegreesToRadians(fcb.getControlPointIn()));
fcb.setControlPointOut(osg::DegreesToRadians(fcb.getControlPointOut()));
fcbk.setValue(fcb);
}
}
else
{
OSG_WARN << "Warning: rotation keyframes not converted to radians." << std::endl;
}
}
// Channel connects animation output to parameter to animate
// <channel>
// 1 source
// 1 target
void daeReader::processChannel(domChannel* pDomChannel, SourceMap& sources, TargetChannelPartMap& tcm)
{
domSampler *pDomSampler = daeSafeCast<domSampler>(getElementFromURI(pDomChannel->getSource()));
if (pDomSampler)
{
ChannelPart* pChannelPart = processSampler(pDomChannel, sources);
if (pChannelPart)
{
domChannelOsgAnimationUpdateCallbackMap::iterator iter = _domChannelOsgAnimationUpdateCallbackMap.find(pDomChannel);
if (iter != _domChannelOsgAnimationUpdateCallbackMap.end())
{
osg::NodeCallback* nc = iter->second.get();
std::string channelName, targetName, componentName;
extractTargetName(pDomChannel->getTarget(), channelName, targetName, componentName);
//assert(targetName == nc->getName());
bool bRotationChannel = false;
if (osgAnimation::Target* pTarget = findChannelTarget(nc, channelName, bRotationChannel))
{
if (bRotationChannel)
{
convertDegreesToRadians(pChannelPart->keyframes.get());
}
tcm.insert(TargetChannelPartMap::value_type(pTarget, pChannelPart));
}
else
{
OSG_WARN << "Target \"" << channelName << "\" not found." << std::endl;
}
}
else
{
OSG_WARN << "Could not locate UpdateCallback for <channel> target " << pDomChannel->getTarget()<< std::endl;
}
}
else
{
OSG_WARN << "<channel> source " << pDomChannel->getSource().getURI() << " has no corresponding osgAnimation::Channel" << std::endl;
}
}
else
{
OSG_WARN << "Could not locate <channel> source " << pDomChannel->getSource().getURI() << std::endl;
}
}
void daeReader::extractTargetName(const std::string& daeTarget, std::string& channelName, std::string& targetName, std::string& component)
{
size_t slash = daeTarget.find_last_of("/");
if (slash != std::string::npos)
{
// Handle /translation
targetName = daeTarget.substr(0, slash);
channelName = daeTarget.substr(slash+1, std::string::npos);
}
else
{
size_t parenthesis = daeTarget.find_last_of("(");
size_t endpos = daeTarget.find_last_of(")");
if (parenthesis != std::string::npos && endpos != std::string::npos)
{
// Handle (1)
targetName = daeTarget.substr(0, parenthesis);
channelName = daeTarget.substr(parenthesis+1, endpos - parenthesis - 1);
}
else
{
OSG_WARN << "Couldn't extract a proper name for <channel> target " << daeTarget << std::endl;
}
}
size_t period = channelName.find_last_of(".");
if (period != std::string::npos)
{
component = channelName.substr(period+1, std::string::npos);
channelName = channelName.substr(0, period);
}
else
{
component.clear();
size_t first_parenthesis = channelName.find_first_of("(");
if (first_parenthesis != std::string::npos)
{
size_t open_parenthesis = first_parenthesis;
do
{
if (open_parenthesis != first_parenthesis) component += ",";
size_t close_parenthesis = channelName.find_first_of(")", open_parenthesis);
component += channelName.substr(open_parenthesis+1, close_parenthesis-open_parenthesis-1);
open_parenthesis = channelName.find_first_of("(", close_parenthesis);
}
while (open_parenthesis != std::string::npos);
channelName = channelName.substr(0, first_parenthesis);
}
}
}