2.8 branch: backport of osgAnimation from svn head 11026.

This commit is contained in:
Paul MARTZ
2010-03-13 20:55:16 +00:00
parent 15fd3bdcc2
commit 38e68ed7f1
84 changed files with 6677 additions and 1331 deletions

View File

@@ -0,0 +1,83 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/Action>
using namespace osgAnimation;
Action::Action()
{
_numberFrame = 25;
_fps = 25;
_speed = 1.0;
_loop = 1;
}
Action::Action(const Action&,const osg::CopyOp&) {}
Action::Callback* Action::getFrameCallback(unsigned int frame)
{
if (_framesCallback.find(frame) != _framesCallback.end())
{
return _framesCallback[frame].get();
}
return 0;
}
void Action::removeCallback(Callback* cb)
{
std::vector<unsigned int> keyToRemove;
for (FrameCallback::iterator it = _framesCallback.begin(); it != _framesCallback.end(); ++it)
{
if (it->second.get())
{
if (it->second.get() == cb)
{
it->second = it->second->getNestedCallback();
if (!it->second.valid())
keyToRemove.push_back(it->first);
}
else
{
it->second->removeCallback(cb);
}
}
}
for (std::vector<unsigned int>::iterator it = keyToRemove.begin(); it != keyToRemove.end(); ++it)
_framesCallback.erase(*it);
}
Action::Callback* Action::getFrameCallback(double time)
{
unsigned int frame = static_cast<unsigned int>(floor(time * _fps));
return getFrameCallback(frame);
}
bool osgAnimation::Action::evaluateFrame(unsigned int frame, unsigned int& resultframe, unsigned int& nbloop )
{
nbloop = frame / getNumFrames();
resultframe = frame;
if (frame > getNumFrames()-1)
{
if (!getLoop())
resultframe = frame % getNumFrames();
else
{
if (nbloop >= getLoop())
return false;
else
resultframe = frame % getNumFrames();
}
}
return true;
}

View File

@@ -0,0 +1,32 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/ActionAnimation>
using namespace osgAnimation;
ActionAnimation::ActionAnimation() {}
ActionAnimation::ActionAnimation(const ActionAnimation& a, const osg::CopyOp& c) : Action(a,c) { _animation = a._animation;}
ActionAnimation::ActionAnimation(Animation* animation) : _animation(animation)
{
Action::setDuration(animation->getDuration());
setName(animation->getName());
}
void ActionAnimation::updateAnimation(unsigned int frame, int priority)
{
_animation->update(frame * 1.0/_fps, priority);
}

View File

@@ -0,0 +1,45 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/ActionBlendIn>
using namespace osgAnimation;
ActionBlendIn::ActionBlendIn() : _weight(0) {}
ActionBlendIn::ActionBlendIn(const ActionBlendIn& a, const osg::CopyOp& c) : Action(a,c)
{
_weight = a._weight;
_animation = a._animation;
}
ActionBlendIn::ActionBlendIn(Animation* animation, double duration, double weight)
{
_animation = animation;
_weight = weight;
float d = duration * _fps;
setNumFrames(static_cast<unsigned int>(floor(d)) + 1);
setName("BlendIn");
}
void ActionBlendIn::computeWeight(unsigned int frame)
{
// frame + 1 because the start is 0 and we want to start the blend in at the first
// frame.
double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
double w = _weight * ratio;
osg::notify(osg::DEBUG_INFO) << getName() << " BlendIn frame " << frame << " weight " << w << std::endl;
_animation->setWeight(w);
}

View File

@@ -0,0 +1,41 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/ActionBlendOut>
using namespace osgAnimation;
ActionBlendOut::ActionBlendOut() : _weight(0) {}
ActionBlendOut::ActionBlendOut(const ActionBlendOut& a, const osg::CopyOp& c) : Action(a,c)
{
_weight = a._weight;
_animation = a._animation;
}
ActionBlendOut::ActionBlendOut(Animation* animation, double duration)
{
_animation = animation;
float d = duration * _fps;
setNumFrames(static_cast<unsigned int>(floor(d) + 1));
_weight = 1.0;
setName("BlendOut");
}
void ActionBlendOut::computeWeight(unsigned int frame)
{
double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
double w = _weight * (1.0-ratio);
osg::notify(osg::DEBUG_INFO) << getName() << " BlendOut frame " << frame << " weight " << w << std::endl;
_animation->setWeight(w);
}

View File

@@ -0,0 +1,23 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/ActionCallback>
#include <osgAnimation/Timeline>
void osgAnimation::RunAction::operator()(Action* action, ActionVisitor* visitor)
{
Timeline* tm = visitor->getCurrentTimeline();
tm->addActionNow(_action.get(), _priority);
}

View File

@@ -0,0 +1,88 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/ActionStripAnimation>
using namespace osgAnimation;
ActionAnimation* ActionStripAnimation::getAnimation() { return _animation.get(); }
ActionBlendIn* ActionStripAnimation::getBlendIn() { return _blendIn.get(); }
ActionBlendOut* ActionStripAnimation::getBlendOut() { return _blendOut.second.get(); }
const ActionAnimation* ActionStripAnimation::getAnimation() const { return _animation.get(); }
const ActionBlendIn* ActionStripAnimation::getBlendIn() const { return _blendIn.get(); }
const ActionBlendOut* ActionStripAnimation::getBlendOut() const { return _blendOut.second.get(); }
unsigned int ActionStripAnimation::getBlendOutStartFrame() const { return _blendOut.first; }
unsigned int ActionStripAnimation::getLoop() const { return _animation->getLoop(); }
ActionStripAnimation::ActionStripAnimation(const ActionStripAnimation& a, const osg::CopyOp& c) : Action(a,c)
{
_animation = a._animation;
_blendIn = a._blendIn;
_blendOut = a._blendOut;
}
ActionStripAnimation::ActionStripAnimation(Animation* animation, double blendInDuration, double blendOutDuration, double blendInWeightTarget)
{
_blendIn = new ActionBlendIn(animation, blendInDuration, blendInWeightTarget);
_animation = new ActionAnimation(animation);
unsigned int start = static_cast<unsigned int>(floor((_animation->getDuration() - blendOutDuration) * _fps));
_blendOut = FrameBlendOut(start, new ActionBlendOut(animation, blendOutDuration));
setName(animation->getName() + "_Strip");
_blendIn->setName(_animation->getName() + "_" + _blendIn->getName());
_blendOut.second->setName(_animation->getName() + "_" + _blendOut.second->getName());
setDuration(animation->getDuration());
}
void ActionStripAnimation::setLoop(unsigned int loop)
{
_animation->setLoop(loop);
if (!loop)
setDuration(-1);
else
setDuration(loop * _animation->getDuration());
// duration changed re evaluate the blendout duration
unsigned int start = static_cast<unsigned int>(floor((getDuration() - _blendOut.second->getDuration()) * _fps));
_blendOut = FrameBlendOut(start, _blendOut.second);
}
void ActionStripAnimation::traverse(ActionVisitor& visitor)
{
if (_blendIn.valid())
{
unsigned int f = visitor.getStackedFrameAction().back().first;
visitor.pushFrameActionOnStack(FrameAction(f,_blendIn.get()));
_blendIn->accept(visitor);
visitor.popFrameAction();
}
if (_blendOut.second.valid())
{
unsigned int f = visitor.getStackedFrameAction().back().first;
visitor.pushFrameActionOnStack(FrameAction(f + _blendOut.first,_blendOut.second.get()));
_blendOut.second.get()->accept(visitor);
visitor.popFrameAction();
}
if (_animation.valid())
{
unsigned int f = visitor.getStackedFrameAction().back().first;
visitor.pushFrameActionOnStack(FrameAction(f,_animation.get()));
_animation->accept(visitor);
visitor.popFrameAction();
}
}

View File

@@ -0,0 +1,184 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/Action>
#include <osgAnimation/ActionBlendIn>
#include <osgAnimation/ActionBlendOut>
#include <osgAnimation/ActionStripAnimation>
#include <osgAnimation/ActionAnimation>
#include <osgAnimation/ActionVisitor>
#include <osgAnimation/Timeline>
using namespace osgAnimation;
ActionVisitor::ActionVisitor()
{
_currentLayer = 0;
}
void ActionVisitor::pushFrameActionOnStack(const FrameAction& fa) { _stackFrameAction.push_back(fa); }
void ActionVisitor::popFrameAction() { _stackFrameAction.pop_back(); }
void ActionVisitor::pushTimelineOnStack(Timeline* tm) { _stackTimeline.push_back(tm); }
void ActionVisitor::popTimeline() { _stackTimeline.pop_back(); }
void ActionVisitor::apply(Action& action) { traverse(action); }
void ActionVisitor::apply(Timeline& tm) { tm.traverse(*this); }
void ActionVisitor::apply(ActionBlendIn& action) { apply(static_cast<Action&>(action));}
void ActionVisitor::apply(ActionBlendOut& action) { apply(static_cast<Action&>(action)); }
void ActionVisitor::apply(ActionAnimation& action) { apply(static_cast<Action&>(action)); }
void ActionVisitor::apply(ActionStripAnimation& action) { apply(static_cast<Action&>(action)); }
void ActionVisitor::traverse(Action& action)
{
action.traverse(*this);
}
Timeline* ActionVisitor::getCurrentTimeline()
{
if (_stackTimeline.empty())
return 0;
return _stackTimeline.back();
}
UpdateActionVisitor::UpdateActionVisitor()
{
_frame = 0;
_currentAnimationPriority = 0;
}
void UpdateActionVisitor::apply(Timeline& tm)
{
_currentAnimationPriority = 0;
tm.setEvaluating(true);
tm.traverse(*this);
tm.setEvaluating(false);
tm.setLastFrameEvaluated(_frame);
}
bool UpdateActionVisitor::isActive(Action& action) const
{
FrameAction fa = _stackFrameAction.back();
if (_frame < fa.first)
return false;
if (!fa.second.valid())
return false;
unsigned int f = getLocalFrame();
unsigned int frameInAction;
unsigned int loopDone;
return action.evaluateFrame(f, frameInAction, loopDone);
}
unsigned int UpdateActionVisitor::getLocalFrame() const
{
return _frame - _stackFrameAction.back().first;
}
void UpdateActionVisitor::apply(Action& action)
{
if (isActive(action))
{
unsigned int frame = getLocalFrame();
unsigned int frameInAction;
unsigned int loopDone;
bool result = action.evaluateFrame(frame, frameInAction, loopDone);
if (!result)
{
osg::notify(osg::DEBUG_INFO) << action.getName() << " Action frame " << frameInAction << " finished" << std::endl;
return;
}
osg::notify(osg::DEBUG_INFO) << action.getName() << " Action frame " << frame << " relative to loop " << frameInAction << " no loop " << loopDone<< std::endl;
frame = frameInAction;
Action::Callback* cb = action.getFrameCallback(frame);
while (cb)
{
osg::notify(osg::DEBUG_INFO) << action.getName() << " evaluate callback " << cb->getName() << " at " << frame << std::endl;
(*cb)(&action, this);
cb = cb->getNestedCallback();
}
}
}
void UpdateActionVisitor::apply(ActionBlendIn& action)
{
if (isActive(action))
{
unsigned int frame = getLocalFrame();
apply(static_cast<Action&>(action));
action.computeWeight(frame);
}
}
void UpdateActionVisitor::apply(ActionBlendOut& action)
{
if (isActive(action))
{
unsigned int frame = getLocalFrame();
apply(static_cast<Action&>(action));
action.computeWeight(frame);
}
}
void UpdateActionVisitor::apply(ActionAnimation& action)
{
if (isActive(action))
{
unsigned int frame = getLocalFrame();
apply(static_cast<Action&>(action));
int pri = static_cast<int>(_currentAnimationPriority);
_currentAnimationPriority++;
action.updateAnimation(frame, -pri);
}
}
void UpdateActionVisitor::apply(ActionStripAnimation& action)
{
if (isActive(action))
{
apply(static_cast<Action&>(action));
action.traverse(*this);
}
}
ClearActionVisitor::ClearActionVisitor(ClearType type) : _clearType(type)
{
}
void ClearActionVisitor::apply(Timeline& tm)
{
_remove.clear();
tm.traverse(*this);
for (int i = 0; i < (int)_remove.size(); i++)
tm.removeAction(_remove[i].get());
}
void ClearActionVisitor::apply(Action& action)
{
FrameAction fa = _stackFrameAction.back();
switch( _clearType) {
case BEFORE_FRAME:
if (_frame > fa.first)
_remove.push_back(&action);
break;
case AFTER_FRAME:
if (_frame - fa.first > action.getNumFrames())
_remove.push_back(&action);
break;
}
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -16,13 +16,18 @@
using namespace osgAnimation;
Animation::Animation(const osgAnimation::Animation& anim, const osg::CopyOp& c)
Animation::Animation(const osgAnimation::Animation& anim, const osg::CopyOp& copyop): osg::Object(anim, copyop),
_duration(anim._duration),
_originalDuration(anim._originalDuration),
_weight(anim._weight),
_startTime(anim._startTime),
_playmode(anim._playmode)
{
_duration = anim._duration;
_originalDuration = anim._originalDuration;
_weight = anim._weight;
_startTime = anim._startTime;
_playmode = anim._playmode;
const ChannelList& cl = anim.getChannels();
for (ChannelList::const_iterator it = cl.begin(); it != cl.end(); ++it)
{
addChannel(it->get()->clone());
}
}
@@ -90,7 +95,7 @@ void Animation::setWeight (float weight)
_weight = weight;
}
bool Animation::update (float time)
bool Animation::update (float time, int priority)
{
if (!_duration) // if not initialized then do it
computeDuration();
@@ -128,13 +133,10 @@ bool Animation::update (float time)
break;
}
// std::cout << "t " << t << " / " << _duration << std::endl;
ChannelList::const_iterator chan;
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
{
(*chan)->setWeight(_weight);
(*chan)->update(t);
(*chan)->update(t, _weight, priority);
}
return true;
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -14,6 +14,7 @@
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/LinkVisitor>
#include <algorithm>
using namespace osgAnimation;
@@ -21,23 +22,27 @@ AnimationManagerBase::~AnimationManagerBase() {}
AnimationManagerBase::AnimationManagerBase()
{
_needToLink = false;
_needToLink = false;
_automaticLink = true;
}
void AnimationManagerBase::clearTargets()
{
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); ++it)
(*it).get()->reset();
}
void AnimationManagerBase::normalizeTargets()
void AnimationManagerBase::dirty()
{
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
(*it).get()->normalize();
_needToLink = true;
}
void AnimationManagerBase::setAutomaticLink(bool state) { _automaticLink = state; }
bool AnimationManagerBase::isAutomaticLink() const { return _automaticLink; }
void AnimationManagerBase::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
if (needToLink())
{
@@ -57,22 +62,30 @@ void AnimationManagerBase::operator()(osg::Node* node, osg::NodeVisitor* nv)
}
AnimationManagerBase::AnimationManagerBase(const AnimationManagerBase& b, const osg::CopyOp& copyop) : osg::NodeCallback(b,copyop)
AnimationManagerBase::AnimationManagerBase(const AnimationManagerBase& b, const osg::CopyOp& copyop) : osg::NodeCallback(b,copyop)
{
_animations = b._animations;
_targets = b._targets;
_needToLink = b._needToLink;
const AnimationList& animationList = b.getAnimationList();
for (AnimationList::const_iterator it = animationList.begin();
it != animationList.end();
++it)
{
Animation* animation = dynamic_cast<osgAnimation::Animation*>(it->get()->clone(copyop));
_animations.push_back(animation);
}
_needToLink = true;
_automaticLink = b._automaticLink;
buildTargetReference();
}
void AnimationManagerBase::buildTargetReference()
{
_targets.clear();
for( AnimationList::iterator iterAnim = _animations.begin(); iterAnim != _animations.end(); ++iterAnim )
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++)
++it)
_targets.insert((*it)->getTarget());
}
}
@@ -85,14 +98,38 @@ void AnimationManagerBase::registerAnimation (Animation* animation)
buildTargetReference();
}
bool AnimationManagerBase::needToLink() const { return _needToLink; }
void AnimationManagerBase::unregisterAnimation (Animation* animation)
{
AnimationList::iterator it = std::find(_animations.begin(), _animations.end(), animation);
if (it != _animations.end())
{
_animations.erase(it);
}
buildTargetReference();
}
bool AnimationManagerBase::needToLink() const { return _needToLink && isAutomaticLink(); }
void AnimationManagerBase::setLinkVisitor(LinkVisitor* visitor)
{
_linker = visitor;
}
LinkVisitor* AnimationManagerBase::getOrCreateLinkVisitor()
{
if (!_linker.valid())
_linker = new LinkVisitor;
return _linker.get();
}
void AnimationManagerBase::link(osg::Node* subgraph)
{
LinkVisitor linker(_animations);
subgraph->accept(linker);
LinkVisitor* linker = getOrCreateLinkVisitor();
linker->getAnimationList().clear();
linker->getAnimationList() = _animations;
subgraph->accept(*linker);
_needToLink = false;
buildTargetReference();
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -38,7 +38,7 @@ void BasicAnimationManager::stopAll()
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
{
AnimationList& list = iterAnim->second;
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
for (AnimationList::iterator it = list.begin(); it != list.end(); ++it)
(*it)->resetTargets();
}
_animationsPlaying.clear();
@@ -47,14 +47,14 @@ void BasicAnimationManager::stopAll()
void BasicAnimationManager::playAnimation(Animation* pAnimation, int priority, float weight)
{
if (!findAnimation(pAnimation))
{
return;
}
if ( isPlaying(pAnimation) )
stopAnimation(pAnimation);
_animationsPlaying[priority].push_back(pAnimation);
// for debug
//std::cout << "player Animation " << pAnimation->getName() << " at " << _lastUpdate << std::endl;
pAnimation->setStartTime(_lastUpdate);
pAnimation->setWeight(weight);
}
@@ -62,10 +62,10 @@ void BasicAnimationManager::playAnimation(Animation* pAnimation, int priority, f
bool BasicAnimationManager::stopAnimation(Animation* pAnimation)
{
// search though the layer and remove animation
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
{
AnimationList& list = iterAnim->second;
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
for (AnimationList::iterator it = list.begin(); it != list.end(); ++it)
if( (*it) == pAnimation )
{
(*it)->resetTargets();
@@ -79,11 +79,10 @@ bool BasicAnimationManager::stopAnimation(Animation* pAnimation)
void BasicAnimationManager::update (double time)
{
if (!_lastUpdate)
_lastUpdate = time;
_lastUpdate = time; // keep time of last update
// could filtered with an active flag
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); ++it)
(*it).get()->reset();
// update from high priority to low priority
@@ -91,11 +90,20 @@ void BasicAnimationManager::update (double time)
{
// update all animation
std::vector<int> toremove;
int priority = iterAnim->first;
AnimationList& list = iterAnim->second;
for (unsigned int i = 0; i < list.size(); i++)
{
if (! list[i]->update(time))
if (! list[i]->update(time, priority))
{
// debug
// std::cout << list[i]->getName() << " finished at " << time << std::endl;
toremove.push_back(i);
} else
{
// debug
//std::cout << list[i]->getName() << " updated" << std::endl;
}
}
// remove finished animation
@@ -105,9 +113,6 @@ void BasicAnimationManager::update (double time)
toremove.pop_back();
}
}
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
(*it).get()->normalize();
}
@@ -127,7 +132,7 @@ bool BasicAnimationManager::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++)
for (AnimationList::iterator it = list.begin(); it != list.end(); ++it)
if ( (*it) == pAnimation )
return true;
}
@@ -140,7 +145,7 @@ bool BasicAnimationManager::isPlaying(const std::string& name)
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
{
AnimationList& list = iterAnim->second;
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
for (AnimationList::iterator it = list.begin(); it != list.end(); ++it)
if ( (*it)->getName() == name )
return true;
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -12,36 +12,25 @@
* OpenSceneGraph Public License for more details.
*/
#include <osgAnimation/Skinning>
#include <osgAnimation/Bone>
#include <osgAnimation/Skeleton>
#include <osgAnimation/UpdateBone>
#include <osgAnimation/BoneMapVisitor>
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)
using namespace osgAnimation;
Bone::Bone(const Bone& b, const osg::CopyOp& copyop) : osg::MatrixTransform(b,copyop), _invBindInSkeletonSpace(b._invBindInSkeletonSpace), _boneInSkeletonSpace(b._boneInSkeletonSpace)
{
}
osgAnimation::Bone::Bone(const Bone& b, const osg::CopyOp& copyop)
: osg::Transform(b,copyop),
_position(b._position),
_rotation(b._rotation),
_scale(b._scale)
{
}
osgAnimation::Bone::Bone(const std::string& name)
Bone::Bone(const std::string& name)
{
if (!name.empty())
setName(name);
_needToRecomputeBindMatrix = false;
}
void osgAnimation::Bone::setDefaultUpdateCallback(const std::string& name)
void Bone::setDefaultUpdateCallback(const std::string& name)
{
std::string cbName = name;
if (cbName.empty())
@@ -49,42 +38,12 @@ void osgAnimation::Bone::setDefaultUpdateCallback(const std::string& name)
setUpdateCallback(new UpdateBone(cbName));
}
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()
Bone* Bone::getBoneParent()
{
if (getParents().empty())
return 0;
osg::Node::ParentList parents = getParents();
for (osg::Node::ParentList::iterator it = parents.begin(); it != parents.end(); it++)
for (osg::Node::ParentList::iterator it = parents.begin(); it != parents.end(); ++it)
{
Bone* pb = dynamic_cast<Bone*>(*it);
if (pb)
@@ -92,12 +51,12 @@ osgAnimation::Bone* osgAnimation::Bone::getBoneParent()
}
return 0;
}
const osgAnimation::Bone* osgAnimation::Bone::getBoneParent() const
const Bone* 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++)
for (osg::Node::ParentList::const_iterator it = parents.begin(); it != parents.end(); ++it)
{
const Bone* pb = dynamic_cast<const Bone*>(*it);
if (pb)
@@ -105,25 +64,3 @@ const osgAnimation::Bone* osgAnimation::Bone::getBoneParent() const
}
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;
}

