From Cedric Pinson, Pulled in osgAnimation from OpenSceneGraph-osgWidget-dev into svn/trunk.
This commit is contained in:
@@ -6,14 +6,15 @@ FOREACH( mylibfolder
|
||||
osgUtil
|
||||
osgGA
|
||||
osgText
|
||||
osgManipulator
|
||||
osgSim
|
||||
osgViewer
|
||||
osgAnimation
|
||||
osgFX
|
||||
osgManipulator
|
||||
osgParticle
|
||||
osgShadow
|
||||
osgSim
|
||||
osgTerrain
|
||||
osgVolume
|
||||
osgViewer
|
||||
)
|
||||
|
||||
ADD_SUBDIRECTORY(${mylibfolder})
|
||||
|
||||
147
src/osgAnimation/Animation.cpp
Normal file
147
src/osgAnimation/Animation.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgAnimation/Animation>
|
||||
|
||||
using namespace osgAnimation;
|
||||
|
||||
Animation::Animation(const osgAnimation::Animation& anim, const osg::CopyOp& c)
|
||||
{
|
||||
_duration = anim._duration;
|
||||
_originalDuration = anim._originalDuration;
|
||||
_weight = anim._weight;
|
||||
_startTime = anim._startTime;
|
||||
_playmode = anim._playmode;
|
||||
}
|
||||
|
||||
|
||||
void Animation::addChannel(Channel* pChannel)
|
||||
{
|
||||
_channels.push_back(pChannel);
|
||||
if (!_duration)
|
||||
computeDuration();
|
||||
else
|
||||
_originalDuration = computeDurationFromChannels();
|
||||
}
|
||||
|
||||
double Animation::computeDurationFromChannels() const
|
||||
{
|
||||
double tmin = 1e5;
|
||||
double tmax = -1e5;
|
||||
ChannelList::const_iterator chan;
|
||||
for( chan=_channels.begin(); chan!=_channels.end(); chan++ )
|
||||
{
|
||||
float min = (*chan)->getStartTime();
|
||||
if (min < tmin)
|
||||
tmin = min;
|
||||
float max = (*chan)->getEndTime();
|
||||
if (max > tmax)
|
||||
tmax = max;
|
||||
}
|
||||
return tmax-tmin;
|
||||
}
|
||||
|
||||
void Animation::computeDuration()
|
||||
{
|
||||
_duration = computeDurationFromChannels();
|
||||
_originalDuration = _duration;
|
||||
}
|
||||
|
||||
osgAnimation::ChannelList& Animation::getChannels()
|
||||
{
|
||||
return _channels;
|
||||
}
|
||||
|
||||
const osgAnimation::ChannelList& Animation::getChannels() const
|
||||
{
|
||||
return _channels;
|
||||
}
|
||||
|
||||
|
||||
void Animation::setDuration(double duration)
|
||||
{
|
||||
_originalDuration = computeDurationFromChannels();
|
||||
_duration = duration;
|
||||
}
|
||||
|
||||
float Animation::getDuration() const
|
||||
{
|
||||
return _duration;
|
||||
}
|
||||
|
||||
float Animation::getWeight () const
|
||||
{
|
||||
return _weight;
|
||||
}
|
||||
|
||||
void Animation::setWeight (float weight)
|
||||
{
|
||||
_weight = weight;
|
||||
}
|
||||
|
||||
bool Animation::update (float time)
|
||||
{
|
||||
if (!_duration) // if not initialized then do it
|
||||
computeDuration();
|
||||
|
||||
double ratio = _originalDuration / _duration;
|
||||
|
||||
float t = (time - _startTime) * ratio;
|
||||
switch (_playmode)
|
||||
{
|
||||
case ONCE:
|
||||
if (t > _duration)
|
||||
return false;
|
||||
break;
|
||||
case STAY:
|
||||
if (t > _duration)
|
||||
t = _duration;
|
||||
break;
|
||||
case LOOP:
|
||||
if (!_duration)
|
||||
t = _startTime;
|
||||
else if (t > _duration)
|
||||
t = fmodf(t, _duration);
|
||||
// std::cout << "t " << t << " duration " << _duration << std::endl;
|
||||
break;
|
||||
case PPONG:
|
||||
if (!_duration)
|
||||
t = _startTime;
|
||||
else
|
||||
{
|
||||
int tt = (int) (t / _duration);
|
||||
t = fmodf(t, _duration);
|
||||
if (tt%2)
|
||||
t = _duration - t;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// std::cout << "t " << t << " / " << _duration << std::endl;
|
||||
|
||||
ChannelList::const_iterator chan;
|
||||
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
|
||||
{
|
||||
(*chan)->setWeight(_weight);
|
||||
(*chan)->update(t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Animation::resetTargets()
|
||||
{
|
||||
ChannelList::const_iterator chan;
|
||||
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
|
||||
(*chan)->reset();
|
||||
}
|
||||
141
src/osgAnimation/AnimationManager.cpp
Normal file
141
src/osgAnimation/AnimationManager.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgAnimation/AnimationManager>
|
||||
#include <osgAnimation/LinkVisitor>
|
||||
#include <osgAnimation/Assert>
|
||||
|
||||
using namespace osgAnimation;
|
||||
|
||||
|
||||
AnimationManager::~AnimationManager() {}
|
||||
|
||||
|
||||
void AnimationManager::stopAll()
|
||||
{
|
||||
// loop over all playing animation
|
||||
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
|
||||
{
|
||||
AnimationList& list = iterAnim->second;
|
||||
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
|
||||
(*it)->resetTargets();
|
||||
}
|
||||
_animationsPlaying.clear();
|
||||
}
|
||||
|
||||
AnimationManager::AnimationManager()
|
||||
{
|
||||
_lastUpdate = 0;
|
||||
}
|
||||
void AnimationManager::playAnimation(Animation* pAnimation, int priority, float weight)
|
||||
{
|
||||
bool r = findAnimation(pAnimation);
|
||||
OSGANIMATION_ASSERT(r && "This animation is not registered");
|
||||
|
||||
if ( isPlaying(pAnimation) )
|
||||
stopAnimation(pAnimation);
|
||||
|
||||
_animationsPlaying[priority].push_back(pAnimation);
|
||||
pAnimation->setStartTime(_lastUpdate);
|
||||
pAnimation->setWeight(weight);
|
||||
}
|
||||
|
||||
bool AnimationManager::stopAnimation(Animation* pAnimation)
|
||||
{
|
||||
// search though the layer and remove animation
|
||||
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
|
||||
{
|
||||
AnimationList& list = iterAnim->second;
|
||||
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
|
||||
if( (*it) == pAnimation )
|
||||
{
|
||||
(*it)->resetTargets();
|
||||
list.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void AnimationManager::update (double time)
|
||||
{
|
||||
if (!_lastUpdate)
|
||||
_lastUpdate = time;
|
||||
|
||||
// could filtered with an active flag
|
||||
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
|
||||
(*it).get()->reset();
|
||||
|
||||
|
||||
// update from high priority to low priority
|
||||
for( AnimationLayers::reverse_iterator iterAnim = _animationsPlaying.rbegin(); iterAnim != _animationsPlaying.rend(); ++iterAnim )
|
||||
{
|
||||
// update all animation
|
||||
std::vector<int> toremove;
|
||||
AnimationList& list = iterAnim->second;
|
||||
for (unsigned int i = 0; i < list.size(); i++)
|
||||
{
|
||||
if (! list[i]->update(time))
|
||||
toremove.push_back(i);
|
||||
}
|
||||
|
||||
// remove finished animation
|
||||
while (!toremove.empty())
|
||||
{
|
||||
list.erase(list.begin() + toremove.back());
|
||||
toremove.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
|
||||
(*it).get()->normalize();
|
||||
}
|
||||
|
||||
|
||||
bool AnimationManager::findAnimation(Animation* pAnimation)
|
||||
{
|
||||
for( AnimationList::const_iterator iterAnim = _animations.begin(); iterAnim != _animations.end(); ++iterAnim )
|
||||
{
|
||||
if ( (*iterAnim) == pAnimation )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool AnimationManager::isPlaying(Animation* pAnimation)
|
||||
{
|
||||
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
|
||||
{
|
||||
AnimationList& list = iterAnim->second;
|
||||
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
|
||||
if ( (*it) == pAnimation )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AnimationManager::isPlaying(const std::string& name)
|
||||
{
|
||||
// loop over all playing animation
|
||||
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
|
||||
{
|
||||
AnimationList& list = iterAnim->second;
|
||||
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
|
||||
if ( (*it)->getName() == name )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
71
src/osgAnimation/AnimationManagerBase.cpp
Normal file
71
src/osgAnimation/AnimationManagerBase.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgAnimation/AnimationManagerBase>
|
||||
#include <osgAnimation/LinkVisitor>
|
||||
#include <osgAnimation/Assert>
|
||||
|
||||
using namespace osgAnimation;
|
||||
|
||||
|
||||
AnimationManagerBase::~AnimationManagerBase() {}
|
||||
|
||||
AnimationManagerBase::AnimationManagerBase()
|
||||
{
|
||||
setUpdateCallback(new UpdateCallback);
|
||||
_needToLink = false;
|
||||
}
|
||||
|
||||
void AnimationManagerBase::buildTargetReference()
|
||||
{
|
||||
_targets.clear();
|
||||
for( AnimationList::iterator iterAnim = _animations.begin(); iterAnim != _animations.end(); ++iterAnim )
|
||||
{
|
||||
Animation* anim = (*iterAnim).get();
|
||||
for (ChannelList::iterator it = anim->getChannels().begin();
|
||||
it != anim->getChannels().end();
|
||||
it++)
|
||||
_targets.insert((*it)->getTarget());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AnimationManagerBase::registerAnimation (Animation* animation)
|
||||
{
|
||||
_needToLink = true;
|
||||
_animations.push_back(animation);
|
||||
buildTargetReference();
|
||||
}
|
||||
|
||||
bool AnimationManagerBase::needToLink() const { return _needToLink; }
|
||||
|
||||
|
||||
|
||||
void AnimationManagerBase::link()
|
||||
{
|
||||
LinkVisitor linker(_animations);
|
||||
accept(linker);
|
||||
_needToLink = false;
|
||||
buildTargetReference();
|
||||
}
|
||||
|
||||
|
||||
osgAnimation::AnimationMap AnimationManagerBase::getAnimationMap() const
|
||||
{
|
||||
osgAnimation::AnimationMap map;
|
||||
for (AnimationList::const_iterator it = _animations.begin(); it != _animations.end(); it++)
|
||||
map[(*it)->getName()] = *it;
|
||||
return map;
|
||||
}
|
||||
|
||||
104
src/osgAnimation/Bone.cpp
Normal file
104
src/osgAnimation/Bone.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgAnimation/Skinning>
|
||||
#include <osgAnimation/Bone>
|
||||
#include <osgAnimation/Skeleton>
|
||||
|
||||
osgAnimation::Bone::UpdateBone::UpdateBone(const osgAnimation::Bone::UpdateBone& apc,const osg::CopyOp& copyop):
|
||||
osgAnimation::AnimationUpdateCallback(apc, copyop),
|
||||
_position(apc._position),
|
||||
_quaternion(apc._quaternion),
|
||||
_scale(apc._scale)
|
||||
{
|
||||
}
|
||||
|
||||
void osgAnimation::Bone::computeBindMatrix()
|
||||
{
|
||||
_invBindInSkeletonSpace = osg::Matrix::inverse(_bindInBoneSpace);
|
||||
const Bone* parent = getBoneParent();
|
||||
_needToRecomputeBindMatrix = false;
|
||||
if (!parent)
|
||||
{
|
||||
#if 0
|
||||
// no more parent means, we get the skeleton
|
||||
if (getParents().empty()) {
|
||||
osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you should not have this message, it means you miss to attach this bone(" << getName() <<") to a Skeleton node" << std::endl;
|
||||
return;
|
||||
} else if (getParents().size() > 1) {
|
||||
osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you have more than one parent in a skeleton structure (" << getName() <<") unknown behaviour" << std::endl;
|
||||
return;
|
||||
}
|
||||
osgAnimation::Skeleton* skel = dynamic_cast<osgAnimation::Skeleton*>(getParents()[0]);
|
||||
if (!skel) {
|
||||
osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you should not have this message, it means you miss to attach this bone(" << getName() <<") to a Skeleton node" << std::endl;
|
||||
return;
|
||||
}
|
||||
_invBindInSkeletonSpace = osg::Matrix::inverse(skel->getMatrix()) * _invBindInSkeletonSpace;
|
||||
#else
|
||||
osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you should not have this message, it means you miss to attach this bone(" << getName() <<") to a Skeleton node" << std::endl;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
_invBindInSkeletonSpace = parent->getInvBindMatrixInSkeletonSpace() * _invBindInSkeletonSpace;
|
||||
}
|
||||
|
||||
osgAnimation::Bone* osgAnimation::Bone::getBoneParent()
|
||||
{
|
||||
if (getParents().empty())
|
||||
return 0;
|
||||
osg::Node::ParentList parents = getParents();
|
||||
for (osg::Node::ParentList::iterator it = parents.begin(); it != parents.end(); it++)
|
||||
{
|
||||
Bone* pb = dynamic_cast<Bone*>(*it);
|
||||
if (pb)
|
||||
return pb;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const osgAnimation::Bone* osgAnimation::Bone::getBoneParent() const
|
||||
{
|
||||
if (getParents().empty())
|
||||
return 0;
|
||||
const osg::Node::ParentList& parents = getParents();
|
||||
for (osg::Node::ParentList::const_iterator it = parents.begin(); it != parents.end(); it++)
|
||||
{
|
||||
const Bone* pb = dynamic_cast<const Bone*>(*it);
|
||||
if (pb)
|
||||
return pb;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Add Node to Group.
|
||||
* If node is not NULL and is not contained in Group then increment its
|
||||
* reference count, add it to the child list and dirty the bounding
|
||||
* sphere to force it to recompute on next getBound() and return true for success.
|
||||
* Otherwise return false. Scene nodes can't be added as child nodes.
|
||||
*/
|
||||
bool osgAnimation::Bone::addChild( Node *child )
|
||||
{
|
||||
Bone* bone = dynamic_cast<Bone*>(child);
|
||||
if (bone)
|
||||
bone->setNeedToComputeBindMatrix(true);
|
||||
return osg::Group::addChild(child);
|
||||
}
|
||||
|
||||
osgAnimation::Bone::BoneMap osgAnimation::Bone::getBoneMap()
|
||||
{
|
||||
BoneMapVisitor mapVisitor;
|
||||
this->accept(mapVisitor);
|
||||
return mapVisitor._map;
|
||||
}
|
||||
56
src/osgAnimation/CMakeLists.txt
Normal file
56
src/osgAnimation/CMakeLists.txt
Normal file
@@ -0,0 +1,56 @@
|
||||
|
||||
IF (DYNAMIC_OPENSCENEGRAPH)
|
||||
ADD_DEFINITIONS(-DOSGANIMATION_LIBRARY)
|
||||
ELSE (DYNAMIC_OPENSCENEGRAPH)
|
||||
ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC)
|
||||
ENDIF(DYNAMIC_OPENSCENEGRAPH)
|
||||
|
||||
SET(LIB_NAME osgAnimation)
|
||||
|
||||
|
||||
SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME})
|
||||
SET(LIB_PUBLIC_HEADERS
|
||||
${HEADER_PATH}/Export
|
||||
${HEADER_PATH}/Bone
|
||||
${HEADER_PATH}/Skeleton
|
||||
${HEADER_PATH}/Channel
|
||||
${HEADER_PATH}/Sampler
|
||||
${HEADER_PATH}/Interpolator
|
||||
${HEADER_PATH}/Target
|
||||
${HEADER_PATH}/Animation
|
||||
${HEADER_PATH}/Keyframe
|
||||
${HEADER_PATH}/Skinning
|
||||
${HEADER_PATH}/CubicBezier
|
||||
${HEADER_PATH}/Vec3Packed
|
||||
${HEADER_PATH}/AnimationManager
|
||||
${HEADER_PATH}/AnimationManagerBase
|
||||
${HEADER_PATH}/UpdateCallback
|
||||
${HEADER_PATH}/LinkVisitor
|
||||
${HEADER_PATH}/VertexInfluence
|
||||
${HEADER_PATH}/EaseMotion
|
||||
${HEADER_PATH}/Assert
|
||||
${HEADER_PATH}/Timeline
|
||||
)
|
||||
|
||||
|
||||
ADD_LIBRARY(${LIB_NAME}
|
||||
${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC}
|
||||
${LIB_PUBLIC_HEADERS}
|
||||
Channel.cpp
|
||||
Target.cpp
|
||||
Animation.cpp
|
||||
Bone.cpp
|
||||
RigGeometry.cpp
|
||||
AnimationManager.cpp
|
||||
AnimationManagerBase.cpp
|
||||
Skeleton.cpp
|
||||
VertexInfluence.cpp
|
||||
UpdateCallback.cpp
|
||||
Timeline.cpp
|
||||
)
|
||||
|
||||
LINK_INTERNAL(${LIB_NAME}
|
||||
osg
|
||||
)
|
||||
LINK_CORELIB_DEFAULT(${LIB_NAME})
|
||||
INCLUDE(ModuleInstall OPTIONAL)
|
||||
29
src/osgAnimation/Channel.cpp
Normal file
29
src/osgAnimation/Channel.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgAnimation/Channel>
|
||||
using namespace osgAnimation;
|
||||
|
||||
Channel::Channel() { _weight=1; }
|
||||
Channel::~Channel() {}
|
||||
|
||||
const std::string& Channel::getName() const { return _name; }
|
||||
void Channel::setName (const std::string& name) { _name = name; }
|
||||
|
||||
const std::string& Channel::getTargetName() const { return _targetName;}
|
||||
void Channel::setTargetName (const std::string& name) { _targetName = name; }
|
||||
|
||||
float Channel::getWeight() const { return _weight;}
|
||||
void Channel::setWeight(float w) { _weight = w;}
|
||||
|
||||
93
src/osgAnimation/RigGeometry.cpp
Normal file
93
src/osgAnimation/RigGeometry.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Authors:
|
||||
*
|
||||
* Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
*/
|
||||
#include <osgAnimation/RigGeometry>
|
||||
|
||||
void osgAnimation::RigGeometry::buildTransformer(Skeleton* root)
|
||||
{
|
||||
Bone::BoneMap bm = root->getBoneMap();
|
||||
_transformVertexes.init(bm, _vertexInfluenceSet.getUniqVertexSetToBoneSetList());
|
||||
_root = root;
|
||||
}
|
||||
|
||||
void osgAnimation::RigGeometry::buildVertexSet()
|
||||
{
|
||||
if (!_vertexInfluenceMap.valid())
|
||||
{
|
||||
osg::notify(osg::WARN) << "buildVertexSet can't be called without VertexInfluence already set to the RigGeometry ( " << getName() << " ) " << std::endl;
|
||||
return;
|
||||
}
|
||||
_vertexInfluenceSet.clear();
|
||||
for (osgAnimation::VertexInfluenceMap::iterator it = _vertexInfluenceMap->begin();
|
||||
it != _vertexInfluenceMap->end();
|
||||
it++)
|
||||
_vertexInfluenceSet.addVertexInfluence(it->second);
|
||||
|
||||
_vertexInfluenceSet.buildVertex2BoneList();
|
||||
_vertexInfluenceSet.buildUniqVertexSetToBoneSetList();
|
||||
std::cout << "uniq groups " << _vertexInfluenceSet.getUniqVertexSetToBoneSetList().size() << " for " << getName() << std::endl;
|
||||
}
|
||||
|
||||
void osgAnimation::RigGeometry::computeMatrixFromRootSkeleton()
|
||||
{
|
||||
if (!_root.valid())
|
||||
{
|
||||
osg::notify(osg::WARN) << "Warning " << className() <<"::computeMatrixFromRootSkeleton if you have this message it means you miss to call buildTransformer(Skeleton* root), or your RigGeometry (" << getName() <<") is not attached to a Skeleton subgraph" << std::endl;
|
||||
return;
|
||||
}
|
||||
osg::MatrixList mtxList = getParent(0)->getWorldMatrices(_root.get());
|
||||
_matrixFromSkeletonToGeometry = mtxList[0];
|
||||
_invMatrixFromSkeletonToGeometry = osg::Matrix::inverse(_matrixFromSkeletonToGeometry);
|
||||
_needToComputeMatrix = false;
|
||||
}
|
||||
|
||||
void osgAnimation::RigGeometry::transformSoftwareMethod()
|
||||
{
|
||||
// std::cout << getName() << " _matrixFromSkeletonToGeometry" << _matrixFromSkeletonToGeometry << std::endl;
|
||||
osg::Vec3Array* pos = dynamic_cast<osg::Vec3Array*>(getVertexArray());
|
||||
if (pos && _positionSource.size() != pos->size())
|
||||
{
|
||||
_positionSource = std::vector<osg::Vec3>(pos->begin(),pos->end());
|
||||
getVertexArray()->setDataVariance(osg::Object::DYNAMIC);
|
||||
}
|
||||
osg::Vec3Array* normal = dynamic_cast<osg::Vec3Array*>(getNormalArray());
|
||||
if (normal && _normalSource.size() != normal->size())
|
||||
{
|
||||
_normalSource = std::vector<osg::Vec3>(normal->begin(),normal->end());
|
||||
getNormalArray()->setDataVariance(osg::Object::DYNAMIC);
|
||||
}
|
||||
|
||||
if (!_positionSource.empty())
|
||||
{
|
||||
_transformVertexes.compute<osg::Vec3>(_matrixFromSkeletonToGeometry, _invMatrixFromSkeletonToGeometry, &_positionSource.front(), &pos->front());
|
||||
pos->dirty();
|
||||
}
|
||||
if (!_normalSource.empty())
|
||||
{
|
||||
_transformVertexes.compute<osg::Vec3>(_matrixFromSkeletonToGeometry, _invMatrixFromSkeletonToGeometry, &_normalSource.front(), &normal->front());
|
||||
normal->dirty();
|
||||
}
|
||||
dirtyBound();
|
||||
}
|
||||
|
||||
const osgAnimation::Skeleton* osgAnimation::RigGeometry::getSkeleton() const { return _root.get(); }
|
||||
osgAnimation::Skeleton* osgAnimation::RigGeometry::getSkeleton() { return _root.get(); }
|
||||
94
src/osgAnimation/Skeleton.cpp
Normal file
94
src/osgAnimation/Skeleton.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgAnimation/Skeleton>
|
||||
#include <osgAnimation/Bone>
|
||||
|
||||
using namespace osgAnimation;
|
||||
|
||||
struct computeBindMatrixVisitor : public osg::NodeVisitor
|
||||
{
|
||||
osg::Matrix _skeleton;
|
||||
computeBindMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
|
||||
void apply(osg::Node& node) { return ;}
|
||||
void apply(osg::Transform& node)
|
||||
{
|
||||
Bone* bone = dynamic_cast<Bone*>(&node);
|
||||
if (!bone)
|
||||
return;
|
||||
bone->computeBindMatrix();
|
||||
traverse(node);
|
||||
}
|
||||
};
|
||||
|
||||
struct updateMatrixVisitor : public osg::NodeVisitor
|
||||
{
|
||||
osg::Matrix _skeleton;
|
||||
updateMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
|
||||
void apply(osg::Node& node) { return ;}
|
||||
void apply(osg::Transform& node)
|
||||
{
|
||||
// the idea is to traverse the skeleton or bone but to stop if other node is found
|
||||
Bone* bone = dynamic_cast<Bone*>(&node);
|
||||
if (!bone)
|
||||
return;
|
||||
|
||||
Bone* parent = bone->getBoneParent();
|
||||
if (bone->needToComputeBindMatrix())
|
||||
{
|
||||
computeBindMatrixVisitor visitor;
|
||||
bone->accept(visitor);
|
||||
}
|
||||
|
||||
if (parent)
|
||||
bone->_boneInSkeletonSpace = bone->getMatrixInBoneSpace() * bone->getBoneParent()->getMatrixInSkeletonSpace();
|
||||
else
|
||||
bone->_boneInSkeletonSpace = bone->getMatrixInBoneSpace();// * _skeleton;
|
||||
|
||||
traverse(node);
|
||||
}
|
||||
};
|
||||
|
||||
void Skeleton::UpdateCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
|
||||
{
|
||||
Skeleton* b = dynamic_cast<Skeleton*>(node);
|
||||
if (b)
|
||||
{
|
||||
// apply the updater only on the root bone, The udpateMatrixVisitor will
|
||||
// traverse only bone and will update only bone. Then we continu on the classic
|
||||
// process. It's important to update Bone before other things because the update
|
||||
// of RigGeometry need it
|
||||
updateMatrixVisitor visitor;
|
||||
#if 0
|
||||
visitor._skeleton = b->getMatrix();
|
||||
int numChildren = b->getNumChildren();
|
||||
for (int i = 0; i < numChildren; i++)
|
||||
{
|
||||
b->getChild(i)->accept(visitor);
|
||||
}
|
||||
#else
|
||||
b->accept(visitor);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
traverse(node,nv);
|
||||
}
|
||||
|
||||
|
||||
Skeleton::Skeleton()
|
||||
{
|
||||
setUpdateCallback(new UpdateCallback());
|
||||
}
|
||||
22
src/osgAnimation/Target.cpp
Normal file
22
src/osgAnimation/Target.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include <osgAnimation/Target>
|
||||
#include <osgAnimation/Channel>
|
||||
|
||||
using namespace osgAnimation;
|
||||
|
||||
Target::Target() { reset();}
|
||||
Target::~Target() {}
|
||||
49
src/osgAnimation/Timeline.cpp
Normal file
49
src/osgAnimation/Timeline.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgAnimation/Timeline>
|
||||
|
||||
using namespace osgAnimation;
|
||||
|
||||
// temporary
|
||||
// the problem comes that the AnimationManagerBase should only a group
|
||||
// and it's data should be in an update callback
|
||||
struct TimelineAdaptator : public Timeline
|
||||
{
|
||||
osg::ref_ptr<AnimationManagerTimeline> _manager;
|
||||
|
||||
TimelineAdaptator(AnimationManagerTimeline* manager) : _manager(manager) {}
|
||||
void evaluate(unsigned int frame)
|
||||
{
|
||||
_manager->clearTargets();
|
||||
Timeline::evaluate(frame);
|
||||
_manager->normalizeTargets();
|
||||
}
|
||||
};
|
||||
|
||||
AnimationManagerTimeline::AnimationManagerTimeline()
|
||||
{
|
||||
_timeline = new TimelineAdaptator(this);
|
||||
}
|
||||
|
||||
AnimationManagerTimeline::AnimationManagerTimeline(const AnimationManagerBase& manager) : AnimationManagerBase(manager)
|
||||
{
|
||||
_timeline = new TimelineAdaptator(this);
|
||||
}
|
||||
|
||||
void AnimationManagerTimeline::update(double time)
|
||||
{
|
||||
_timeline->update(time);
|
||||
}
|
||||
|
||||
170
src/osgAnimation/UpdateCallback.cpp
Normal file
170
src/osgAnimation/UpdateCallback.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgAnimation/UpdateCallback>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
using namespace osgAnimation;
|
||||
|
||||
osgAnimation::AnimationManagerBase* AnimationUpdateCallback::getAnimationManager() { return _manager.get(); }
|
||||
|
||||
AnimationUpdateCallback::AnimationUpdateCallback(const AnimationUpdateCallback& apc,const osg::CopyOp& copyop):
|
||||
osg::NodeCallback(apc, copyop),
|
||||
_manager(apc._manager) {}
|
||||
|
||||
int AnimationUpdateCallback::link(osgAnimation::Animation* animation)
|
||||
{
|
||||
int nbLinks = 0;
|
||||
for (osgAnimation::ChannelList::iterator it = animation->getChannels().begin();
|
||||
it != animation->getChannels().end();
|
||||
it++)
|
||||
{
|
||||
std::string targetName = (*it)->getTargetName();
|
||||
if (targetName == getName())
|
||||
{
|
||||
link((*it).get());
|
||||
nbLinks++;
|
||||
}
|
||||
}
|
||||
return nbLinks;
|
||||
}
|
||||
|
||||
void AnimationUpdateCallback::updateLink()
|
||||
{
|
||||
if (_manager.valid())
|
||||
{
|
||||
if (needLink())
|
||||
{
|
||||
/** this item is not linked yet then we do it for all animation
|
||||
registered in the manager.
|
||||
Maybe this function should be on the manager side like
|
||||
_manager->linkItem(Bone);
|
||||
*/
|
||||
AnimationMap map = _manager->getAnimationMap();
|
||||
for (AnimationMap::iterator it = map.begin(); it != map.end(); it++)
|
||||
link(it->second.get());
|
||||
_manager->buildTargetReference();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
UpdateTransform::UpdateTransform(const UpdateTransform& apc,const osg::CopyOp& copyop)
|
||||
: AnimationUpdateCallback(apc, copyop),
|
||||
_euler(apc._euler),
|
||||
_position(apc._position),
|
||||
_scale(apc._scale)
|
||||
{
|
||||
}
|
||||
|
||||
UpdateTransform::UpdateTransform(const std::string& name) : AnimationUpdateCallback(name)
|
||||
{
|
||||
_euler = new osgAnimation::Vec3Target;
|
||||
_position = new osgAnimation::Vec3Target;
|
||||
_scale = new osgAnimation::Vec3Target(osg::Vec3(1,1,1));
|
||||
}
|
||||
|
||||
/** Callback method called by the NodeVisitor when visiting a node.*/
|
||||
void UpdateTransform::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
|
||||
{
|
||||
osg::MatrixTransform* matrix = dynamic_cast<osg::MatrixTransform*>(node);
|
||||
if (matrix)
|
||||
{
|
||||
update(*matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::PositionAttitudeTransform* pat = dynamic_cast<osg::PositionAttitudeTransform*>(node);
|
||||
if (pat)
|
||||
update(*pat);
|
||||
}
|
||||
}
|
||||
traverse(node,nv);
|
||||
}
|
||||
|
||||
void UpdateTransform::update(osg::MatrixTransform& mat)
|
||||
{
|
||||
float z = _euler->getValue()[2];
|
||||
float x = _euler->getValue()[0];
|
||||
float y = _euler->getValue()[1];
|
||||
osg::Matrix m =
|
||||
osg::Matrix::rotate(x,1.0,0.0,0.0) *
|
||||
osg::Matrix::rotate(y,0.0,1.0,0.0) *
|
||||
osg::Matrix::rotate(z,0.0,0.0,1.0);
|
||||
mat.setMatrix(osg::Matrix::scale(_scale->getValue()) *
|
||||
m *
|
||||
osg::Matrix::translate(_position->getValue()));
|
||||
mat.dirtyBound();
|
||||
}
|
||||
|
||||
void UpdateTransform::update(osg::PositionAttitudeTransform& pat)
|
||||
{
|
||||
float heading = _euler->getValue()[0];
|
||||
float pitch = _euler->getValue()[1];
|
||||
float roll = _euler->getValue()[2];
|
||||
osg::Matrix m = osg::Matrix::rotate(roll,0.0,1.0,0.0) * osg::Matrix::rotate(pitch,1.0,0.0,0.0) * osg::Matrix::rotate(-heading,0.0,0.0,1.0);
|
||||
osg::Quat q = m.getRotate();
|
||||
|
||||
pat.setPosition(_position->getValue());
|
||||
pat.setScale(_scale->getValue());
|
||||
pat.setAttitude(q);
|
||||
pat.dirtyBound();
|
||||
}
|
||||
|
||||
bool UpdateTransform::needLink() const
|
||||
{
|
||||
// the idea is to return true if nothing is linked
|
||||
return !((_position->getCount() + _euler->getCount() + _scale->getCount()) > 3);
|
||||
}
|
||||
|
||||
bool UpdateTransform::link(osgAnimation::Channel* channel)
|
||||
{
|
||||
if (channel->getName().find("euler") != std::string::npos)
|
||||
{
|
||||
osgAnimation::Vec3LinearChannel* qc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
|
||||
if (qc)
|
||||
{
|
||||
qc->setTarget(_euler.get());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (channel->getName().find("position") != std::string::npos)
|
||||
{
|
||||
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
|
||||
if (vc)
|
||||
{
|
||||
vc->setTarget(_position.get());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (channel->getName().find("scale") != std::string::npos)
|
||||
{
|
||||
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
|
||||
if (vc)
|
||||
{
|
||||
vc->setTarget(_scale.get());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
130
src/osgAnimation/VertexInfluence.cpp
Normal file
130
src/osgAnimation/VertexInfluence.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgAnimation/VertexInfluence>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace osgAnimation;
|
||||
|
||||
// this class manage VertexInfluence database by mesh
|
||||
// reference bones per vertex ...
|
||||
void osgAnimation::VertexInfluenceSet::buildVertex2BoneList()
|
||||
{
|
||||
_vertex2Bones.clear();
|
||||
for (BoneToVertexList::const_iterator it = _bone2Vertexes.begin(); it != _bone2Vertexes.end(); it++)
|
||||
{
|
||||
const VertexInfluence& vi = (*it);
|
||||
int size = vi.size();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
VertexIndexWeight viw = vi[i];
|
||||
int index = viw.first;
|
||||
float weight = viw.second;
|
||||
if (vi.getName().empty())
|
||||
std::cout << "osgAnimation::VertexInfluenceSet::buildVertex2BoneList warning vertex " << index << " is not assigned to a bone" << std::endl;
|
||||
_vertex2Bones[index].push_back(BoneWeight(vi.getName(), weight));
|
||||
}
|
||||
}
|
||||
|
||||
// normalize weight per vertex
|
||||
for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); it++)
|
||||
{
|
||||
BoneWeightList& bones = it->second;
|
||||
int size = bones.size();
|
||||
float sum = 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
sum += bones[i].getWeight();
|
||||
if (sum < 1e-4)
|
||||
{
|
||||
std::cerr << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << it->first << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
float mult = 1.0/sum;
|
||||
for (int i = 0; i < size; i++)
|
||||
bones[i].setWeight(bones[i].getWeight() * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// sort by name and weight
|
||||
struct SortByNameAndWeight : public std::less<osgAnimation::VertexInfluenceSet::BoneWeight>
|
||||
{
|
||||
bool operator()(const osgAnimation::VertexInfluenceSet::BoneWeight& b0,
|
||||
const osgAnimation::VertexInfluenceSet::BoneWeight& b1) const
|
||||
{
|
||||
if (b0.getBoneName() < b1.getBoneName())
|
||||
return true;
|
||||
else if (b0.getBoneName() > b1.getBoneName())
|
||||
return false;
|
||||
if (b0.getWeight() < b1.getWeight())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct SortByBoneWeightList : public std::less<osgAnimation::VertexInfluenceSet::BoneWeightList>
|
||||
{
|
||||
bool operator()(const osgAnimation::VertexInfluenceSet::BoneWeightList& b0,
|
||||
const osgAnimation::VertexInfluenceSet::BoneWeightList& b1) const
|
||||
{
|
||||
if (b0.size() < b1.size())
|
||||
return true;
|
||||
else if (b0.size() > b1.size())
|
||||
return false;
|
||||
|
||||
int size = b0.size();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
bool result = SortByNameAndWeight()(b0[i], b1[i]);
|
||||
if (result)
|
||||
return true;
|
||||
else if (SortByNameAndWeight()(b1[i], b0[i]))
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void osgAnimation::VertexInfluenceSet::buildUniqVertexSetToBoneSetList()
|
||||
{
|
||||
_uniqVertexSetToBoneSet.clear();
|
||||
|
||||
typedef std::map<BoneWeightList,UniqVertexSetToBoneSet, SortByBoneWeightList> UnifyBoneGroup;
|
||||
UnifyBoneGroup unifyBuffer;
|
||||
|
||||
for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); it++)
|
||||
{
|
||||
BoneWeightList bones = it->second;
|
||||
int vertexIndex = it->first;
|
||||
|
||||
// sort the vector to have a consistent key
|
||||
std::sort(bones.begin(), bones.end(), SortByNameAndWeight());
|
||||
|
||||
// we use the vector<BoneWeight> as key to differentiate group
|
||||
UnifyBoneGroup::iterator result = unifyBuffer.find(bones);
|
||||
if (result == unifyBuffer.end())
|
||||
unifyBuffer[bones].setBones(bones);
|
||||
unifyBuffer[bones].getVertexes().push_back(vertexIndex);
|
||||
}
|
||||
|
||||
_uniqVertexSetToBoneSet.reserve(unifyBuffer.size());
|
||||
for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); it++)
|
||||
{
|
||||
_uniqVertexSetToBoneSet.push_back(it->second);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ SET(TARGET_COMMON_LIBRARIES
|
||||
#
|
||||
# NodeKit/Psudo loader plugins
|
||||
#
|
||||
ADD_SUBDIRECTORY(osgAnimation)
|
||||
ADD_SUBDIRECTORY(osgFX)
|
||||
ADD_SUBDIRECTORY(osgParticle)
|
||||
ADD_SUBDIRECTORY(osgSim)
|
||||
|
||||
9
src/osgPlugins/osgAnimation/CMakeLists.txt
Normal file
9
src/osgPlugins/osgAnimation/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
SET(TARGET_SRC
|
||||
ReaderWriter.cpp
|
||||
)
|
||||
|
||||
SET(TARGET_ADDED_LIBRARIES osgAnimation )
|
||||
#### end var setup ###
|
||||
SETUP_PLUGIN(osganimation)
|
||||
|
||||
|
||||
491
src/osgPlugins/osgAnimation/ReaderWriter.cpp
Normal file
491
src/osgPlugins/osgAnimation/ReaderWriter.cpp
Normal file
@@ -0,0 +1,491 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include <osgDB/Registry>
|
||||
#include <osgDB/FileNameUtils>
|
||||
#include <osgDB/FileUtils>
|
||||
#include <osgDB/ReaderWriter>
|
||||
|
||||
#include <osgAnimation/AnimationManager>
|
||||
#include <osgAnimation/VertexInfluence>
|
||||
#include <osgAnimation/Animation>
|
||||
#include <osgAnimation/Bone>
|
||||
#include <osgAnimation/Skeleton>
|
||||
#include <osgAnimation/RigGeometry>
|
||||
#include <osgAnimation/UpdateCallback>
|
||||
|
||||
#include <osgDB/Registry>
|
||||
#include <osgDB/Input>
|
||||
#include <osgDB/Output>
|
||||
|
||||
using namespace osgDB;
|
||||
using namespace osg;
|
||||
|
||||
bool Bone_readLocalData(Object& obj, Input& fr)
|
||||
{
|
||||
osgAnimation::Bone& bone = dynamic_cast<osgAnimation::Bone&>(obj);
|
||||
|
||||
osg::Quat att;
|
||||
bool iteratorAdvanced = false;
|
||||
if (fr.matchSequence("bindQuaternion %f %f %f %f"))
|
||||
{
|
||||
fr[1].getFloat(att[0]);
|
||||
fr[2].getFloat(att[1]);
|
||||
fr[3].getFloat(att[2]);
|
||||
fr[4].getFloat(att[3]);
|
||||
|
||||
fr += 5;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
osg::Vec3d pos(0,0,0);
|
||||
if (fr.matchSequence("bindPosition %f %f %f"))
|
||||
{
|
||||
fr[1].getFloat(pos[0]);
|
||||
fr[2].getFloat(pos[1]);
|
||||
fr[3].getFloat(pos[2]);
|
||||
|
||||
fr += 4;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
osg::Vec3d scale(1,1,1);
|
||||
if (fr.matchSequence("bindScale %f %f %f"))
|
||||
{
|
||||
fr[1].getFloat(scale[0]);
|
||||
fr[2].getFloat(scale[1]);
|
||||
fr[3].getFloat(scale[2]);
|
||||
|
||||
fr += 4;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
bone.setBindMatrixInBoneSpace( osg::Matrix(att) * osg::Matrix::translate(pos));
|
||||
if (bone.getUpdateCallback() && bone.getUpdateCallback()->getName().empty() && bone.getUpdateCallback()->getNestedCallback())
|
||||
bone.setUpdateCallback(bone.getUpdateCallback()->getNestedCallback()); // skip the default callback build in constructor of Bone
|
||||
return iteratorAdvanced;
|
||||
}
|
||||
|
||||
bool Bone_writeLocalData(const Object& obj, Output& fw)
|
||||
{
|
||||
const osgAnimation::Bone& bone = dynamic_cast<const osgAnimation::Bone&>(obj);
|
||||
osg::Vec3 t;
|
||||
osg::Quat r;
|
||||
osg::Vec3 s;
|
||||
osg::Quat rs;
|
||||
bone.getBindMatrixInBoneSpace().decompose(t,r,s,rs);
|
||||
fw.indent() << "bindQuaternion " << r << std::endl;
|
||||
fw.indent() << "bindPosition " << t << std::endl;
|
||||
fw.indent() << "bindScale " << s << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
RegisterDotOsgWrapperProxy g_atkBoneProxy
|
||||
(
|
||||
new osgAnimation::Bone,
|
||||
"osgAnimation::Bone",
|
||||
"Object Node Transform osgAnimation::Bone Group",
|
||||
&Bone_readLocalData,
|
||||
&Bone_writeLocalData
|
||||
);
|
||||
|
||||
|
||||
|
||||
bool Skeleton_readLocalData(Object& obj, Input& fr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool Skeleton_writeLocalData(const Object& obj, Output& fr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
RegisterDotOsgWrapperProxy g_atkRootSkeletonProxy
|
||||
(
|
||||
new osgAnimation::Skeleton,
|
||||
"osgAnimation::Skeleton",
|
||||
"Object Node Transform osgAnimation::Bone osgAnimation::Skeleton Group",
|
||||
&Skeleton_readLocalData,
|
||||
&Skeleton_writeLocalData,
|
||||
DotOsgWrapper::READ_AND_WRITE
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
bool Animation_readLocalData(Object& obj, Input& fr)
|
||||
{
|
||||
osgAnimation::Animation& anim = dynamic_cast<osgAnimation::Animation&>(obj);
|
||||
bool iteratorAdvanced = false;
|
||||
int nbChannels = 0;
|
||||
if (fr.matchSequence("num_channels %i"))
|
||||
{
|
||||
fr[1].getInt(nbChannels);
|
||||
fr += 2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nbChannels; i++)
|
||||
{
|
||||
if (fr.matchSequence("Channel {"))
|
||||
{
|
||||
fr += 2;
|
||||
|
||||
std::string name = "unknown";
|
||||
if (fr.matchSequence("name %s"))
|
||||
{
|
||||
name = fr[1].getStr();
|
||||
fr += 2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
std::string target = "unknown";
|
||||
if (fr.matchSequence("target %s"))
|
||||
{
|
||||
target = fr[1].getStr();
|
||||
fr += 2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
std::string type;
|
||||
int nbKeys;
|
||||
if (fr.matchSequence("Keyframes %s %i {"))
|
||||
{
|
||||
type = fr[1].getStr();
|
||||
fr[2].getInt(nbKeys);
|
||||
fr += 4;
|
||||
iteratorAdvanced = true;
|
||||
|
||||
osgAnimation::Channel* channel = 0;
|
||||
if (type == "Quat")
|
||||
{
|
||||
osgAnimation::QuatSphericalLinearChannel* c = new osgAnimation::QuatSphericalLinearChannel;
|
||||
c->getOrCreateSampler()->getOrCreateKeyframeContainer();
|
||||
channel = c;
|
||||
}
|
||||
else if (type == "Vec3")
|
||||
{
|
||||
channel = new osgAnimation::Vec3LinearChannel;
|
||||
osgAnimation::Vec3LinearChannel* c = new osgAnimation::Vec3LinearChannel;
|
||||
c->getOrCreateSampler()->getOrCreateKeyframeContainer();
|
||||
channel = c;
|
||||
}
|
||||
if (channel)
|
||||
{
|
||||
for (int k = 0; k < nbKeys; k++)
|
||||
{
|
||||
if (type == "Quat")
|
||||
{
|
||||
osg::Quat q;
|
||||
float time;
|
||||
fr.matchSequence("key %f %f %f %f %f");
|
||||
fr[1].getFloat(time);
|
||||
fr[2].getFloat(q[0]);
|
||||
fr[3].getFloat(q[1]);
|
||||
fr[4].getFloat(q[2]);
|
||||
fr[5].getFloat(q[3]);
|
||||
fr += 6;
|
||||
osgAnimation::QuatSphericalLinearChannel* c = dynamic_cast<osgAnimation::QuatSphericalLinearChannel*>(channel);
|
||||
c->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::QuatKeyframe(time, q));
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
else if (type == "Vec3")
|
||||
{
|
||||
osg::Vec3 v;
|
||||
float time;
|
||||
fr.matchSequence("key %f %f %f %f");
|
||||
fr[1].getFloat(time);
|
||||
fr[2].getFloat(v[0]);
|
||||
fr[3].getFloat(v[1]);
|
||||
fr[4].getFloat(v[2]);
|
||||
fr += 5;
|
||||
osgAnimation::Vec3LinearChannel* c = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
|
||||
c->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec3Keyframe(time, v));
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
}
|
||||
channel->setName(name);
|
||||
channel->setTargetName(target);
|
||||
anim.addChannel(channel);
|
||||
}
|
||||
if (fr.matchSequence("}")) // keyframes
|
||||
fr += 1;
|
||||
|
||||
if (fr.matchSequence("}")) // channel
|
||||
fr += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return iteratorAdvanced;
|
||||
}
|
||||
|
||||
bool Animation_writeLocalData(const Object& obj, Output& fw)
|
||||
{
|
||||
const osgAnimation::Animation& anim = dynamic_cast<const osgAnimation::Animation&>(obj);
|
||||
|
||||
fw.indent() << "num_channels " << anim.getChannels().size() << std::endl;
|
||||
for (unsigned int i = 0; i < anim.getChannels().size(); i++)
|
||||
{
|
||||
fw.indent() << "Channel {" << std::endl;
|
||||
fw.moveIn();
|
||||
fw.indent() << "name \"" << anim.getChannels()[i]->getName() << "\"" << std::endl;
|
||||
fw.indent() << "target \"" << anim.getChannels()[i]->getTargetName() << "\"" << std::endl;
|
||||
|
||||
std::string type = "unknown";
|
||||
if (anim.getChannels()[i]->getName() == std::string("quaternion"))
|
||||
{
|
||||
type = "Quat";
|
||||
}
|
||||
else if (anim.getChannels()[i]->getName() == std::string("rotation"))
|
||||
{
|
||||
type = "Quat";
|
||||
}
|
||||
else if (anim.getChannels()[i]->getName() == std::string("euler"))
|
||||
{
|
||||
type = "Vec3";
|
||||
}
|
||||
else if (anim.getChannels()[i]->getName() == std::string("scale"))
|
||||
{
|
||||
type = "Vec3";
|
||||
}
|
||||
else if (anim.getChannels()[i]->getName() == std::string("position"))
|
||||
{
|
||||
type = "Vec3";
|
||||
}
|
||||
|
||||
osgAnimation::KeyframeContainer* kf = anim.getChannels()[i]->getSampler()->getKeyframeContainer();
|
||||
fw.indent() << "Keyframes \"" << type << "\" " << kf->size() << " {" << std::endl;
|
||||
fw.moveIn();
|
||||
for (unsigned int k = 0; k < kf->size(); k++)
|
||||
{
|
||||
if (type == "Vec3")
|
||||
{
|
||||
osgAnimation::Vec3KeyframeContainer* kk = dynamic_cast<osgAnimation::Vec3KeyframeContainer*>(kf);
|
||||
fw.indent() << "key " << (*kk)[k].getTime() << " " << (*kk)[k].getValue() << std::endl;
|
||||
}
|
||||
else if ( type == "Quat")
|
||||
{
|
||||
osgAnimation::QuatKeyframeContainer* kk = dynamic_cast<osgAnimation::QuatKeyframeContainer*>(kf);
|
||||
fw.indent() << "key " << (*kk)[k].getTime() << " " << (*kk)[k].getValue() << std::endl;
|
||||
}
|
||||
}
|
||||
fw.moveOut();
|
||||
fw.indent() << "}" << std::endl;
|
||||
fw.moveOut();
|
||||
fw.indent() << "}" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
RegisterDotOsgWrapperProxy g_atkAnimationProxy
|
||||
(
|
||||
new osgAnimation::Animation,
|
||||
"osgAnimation::Animation",
|
||||
"Object osgAnimation::Animation",
|
||||
&Animation_readLocalData,
|
||||
&Animation_writeLocalData
|
||||
);
|
||||
|
||||
|
||||
|
||||
bool AnimationManager_readLocalData(Object& obj, Input& fr)
|
||||
{
|
||||
osgAnimation::AnimationManager& manager = dynamic_cast<osgAnimation::AnimationManager&>(obj);
|
||||
int nbAnims = 0;
|
||||
bool iteratorAdvanced = false;
|
||||
|
||||
if (fr.matchSequence("num_animations %i"))
|
||||
{
|
||||
fr[1].getInt(nbAnims);
|
||||
fr += 2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nbAnims; i++)
|
||||
{
|
||||
Object* o = fr.readObject();
|
||||
osgAnimation::Animation* a = dynamic_cast<osgAnimation::Animation*>(o);
|
||||
if (a)
|
||||
{
|
||||
manager.registerAnimation(a);
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
else
|
||||
osg::notify(osg::WARN)<<"Warning: can't read an animation object"<< std::endl;
|
||||
}
|
||||
|
||||
return iteratorAdvanced;
|
||||
}
|
||||
|
||||
bool AnimationManager_writeLocalData(const Object& obj, Output& fw)
|
||||
{
|
||||
const osgAnimation::AnimationManager& manager = dynamic_cast<const osgAnimation::AnimationManager&>(obj);
|
||||
|
||||
osgAnimation::AnimationMap map = manager.getAnimationMap();
|
||||
int nbanims = map.size();
|
||||
fw.indent() << "num_animations " << nbanims << std::endl;
|
||||
for (osgAnimation::AnimationMap::iterator it = map.begin(); it != map.end(); it++)
|
||||
{
|
||||
if (!fw.writeObject(*it->second))
|
||||
osg::notify(osg::WARN)<<"Warning: can't write an animation object"<< std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RegisterDotOsgWrapperProxy g_atkAnimationManagerProxy
|
||||
(
|
||||
new osgAnimation::AnimationManager,
|
||||
"osgAnimation::AnimationManager",
|
||||
"Object Node Group osgAnimation::AnimationManager",
|
||||
&AnimationManager_readLocalData,
|
||||
&AnimationManager_writeLocalData,
|
||||
DotOsgWrapper::READ_AND_WRITE
|
||||
);
|
||||
|
||||
|
||||
bool RigGeometry_readLocalData(Object& obj, Input& fr)
|
||||
{
|
||||
osgAnimation::RigGeometry& geom = dynamic_cast<osgAnimation::RigGeometry&>(obj);
|
||||
osg::ref_ptr<osgAnimation::VertexInfluenceMap> vmap = new osgAnimation::VertexInfluenceMap;
|
||||
|
||||
int nbGroups = 0;
|
||||
bool iteratorAdvanced = false;
|
||||
if (fr.matchSequence("num_influences %i"))
|
||||
{
|
||||
fr[1].getInt(nbGroups);
|
||||
fr += 2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nbGroups; i++)
|
||||
{
|
||||
int nbVertexes = 0;
|
||||
std::string name;
|
||||
if (fr.matchSequence("osgAnimation::VertexInfluence %s %i {"))
|
||||
{
|
||||
name = fr[1].getStr();
|
||||
fr[2].getInt(nbVertexes);
|
||||
fr += 4;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
|
||||
osgAnimation::VertexInfluence vi;
|
||||
vi.setName(name);
|
||||
vi.reserve(nbVertexes);
|
||||
for (int j = 0; j < nbVertexes; j++)
|
||||
{
|
||||
int index = -1;
|
||||
float weight = 1;
|
||||
if (fr.matchSequence("%i %f"))
|
||||
{
|
||||
fr[0].getInt(index);
|
||||
fr[1].getFloat(weight);
|
||||
fr += 2;
|
||||
iteratorAdvanced = true;
|
||||
}
|
||||
vi.push_back(osgAnimation::VertexIndexWeight(index, weight));
|
||||
}
|
||||
if (fr.matchSequence("}"))
|
||||
{
|
||||
fr+=1;
|
||||
}
|
||||
(*vmap)[name] = vi;
|
||||
}
|
||||
if (!vmap->empty())
|
||||
geom.setInfluenceMap(vmap.get());
|
||||
|
||||
return iteratorAdvanced;
|
||||
}
|
||||
|
||||
bool RigGeometry_writeLocalData(const Object& obj, Output& fw)
|
||||
{
|
||||
const osgAnimation::RigGeometry& geom = dynamic_cast<const osgAnimation::RigGeometry&>(obj);
|
||||
const osgAnimation::VertexInfluenceMap* vm = geom.getInfluenceMap();
|
||||
if (!vm)
|
||||
return true;
|
||||
fw.indent() << "num_influences " << vm->size() << std::endl;
|
||||
fw.moveIn();
|
||||
for (osgAnimation::VertexInfluenceMap::const_iterator it = vm->begin(); it != vm->end(); it++)
|
||||
{
|
||||
std::string name = it->first;
|
||||
if (name.empty())
|
||||
name = "Empty";
|
||||
fw.indent() << "osgAnimation::VertexInfluence \"" << name << "\" " << it->second.size() << " {" << std::endl;
|
||||
fw.moveIn();
|
||||
const osgAnimation::VertexInfluence& vi = it->second;
|
||||
for (osgAnimation::VertexInfluence::const_iterator itv = vi.begin(); itv != vi.end(); itv++)
|
||||
{
|
||||
fw.indent() << itv->first << " " << itv->second << std::endl;
|
||||
}
|
||||
fw.moveOut();
|
||||
fw.indent() << "}" << std::endl;
|
||||
}
|
||||
fw.moveOut();
|
||||
return true;
|
||||
}
|
||||
|
||||
RegisterDotOsgWrapperProxy g_atkRigGeometryProxy
|
||||
(
|
||||
new osgAnimation::RigGeometry,
|
||||
"osgAnimation::RigGeometry",
|
||||
"Object Drawable osgAnimation::RigGeometry Geometry",
|
||||
&RigGeometry_readLocalData,
|
||||
&RigGeometry_writeLocalData,
|
||||
DotOsgWrapper::READ_AND_WRITE
|
||||
);
|
||||
|
||||
|
||||
|
||||
bool UpdateBone_readLocalData(Object& obj, Input& fr)
|
||||
{
|
||||
bool iteratorAdvanced = false;
|
||||
return iteratorAdvanced;
|
||||
}
|
||||
|
||||
bool UpdateBone_writeLocalData(const Object& obj, Output& fw)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
RegisterDotOsgWrapperProxy g_atkUpdateBoneProxy
|
||||
(
|
||||
new osgAnimation::Bone::UpdateBone,
|
||||
"osgAnimation::UpdateBone",
|
||||
"Object osgAnimation::UpdateBone",
|
||||
&UpdateBone_readLocalData,
|
||||
&UpdateBone_writeLocalData,
|
||||
DotOsgWrapper::READ_AND_WRITE
|
||||
);
|
||||
|
||||
|
||||
|
||||
bool UpdateTransform_readLocalData(Object& obj, Input& fr)
|
||||
{
|
||||
bool iteratorAdvanced = false;
|
||||
return iteratorAdvanced;
|
||||
}
|
||||
|
||||
bool UpdateTransform_writeLocalData(const Object& obj, Output& fw)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
RegisterDotOsgWrapperProxy g_atkUpdateTransformProxy
|
||||
(
|
||||
new osgAnimation::UpdateTransform,
|
||||
"osgAnimation::UpdateTransform",
|
||||
"Object osgAnimation::UpdateTransform",
|
||||
&UpdateTransform_readLocalData,
|
||||
&UpdateTransform_writeLocalData,
|
||||
DotOsgWrapper::READ_AND_WRITE
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user