View File

@@ -0,0 +1,42 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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.
*
* Authors:
* Cedric Pinson <cedric.pinson@plopbyte.net>
*/
#include <osgAnimation/BoneMapVisitor>
#include <osgAnimation/Skeleton>
using namespace osgAnimation;
BoneMapVisitor::BoneMapVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void BoneMapVisitor::apply(osg::Node&) { return; }
void BoneMapVisitor::apply(osg::Transform& node)
{
Bone* bone = dynamic_cast<Bone*>(&node);
if (bone)
{
_map[bone->getName()] = bone;
traverse(node);
}
Skeleton* skeleton = dynamic_cast<Skeleton*>(&node);
if (skeleton)
traverse(node);
}
const BoneMap& BoneMapVisitor::getBoneMap() const
{
return _map;
}

View File

@@ -1,60 +1,108 @@
IF (DYNAMIC_OPENSCENEGRAPH)
IF(DYNAMIC_OPENSCENEGRAPH)
ADD_DEFINITIONS(-DOSGANIMATION_LIBRARY)
ELSE (DYNAMIC_OPENSCENEGRAPH)
ELSE()
ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC)
ENDIF(DYNAMIC_OPENSCENEGRAPH)
ENDIF()
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}/Action
${HEADER_PATH}/ActionAnimation
${HEADER_PATH}/ActionBlendIn
${HEADER_PATH}/ActionBlendOut
${HEADER_PATH}/ActionCallback
${HEADER_PATH}/ActionStripAnimation
${HEADER_PATH}/ActionVisitor
${HEADER_PATH}/Animation
${HEADER_PATH}/Keyframe
${HEADER_PATH}/Skinning
${HEADER_PATH}/CubicBezier
${HEADER_PATH}/Vec3Packed
${HEADER_PATH}/BasicAnimationManager
${HEADER_PATH}/TimelineAnimationManager
${HEADER_PATH}/AnimationManagerBase
${HEADER_PATH}/UpdateCallback
${HEADER_PATH}/LinkVisitor
${HEADER_PATH}/VertexInfluence
${HEADER_PATH}/AnimationUpdateCallback
${HEADER_PATH}/BasicAnimationManager
${HEADER_PATH}/Bone
${HEADER_PATH}/BoneMapVisitor
${HEADER_PATH}/Channel
${HEADER_PATH}/CubicBezier
${HEADER_PATH}/EaseMotion
${HEADER_PATH}/Assert
${HEADER_PATH}/Timeline
${HEADER_PATH}/Export
${HEADER_PATH}/FrameAction
${HEADER_PATH}/Interpolator
${HEADER_PATH}/Keyframe
${HEADER_PATH}/LinkVisitor
${HEADER_PATH}/MorphGeometry
${HEADER_PATH}/RigGeometry
${HEADER_PATH}/RigTransform
${HEADER_PATH}/RigTransformHardware
${HEADER_PATH}/RigTransformSoftware
${HEADER_PATH}/Sampler
${HEADER_PATH}/Skeleton
${HEADER_PATH}/StackedMatrixElement
${HEADER_PATH}/StackedQuaternionElement
${HEADER_PATH}/StackedRotateAxisElement
${HEADER_PATH}/StackedScaleElement
${HEADER_PATH}/StackedTransformElement
${HEADER_PATH}/StackedTranslateElement
${HEADER_PATH}/StackedTransform
${HEADER_PATH}/StatsVisitor
${HEADER_PATH}/StatsHandler
${HEADER_PATH}/Target
${HEADER_PATH}/Timeline
${HEADER_PATH}/TimelineAnimationManager
${HEADER_PATH}/UpdateBone
${HEADER_PATH}/UpdateMaterial
${HEADER_PATH}/UpdateMatrixTransform
${HEADER_PATH}/Vec3Packed
${HEADER_PATH}/VertexInfluence
)
ADD_LIBRARY(${LIB_NAME}
${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC}
${LIB_PUBLIC_HEADERS}
Channel.cpp
Target.cpp
Action.cpp
ActionAnimation.cpp
ActionBlendIn.cpp
ActionBlendOut.cpp
ActionCallback.cpp
ActionStripAnimation.cpp
ActionVisitor.cpp
Animation.cpp
Bone.cpp
RigGeometry.cpp
AnimationManager.cpp
BasicAnimationManager.cpp
TimelineAnimationManager.cpp
AnimationManagerBase.cpp
BasicAnimationManager.cpp
Bone.cpp
BoneMapVisitor.cpp
Channel.cpp
LinkVisitor.cpp
MorphGeometry.cpp
RigGeometry.cpp
RigTransformHardware.cpp
RigTransformSoftware.cpp
Skeleton.cpp
VertexInfluence.cpp
UpdateCallback.cpp
StackedMatrixElement.cpp
StackedQuaternionElement.cpp
StackedRotateAxisElement.cpp
StackedScaleElement.cpp
StackedTransform.cpp
StackedTranslateElement.cpp
StatsVisitor.cpp
StatsHandler.cpp
Target.cpp
TimelineAnimationManager.cpp
Timeline.cpp
UpdateBone.cpp
UpdateMaterial.cpp
UpdateMatrixTransform.cpp
VertexInfluence.cpp
${OPENSCENEGRAPH_VERSIONINFO_RC}
)
LINK_INTERNAL(${LIB_NAME}
osg
osgText
osgGA
osgViewer
OpenThreads
)

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -15,15 +15,16 @@
#include <osgAnimation/Channel>
using namespace osgAnimation;
Channel::Channel() { _weight=1; }
Channel::Channel() {}
Channel::~Channel() {}
Channel::Channel(const Channel& channel) : osg::Referenced(channel),
_targetName(channel._targetName),
_name(channel._name)
{
}
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;}

View File

@@ -0,0 +1,87 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/LinkVisitor>
#include <osgAnimation/AnimationUpdateCallback>
#include <osg/Notify>
#include <osg/Geode>
using namespace osgAnimation;
LinkVisitor::LinkVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
_nbLinkedTarget = 0;
}
void LinkVisitor::reset()
{
_nbLinkedTarget = 0;
}
AnimationList& LinkVisitor::getAnimationList()
{
return _animations;
}
void LinkVisitor::link(AnimationUpdateCallbackBase* cb)
{
int result = 0;
for (int i = 0; i < (int)_animations.size(); i++)
{
result += cb->link(_animations[i].get());
_nbLinkedTarget += result;
}
osg::notify(osg::NOTICE) << "LinkVisitor links " << result << " for \"" << cb->getName() << '"' << std::endl;
}
void LinkVisitor::handle_stateset(osg::StateSet* stateset)
{
if (!stateset)
return;
osg::StateSet::AttributeList& attr = stateset->getAttributeList();
for (osg::StateSet::AttributeList::iterator it = attr.begin(); it != attr.end(); ++it)
{
osg::StateAttribute* sattr = it->second.first.get();
osgAnimation::AnimationUpdateCallbackBase* cb = dynamic_cast<osgAnimation::AnimationUpdateCallbackBase*>(sattr->getUpdateCallback());
if (cb)
link(cb);
}
}
void LinkVisitor::apply(osg::Node& node)
{
osg::StateSet* st = node.getStateSet();
if (st)
handle_stateset(st);
osg::NodeCallback* cb = node.getUpdateCallback();
while (cb)
{
osgAnimation::AnimationUpdateCallbackBase* cba = dynamic_cast<osgAnimation::AnimationUpdateCallbackBase*>(cb);
if (cba)
link(cba);
cb = cb->getNestedCallback();
}
traverse(node);
}
void LinkVisitor::apply(osg::Geode& node)
{
for (unsigned int i = 0; i < node.getNumDrawables(); i++)
{
osg::Drawable* drawable = node.getDrawable(i);
if (drawable && drawable->getStateSet())
handle_stateset(drawable->getStateSet());
}
apply(static_cast<osg::Node&>(node));
}

View File

@@ -0,0 +1,277 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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:
*
* Roland Smeenk
* Cedric Pinson <cedric.pinson@plopbyte.net>
*
*/
#include <osg/Geode>
#include <osgAnimation/MorphGeometry>
#include <stdlib.h>
using namespace osgAnimation;
MorphGeometry::MorphGeometry() :
_dirty(false),
_method(NORMALIZED),
_morphNormals(true)
{
setUseDisplayList(false);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
setUseVertexBufferObjects(true);
}
MorphGeometry::MorphGeometry(const osg::Geometry& b) :
osg::Geometry(b, osg::CopyOp::DEEP_COPY_ARRAYS),
_dirty(false),
_method(NORMALIZED),
_morphNormals(true)
{
setUseDisplayList(false);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
setUseVertexBufferObjects(true);
if (b.getInternalOptimizedGeometry())
computeInternalOptimizedGeometry();
}
MorphGeometry::MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop) :
osg::Geometry(b,copyop),
_dirty(b._dirty),
_method(b._method),
_morphTargets(b._morphTargets),
_positionSource(b._positionSource),
_normalSource(b._normalSource),
_morphNormals(b._morphNormals)
{
setUseDisplayList(false);
setUseVertexBufferObjects(true);
if (b.getInternalOptimizedGeometry())
computeInternalOptimizedGeometry();
}
void MorphGeometry::transformSoftwareMethod()
{
if (_dirty)
{
// See if we have an internal optimized geometry
osg::Geometry* morphGeometry = this;
if (_internalOptimizedGeometry.valid())
morphGeometry = _internalOptimizedGeometry.get();
osg::Vec3Array* pos = dynamic_cast<osg::Vec3Array*>(morphGeometry->getVertexArray());
if (pos && _positionSource.size() != pos->size())
{
_positionSource = std::vector<osg::Vec3>(pos->begin(),pos->end());
pos->setDataVariance(osg::Object::DYNAMIC);
}
osg::Vec3Array* normal = dynamic_cast<osg::Vec3Array*>(morphGeometry->getNormalArray());
if (normal && _normalSource.size() != normal->size())
{
_normalSource = std::vector<osg::Vec3>(normal->begin(),normal->end());
normal->setDataVariance(osg::Object::DYNAMIC);
}
if (!_positionSource.empty())
{
bool initialized = false;
if (_method == NORMALIZED)
{
// base * 1 - (sum of weights) + sum of (weight * target)
float baseWeight = 0;
for (unsigned int i=0; i < _morphTargets.size(); i++)
{
baseWeight += _morphTargets[i].getWeight();
}
baseWeight = 1 - baseWeight;
if (baseWeight != 0)
{
initialized = true;
for (unsigned int i=0; i < pos->size(); i++)
{
(*pos)[i] = _positionSource[i] * baseWeight;
}
if (_morphNormals)
{
for (unsigned int i=0; i < normal->size(); i++)
{
(*normal)[i] = _normalSource[i] * baseWeight;
}
}
}
}
else //if (_method == RELATIVE)
{
// base + sum of (weight * target)
initialized = true;
for (unsigned int i=0; i < pos->size(); i++)
{
(*pos)[i] = _positionSource[i];
}
if (_morphNormals)
{
for (unsigned int i=0; i < normal->size(); i++)
{
(*normal)[i] = _normalSource[i];
}
}
}
for (unsigned int i=0; i < _morphTargets.size(); i++)
{
if (_morphTargets[i].getWeight() > 0)
{
// See if any the targets use the internal optimized geometry
osg::Geometry* targetGeometry = _morphTargets[i].getGeometry()->getInternalOptimizedGeometry();
if (!targetGeometry)
targetGeometry = _morphTargets[i].getGeometry();
osg::Vec3Array* targetPos = dynamic_cast<osg::Vec3Array*>(targetGeometry->getVertexArray());
osg::Vec3Array* targetNormals = dynamic_cast<osg::Vec3Array*>(targetGeometry->getNormalArray());
if (initialized)
{
// If vertices are initialized, add the morphtargets
for (unsigned int j=0; j < pos->size(); j++)
{
(*pos)[j] += (*targetPos)[j] * _morphTargets[i].getWeight();
}
if (_morphNormals)
{
for (unsigned int j=0; j < normal->size(); j++)
{
(*normal)[j] += (*targetNormals)[j] * _morphTargets[i].getWeight();
}
}
}
else
{
// If not initialized, initialize with this morph target
initialized = true;
for (unsigned int j=0; j < pos->size(); j++)
{
(*pos)[j] = (*targetPos)[j] * _morphTargets[i].getWeight();
}
if (_morphNormals)
{
for (unsigned int j=0; j < normal->size(); j++)
{
(*normal)[j] = (*targetNormals)[j] * _morphTargets[i].getWeight();
}
}
}
}
}
pos->dirty();
if (_morphNormals)
{
for (unsigned int j=0; j < normal->size(); j++)
{
(*normal)[j].normalize();
}
normal->dirty();
}
}
dirtyBound();
_dirty = false;
}
}
UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) :
osg::Object(apc, copyop),
AnimationUpdateCallback<osg::NodeCallback>(apc, copyop)
{
}
UpdateMorph::UpdateMorph(const std::string& name) : AnimationUpdateCallback<osg::NodeCallback>(name)
{
}
/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateMorph::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
osg::Geode* geode = dynamic_cast<osg::Geode*>(node);
if (geode)
{
unsigned int numDrawables = geode->getNumDrawables();
for (unsigned int i = 0; i != numDrawables; ++i)
{
osgAnimation::MorphGeometry* morph = dynamic_cast<osgAnimation::MorphGeometry*>(geode->getDrawable(i));
if (morph)
{
// Update morph weights
std::map<int, osg::ref_ptr<osgAnimation::FloatTarget> >::iterator iter = _weightTargets.begin();
while (iter != _weightTargets.end())
{
if (iter->second->getValue() >= 0)
{
morph->setWeight(iter->first, iter->second->getValue());
}
++iter;
}
}
}
}
}
traverse(node,nv);
}
bool UpdateMorph::needLink() const
{
// the idea is to return true if nothing is linked
return (_weightTargets.size() == 0);
}
bool UpdateMorph::link(osgAnimation::Channel* channel)
{
// Typically morph geometries only have the weights for morph targets animated
// Expect a weight value
// TODO Should we make this more generic to handle other things than single values?
int weightIndex = atoi(channel->getName().c_str());
if (weightIndex >= 0)
{
osgAnimation::FloatTarget* ft = _weightTargets[weightIndex].get();
if (!ft)
{
ft = new osgAnimation::FloatTarget;
_weightTargets[weightIndex] = ft;
}
return channel->setTarget(ft);
}
else
{
osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
}
return false;
}

View File

@@ -1,129 +1,209 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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:
* 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.
*
* Cedric Pinson <mornifle@plopbyte.net>
*
* 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 <osgAnimation/RigGeometry>
#include <osgAnimation/RigTransformSoftware>
#include <sstream>
#include <osg/GL2Extensions>
using namespace osgAnimation;
// The idea is to compute a bounding box with a factor x of the first step we compute the bounding box
class RigComputeBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback
{
public:
RigComputeBoundingBoxCallback(double factor = 2.0) : _computed(false), _factor(factor) {}
void reset() { _computed = false; }
virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const
{
const osgAnimation::RigGeometry& rig = dynamic_cast<const osgAnimation::RigGeometry&>(drawable);
// if a valid inital bounding box is set we use it without asking more
if (rig.getInitialBound().valid())
return rig.getInitialBound();
if (_computed)
return _boundingBox;
// if the computing of bb is invalid (like no geometry inside)
// then dont tag the bounding box as computed
osg::BoundingBox bb = rig.computeBound();
if (!bb.valid())
return bb;
_boundingBox.expandBy(bb);
osg::Vec3 center = _boundingBox.center();
osg::Vec3 vec = (_boundingBox._max-center)*_factor;
_boundingBox.expandBy(center + vec);
_boundingBox.expandBy(center - vec);
_computed = true;
// osg::notify(osg::NOTICE) << "build the bounding box for RigGeometry " << rig.getName() << " " << _boundingBox._min << " " << _boundingBox._max << std::endl;
return _boundingBox;
}
protected:
mutable bool _computed;
double _factor;
mutable osg::BoundingBox _boundingBox;
};
RigGeometry::RigGeometry()
{
setUseDisplayList(false);
_supportsDisplayList = false;
setUseVertexBufferObjects(true);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
_needToComputeMatrix = true;
_matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity();
// disable the computation of boundingbox for the rig mesh
setComputeBoundingBoxCallback(new RigComputeBoundingBoxCallback);
}
RigGeometry::RigGeometry(const osg::Geometry& b) : osg::Geometry(b, osg::CopyOp::SHALLOW_COPY)
{
setUseDisplayList(false);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
_needToComputeMatrix = true;
_matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity();
}
RigGeometry::RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop) :
RigGeometry::RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop) :
osg::Geometry(b,copyop),
_positionSource(b._positionSource),
_normalSource(b._normalSource),
_geometry(b._geometry),
_vertexInfluenceSet(b._vertexInfluenceSet),
_vertexInfluenceMap(b._vertexInfluenceMap),
_transformVertexes(b._transformVertexes),
_needToComputeMatrix(b._needToComputeMatrix)
_needToComputeMatrix(b._needToComputeMatrix)
{
// we dont copy the RigImplementation yet. because the RigImplementation need to be initialized in a valid graph, with a skeleton ...
// dont know yet what to do with a clone of a RigGeometry
}
void RigGeometry::buildTransformer(Skeleton* root)
const osg::Matrix& RigGeometry::getMatrixFromSkeletonToGeometry() const { return _matrixFromSkeletonToGeometry; }
const osg::Matrix& RigGeometry::getInvMatrixFromSkeletonToGeometry() const { return _invMatrixFromSkeletonToGeometry;}
void RigGeometry::drawImplementation(osg::RenderInfo& renderInfo) const
{
Bone::BoneMap bm = root->getBoneMap();
_transformVertexes.init(bm, _vertexInfluenceSet.getUniqVertexSetToBoneSetList());
_root = root;
osg::Geometry::drawImplementation(renderInfo);
}
void RigGeometry::buildVertexSet()
void RigGeometry::buildVertexInfluenceSet()
{
if (!_vertexInfluenceMap.valid())
if (!_vertexInfluenceMap.valid())
{
osg::notify(osg::WARN) << "buildVertexSet can't be called without VertexInfluence already set to the RigGeometry ( " << getName() << " ) " << std::endl;
osg::notify(osg::WARN) << "buildVertexInfluenceSet 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++)
++it)
_vertexInfluenceSet.addVertexInfluence(it->second);
_vertexInfluenceSet.buildVertex2BoneList();
_vertexInfluenceSet.buildUniqVertexSetToBoneSetList();
std::cout << "uniq groups " << _vertexInfluenceSet.getUniqVertexSetToBoneSetList().size() << " for " << getName() << std::endl;
osg::notify(osg::NOTICE) << "uniq groups " << _vertexInfluenceSet.getUniqVertexSetToBoneSetList().size() << " for " << getName() << std::endl;
}
void RigGeometry::computeMatrixFromRootSkeleton()
void RigGeometry::computeMatrixFromRootSkeleton()
{
if (!_root.valid())
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];
osg::Matrix notRoot = _root->getMatrix();
_matrixFromSkeletonToGeometry = mtxList[0] * osg::Matrix::inverse(notRoot);
_invMatrixFromSkeletonToGeometry = osg::Matrix::inverse(_matrixFromSkeletonToGeometry);
_needToComputeMatrix = false;
}
void RigGeometry::transformSoftwareMethod()
void RigGeometry::update()
{
setUseDisplayList(false);
setUseVertexBufferObjects(true);
// std::cout << getName() << " _matrixFromSkeletonToGeometry" << _matrixFromSkeletonToGeometry << std::endl;
osg::Vec3Array* pos = dynamic_cast<osg::Vec3Array*>(getVertexArray());
if (pos && _positionSource.size() != pos->size())
if (!getRigTransformImplementation())
{
_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);
_rigTransformImplementation = new RigTransformSoftware;
}
if (!_positionSource.empty())
{
_transformVertexes.compute<osg::Vec3>(_matrixFromSkeletonToGeometry, _invMatrixFromSkeletonToGeometry, &_positionSource.front(), &pos->front());
pos->dirty();
}
if (!_normalSource.empty())
{
_transformVertexes.computeNormal<osg::Vec3>(_matrixFromSkeletonToGeometry, _invMatrixFromSkeletonToGeometry, &_normalSource.front(), &normal->front());
normal->dirty();
}
if (getUseDisplayList())
dirtyDisplayList();
dirtyBound();
RigTransform& implementation = *getRigTransformImplementation();
(implementation)(*this);
}
const osgAnimation::Skeleton* RigGeometry::getSkeleton() const { return _root.get(); }
osgAnimation::Skeleton* RigGeometry::getSkeleton() { return _root.get(); }
void RigGeometry::copyFrom(osg::Geometry& from)
{
bool copyToSelf = (this==&from);
osg::Geometry& target = *this;
if (!copyToSelf) target.setStateSet(from.getStateSet());
// copy over primitive sets.
if (!copyToSelf) target.getPrimitiveSetList() = from.getPrimitiveSetList();
if (from.getVertexArray())
{
if (!copyToSelf) target.setVertexArray(from.getVertexArray());
}
target.setNormalBinding(from.getNormalBinding());
if (from.getNormalArray())
{
if (!copyToSelf) target.setNormalArray(from.getNormalArray());
}
target.setColorBinding(from.getColorBinding());
if (from.getColorArray())
{
if (!copyToSelf) target.setColorArray(from.getColorArray());
}
target.setSecondaryColorBinding(from.getSecondaryColorBinding());
if (from.getSecondaryColorArray())
{
if (!copyToSelf) target.setSecondaryColorArray(from.getSecondaryColorArray());
}
target.setFogCoordBinding(from.getFogCoordBinding());
if (from.getFogCoordArray())
{
if (!copyToSelf) target.setFogCoordArray(from.getFogCoordArray());
}
for(unsigned int ti=0;ti<from.getNumTexCoordArrays();++ti)
{
if (from.getTexCoordArray(ti))
{
if (!copyToSelf) target.setTexCoordArray(ti,from.getTexCoordArray(ti));
}
}
ArrayDataList& arrayList = from.getVertexAttribArrayList();
for(unsigned int vi=0;vi< arrayList.size();++vi)
{
ArrayData& arrayData = arrayList[vi];
if (arrayData.array.valid())
{
if (!copyToSelf) target.setVertexAttribData(vi,arrayData);
}
}
}
const VertexInfluenceSet& RigGeometry::getVertexInfluenceSet() const { return _vertexInfluenceSet;}
const Skeleton* RigGeometry::getSkeleton() const { return _root.get(); }
Skeleton* RigGeometry::getSkeleton() { return _root.get(); }
void RigGeometry::setSkeleton(Skeleton* root) { _root = root;}
RigTransform* RigGeometry::getRigTransformImplementation() { return _rigTransformImplementation.get(); }
void RigGeometry::setRigTransformImplementation(RigTransform* rig) { _rigTransformImplementation = rig; }
osg::Geometry* RigGeometry::getSourceGeometry() { return _geometry.get(); }
const osg::Geometry* RigGeometry::getSourceGeometry() const { return _geometry.get(); }
void RigGeometry::setSourceGeometry(osg::Geometry* geometry) { _geometry = geometry; }

View File

@@ -0,0 +1,272 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/RigTransformHardware>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/BoneMapVisitor>
#include <sstream>
using namespace osgAnimation;
RigTransformHardware::RigTransformHardware()
{
_needInit = true;
_bonesPerVertex = 0;
_nbVertexes = 0;
}
osg::Vec4Array* RigTransformHardware::getVertexAttrib(int index)
{
if (index >= (int)_boneWeightAttribArrays.size())
return 0;
return _boneWeightAttribArrays[index].get();
}
int RigTransformHardware::getNumVertexAttrib()
{
return _boneWeightAttribArrays.size();
}
osg::Uniform* RigTransformHardware::getMatrixPaletteUniform()
{
return _uniformMatrixPalette.get();
}
void RigTransformHardware::computeMatrixPaletteUniform(const osg::Matrix& transformFromSkeletonToGeometry, const osg::Matrix& invTransformFromSkeletonToGeometry)
{
for (int i = 0; i < (int)_bonePalette.size(); i++)
{
osg::ref_ptr<Bone> bone = _bonePalette[i].get();
const osg::Matrix& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace();
const osg::Matrix& boneMatrix = bone->getMatrixInSkeletonSpace();
osg::Matrix resultBoneMatrix = invBindMatrix * boneMatrix;
osg::Matrix result = transformFromSkeletonToGeometry * resultBoneMatrix * invTransformFromSkeletonToGeometry;
if (!_uniformMatrixPalette->setElement(i, result))
osg::notify(osg::WARN) << "RigTransformHardware::computeUniformMatrixPalette can't set uniform at " << i << " elements" << std::endl;
}
}
int RigTransformHardware::getNumBonesPerVertex() const { return _bonesPerVertex;}
int RigTransformHardware::getNumVertexes() const { return _nbVertexes;}
bool RigTransformHardware::createPalette(int nbVertexes, BoneMap boneMap, const VertexInfluenceSet::VertexIndexToBoneWeightMap& vertexIndexToBoneWeightMap)
{
typedef std::map<std::string, int> BoneNameCountMap;
typedef std::map<std::string, int> BoneNamePaletteIndex;
BoneNamePaletteIndex bname2palette;
BonePalette palette;
BoneNameCountMap boneNameCountMap;
// init vertex attribute data
VertexIndexWeightList vertexIndexWeight;
vertexIndexWeight.resize(nbVertexes);
int maxBonePerVertex = 0;
for (VertexInfluenceSet::VertexIndexToBoneWeightMap::const_iterator it = vertexIndexToBoneWeightMap.begin(); it != vertexIndexToBoneWeightMap.end(); ++it)
{
int vertexIndex = it->first;
const VertexInfluenceSet::BoneWeightList& boneWeightList = it->second;
int bonesForThisVertex = 0;
for (VertexInfluenceSet::BoneWeightList::const_iterator it = boneWeightList.begin(); it != boneWeightList.end(); ++it)
{
const VertexInfluenceSet::BoneWeight& bw = *it;
if (boneNameCountMap.find(bw.getBoneName()) != boneNameCountMap.end())
{
boneNameCountMap[bw.getBoneName()]++;
bonesForThisVertex++; // count max number of bones per vertexes
vertexIndexWeight[vertexIndex].push_back(IndexWeightEntry(bname2palette[bw.getBoneName()],bw.getWeight()));
}
else if (fabs(bw.getWeight()) > 1e-2) // dont use bone with weight too small
{
if (boneMap.find(bw.getBoneName()) == boneMap.end())
{
osg::notify(osg::INFO) << "RigTransformHardware::createPalette can't find bone " << bw.getBoneName() << " skip this influence" << std::endl;
continue;
}
boneNameCountMap[bw.getBoneName()] = 1; // for stats
bonesForThisVertex++;
palette.push_back(boneMap[bw.getBoneName()]);
bname2palette[bw.getBoneName()] = palette.size()-1;
vertexIndexWeight[vertexIndex].push_back(IndexWeightEntry(bname2palette[bw.getBoneName()],bw.getWeight()));
}
else
{
osg::notify(osg::WARN) << "RigTransformHardware::createPalette Bone " << bw.getBoneName() << " has a weight " << bw.getWeight() << " for vertex " << vertexIndex << " this bone will not be in the palette" << std::endl;
}
}
maxBonePerVertex = osg::maximum(maxBonePerVertex, bonesForThisVertex);
}
osg::notify(osg::INFO) << "RigTransformHardware::createPalette maximum number of bone per vertex is " << maxBonePerVertex << std::endl;
osg::notify(osg::INFO) << "RigTransformHardware::createPalette matrix palette has " << boneNameCountMap.size() << " entries" << std::endl;
for (BoneNameCountMap::iterator it = boneNameCountMap.begin(); it != boneNameCountMap.end(); ++it)
{
osg::notify(osg::INFO) << "RigTransformHardware::createPalette Bone " << it->first << " is used " << it->second << " times" << std::endl;
}
osg::notify(osg::INFO) << "RigTransformHardware::createPalette will use " << boneNameCountMap.size() * 4 << " uniforms" << std::endl;
for (int i = 0 ; i < (int)vertexIndexWeight.size(); i++)
vertexIndexWeight[i].resize(maxBonePerVertex);
_nbVertexes = nbVertexes;
_bonesPerVertex = maxBonePerVertex;
_bonePalette = palette;
_vertexIndexMatrixWeightList = vertexIndexWeight;
_uniformMatrixPalette = createVertexUniform();
_boneWeightAttribArrays = createVertexAttribList();
return true;
}
//
// create vertex attribute by 2 bones
// vec4(boneIndex0, weight0, boneIndex1, weight1)
// if more bones are needed then other attributes are created
// vec4(boneIndex2, weight2, boneIndex3, weight3)
// the idea is to use this format to have a granularity smaller
// than the 4 bones using two vertex attributes
//
RigTransformHardware::BoneWeightAttribList RigTransformHardware::createVertexAttribList()
{
BoneWeightAttribList arrayList;
int nbArray = static_cast<int>(ceilf(getNumBonesPerVertex() * 0.5));
if (!nbArray)
return arrayList;
arrayList.resize(nbArray);
for (int i = 0; i < nbArray; i++)
{
osg::ref_ptr<osg::Vec4Array> array = new osg::Vec4Array;
arrayList[i] = array;
int nbVertexes = getNumVertexes();
array->resize(nbVertexes);
for (int j = 0; j < nbVertexes; j++)
{
for (int b = 0; b < 2; b++)
{
// the granularity is 2 so if we have only one bone
// it's convenient to init the second with a weight 0
int boneIndexInList = i*2 + b;
int boneIndexInVec4 = b*2;
(*array)[j][0 + boneIndexInVec4] = 0;
(*array)[j][1 + boneIndexInVec4] = 0;
if (boneIndexInList < getNumBonesPerVertex())
{
float boneIndex = static_cast<float>(_vertexIndexMatrixWeightList[j][boneIndexInList].getIndex());
float boneWeight = _vertexIndexMatrixWeightList[j][boneIndexInList].getWeight();
// fill the vec4
(*array)[j][0 + boneIndexInVec4] = boneIndex;
(*array)[j][1 + boneIndexInVec4] = boneWeight;
}
}
}
}
return arrayList;
}
osg::Uniform* RigTransformHardware::createVertexUniform()
{
osg::Uniform* uniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "matrixPalette", _bonePalette.size());
return uniform;
}
void RigTransformHardware::setShader(osg::Shader* shader)
{
_shader = shader;
}
bool RigTransformHardware::init(RigGeometry& geom)
{
osg::Geometry& source = *geom.getSourceGeometry();
osg::Vec3Array* positionSrc = dynamic_cast<osg::Vec3Array*>(source.getVertexArray());
if (!positionSrc)
{
osg::notify(osg::WARN) << "RigTransformHardware no vertex array in the geometry " << geom.getName() << std::endl;
return false;
}
if (!geom.getSkeleton())
{
osg::notify(osg::WARN) << "RigTransformHardware no skeleton set in geometry " << geom.getName() << std::endl;
return false;
}
// copy shallow from source geometry to rig
geom.copyFrom(source);
BoneMapVisitor mapVisitor;
geom.getSkeleton()->accept(mapVisitor);
BoneMap bm = mapVisitor.getBoneMap();
if (!createPalette(positionSrc->size(),bm, geom.getVertexInfluenceSet().getVertexToBoneList()))
return false;
osg::ref_ptr<osg::Program> program = new osg::Program;
program->setName("HardwareSkinning");
if (!_shader.valid())
_shader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"skinning.vert");
if (!_shader.valid()) {
osg::notify(osg::WARN) << "RigTransformHardware can't load VertexShader" << std::endl;
return false;
}
// replace max matrix by the value from uniform
{
std::string str = _shader->getShaderSource();
std::string toreplace = std::string("MAX_MATRIX");
std::size_t start = str.find(toreplace);
std::stringstream ss;
ss << getMatrixPaletteUniform()->getNumElements();
str.replace(start, toreplace.size(), ss.str());
_shader->setShaderSource(str);
osg::notify(osg::INFO) << "Shader " << str << std::endl;
}
int attribIndex = 11;
int nbAttribs = getNumVertexAttrib();
for (int i = 0; i < nbAttribs; i++)
{
std::stringstream ss;
ss << "boneWeight" << i;
program->addBindAttribLocation(ss.str(), attribIndex + i);
geom.setVertexAttribData(attribIndex + i, osg::Geometry::ArrayData(getVertexAttrib(i),osg::Geometry::BIND_PER_VERTEX));
osg::notify(osg::INFO) << "set vertex attrib " << ss.str() << std::endl;
}
program->addShader(_shader.get());
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
ss->addUniform(getMatrixPaletteUniform());
ss->addUniform(new osg::Uniform("nbBonesPerVertex", getNumBonesPerVertex()));
ss->setAttributeAndModes(program.get());
geom.setStateSet(ss.get());
_needInit = false;
return true;
}
void RigTransformHardware::operator()(RigGeometry& geom)
{
if (_needInit)
if (!init(geom))
return;
computeMatrixPaletteUniform(geom.getMatrixFromSkeletonToGeometry(), geom.getInvMatrixFromSkeletonToGeometry());
}

View File

@@ -0,0 +1,144 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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 <osgAnimation/RigTransformSoftware>
#include <osgAnimation/BoneMapVisitor>
#include <osgAnimation/RigGeometry>
using namespace osgAnimation;
RigTransformSoftware::RigTransformSoftware()
{
_needInit = true;
}
bool RigTransformSoftware::init(RigGeometry& geom)
{
if (!geom.getSkeleton())
return false;
BoneMapVisitor mapVisitor;
geom.getSkeleton()->accept(mapVisitor);
BoneMap bm = mapVisitor.getBoneMap();
initVertexSetFromBones(bm, geom.getVertexInfluenceSet().getUniqVertexSetToBoneSetList());
if (geom.getSourceGeometry())
geom.copyFrom(*geom.getSourceGeometry());
geom.setVertexArray(0);
geom.setNormalArray(0);
_needInit = false;
return true;
}
void RigTransformSoftware::operator()(RigGeometry& geom)
{
if (_needInit)
if (!init(geom))
return;
if (!geom.getSourceGeometry()) {
osg::notify(osg::WARN) << this << " RigTransformSoftware no source geometry found on RigGeometry" << std::endl;
return;
}
osg::Geometry& source = *geom.getSourceGeometry();
osg::Geometry& destination = geom;
osg::Vec3Array* positionSrc = dynamic_cast<osg::Vec3Array*>(source.getVertexArray());
osg::Vec3Array* positionDst = dynamic_cast<osg::Vec3Array*>(destination.getVertexArray());
if (positionSrc && (!positionDst || (positionDst->size() != positionSrc->size()) ) )
{
if (!positionDst)
{
positionDst = new osg::Vec3Array;
positionDst->setDataVariance(osg::Object::DYNAMIC);
destination.setVertexArray(positionDst);
}
*positionDst = *positionSrc;
}
osg::Vec3Array* normalSrc = dynamic_cast<osg::Vec3Array*>(source.getNormalArray());
osg::Vec3Array* normalDst = dynamic_cast<osg::Vec3Array*>(destination.getNormalArray());
if (normalSrc && (!normalDst || (normalDst->size() != normalSrc->size()) ) )
{
if (!normalDst)
{
normalDst = new osg::Vec3Array;
normalDst->setDataVariance(osg::Object::DYNAMIC);
destination.setNormalArray(normalDst);
destination.setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
}
*normalDst = *normalSrc;
}
if (positionDst && !positionDst->empty())
{
compute<osg::Vec3>(geom.getMatrixFromSkeletonToGeometry(),
geom.getInvMatrixFromSkeletonToGeometry(),
&positionSrc->front(),
&positionDst->front());
positionDst->dirty();
}
if (normalDst && !normalDst->empty())
{
computeNormal<osg::Vec3>(geom.getMatrixFromSkeletonToGeometry(),
geom.getInvMatrixFromSkeletonToGeometry(),
&normalSrc->front(),
&normalDst->front());
normalDst->dirty();
}
}
void RigTransformSoftware::initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexSetToBoneSetList& influence)
{
_boneSetVertexSet.clear();
int size = influence.size();
_boneSetVertexSet.resize(size);
for (int i = 0; i < size; i++)
{
const VertexInfluenceSet::UniqVertexSetToBoneSet& inf = influence[i];
int nbBones = inf.getBones().size();
BoneWeightList& boneList = _boneSetVertexSet[i].getBones();
double sumOfWeight = 0;
for (int b = 0; b < nbBones; b++)
{
const std::string& bname = inf.getBones()[b].getBoneName();
float weight = inf.getBones()[b].getWeight();
BoneMap::const_iterator it = map.find(bname);
if (it == map.end())
{
osg::notify(osg::WARN) << "RigTransformSoftware Bone " << bname << " not found, skip the influence group " <<bname << std::endl;
continue;
}
Bone* bone = it->second.get();
boneList.push_back(BoneWeight(bone, weight));
sumOfWeight += weight;
}
// if a bone referenced by a vertexinfluence is missed it can make the sum less than 1.0
// so we check it and renormalize the all weight bone
const double threshold = 1e-4;
if (!_boneSetVertexSet[i].getBones().empty() &&
(sumOfWeight < 1.0 - threshold || sumOfWeight > 1.0 + threshold))
{
for (int b = 0; b < (int)boneList.size(); b++)
boneList[b].setWeight(boneList[b].getWeight() / sumOfWeight);
}
_boneSetVertexSet[i].getVertexes() = inf.getVertexes();
}
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -14,29 +14,29 @@
#include <osgAnimation/Skeleton>
#include <osgAnimation/Bone>
#include <osg/Notify>
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);
}
};
Skeleton::Skeleton() {}
Skeleton::Skeleton(const Skeleton& b, const osg::CopyOp& copyop) : osg::MatrixTransform(b,copyop) {}
struct updateMatrixVisitor : public osg::NodeVisitor
Skeleton::UpdateSkeleton::UpdateSkeleton() : _needValidate(true) {}
Skeleton::UpdateSkeleton::UpdateSkeleton(const UpdateSkeleton& us, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : osg::Object(us, copyop), osg::NodeCallback(us, copyop)
{
osg::Matrix _skeleton;
updateMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void apply(osg::Node& node) { return ;}
_needValidate = true;
}
bool Skeleton::UpdateSkeleton::needToValidate() const
{
return _needValidate;
}
class ValidateSkeletonVisitor : public osg::NodeVisitor
{
public:
ValidateSkeletonVisitor(): 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
@@ -44,45 +44,50 @@ struct updateMatrixVisitor : public osg::NodeVisitor
if (!bone)
return;
Bone* parent = bone->getBoneParent();
if (bone->needToComputeBindMatrix())
bool foundNonBone = false;
for (unsigned int i = 0; i < bone->getNumChildren(); ++i)
{
computeBindMatrixVisitor visitor;
bone->accept(visitor);
if (dynamic_cast<Bone*>(bone->getChild(i)))
{
if (foundNonBone)
{
osg::notify(osg::WARN) <<
"Warning: a Bone was found after a non-Bone child "
"within a Skeleton. Children of a Bone must be ordered "
"with all child Bones first for correct update order." << std::endl;
setTraversalMode(TRAVERSE_NONE);
return;
}
}
else
{
foundNonBone = true;
}
}
if (parent)
bone->setMatrixInSkeletonSpace(bone->getMatrixInBoneSpace() * bone->getBoneParent()->getMatrixInSkeletonSpace());
else
bone->setMatrixInSkeletonSpace(bone->getMatrixInBoneSpace());
traverse(node);
}
};
void Skeleton::UpdateSkeleton::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
if (nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
Skeleton* b = dynamic_cast<Skeleton*>(node);
if (b)
Skeleton* skeleton = dynamic_cast<Skeleton*>(node);
if (_needValidate && skeleton)
{
// 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;
b->accept(visitor);
ValidateSkeletonVisitor visitor;
for (unsigned int i = 0; i < skeleton->getNumChildren(); ++i)
{
osg::Node* child = skeleton->getChild(i);
child->accept(visitor);
}
_needValidate = false;
}
}
traverse(node,nv);
}
Skeleton::Skeleton()
{
}
void Skeleton::setDefaultUpdateCallback()
{
setUpdateCallback(new Skeleton::UpdateSkeleton );

View File

@@ -0,0 +1,40 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedMatrixElement>
using namespace osgAnimation;
StackedMatrixElement::StackedMatrixElement() {}
StackedMatrixElement::StackedMatrixElement(const std::string& name, const osg::Matrix& matrix) : StackedTransformElement(), _matrix(matrix) { setName(name); }
StackedMatrixElement::StackedMatrixElement(const osg::Matrix& matrix) : _matrix(matrix) { setName("matrix"); }
StackedMatrixElement::StackedMatrixElement(const StackedMatrixElement& rhs, const osg::CopyOp& c) : StackedTransformElement(rhs, c), _matrix(rhs._matrix)
{
if (rhs._target.valid())
_target = new MatrixTarget(*rhs._target);
}
Target* StackedMatrixElement::getOrCreateTarget()
{
if (!_target.valid())
_target = new MatrixTarget(_matrix);
return _target.get();
}
void StackedMatrixElement::update()
{
if (_target.valid())
_matrix = _target->getValue();
}

View File

@@ -0,0 +1,53 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedQuaternionElement>
using namespace osgAnimation;
StackedQuaternionElement::StackedQuaternionElement(const std::string& name, const osg::Quat& quaternion) : _quaternion(quaternion) { setName(name); }
StackedQuaternionElement::StackedQuaternionElement(const StackedQuaternionElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _quaternion(rhs._quaternion)
{
if (rhs._target.valid())
_target = new QuatTarget(*rhs._target);
}
StackedQuaternionElement::StackedQuaternionElement(const osg::Quat& quat) : _quaternion(quat) { setName("quaternion"); }
StackedQuaternionElement::StackedQuaternionElement()
{
}
const osg::Quat& StackedQuaternionElement::getQuaternion() const { return _quaternion; }
void StackedQuaternionElement::setQuaternion(const osg::Quat& q) { _quaternion = q; }
void StackedQuaternionElement::applyToMatrix(osg::Matrix& matrix) const {matrix.preMultRotate(_quaternion);}
osg::Matrix StackedQuaternionElement::getAsMatrix() const { return osg::Matrix(_quaternion); }
bool StackedQuaternionElement::isIdentity() const { return (_quaternion[0] == 0 && _quaternion[1] == 0 && _quaternion[2] == 0 && _quaternion[3] == 1.0); }
void StackedQuaternionElement::update()
{
if (_target.valid())
_quaternion = _target->getValue();
}
Target* StackedQuaternionElement::getOrCreateTarget()
{
if (!_target.valid())
_target = new QuatTarget(_quaternion);
return _target.get();
}
Target* StackedQuaternionElement::getTarget() {return _target.get();}
const Target* StackedQuaternionElement::getTarget() const {return _target.get();}

View File

@@ -0,0 +1,55 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedRotateAxisElement>
using namespace osgAnimation;
StackedRotateAxisElement::StackedRotateAxisElement(const std::string& name, const osg::Vec3& axis, double angle) : StackedTransformElement(), _axis(axis), _angle(angle) { setName(name); }
StackedRotateAxisElement::StackedRotateAxisElement(const osg::Vec3& axis, double angle) : _axis(axis), _angle(angle) { setName("rotateaxis"); }
StackedRotateAxisElement::StackedRotateAxisElement() {}
StackedRotateAxisElement::StackedRotateAxisElement(const StackedRotateAxisElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _axis(rhs._axis), _angle(rhs._angle)
{
if (rhs._target.valid())
_target = new FloatTarget(*rhs._target);
}
osg::Matrix StackedRotateAxisElement::getAsMatrix() const { return osg::Matrix::rotate(osg::Quat(_angle, _axis)); }
void StackedRotateAxisElement::update()
{
if (_target.valid())
_angle = _target->getValue();
}
const osg::Vec3& StackedRotateAxisElement::getAxis() const { return _axis; }
const double StackedRotateAxisElement::getAngle() const { return _angle; }
void StackedRotateAxisElement::setAxis(const osg::Vec3& axis)
{
_axis = axis;
}
void StackedRotateAxisElement::setAngle(const double& angle)
{
_angle = angle;
}
Target* StackedRotateAxisElement::getOrCreateTarget()
{
if (!_target.valid())
_target = new FloatTarget(_angle);
return _target.get();
}
void StackedRotateAxisElement::applyToMatrix(osg::Matrix& matrix) const { matrix.preMultRotate(osg::Quat(_angle, _axis)); }

View File

@@ -0,0 +1,56 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedScaleElement>
using namespace osgAnimation;
StackedScaleElement::StackedScaleElement(const std::string& name, const osg::Vec3& scale) : _scale(scale) { setName(name); }
StackedScaleElement::StackedScaleElement(const osg::Vec3& scale) : _scale(scale) { setName("scale"); }
StackedScaleElement::StackedScaleElement(const StackedScaleElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _scale(rhs._scale)
{
if (rhs._target.valid())
_target = new Vec3Target(*rhs._target);
}
const osg::Vec3& StackedScaleElement::getScale() const { return _scale; }
void StackedScaleElement::setScale(const osg::Vec3& scale) { _scale = scale; }
Target* StackedScaleElement::getTarget() {return _target.get();}
const Target* StackedScaleElement::getTarget() const {return _target.get();}
bool StackedScaleElement::isIdentity() const { return (_scale.x() == 1 && _scale.y() == 1 && _scale.z() == 1); }
osg::Matrix StackedScaleElement::getAsMatrix() const { return osg::Matrix::scale(_scale); }
void StackedScaleElement::applyToMatrix(osg::Matrix& matrix) const { matrix.preMultScale(_scale); }
StackedScaleElement::StackedScaleElement()
{
_scale = osg::Vec3(1,1,1);
}
void StackedScaleElement::update()
{
if (_target.valid())
_scale = _target->getValue();
}
Target* StackedScaleElement::getOrCreateTarget()
{
if (!_target.valid())
_target = new Vec3Target(_scale);
return _target.get();
}

View File

@@ -0,0 +1,66 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedTransform>
using namespace osgAnimation;
StackedTransform::StackedTransform() {}
StackedTransform::StackedTransform(const StackedTransform& rhs, const osg::CopyOp& co)
{
reserve(rhs.size());
for (StackedTransform::const_iterator it = rhs.begin(); it != rhs.end(); ++it)
{
const StackedTransformElement* element = it->get();
if (element)
push_back(osg::clone(element,co));
}
}
void StackedTransform::update()
{
int dirty = 0;
for (StackedTransform::iterator it = begin(); it != end(); ++it)
{
StackedTransformElement* element = it->get();
if (!element)
continue;
// update and check if there are changes
element->update();
if (element->isIdentity())
continue;
dirty++;
}
if (!dirty)
return;
// dirty update matrix
_matrix.makeIdentity();
for (StackedTransform::iterator it = begin(); it != end(); ++it)
{
StackedTransformElement* element = it->get();
if (!element || element->isIdentity())
continue;
element->applyToMatrix(_matrix);
}
}
const osg::Matrix& StackedTransform::getMatrix() const
{
return _matrix;
}

View File

@@ -0,0 +1,50 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedTranslateElement>
using namespace osgAnimation;
StackedTranslateElement::StackedTranslateElement(const std::string& name, const osg::Vec3& translate) : _translate(translate) { setName(name); }
StackedTranslateElement::StackedTranslateElement(const osg::Vec3& translate) : _translate(translate) { setName("translate"); }
StackedTranslateElement::StackedTranslateElement() {}
StackedTranslateElement::StackedTranslateElement(const StackedTranslateElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _translate(rhs._translate)
{
if (rhs._target.valid())
_target = new Vec3Target(*rhs._target);
}
void StackedTranslateElement::applyToMatrix(osg::Matrix& matrix) const {matrix.preMultTranslate(_translate);}
osg::Matrix StackedTranslateElement::getAsMatrix() const { return osg::Matrix::translate(_translate); }
bool StackedTranslateElement::isIdentity() const { return (_translate[0] == 0 && _translate[1] == 0 && _translate[2] == 0); }
const osg::Vec3& StackedTranslateElement::getTranslate() const { return _translate; }
void StackedTranslateElement::setTranslate(const osg::Vec3& value) { _translate = value; }
Target* StackedTranslateElement::getOrCreateTarget()
{
if (!_target.valid())
_target = new Vec3Target(_translate);
return _target.get();
}
Target* StackedTranslateElement::getTarget() {return _target.get();}
const Target* StackedTranslateElement::getTarget() const {return _target.get();}
void StackedTranslateElement::update()
{
if (_target.valid())
_translate = _target->getValue();
}

View File

@@ -0,0 +1,722 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* 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 <sstream>
#include <iomanip>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <osg/io_utils>
#include <osg/NodeVisitor>
#include <osg/MatrixTransform>
#include <osgViewer/Renderer>
#include <osgAnimation/StatsHandler>
#include <osgAnimation/EaseMotion>
#include <osgAnimation/StatsVisitor>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/Renderer>
#include <osgAnimation/TimelineAnimationManager>
#include <osg/PolygonMode>
#include <osg/Geometry>
#include <iostream>
#include <cstdlib>
static unsigned int getRandomValueinRange(unsigned int v)
{
return static_cast<unsigned int>((rand() * 1.0 * v)/(RAND_MAX-1));
}
namespace osgAnimation
{
osg::Geometry* createBackgroundRectangle(const osg::Vec3& pos, const float width, const float height, osg::Vec4& color)
{
osg::StateSet *ss = new osg::StateSet;
osg::Geometry* geometry = new osg::Geometry;
geometry->setUseDisplayList(false);
geometry->setStateSet(ss);
osg::Vec3Array* vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices);
vertices->push_back(osg::Vec3(pos.x(), pos.y(), 0));
vertices->push_back(osg::Vec3(pos.x(), pos.y()-height,0));
vertices->push_back(osg::Vec3(pos.x()+width, pos.y()-height,0));
vertices->push_back(osg::Vec3(pos.x()+width, pos.y(),0));
osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back(color);
geometry->setColorArray(colors);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
osg::DrawElementsUInt *base = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS,0);
base->push_back(0);
base->push_back(1);
base->push_back(2);
base->push_back(3);
geometry->addPrimitiveSet(base);
return geometry;
}
struct StatsGraph : public osg::MatrixTransform
{
StatsGraph(osg::Vec3 pos, float width, float height)
: _pos(pos), _width(width), _height(height),
_statsGraphGeode(new osg::Geode)
{
_pos = pos - osg::Vec3(0, _height, 0.1);
setMatrix(osg::Matrix::translate(_pos));
setDataVariance(osg::Object::DYNAMIC);
addChild(_statsGraphGeode.get());
_statsGraphGeode->setCullingActive(false);
}
void changeYposition(float y)
{
osg::Vec3 _pos = getMatrix().getTrans();
_pos[1] = y - _height;
setMatrix(osg::Matrix::translate(_pos));
}
void addStatGraph(osg::Stats* viewerStats, osg::Stats* stats, const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "")
{
_statsGraphGeode->addDrawable(new Graph(_width, _height, viewerStats, stats, color, max, nameBegin, nameEnd));
}
osg::Vec3 _pos;
float _width;
float _height;
osg::ref_ptr<osg::Geode> _statsGraphGeode;
struct NeverCull : public osg::Drawable::CullCallback
{
NeverCull() {}
bool cull(osg::NodeVisitor* nv, osg::Drawable* drawable, osg::RenderInfo* renderInfo) const { return false;}
};
struct Graph : public osg::Geometry
{
Graph(float width, float height, osg::Stats* viewerStats, osg::Stats* stats,
const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "")
{
setDataVariance(osg::Object::DYNAMIC);
setUseDisplayList(false);
setVertexArray(new osg::Vec3Array);
getVertexArray()->setDataVariance(osg::Object::DYNAMIC);
setColor(color);
setUpdateCallback(new GraphUpdateCallback(width, height, viewerStats, stats, max, nameBegin, nameEnd));
setCullCallback(new NeverCull);
}
void setColor(const osg::Vec4& color) {
osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back(color);
setColorArray(colors);
setColorBinding(osg::Geometry::BIND_OVERALL);
}
};
struct GraphUpdateCallback : public osg::Drawable::UpdateCallback
{
const unsigned int _width;
const unsigned int _height;
mutable unsigned int _curX;
osg::Stats* _viewerStats;
osg::Stats* _stats;
const float _max;
const std::string _nameBegin;
const std::string _nameEnd;
mutable int _frameNumber;
GraphUpdateCallback(float width, float height, osg::Stats* viewerStats, osg::Stats* stats,
float max, const std::string& nameBegin, const std::string& nameEnd = "")
: _width((unsigned int)width), _height((unsigned int)height), _curX(0),
_viewerStats(viewerStats), _stats(stats), _max(max), _nameBegin(nameBegin), _nameEnd(nameEnd), _frameNumber(0)
{
}
virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable)
{
if (nv->getVisitorType() != osg::NodeVisitor::UPDATE_VISITOR)
return;
osg::Geometry* geometry = const_cast<osg::Geometry*>(drawable->asGeometry());
if (!geometry) return;
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
if (!vertices) return;
int frameNumber = nv->getFrameStamp()->getFrameNumber();
if (frameNumber == _frameNumber)
return;
// Get stats
double value;
if (_nameEnd.empty())
{
if (!_stats->getAttribute(_stats->getLatestFrameNumber(), _nameBegin, value ))
{
value = 0.0;
}
}
else
{
double beginValue, endValue;
if (_stats->getAttribute( frameNumber, _nameBegin, beginValue) &&
_stats->getAttribute( frameNumber, _nameEnd, endValue) )
{
value = endValue - beginValue;
}
else
{
value = 0.0;
}
}
// Add new vertex for this frame.
value = osg::clampTo(value, 0.0, double(_max));
if (!vertices->size()) {
for (int i = 0; i < (int)_width; i++)
vertices->push_back(osg::Vec3(float(_curX++), 0, 0));
// Create primitive set if none exists.
if (geometry->getNumPrimitiveSets() == 0)
geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, 0));
osg::DrawArrays* drawArrays = dynamic_cast<osg::DrawArrays*>(geometry->getPrimitiveSet(0));
drawArrays->setFirst(0);
drawArrays->setCount(vertices->size());
}
vertices->push_back(osg::Vec3(float(_curX), float(_height) / _max * value, 0));
unsigned int excedent = vertices->size() - _width;
vertices->erase(vertices->begin(), vertices->begin() + excedent);
// Make the graph scroll when there is enough data.
// Note: We check the frame number so that even if we have
// many graphs, the transform is translated only once per
// frame.
static const float increment = -1.0;
if (_frameNumber != frameNumber)
{
// We know the exact layout of this part of the scene
// graph, so this is OK...
osg::MatrixTransform* transform =
geometry->getParent(0)->getParent(0)->asTransform()->asMatrixTransform();
if (transform)
{
transform->setMatrix(transform->getMatrix() * osg::Matrix::translate(osg::Vec3(increment, 0, 0)));
}
}
_curX++;
_frameNumber = frameNumber;
geometry->dirtyBound();
}
};
};
// Drawcallback to draw averaged attribute
struct ValueTextDrawCallback : public virtual osg::Drawable::DrawCallback
{
ValueTextDrawCallback(osg::Stats* stats, const std::string& name):
_stats(stats),
_attributeName(name),
_frameNumber(0)
{
}
/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osgText::Text* text = (osgText::Text*)drawable;
int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
if (frameNumber == _frameNumber) {
text->drawImplementation(renderInfo);
return;
}
double value;
if (_stats->getAttribute(_stats->getLatestFrameNumber(), _attributeName, value))
{
sprintf(_tmpText,"%4.2f",value);
text->setText(_tmpText);
}
else
{
text->setText("");
}
_frameNumber = frameNumber;
text->drawImplementation(renderInfo);
}
osg::ref_ptr<osg::Stats> _stats;
std::string _attributeName;
mutable char _tmpText[128];
mutable int _frameNumber;
};
struct StatAction
{
double _lastTime;
std::string _name;
osg::ref_ptr<osg::Group> _group;
osg::ref_ptr<osg::Geode> _label;
osg::ref_ptr<osg::MatrixTransform> _graph;
osg::ref_ptr<osgText::Text> _textLabel;
osgAnimation::OutCubicMotion _fade;
StatAction() { _lastTime = 0; _fade = osgAnimation::OutCubicMotion(0,5); }
void init(osg::Stats* stats, const std::string& name, const osg::Vec3& pos, float width, float heigh, const osg::Vec4& color);
void setPosition(const osg::Vec3& pos);
#if 0
void touch()
{
_lastTime = osg::Timer::instance()->time_s();
float a = 1.0 - _fade.getValueAt(0.0);
setAlpha(a);
}
bool update() {
double t = osg::Timer::instance()->time_s();
float alpha = 1.0 - _fade.getValueAt(t-_lastTime);
if (t - _lastTime > _fade.getDuration())
return true;
setAlpha(alpha);
return false;
}
#endif
void setAlpha(float v);
};
struct StatsTimeline : public osg::NodeCallback
{
static float _statsHeight;
static float _statsWidth;
osg::ref_ptr<osg::Geometry> _background;
osg::ref_ptr<osgAnimation::Timeline> _timeline;
osg::ref_ptr<osg::MatrixTransform> _group;
std::map<std::string, StatAction > _actions;
StatsTimeline()
{
_statsHeight = 1024;
_statsWidth = 1280;
}
osg::MatrixTransform* createStatsForTimeline(osgAnimation::Timeline* timeline)
{
_timeline = timeline;
std::string font("fonts/arial.ttf");
float leftPos = 10.0f;
float startBlocks = 150.0f;
float characterSize = 20.0f;
osg::Vec4 backgroundColor(0.0, 0.0, 0.0f, 0.3);
float backgroundMargin = 5;
//float backgroundSpacing = 3;
osg::Vec4 color(1.0, 1.0, 1.0, 1.0);
_group = new osg::MatrixTransform;
_group->setDataVariance(osg::Object::DYNAMIC);
{
osg::Vec3 pos(leftPos, _statsHeight-24.0f,0.0f);
//float topOfViewerStats = pos.y() + characterSize;
osg::ref_ptr<osg::Stats> stats = _timeline->getStats();
pos.y() -= characterSize + backgroundMargin;
{
osg::Geode* geode = new osg::Geode();
_group->addChild(geode);
osg::ref_ptr<osgText::Text> timeLabel = new osgText::Text;
geode->addDrawable( timeLabel.get() );
timeLabel->setColor(color);
timeLabel->setFont(font);
timeLabel->setCharacterSize(characterSize);
timeLabel->setPosition(pos);
timeLabel->setText("Time: ");
osg::ref_ptr<osgText::Text> timeLabelValue = new osgText::Text;
geode->addDrawable( timeLabelValue.get() );
timeLabelValue->setColor(color);
timeLabelValue->setFont(font);
timeLabelValue->setCharacterSize(characterSize);
timeLabelValue->setPosition(pos + osg::Vec3(startBlocks, 0,0));
timeLabelValue->setText("0.0");
timeLabelValue->setDrawCallback(new ValueTextDrawCallback(stats.get(),"Timeline"));
}
}
{
osg::Vec3 pos(leftPos, _statsHeight - 24.0f ,0.0f);
//float topOfViewerStats = pos.y();
osg::Geode* geode = new osg::Geode;
_background = createBackgroundRectangle(
pos + osg::Vec3(-backgroundMargin, backgroundMargin, 0),
_statsWidth - 2 * backgroundMargin,
(3 + 4.5 * 1) * characterSize + 2 * backgroundMargin,
backgroundColor);
geode->addDrawable(_background.get());
_group->addChild(geode);
}
return _group.get();
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) {
updateGraph();
}
traverse(node,nv);
}
void updateGraph()
{
osgAnimation::StatsActionVisitor* visitor = _timeline->getStatsVisitor();
if (!visitor)
return;
std::string font("fonts/arial.ttf");
float leftPos = 10.0f;
float characterSize = 20.0f;
float backgroundMargin = 5;
//float backgroundSpacing = 3;
float graphSpacing = 5;
float width = _statsWidth - 4 * backgroundMargin;
float height = characterSize;
osg::Vec3 pos(leftPos, _statsHeight-24.0f,0.0f);
pos.y() -= characterSize *2 + backgroundMargin;
for (std::map<std::string, StatAction >::iterator it = _actions.begin(); it != _actions.end(); ++it) {
(*it).second._group->setNodeMask(~osg::Node::NodeMask(1));
}
const std::vector<std::string>& channels = visitor->getChannels();
std::map<std::string,int> size;
for (int i = 0; i < (int)channels.size(); i++) {
std::string name = channels[i];
if (_actions.find(name) == _actions.end()) {
osg::Vec4 color(getRandomValueinRange(255)/255.0, getRandomValueinRange(255)/255.0, getRandomValueinRange(255)/255.0, 1.0);
_actions[name].init(visitor->getStats(), name, pos, width, height, color);
_group->addChild(_actions[name]._group.get());
//_actions[name].touch();
} else {
_actions[name].setPosition(pos);
//_actions[name].touch();
}
_actions[name]._group->setNodeMask(~osg::Node::NodeMask(0x0));
size[name] = 0;
pos.y() -= characterSize + graphSpacing;
}
pos.y() -= backgroundMargin;
osg::Vec3Array* array = dynamic_cast<osg::Vec3Array*>(_background->getVertexArray());
float y = (*array)[0][1];
y = y - (pos.y() + backgroundMargin); //(2 * backgroundMargin + (size.size() * (characterSize + graphSpacing)));
(*array)[1][1] = pos.y();
(*array)[2][1] = pos.y();
array->dirty();
_background->dirtyBound();
}
};
float StatsTimeline::_statsHeight;
float StatsTimeline::_statsWidth;
struct FindTimelineStats : public osg::NodeVisitor
{
std::vector<osg::ref_ptr<osgAnimation::Timeline> > _timelines;
FindTimelineStats() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void apply(osg::Node& node) {
osg::NodeCallback* cb = node.getUpdateCallback();
while (cb) {
osgAnimation::TimelineAnimationManager* tam = dynamic_cast<osgAnimation::TimelineAnimationManager*>(cb);
if (tam)
_timelines.push_back(tam->getTimeline());
cb = cb->getNestedCallback();
}
traverse(node);
}
};
StatsHandler::StatsHandler():
_keyEventTogglesOnScreenStats('a'),
_keyEventPrintsOutStats('A'),
_statsType(NO_STATS),
_initialized(false),
_statsWidth(1280.0f),
_statsHeight(1024.0f)
{
_camera = new osg::Camera;
_camera->setRenderer(new osgViewer::Renderer(_camera.get()));
_camera->setProjectionResizePolicy(osg::Camera::FIXED);
}
bool StatsHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
osgViewer::View* myview = dynamic_cast<osgViewer::View*>(&aa);
if (!myview) return false;
osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(myview->getViewerBase());
if (!viewer->getSceneData())
return false;
if (ea.getHandled()) return false;
switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::KEYDOWN):
{
if (ea.getKey()==_keyEventTogglesOnScreenStats)
{
if (viewer->getViewerStats())
{
if (!_switch.get()) {
FindTimelineStats finder;
viewer->getSceneData()->accept(finder);
if (finder._timelines.empty())
return false;
}
if (!_initialized)
{
setUpHUDCamera(viewer);
setUpScene(dynamic_cast<osgViewer::Viewer*>(viewer));
}
++_statsType;
if (_statsType==LAST) _statsType = NO_STATS;
switch(_statsType)
{
case(NO_STATS):
{
_camera->setNodeMask(0x0);
_switch->setAllChildrenOff();
break;
}
case(FRAME_RATE):
{
_camera->setNodeMask(0xffffffff);
_switch->setAllChildrenOn();
break;
}
default:
break;
}
}
return true;
}
if (ea.getKey()==_keyEventPrintsOutStats)
{
FindTimelineStats finder;
viewer->getSceneData()->accept(finder);
if (!finder._timelines.empty()) {
osg::notify(osg::NOTICE)<<std::endl<<"Stats report:"<<std::endl;
typedef std::vector<osg::Stats*> StatsList;
StatsList statsList;
for (int i = 0; i < (int)finder._timelines.size(); i++)
statsList.push_back(finder._timelines[i]->getStats());
for(int i = statsList[0]->getEarliestFrameNumber(); i<= statsList[0]->getLatestFrameNumber()-1; ++i)
{
for(StatsList::iterator itr = statsList.begin();
itr != statsList.end();
++itr)
{
if (itr==statsList.begin()) (*itr)->report(osg::notify(osg::NOTICE), i);
else (*itr)->report(osg::notify(osg::NOTICE), i, " ");
}
osg::notify(osg::NOTICE)<<std::endl;
}
}
return true;
}
}
default: break;
}
return false;
}
void StatsHandler::reset()
{
_initialized = false;
_camera->setGraphicsContext(0);
_camera->removeChildren( 0, _camera->getNumChildren() );
}
void StatsHandler::setUpHUDCamera(osgViewer::ViewerBase* viewer)
{
osgViewer::GraphicsWindow* window = dynamic_cast<osgViewer::GraphicsWindow*>(_camera->getGraphicsContext());
if (!window)
{
osgViewer::Viewer::Windows windows;
viewer->getWindows(windows);
if (windows.empty()) return;
window = windows.front();
}
_camera->setGraphicsContext(window);
_camera->setViewport(0, 0, window->getTraits()->width, window->getTraits()->height);
_camera->setRenderOrder(osg::Camera::POST_RENDER, 10);
_camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0,_statsWidth,0.0,_statsHeight));
_camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
_camera->setViewMatrix(osg::Matrix::identity());
// only clear the depth buffer
_camera->setClearMask(0); //GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //-1);
_camera->setAllowEventFocus(false);
_camera->setCullMask(0x1);
osgViewer::Viewer* v = dynamic_cast<osgViewer::Viewer*>(viewer);
v->getSceneData()->asGroup()->addChild(_camera.get());
_initialized = true;
}
void StatsHandler::setUpScene(osgViewer::Viewer* viewer)
{
if (!viewer->getSceneData())
return;
FindTimelineStats finder;
viewer->getSceneData()->accept(finder);
if (finder._timelines.empty())
return;
_switch = new osg::Switch;
osg::StateSet* stateset = _switch->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
stateset->setAttribute(new osg::PolygonMode(), osg::StateAttribute::PROTECTED);
_group = new osg::Group;
_camera->addChild(_switch.get());
_switch->addChild(_group.get());
for (int i = 0; i < (int)finder._timelines.size(); i++) {
StatsTimeline* s = new StatsTimeline;
osg::MatrixTransform* m = s->createStatsForTimeline(finder._timelines[i].get());
m->setUpdateCallback(s);
m->setMatrix(osg::Matrix::translate(0, -i * 100, 0));
_group->addChild(m);
}
}
void StatAction::init(osg::Stats* stats, const std::string& name, const osg::Vec3& pos, float width, float height, const osg::Vec4& color)
{
std::string font("fonts/arial.ttf");
float characterSize = 20.0f;
float startBlocks = 150.0f;
_name = name;
_group = new osg::Group;
_label = new osg::Geode;
_textLabel = new osgText::Text;
_label->addDrawable(_textLabel.get());
_textLabel->setDataVariance(osg::Object::DYNAMIC);
_textLabel->setColor(color);
_textLabel->setFont(font);
_textLabel->setCharacterSize(characterSize);
_textLabel->setPosition(pos - osg::Vec3(0, height, 0));
_textLabel->setText(name);
StatsGraph* graph = new StatsGraph(pos + osg::Vec3(startBlocks, 0,0) , width-startBlocks, height);
graph->setCullingActive(false);
graph->addStatGraph(stats, stats, color, 1.0, name);
_graph = graph;
_group->addChild(_label.get());
_group->addChild(_graph.get());
}
void StatAction::setAlpha(float v)
{
std::cout << this << " color alpha " << v << std::endl;
StatsGraph* gfx = dynamic_cast<StatsGraph*>(_graph.get());
osg::Vec4 color = _textLabel->getColor();
color[3] = v;
_textLabel->setColor(color);
for (int i = 0; i < (int) gfx->_statsGraphGeode->getNumDrawables(); i++) {
StatsGraph::Graph* g = dynamic_cast<StatsGraph::Graph*>(gfx->_statsGraphGeode->getDrawable(0));
g->setColor(color);
}
}
void StatAction::setPosition(const osg::Vec3& pos)
{
float characterSize = 20.0f;
StatsGraph* gfx = dynamic_cast<StatsGraph*>(_graph.get());
gfx->changeYposition(pos[1]);
_textLabel->setPosition(pos - osg::Vec3(0, characterSize,0));
}
void StatsHandler::getUsage(osg::ApplicationUsage& usage) const
{
usage.addKeyboardMouseBinding("s","On screen stats.");
usage.addKeyboardMouseBinding("S","Output stats to console.");
}
}

View File

@@ -0,0 +1,86 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StatsVisitor>
#include <osgAnimation/Timeline>
#include <osgAnimation/ActionBlendIn>
#include <osgAnimation/ActionBlendOut>
#include <osgAnimation/ActionStripAnimation>
#include <osgAnimation/ActionAnimation>
using namespace osgAnimation;
StatsActionVisitor::StatsActionVisitor() {}
void StatsActionVisitor::reset() { _channels.clear(); }
StatsActionVisitor::StatsActionVisitor(osg::Stats* stats,unsigned int frame)
{
_frame = frame;
_stats = stats;
}
void StatsActionVisitor::apply(Timeline& tm)
{
_stats->setAttribute(_frame,"Timeline", tm.getCurrentTime());
tm.traverse(*this);
}
void StatsActionVisitor::apply(Action& action)
{
if (isActive(action))
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(),1);
}
}
void StatsActionVisitor::apply(ActionBlendIn& action)
{
if (isActive(action))
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(), action.getWeight());
}
}
void StatsActionVisitor::apply(ActionBlendOut& action)
{
if (isActive(action))
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(), action.getWeight());
}
}
void StatsActionVisitor::apply(ActionAnimation& action)
{
if (isActive(action))
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(), action.getAnimation()->getWeight());
}
}
void StatsActionVisitor::apply(ActionStripAnimation& action)
{
if (isActive(action))
{
_channels.push_back(action.getName());
double value;
std::string name = action.getName();
if (_stats->getAttribute(_frame, name, value))
name += "+";
_stats->setAttribute(_frame, action.getName(), action.getAnimation()->getAnimation()->getWeight());
}
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -18,5 +18,4 @@
using namespace osgAnimation;
Target::Target() { reset();}
Target::~Target() {}
Target::Target() : _weight(0), _priorityWeight(0), _lastPriority(0) {}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -13,6 +13,7 @@
*/
#include <osgAnimation/Timeline>
#include <osgAnimation/StatsVisitor>
#include <limits.h>
using namespace osgAnimation;
@@ -29,11 +30,14 @@ Timeline::Timeline()
_previousFrameEvaluated = 0;
_evaluating = 0;
_numberFrame = UINT_MAX; // something like infinity
_collectStats = false;
_stats = new osg::Stats("Timeline");
setName("Timeline");
}
Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, op),
_actions(nc._actions)
Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op)
: Action(nc, op),
_actions(nc._actions)
{
_lastUpdate = 0;
_currentFrame = 0;
@@ -44,5 +48,204 @@ Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, o
_previousFrameEvaluated = 0;
_evaluating = 0;
_numberFrame = UINT_MAX; // something like infinity
_collectStats = false;
_stats = new osg::Stats("Timeline");
setName("Timeline");
}
void Timeline::setAnimationManager(AnimationManagerBase* manager)
{
_animationManager = manager;
}
void Timeline::traverse(ActionVisitor& visitor)
{
int layer = visitor.getCurrentLayer();
visitor.pushTimelineOnStack(this);
// update from high priority to low priority
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
{
visitor.setCurrentLayer(iterAnim->first);
ActionList& list = iterAnim->second;
for (unsigned int i = 0; i < list.size(); i++)
{
visitor.pushFrameActionOnStack(list[i]);
if (list[i].second) list[i].second->accept(visitor);
visitor.popFrameAction();
}
}
visitor.popTimeline();
visitor.setCurrentLayer(layer);
}
void Timeline::setStats(osg::Stats* stats) { _stats = stats;}
osg::Stats* Timeline::getStats() { return _stats.get();}
void Timeline::collectStats(bool state) { _collectStats = state;}
StatsActionVisitor* Timeline::getStatsVisitor() { return _statsVisitor.get(); }
void Timeline::clearActions()
{
_actions.clear();
_addActionOperations.clear();
_removeActionOperations.clear();
}
void Timeline::update(double simulationTime)
{
// first time we call update we generate one frame
UpdateActionVisitor updateTimeline;
if (!_initFirstFrame)
{
_lastUpdate = simulationTime;
_initFirstFrame = true;
_animationManager->clearTargets();
updateTimeline.setFrame(_currentFrame);
accept(updateTimeline);
if (_collectStats)
{
if (!_statsVisitor)
_statsVisitor = new StatsActionVisitor();
_statsVisitor->setStats(_stats.get());
_statsVisitor->setFrame(_currentFrame);
_statsVisitor->reset();
accept(*_statsVisitor);
}
processPendingOperation();
}
// find the number of frame pass since the last update
double delta = (simulationTime - _lastUpdate);
double nbframes = delta * _fps * _speed;
unsigned int nb = static_cast<unsigned int>(floor(nbframes));
for (unsigned int i = 0; i < nb; i++)
{
if (_state == Play)
_currentFrame++;
_animationManager->clearTargets();
updateTimeline.setFrame(_currentFrame);
accept(updateTimeline);
if (_collectStats)
{
if (!_statsVisitor)
_statsVisitor = new StatsActionVisitor;
_statsVisitor->setStats(_stats.get());
_statsVisitor->setFrame(_currentFrame);
_statsVisitor->reset();
accept(*_statsVisitor);
}
processPendingOperation();
}
if (nb)
{
_lastUpdate += ((double)nb) / _fps;
}
}
void Timeline::removeAction(Action* action)
{
if (getEvaluating())
_removeActionOperations.push_back(FrameAction(0, action));
else
internalRemoveAction(action);
}
void Timeline::addActionAt(unsigned int frame, Action* action, int priority)
{
// skip if this action has already been added this frame
for (CommandList::iterator it = _addActionOperations.begin(); it != _addActionOperations.end(); ++it)
{
Command& command = *it;
if (command._action.second.get() == action) {
osg::notify(osg::INFO) << "Timeline::addActionAt command " << action->getName() << " already added this frame, declined" << std::endl;
return;
}
}
if (isActive(action))
{
osg::notify(osg::INFO) << "Timeline::addActionAt command " << action->getName() << " already active, remove the old" << std::endl;
removeAction(action);
}
if (getEvaluating())
_addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
else
internalAddAction(priority, FrameAction(frame, action));
}
void Timeline::addActionAt(double t, Action* action, int priority)
{
unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
addActionAt(frame, action, priority);
}
void Timeline::addActionNow(Action* action, int priority)
{
addActionAt(getCurrentFrame()+1, action, priority);
}
void Timeline::processPendingOperation()
{
// process all pending add action operation
while( !_addActionOperations.empty())
{
internalAddAction(_addActionOperations.back()._priority, _addActionOperations.back()._action);
_addActionOperations.pop_back();
}
// process all pending remove action operation
while( !_removeActionOperations.empty())
{
internalRemoveAction(_removeActionOperations.back().second.get());
_removeActionOperations.pop_back();
}
}
void Timeline::internalRemoveAction(Action* action)
{
for (ActionLayers::iterator it = _actions.begin(); it != _actions.end(); ++it)
{
ActionList& fa = it->second;
for (unsigned int i = 0; i < fa.size(); i++)
if (fa[i].second.get() == action)
{
fa.erase(fa.begin() + i);
return;
}
}
}
void Timeline::internalAddAction(int priority, const FrameAction& ftl)
{
_actions[priority].insert(_actions[priority].begin(), ftl);
}
bool Timeline::isActive(Action* activeAction)
{
// update from high priority to low priority
for( ActionLayers::iterator iterAnim = _actions.begin(); iterAnim != _actions.end(); ++iterAnim )
{
// update all animation
ActionList& list = iterAnim->second;
for (unsigned int i = 0; i < list.size(); i++)
{
Action* action = list[i].second.get();
if (action == activeAction)
{
unsigned int firstFrame = list[i].first;
// check if current frame of timeline hit an action interval
if (_currentFrame >= firstFrame &&
_currentFrame < (firstFrame + action->getNumFrames()) )
return true;
}
}
}
return false;
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -34,7 +34,7 @@ TimelineAnimationManager::TimelineAnimationManager(const TimelineAnimationManage
void TimelineAnimationManager::update(double time)
{
clearTargets();
// clearTargets();
_timeline->setAnimationManager(this);
_timeline->update(time);
normalizeTargets();
}

View File

@@ -0,0 +1,54 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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 <osg/NodeVisitor>
#include <osgAnimation/Bone>
#include <osgAnimation/UpdateBone>
using namespace osgAnimation;
UpdateBone::UpdateBone(const std::string& name) : UpdateMatrixTransform(name)
{
}
UpdateBone::UpdateBone(const UpdateBone& apc,const osg::CopyOp& copyop) : osg::Object(apc,copyop), UpdateMatrixTransform(apc, copyop)
{
}
/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateBone::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
Bone* b = dynamic_cast<Bone*>(node);
if (!b)
{
osg::notify(osg::WARN) << "Warning: UpdateBone set on non-Bone object." << std::endl;
return;
}
// here we would prefer to have a flag inside transform stack in order to avoid update and a dirty state in matrixTransform if it's not require.
_transforms.update();
const osg::Matrix& matrix = _transforms.getMatrix();
b->setMatrix(matrix);
Bone* parent = b->getBoneParent();
if (parent)
b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace());
else
b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace());
}
traverse(node,nv);
}

View File

@@ -0,0 +1,63 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/UpdateMaterial>
#include <osg/NodeVisitor>
using namespace osgAnimation;
UpdateMaterial::UpdateMaterial(const UpdateMaterial& apc,const osg::CopyOp& copyop)
: osg::Object(apc, copyop),
AnimationUpdateCallback<osg::StateAttributeCallback>(apc, copyop)
{
_diffuse = new osgAnimation::Vec4Target(apc._diffuse->getValue());
}
UpdateMaterial::UpdateMaterial(const std::string& name):
AnimationUpdateCallback<osg::StateAttributeCallback>(name)
{
_diffuse = new osgAnimation::Vec4Target(osg::Vec4(1,0,1,1));
}
/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateMaterial::operator()(osg::StateAttribute* sa, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
osg::Material* material = dynamic_cast<osg::Material*>(sa);
if (material)
update(*material);
}
}
osgAnimation::Vec4Target* UpdateMaterial::getDiffuse() { return _diffuse.get(); }
void UpdateMaterial::update(osg::Material& material)
{
osg::Vec4 diffuse = _diffuse->getValue();
material.setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
}
bool UpdateMaterial::link(osgAnimation::Channel* channel)
{
if (channel->getName().find("diffuse") != std::string::npos)
{
return channel->setTarget(_diffuse.get());
}
else
{
osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class " << className() << std::endl;
}
return false;
}

View File

@@ -0,0 +1,67 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/UpdateMatrixTransform>
#include <osg/NodeVisitor>
#include <osg/MatrixTransform>
using namespace osgAnimation;
UpdateMatrixTransform::UpdateMatrixTransform( const UpdateMatrixTransform& apc,const osg::CopyOp& copyop) : osg::Object(apc,copyop), AnimationUpdateCallback<osg::NodeCallback>(apc, copyop)
{
_transforms = StackedTransform(apc.getStackedTransforms(), copyop);
}
UpdateMatrixTransform::UpdateMatrixTransform(const std::string& name) : AnimationUpdateCallback<osg::NodeCallback>(name)
{
}
/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateMatrixTransform::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
osg::MatrixTransform* matrixTransform = dynamic_cast<osg::MatrixTransform*>(node);
if (matrixTransform)
{
// here we would prefer to have a flag inside transform stack in order to avoid update and a dirty state in matrixTransform if it's not require.
_transforms.update();
const osg::Matrix& matrix = _transforms.getMatrix();
matrixTransform->setMatrix(matrix);
}
}
traverse(node,nv);
}
bool UpdateMatrixTransform::link(osgAnimation::Channel* channel)
{
const std::string& channelName = channel->getName();
// check if we can link a StackedTransformElement to the current Channel
for (StackedTransform::iterator it = _transforms.begin(); it != _transforms.end(); ++it)
{
StackedTransformElement* element = it->get();
if (element && !element->getName().empty() && channelName == element->getName())
{
Target* target = element->getOrCreateTarget();
if (target && channel->setTarget(target))
return true;
}
}
osg::notify(osg::INFO) << "UpdateMatrixTransform::link Channel " << channel->getName() << " does not contain a symbolic name that can be linked to a StackedTransformElement." << std::endl;
return false;
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -10,20 +10,23 @@
* 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 <osg/Notify>
#include <iostream>
#include <algorithm>
using namespace osgAnimation;
void VertexInfluenceSet::addVertexInfluence(const VertexInfluence& v) { _bone2Vertexes.push_back(v); }
const VertexInfluenceSet::VertexIndexToBoneWeightMap& VertexInfluenceSet::getVertexToBoneList() const { return _vertex2Bones;}
// this class manage VertexInfluence database by mesh
// reference bones per vertex ...
void osgAnimation::VertexInfluenceSet::buildVertex2BoneList()
void VertexInfluenceSet::buildVertex2BoneList()
{
_vertex2Bones.clear();
for (BoneToVertexList::const_iterator it = _bone2Vertexes.begin(); it != _bone2Vertexes.end(); it++)
for (BoneToVertexList::const_iterator it = _bone2Vertexes.begin(); it != _bone2Vertexes.end(); ++it)
{
const VertexInfluence& vi = (*it);
int size = vi.size();
@@ -33,13 +36,13 @@ void osgAnimation::VertexInfluenceSet::buildVertex2BoneList()
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;
osg::notify(osg::WARN) << "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++)
for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it)
{
BoneWeightList& bones = it->second;
int size = bones.size();
@@ -48,7 +51,7 @@ void osgAnimation::VertexInfluenceSet::buildVertex2BoneList()
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;
osg::notify(osg::WARN) << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << it->first << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
}
else
{
@@ -62,10 +65,10 @@ void osgAnimation::VertexInfluenceSet::buildVertex2BoneList()
// sort by name and weight
struct SortByNameAndWeight : public std::less<osgAnimation::VertexInfluenceSet::BoneWeight>
struct SortByNameAndWeight : public std::less<VertexInfluenceSet::BoneWeight>
{
bool operator()(const osgAnimation::VertexInfluenceSet::BoneWeight& b0,
const osgAnimation::VertexInfluenceSet::BoneWeight& b1) const
bool operator()(const VertexInfluenceSet::BoneWeight& b0,
const VertexInfluenceSet::BoneWeight& b1) const
{
if (b0.getBoneName() < b1.getBoneName())
return true;
@@ -77,10 +80,10 @@ struct SortByNameAndWeight : public std::less<osgAnimation::VertexInfluenceSet::
}
};
struct SortByBoneWeightList : public std::less<osgAnimation::VertexInfluenceSet::BoneWeightList>
struct SortByBoneWeightList : public std::less<VertexInfluenceSet::BoneWeightList>
{
bool operator()(const osgAnimation::VertexInfluenceSet::BoneWeightList& b0,
const osgAnimation::VertexInfluenceSet::BoneWeightList& b1) const
bool operator()(const VertexInfluenceSet::BoneWeightList& b0,
const VertexInfluenceSet::BoneWeightList& b1) const
{
if (b0.size() < b1.size())
return true;
@@ -100,14 +103,20 @@ struct SortByBoneWeightList : public std::less<osgAnimation::VertexInfluenceSet:
}
};
void osgAnimation::VertexInfluenceSet::buildUniqVertexSetToBoneSetList()
void VertexInfluenceSet::clear()
{
_bone2Vertexes.clear();
_uniqVertexSetToBoneSet.clear();
}
void VertexInfluenceSet::buildUniqVertexSetToBoneSetList()
{
_uniqVertexSetToBoneSet.clear();
typedef std::map<BoneWeightList,UniqVertexSetToBoneSet, SortByBoneWeightList> UnifyBoneGroup;
UnifyBoneGroup unifyBuffer;
for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); it++)
for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it)
{
BoneWeightList bones = it->second;
int vertexIndex = it->first;
@@ -123,8 +132,9 @@ void osgAnimation::VertexInfluenceSet::buildUniqVertexSetToBoneSetList()
}
_uniqVertexSetToBoneSet.reserve(unifyBuffer.size());
for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); it++)
for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it)
{
_uniqVertexSetToBoneSet.push_back(it->second);
}
}

View File

@@ -1,9 +1,7 @@
SET(TARGET_SRC
ReaderWriter.cpp
)
FILE(GLOB TARGET_SRC *.cpp)
FILE(GLOB TARGET_H *.h)
SET(TARGET_ADDED_LIBRARIES osgAnimation )
#### end var setup ###
SETUP_PLUGIN(osganimation)

View File

@@ -0,0 +1,51 @@
#include "Matrix.h"
bool readMatrix(osg::Matrix& matrix, osgDB::Input& fr, const char* keyword)
{
bool iteratorAdvanced = false;
if (fr[0].matchWord(keyword) && fr[1].isOpenBracket())
{
int entry = fr[0].getNoNestedBrackets();
fr += 2;
int row=0;
int col=0;
double v;
while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
{
if (fr[0].getFloat(v))
{
matrix(row,col)=v;
++col;
if (col>=4)
{
col = 0;
++row;
}
++fr;
}
else fr.advanceOverCurrentFieldOrBlock();
}
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
bool writeMatrix(const osg::Matrix& matrix, osgDB::Output& fw, const char* keyword)
{
fw.indent() << keyword <<" {" << std::endl;
fw.moveIn();
fw.indent() << matrix(0,0) << " " << matrix(0,1) << " " << matrix(0,2) << " " << matrix(0,3) << std::endl;
fw.indent() << matrix(1,0) << " " << matrix(1,1) << " " << matrix(1,2) << " " << matrix(1,3) << std::endl;
fw.indent() << matrix(2,0) << " " << matrix(2,1) << " " << matrix(2,2) << " " << matrix(2,3) << std::endl;
fw.indent() << matrix(3,0) << " " << matrix(3,1) << " " << matrix(3,2) << " " << matrix(3,3) << std::endl;
fw.moveOut();
fw.indent() << "}"<< std::endl;
return true;
}

View File

@@ -0,0 +1,13 @@
#ifndef DOTOSG_MATRIX
#define DOTOSG_MATRIX
#include <osg/Matrix>
#include <osgDB/Input>
#include <osgDB/Output>
extern bool readMatrix(osg::Matrix& matrix, osgDB::Input& fr, const char* keyword="Matrix");
extern bool writeMatrix(const osg::Matrix& matrix, osgDB::Output& fw, const char* keyword="Matrix");
#endif

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -10,23 +10,30 @@
* 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 <osg/io_utils>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/BasicAnimationManager>
#include <osgAnimation/TimelineAnimationManager>
#include <osgAnimation/VertexInfluence>
#include <osgAnimation/Animation>
#include <osgAnimation/Bone>
#include <osgAnimation/UpdateBone>
#include <osgAnimation/UpdateMatrixTransform>
#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/UpdateCallback>
#include <osgAnimation/MorphGeometry>
#include <osgAnimation/StackedTransform>
#include <osgAnimation/StackedTranslateElement>
#include <osgAnimation/StackedRotateAxisElement>
#include <osgAnimation/StackedMatrixElement>
#include <osgAnimation/StackedScaleElement>
#include "Matrix.h"
#include <osgDB/Registry>
#include <osgDB/Input>
@@ -41,7 +48,7 @@ bool Bone_readLocalData(Object& obj, Input& fr)
osg::Quat att;
bool iteratorAdvanced = false;
if (fr.matchSequence("bindQuaternion %f %f %f %f"))
if (fr.matchSequence("bindQuaternion %f %f %f %f"))
{
fr[1].getFloat(att[0]);
fr[2].getFloat(att[1]);
@@ -50,10 +57,11 @@ bool Bone_readLocalData(Object& obj, Input& fr)
fr += 5;
iteratorAdvanced = true;
osg::notify(osg::WARN) << "Old osgAnimation file format update your data file" << std::endl;
}
osg::Vec3d pos(0,0,0);
if (fr.matchSequence("bindPosition %f %f %f"))
if (fr.matchSequence("bindPosition %f %f %f"))
{
fr[1].getFloat(pos[0]);
fr[2].getFloat(pos[1]);
@@ -61,10 +69,11 @@ bool Bone_readLocalData(Object& obj, Input& fr)
fr += 4;
iteratorAdvanced = true;
osg::notify(osg::WARN) << "Old osgAnimation file format update your data file" << std::endl;
}
osg::Vec3d scale(1,1,1);
if (fr.matchSequence("bindScale %f %f %f"))
if (fr.matchSequence("bindScale %f %f %f"))
{
fr[1].getFloat(scale[0]);
fr[2].getFloat(scale[1]);
@@ -72,31 +81,45 @@ bool Bone_readLocalData(Object& obj, Input& fr)
fr += 4;
iteratorAdvanced = true;
osg::notify(osg::WARN) << "Old osgAnimation file format update your data file" << std::endl;
}
bone.setBindMatrixInBoneSpace( osg::Matrix(att) * osg::Matrix::translate(pos));
if (fr.matchSequence("InvBindMatrixInSkeletonSpace {"))
{
Matrix matrix;
if (readMatrix(matrix,fr, "InvBindMatrixInSkeletonSpace"))
{
bone.setInvBindMatrixInSkeletonSpace(matrix);
iteratorAdvanced = true;
}
}
if (fr.matchSequence("MatrixInSkeletonSpace {"))
{
Matrix matrix;
if (readMatrix(matrix,fr, "MatrixInSkeletonSpace"))
{
bone.setMatrixInSkeletonSpace(matrix);
iteratorAdvanced = true;
}
}
return iteratorAdvanced;
}
bool Bone_writeLocalData(const Object& obj, Output& fw)
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;
bool res1 = writeMatrix(bone.getInvBindMatrixInSkeletonSpace(), fw, "InvBindMatrixInSkeletonSpace");
// write this field for debug only
// because it's recompute at each update
bool res2 = writeMatrix(bone.getMatrixInSkeletonSpace(), fw, "MatrixInSkeletonSpace");
return (res1 || res2);
}
RegisterDotOsgWrapperProxy g_atkBoneProxy
RegisterDotOsgWrapperProxy g_BoneProxy
(
new osgAnimation::Bone,
"osgAnimation::Bone",
"Object Node Transform osgAnimation::Bone Group",
"Object Node MatrixTransform osgAnimation::Bone Group",
&Bone_readLocalData,
&Bone_writeLocalData
);
@@ -111,23 +134,94 @@ bool Skeleton_writeLocalData(const Object& obj, Output& fr)
{
return true;
}
RegisterDotOsgWrapperProxy g_atkRootSkeletonProxy
RegisterDotOsgWrapperProxy g_SkeletonProxy
(
new osgAnimation::Skeleton,
"osgAnimation::Skeleton",
"Object Node Transform osgAnimation::Bone osgAnimation::Skeleton Group",
"Object Node MatrixTransform osgAnimation::Skeleton Group",
&Skeleton_readLocalData,
&Skeleton_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
// Helper method for reading channels
bool Animation_readChannel(osgAnimation::Channel* pChannel, Input& fr)
{
bool iteratorAdvanced = false;
std::string name = "unknown";
if (fr.matchSequence("name %s"))
{
if (fr[1].getStr())
name = fr[1].getStr();
fr += 2;
iteratorAdvanced = true;
}
pChannel->setName(name);
std::string target = "unknown";
if (fr.matchSequence("target %s"))
{
if (fr[1].getStr())
target = fr[1].getStr();
fr += 2;
iteratorAdvanced = true;
}
pChannel->setTargetName(target);
// we dont need this info
float weight = 1.0;
if (fr.matchSequence("weight %f"))
{
fr[1].getFloat(weight);
fr += 2;
iteratorAdvanced = true;
}
// pChannel->setWeight(weight);
return iteratorAdvanced;
}
bool Animation_readLocalData(Object& obj, Input& fr)
bool Animation_readLocalData(Object& obj, Input& fr)
{
osgAnimation::Animation& anim = dynamic_cast<osgAnimation::Animation&>(obj);
bool iteratorAdvanced = false;
if (fr.matchSequence("playmode %w"))
{
if (fr[1].matchWord("ONCE")) anim.setPlaymode(osgAnimation::Animation::ONCE);
else if (fr[1].matchWord("STAY")) anim.setPlaymode(osgAnimation::Animation::STAY);
else if (fr[1].matchWord("LOOP")) anim.setPlaymode(osgAnimation::Animation::LOOP);
else if (fr[1].matchWord("PPONG")) anim.setPlaymode(osgAnimation::Animation::PPONG);
fr += 2;
iteratorAdvanced = true;
}
if (fr.matchSequence("weight %f"))
{
float weight;
fr[1].getFloat(weight);
fr += 2;
iteratorAdvanced = true;
anim.setWeight(weight);
}
if (fr.matchSequence("duration %f"))
{
float duration;
fr[1].getFloat(duration);
fr += 2;
iteratorAdvanced = true;
anim.setDuration(duration);
}
if (fr.matchSequence("starttime %f"))
{
float starttime;
fr[1].getFloat(starttime);
fr += 2;
iteratorAdvanced = true;
anim.setStartTime(starttime);
}
int nbChannels = 0;
if (fr.matchSequence("num_channels %i"))
{
@@ -138,30 +232,267 @@ bool Animation_readLocalData(Object& obj, Input& fr)
for (int i = 0; i < nbChannels; i++)
{
if (fr.matchSequence("Channel {"))
if (fr.matchSequence("DoubleLinearChannel {"))
{
fr += 2;
osgAnimation::DoubleLinearChannel* channel = new osgAnimation::DoubleLinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
double v;
float time;
if (fr.matchSequence("key %f %f"))
{
fr[1].getFloat(time);
fr[2].getFloat(v);
fr += 3;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::DoubleKeyframe(time, v));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
else if (fr.matchSequence("FloatLinearChannel {"))
{
fr += 2;
osgAnimation::FloatLinearChannel* channel = new osgAnimation::FloatLinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
float v;
float time;
if (fr.matchSequence("key %f %f"))
{
fr[1].getFloat(time);
fr[2].getFloat(v);
fr += 3;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::FloatKeyframe(time, v));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
else if (fr.matchSequence("Vec2LinearChannel {"))
{
fr += 2;
osgAnimation::Vec2LinearChannel* channel = new osgAnimation::Vec2LinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
osg::Vec2 v;
float time;
if (fr.matchSequence("key %f %f %f"))
{
fr[1].getFloat(time);
fr[2].getFloat(v[0]);
fr[3].getFloat(v[1]);
fr += 4;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec2Keyframe(time, v));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
else if (fr.matchSequence("Vec3LinearChannel {"))
{
fr += 2;
osgAnimation::Vec3LinearChannel* channel = new osgAnimation::Vec3LinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
osg::Vec3 v;
float time;
if (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;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec3Keyframe(time, v));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
else if (fr.matchSequence("Vec4LinearChannel {"))
{
fr += 2;
osgAnimation::Vec4LinearChannel* channel = new osgAnimation::Vec4LinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
osg::Vec4 v;
float time;
if (fr.matchSequence("key %f %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].getFloat(v[3]);
fr += 6;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec4Keyframe(time, v));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
else if (fr.matchSequence("QuatSphericalLinearChannel {"))
{
fr += 2;
osgAnimation::QuatSphericalLinearChannel* channel = new osgAnimation::QuatSphericalLinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
osg::Quat q;
float time;
if (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;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::QuatKeyframe(time, q));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
// Deprecated
// Reading of old channel info
// Kept here for easy conversion of old .osg data to new format
else if (fr.matchSequence("Channel {"))
{
fr += 2;
std::string name = "unknown";
if (fr.matchSequence("name %s"))
{
name = fr[1].getStr();
if (fr[1].getStr())
name = fr[1].getStr();
fr += 2;
iteratorAdvanced = true;
}
std::string target = "unknown";
if (fr.matchSequence("target %s"))
{
target = fr[1].getStr();
if (fr[1].getStr())
target = fr[1].getStr();
fr += 2;
iteratorAdvanced = true;
}
std::string type;
std::string type = "unknown";
int nbKeys;
if (fr.matchSequence("Keyframes %s %i {"))
{
type = fr[1].getStr();
if (fr[1].getStr())
type = fr[1].getStr();
fr[2].getInt(nbKeys);
fr += 4;
iteratorAdvanced = true;
@@ -175,11 +506,11 @@ bool Animation_readLocalData(Object& obj, Input& fr)
}
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++)
@@ -229,60 +560,130 @@ bool Animation_readLocalData(Object& obj, Input& fr)
return iteratorAdvanced;
}
// Helper method for writing channels
template <typename ChannelType, typename ContainerType>
void Animation_writeChannel(const std::string& channelString, ChannelType* pChannel, Output& fw)
{
fw.indent() << channelString.c_str() << " {" << std::endl;
fw.moveIn();
fw.indent() << "name \"" << pChannel->getName() << "\"" << std::endl;
fw.indent() << "target \"" << pChannel->getTargetName() << "\"" << std::endl;
// fw.indent() << "weight " << pChannel->getWeight() << std::endl;
ContainerType* kfc = pChannel->getSamplerTyped()->getKeyframeContainerTyped();
if (kfc)
{
fw.indent() << "Keyframes " << kfc->size() << " {" << std::endl;
fw.moveIn();
for (unsigned int k = 0; k < kfc->size(); k++)
{
fw.indent() << "key " << (*kfc)[k].getTime() << " " << (*kfc)[k].getValue() << std::endl;
}
fw.moveOut();
fw.indent() << "}" << std::endl;
fw.moveOut();
fw.indent() << "}" << std::endl;
}
}
bool Animation_writeLocalData(const Object& obj, Output& fw)
{
const osgAnimation::Animation& anim = dynamic_cast<const osgAnimation::Animation&>(obj);
switch (anim.getPlayMode())
{
case osgAnimation::Animation::ONCE:
fw.indent() << "playmode ONCE" << std::endl;
break;
case osgAnimation::Animation::STAY:
fw.indent() << "playmode STAY" << std::endl;
break;
case osgAnimation::Animation::LOOP:
fw.indent() << "playmode LOOP" << std::endl;
break;
case osgAnimation::Animation::PPONG:
fw.indent() << "playmode PPONG" << std::endl;
break;
default:
break;
}
fw.indent() << "weight " << anim.getWeight() << std::endl;
fw.indent() << "duration " << anim.getDuration() << std::endl;
fw.indent() << "starttime " << anim.getStartTime() << std::endl;
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;
osgAnimation::Channel* pChannel = anim.getChannels()[i].get();
std::string type = "unknown";
if (anim.getChannels()[i]->getName() == std::string("quaternion"))
osgAnimation::DoubleLinearChannel* pDlc = dynamic_cast<osgAnimation::DoubleLinearChannel*>(pChannel);
if (pDlc)
{
type = "Quat";
Animation_writeChannel<osgAnimation::DoubleLinearChannel, osgAnimation::DoubleKeyframeContainer>("DoubleLinearChannel", pDlc, fw);
continue;
}
else if (anim.getChannels()[i]->getName() == std::string("rotation"))
osgAnimation::FloatLinearChannel* pFlc = dynamic_cast<osgAnimation::FloatLinearChannel*>(pChannel);
if (pFlc)
{
type = "Quat";
Animation_writeChannel<osgAnimation::FloatLinearChannel, osgAnimation::FloatKeyframeContainer>("FloatLinearChannel", pFlc, fw);
continue;
}
else if (anim.getChannels()[i]->getName() == std::string("euler"))
osgAnimation::Vec2LinearChannel* pV2lc = dynamic_cast<osgAnimation::Vec2LinearChannel*>(pChannel);
if (pV2lc)
{
type = "Vec3";
Animation_writeChannel<osgAnimation::Vec2LinearChannel, osgAnimation::Vec2KeyframeContainer>("Vec2LinearChannel", pV2lc, fw);
continue;
}
else if (anim.getChannels()[i]->getName() == std::string("scale"))
osgAnimation::Vec3LinearChannel* pV3lc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(pChannel);
if (pV3lc)
{
type = "Vec3";
Animation_writeChannel<osgAnimation::Vec3LinearChannel, osgAnimation::Vec3KeyframeContainer>("Vec3LinearChannel", pV3lc, fw);
continue;
}
else if (anim.getChannels()[i]->getName() == std::string("position"))
osgAnimation::Vec4LinearChannel* pV4lc = dynamic_cast<osgAnimation::Vec4LinearChannel*>(pChannel);
if (pV4lc)
{
type = "Vec3";
Animation_writeChannel<osgAnimation::Vec4LinearChannel, osgAnimation::Vec4KeyframeContainer>("Vec4LinearChannel", pV4lc, fw);
continue;
}
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++)
osgAnimation::QuatSphericalLinearChannel* pQslc = dynamic_cast<osgAnimation::QuatSphericalLinearChannel*>(pChannel);
if (pQslc)
{
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;
}
Animation_writeChannel<osgAnimation::QuatSphericalLinearChannel, osgAnimation::QuatKeyframeContainer>("QuatSphericalLinearChannel", pQslc, fw);
continue;
}
osgAnimation::FloatCubicBezierChannel* pFcbc = dynamic_cast<osgAnimation::FloatCubicBezierChannel*>(pChannel);
if (pFcbc)
{
Animation_writeChannel<osgAnimation::FloatCubicBezierChannel, osgAnimation::FloatCubicBezierKeyframeContainer>("FloatCubicBezierChannel", pFcbc, fw);
continue;
}
osgAnimation::DoubleCubicBezierChannel* pDcbc = dynamic_cast<osgAnimation::DoubleCubicBezierChannel*>(pChannel);
if (pDcbc)
{
Animation_writeChannel<osgAnimation::DoubleCubicBezierChannel, osgAnimation::DoubleCubicBezierKeyframeContainer>("DoubleCubicBezierChannel", pDcbc, fw);
continue;
}
osgAnimation::Vec2CubicBezierChannel* pV2cbc = dynamic_cast<osgAnimation::Vec2CubicBezierChannel*>(pChannel);
if (pV2cbc)
{
Animation_writeChannel<osgAnimation::Vec2CubicBezierChannel, osgAnimation::Vec2CubicBezierKeyframeContainer>("Vec2CubicBezierChannel", pV2cbc, fw);
continue;
}
osgAnimation::Vec3CubicBezierChannel* pV3cbc = dynamic_cast<osgAnimation::Vec3CubicBezierChannel*>(pChannel);
if (pV3cbc)
{
Animation_writeChannel<osgAnimation::Vec3CubicBezierChannel, osgAnimation::Vec3CubicBezierKeyframeContainer>("Vec3CubicBezierChannel", pV3cbc, fw);
continue;
}
osgAnimation::Vec4CubicBezierChannel* pV4cbc = dynamic_cast<osgAnimation::Vec4CubicBezierChannel*>(pChannel);
if (pV4cbc)
{
Animation_writeChannel<osgAnimation::Vec4CubicBezierChannel, osgAnimation::Vec4CubicBezierKeyframeContainer>("Vec4CubicBezierChannel", pV4cbc, fw);
continue;
}
fw.moveOut();
fw.indent() << "}" << std::endl;
fw.moveOut();
fw.indent() << "}" << std::endl;
}
return true;
}
@@ -344,7 +745,7 @@ bool AnimationManagerBase_writeLocalData(const osgAnimation::AnimationManagerBas
const osgAnimation::AnimationList& animList = manager.getAnimationList();
fw.indent() << "num_animations " << animList.size() << std::endl;
for (osgAnimation::AnimationList::const_iterator it = animList.begin(); it != animList.end(); it++)
for (osgAnimation::AnimationList::const_iterator it = animList.begin(); it != animList.end(); ++it)
{
if (!fw.writeObject(**it))
osg::notify(osg::WARN)<<"Warning: can't write an animation object"<< std::endl;
@@ -437,6 +838,13 @@ bool RigGeometry_readLocalData(Object& obj, Input& fr)
if (!vmap->empty())
geom.setInfluenceMap(vmap.get());
if (fr.matchSequence("Geometry {"))
{
osg::Geometry* source = dynamic_cast<osg::Geometry*>(fr.readObject());
geom.setSourceGeometry(source);
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
@@ -448,7 +856,7 @@ bool RigGeometry_writeLocalData(const Object& obj, Output& fw)
return true;
fw.indent() << "num_influences " << vm->size() << std::endl;
fw.moveIn();
for (osgAnimation::VertexInfluenceMap::const_iterator it = vm->begin(); it != vm->end(); it++)
for (osgAnimation::VertexInfluenceMap::const_iterator it = vm->begin(); it != vm->end(); ++it)
{
std::string name = it->first;
if (name.empty())
@@ -464,6 +872,8 @@ bool RigGeometry_writeLocalData(const Object& obj, Output& fw)
fw.indent() << "}" << std::endl;
}
fw.moveOut();
fw.writeObject(*geom.getSourceGeometry());
return true;
}
@@ -471,15 +881,135 @@ RegisterDotOsgWrapperProxy g_atkRigGeometryProxy
(
new osgAnimation::RigGeometry,
"osgAnimation::RigGeometry",
"Object Drawable osgAnimation::RigGeometry Geometry",
"Object osgAnimation::RigGeometry Drawable Geometry",
&RigGeometry_readLocalData,
&RigGeometry_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
bool MorphGeometry_readLocalData(Object& obj, Input& fr)
{
osgAnimation::MorphGeometry& geom = dynamic_cast<osgAnimation::MorphGeometry&>(obj);
bool UpdateBone_readLocalData(Object& obj, Input& fr)
bool iteratorAdvanced = false;
if (fr[0].matchWord("method"))
{
if (fr[1].matchWord("NORMALIZED"))
{
geom.setMethod(osgAnimation::MorphGeometry::NORMALIZED);
fr+=2;
iteratorAdvanced = true;
}
else if (fr[1].matchWord("RELATIVE"))
{
geom.setMethod(osgAnimation::MorphGeometry::RELATIVE);
fr+=2;
iteratorAdvanced = true;
}
}
if (fr[0].matchWord("morphNormals"))
{
if (fr[1].matchWord("TRUE"))
{
geom.setMorphNormals(true);
fr+=2;
iteratorAdvanced = true;
}
else if (fr[1].matchWord("FALSE"))
{
geom.setMorphNormals(false);
fr+=2;
iteratorAdvanced = true;
}
}
int num_morphTargets = 0;
if (fr.matchSequence("num_morphTargets %i"))
{
fr[1].getInt(num_morphTargets);
fr += 2;
iteratorAdvanced = true;
}
for (int i = 0; i < num_morphTargets; i++)
{
if (fr.matchSequence("MorphTarget {"))
{
int entry = fr[0].getNoNestedBrackets();
fr += 2;
iteratorAdvanced = true;
while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
{
float weight = 1.0;
if (fr.matchSequence("weight %f"))
{
fr[1].getFloat(weight);
fr += 2;
}
osg::Drawable* drawable = NULL;
drawable = fr.readDrawable();
osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(drawable);
if (geometry)
geom.addMorphTarget(geometry, weight);
}
if (fr.matchSequence("}"))
fr += 1;
}
}
return iteratorAdvanced;
}
bool MorphGeometry_writeLocalData(const Object& obj, Output& fw)
{
const osgAnimation::MorphGeometry& geom = dynamic_cast<const osgAnimation::MorphGeometry&>(obj);
switch(geom.getMethod())
{
case(osgAnimation::MorphGeometry::NORMALIZED): fw.indent() << "method NORMALIZED"<<std::endl; break;
case(osgAnimation::MorphGeometry::RELATIVE): fw.indent() << "method RELATIVE"<<std::endl; break;
}
fw.indent() << "morphNormals ";
if (geom.getMorphNormals())
fw << "TRUE" << std::endl;
else
fw << "FALSE" << std::endl;
const osgAnimation::MorphGeometry::MorphTargetList& morphTargets = geom.getMorphTargetList();
fw.indent() << "num_morphTargets " << morphTargets.size() << std::endl;
for (unsigned int i = 0; i < morphTargets.size(); i++)
{
fw.indent() << "MorphTarget {" << std::endl;
fw.moveIn();
fw.indent() << "weight " << morphTargets[i].getWeight() <<std::endl;
fw.writeObject(*morphTargets[i].getGeometry());
fw.moveOut();
fw.indent() << "}" << std::endl;
}
return true;
}
RegisterDotOsgWrapperProxy g_osgAnimationMorphGeometryProxy
(
new osgAnimation::MorphGeometry,
"osgAnimation::MorphGeometry",
"Object Drawable osgAnimation::MorphGeometry Geometry",
&MorphGeometry_readLocalData,
&MorphGeometry_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
bool UpdateBone_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
return iteratorAdvanced;
@@ -490,11 +1020,11 @@ bool UpdateBone_writeLocalData(const Object& obj, Output& fw)
return true;
}
RegisterDotOsgWrapperProxy g_atkUpdateBoneProxy
RegisterDotOsgWrapperProxy g_UpdateBoneProxy
(
new osgAnimation::Bone::UpdateBone,
new osgAnimation::UpdateBone,
"osgAnimation::UpdateBone",
"Object NodeCallback osgAnimation::UpdateBone",
"Object NodeCallback osgAnimation::UpdateMatrixTransform osgAnimation::UpdateBone",
&UpdateBone_readLocalData,
&UpdateBone_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
@@ -513,7 +1043,7 @@ bool UpdateSkeleton_writeLocalData(const Object& obj, Output& fw)
return true;
}
RegisterDotOsgWrapperProxy g_atkUpdateSkeletonProxy
RegisterDotOsgWrapperProxy g_UpdateSkeletonProxy
(
new osgAnimation::Skeleton::UpdateSkeleton,
"osgAnimation::UpdateSkeleton",
@@ -524,25 +1054,24 @@ RegisterDotOsgWrapperProxy g_atkUpdateSkeletonProxy
);
bool UpdateTransform_readLocalData(Object& obj, Input& fr)
bool UpdateMorph_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
return iteratorAdvanced;
}
bool UpdateTransform_writeLocalData(const Object& obj, Output& fw)
bool UpdateMorph_writeLocalData(const Object& obj, Output& fw)
{
return true;
}
RegisterDotOsgWrapperProxy g_atkUpdateTransformProxy
RegisterDotOsgWrapperProxy g_UpdateMorphProxy
(
new osgAnimation::UpdateTransform,
"osgAnimation::UpdateTransform",
"Object NodeCallback osgAnimation::UpdateTransform",
&UpdateTransform_readLocalData,
&UpdateTransform_writeLocalData,
new osgAnimation::UpdateMorph,
"osgAnimation::UpdateMorph",
"Object NodeCallback osgAnimation::UpdateMorph",
&UpdateMorph_readLocalData,
&UpdateMorph_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);

View File

@@ -0,0 +1,228 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedTranslateElement>
#include <osgAnimation/StackedMatrixElement>
#include <osgAnimation/StackedScaleElement>
#include <osgAnimation/StackedRotateAxisElement>
#include <osgAnimation/StackedQuaternionElement>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/Registry>
#include <osgDB/ReaderWriter>
#include <osg/io_utils>
#include "Matrix.h"
using namespace osgDB;
using namespace osg;
bool readStackedTranslateElement(Object& obj, Input& fr)
{
osgAnimation::StackedTranslateElement& element = dynamic_cast<osgAnimation::StackedTranslateElement&>(obj);
bool iteratorAdvanced = false;
if (fr.matchSequence("translate %f %f %f"))
{
++fr;
osg::Vec3 translate;
fr[0].getFloat(translate.x());
fr[1].getFloat(translate.y());
fr[2].getFloat(translate.z());
element.setTranslate(translate);
fr += 3;
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
bool writeStackedTranslateElement(const Object& obj, Output& fw)
{
const osgAnimation::StackedTranslateElement& element = dynamic_cast<const osgAnimation::StackedTranslateElement&>(obj);
fw.indent() << "translate " << element.getTranslate() << std::endl;
return true;
}
RegisterDotOsgWrapperProxy g_StackedTranslateElementProxy
(
new osgAnimation::StackedTranslateElement,
"osgAnimation::StackedTranslateElement",
"Object osgAnimation::StackedTranslateElement",
&readStackedTranslateElement,
&writeStackedTranslateElement,
DotOsgWrapper::READ_AND_WRITE
);
bool readStackedScaleElement(Object& obj, Input& fr)
{
osgAnimation::StackedScaleElement& element = dynamic_cast<osgAnimation::StackedScaleElement&>(obj);
bool iteratorAdvanced = false;
if (fr.matchSequence("scale %f %f %f"))
{
++fr;
osg::Vec3 scale;
fr[0].getFloat(scale.x());
fr[1].getFloat(scale.y());
fr[2].getFloat(scale.z());
element.setScale(scale);
fr += 3;
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
bool writeStackedScaleElement(const Object& obj, Output& fw)
{
const osgAnimation::StackedScaleElement& element = dynamic_cast<const osgAnimation::StackedScaleElement&>(obj);
fw.indent() << "scale " << element.getScale() << std::endl;
return true;
}
RegisterDotOsgWrapperProxy g_StackedScaleElementProxy
(
new osgAnimation::StackedScaleElement,
"osgAnimation::StackedScaleElement",
"Object osgAnimation::StackedScaleElement",
&readStackedScaleElement,
&writeStackedScaleElement,
DotOsgWrapper::READ_AND_WRITE
);
bool readStackedMatrixElement(Object& obj, Input& fr)
{
osgAnimation::StackedMatrixElement& element = dynamic_cast<osgAnimation::StackedMatrixElement&>(obj);
bool iteratorAdvanced = false;
if (fr[0].matchWord("Matrix"))
{
osg::Matrix matrix;
matrix.makeIdentity();
iteratorAdvanced = readMatrix(matrix, fr);
element.setMatrix(matrix);
}
return iteratorAdvanced;
}
bool writeStackedMatrixElement(const Object& obj, Output& fw)
{
const osgAnimation::StackedMatrixElement& element = dynamic_cast<const osgAnimation::StackedMatrixElement&>(obj);
writeMatrix(element.getMatrix(), fw);
return true;
}
RegisterDotOsgWrapperProxy g_StackedMatrixElementProxy
(
new osgAnimation::StackedMatrixElement,
"osgAnimation::StackedMatrixElement",
"Object osgAnimation::StackedMatrixElement",
&readStackedMatrixElement,
&writeStackedMatrixElement,
DotOsgWrapper::READ_AND_WRITE
);
bool writeStackedRotateAxisElement(const Object& obj, Output& fw)
{
const osgAnimation::StackedRotateAxisElement& element = dynamic_cast<const osgAnimation::StackedRotateAxisElement&>(obj);
fw.indent() << "axis " << element.getAxis() << std::endl;
fw.indent() << "angle " << element.getAngle() << std::endl;
return true;
}
bool readStackedRotateAxisElement(Object& obj, Input& fr)
{
osgAnimation::StackedRotateAxisElement& element = dynamic_cast<osgAnimation::StackedRotateAxisElement&>(obj);
bool iteratorAdvanced = false;
if (fr.matchSequence("axis %f %f %f"))
{
++fr;
osg::Vec3 axis;
fr[0].getFloat(axis.x());
fr[1].getFloat(axis.y());
fr[2].getFloat(axis.z());
element.setAxis(axis);
fr += 3;
iteratorAdvanced = true;
}
if (fr.matchSequence("angle %f"))
{
++fr;
double angle = 0;
fr[0].getFloat(angle);
++fr;
element.setAngle(angle);
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
RegisterDotOsgWrapperProxy g_StackedRotateAxisElementProxy
(
new osgAnimation::StackedRotateAxisElement,
"osgAnimation::StackedRotateAxisElement",
"Object osgAnimation::StackedRotateAxisElement",
&readStackedRotateAxisElement,
&writeStackedRotateAxisElement,
DotOsgWrapper::READ_AND_WRITE
);
bool readStackedQuaternionElement(Object& obj, Input& fr)
{
osgAnimation::StackedQuaternionElement& element = dynamic_cast<osgAnimation::StackedQuaternionElement&>(obj);
bool iteratorAdvanced = false;
if (fr.matchSequence("quaternion %f %f %f %f"))
{
++fr;
osg::Quat quaternion;
fr[0].getFloat(quaternion[0]);
fr[1].getFloat(quaternion[1]);
fr[2].getFloat(quaternion[2]);
fr[3].getFloat(quaternion[3]);
element.setQuaternion(quaternion);
fr += 4;
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
bool writeStackedQuaternionElement(const Object& obj, Output& fw)
{
const osgAnimation::StackedQuaternionElement& element = dynamic_cast<const osgAnimation::StackedQuaternionElement&>(obj);
fw.indent() << "quaternion " << element.getQuaternion() << std::endl;
return true;
}
RegisterDotOsgWrapperProxy g_StackedQuaternionElementProxy
(
new osgAnimation::StackedQuaternionElement,
"osgAnimation::StackedQuaternionElement",
"Object osgAnimation::StackedQuaternionElement",
&readStackedQuaternionElement,
&writeStackedQuaternionElement,
DotOsgWrapper::READ_AND_WRITE
);

View File

@@ -0,0 +1,47 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/Input>
#include <osgDB/Output>
#include <osgDB/Registry>
#include <osgDB/ReaderWriter>
#include <osg/io_utils>
#include <osgAnimation/UpdateMaterial>
using namespace osg;
using namespace osgDB;
bool UpdateMaterial_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
return iteratorAdvanced;
}
bool UpdateMaterial_writeLocalData(const Object& obj, Output& fw)
{
return true;
}
RegisterDotOsgWrapperProxy g_UpdateMaterialProxy
(
new osgAnimation::UpdateMaterial,
"osgAnimation::UpdateMaterial",
"Object StateAttribute::Callback osgAnimation::UpdateMaterial",
&UpdateMaterial_readLocalData,
&UpdateMaterial_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);

View File

@@ -0,0 +1,70 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/Input>
#include <osgDB/Output>
#include <osgDB/Registry>
#include <osgDB/ReaderWriter>
#include <osg/io_utils>
#include <osgAnimation/StackedTransformElement>
#include <osgAnimation/UpdateMatrixTransform>
using namespace osg;
using namespace osgDB;
bool UpdateMatrixTransform_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
osgAnimation::UpdateMatrixTransform& updateCallback = dynamic_cast<osgAnimation::UpdateMatrixTransform&>(obj);
osgAnimation::StackedTransform& stackedTransform = updateCallback.getStackedTransforms();
int entry = fr[0].getNoNestedBrackets();
while (!fr.eof() && fr[0].getNoNestedBrackets() == entry && fr.matchSequence("%w {"))
{
osgAnimation::StackedTransformElement* element = dynamic_cast<osgAnimation::StackedTransformElement*>(fr.readObject());
if (element)
stackedTransform.push_back(element);
}
return iteratorAdvanced;
}
bool UpdateMatrixTransform_writeLocalData(const Object& obj, Output& fw)
{
const osgAnimation::UpdateMatrixTransform* uc = dynamic_cast<const osgAnimation::UpdateMatrixTransform*>(&obj);
const osgAnimation::StackedTransform& transforms = uc->getStackedTransforms();
for (osgAnimation::StackedTransform::const_iterator it = transforms.begin(); it != transforms.end(); ++it)
{
osgAnimation::StackedTransformElement* element = it->get();
if (element)
fw.writeObject(*element);
}
return true;
}
RegisterDotOsgWrapperProxy g_UpdateMatrixTransformProxy
(
new osgAnimation::UpdateMatrixTransform,
"osgAnimation::UpdateMatrixTransform",
"Object NodeCallback osgAnimation::UpdateMatrixTransform",
&UpdateMatrixTransform_readLocalData,
&UpdateMatrixTransform_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);