2.8 branch: backport of osgAnimation from svn head 11026.
This commit is contained in:
83
src/osgAnimation/Action.cpp
Normal file
83
src/osgAnimation/Action.cpp
Normal 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;
|
||||
}
|
||||
32
src/osgAnimation/ActionAnimation.cpp
Normal file
32
src/osgAnimation/ActionAnimation.cpp
Normal 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);
|
||||
}
|
||||
45
src/osgAnimation/ActionBlendIn.cpp
Normal file
45
src/osgAnimation/ActionBlendIn.cpp
Normal 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);
|
||||
}
|
||||
41
src/osgAnimation/ActionBlendOut.cpp
Normal file
41
src/osgAnimation/ActionBlendOut.cpp
Normal 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);
|
||||
}
|
||||
23
src/osgAnimation/ActionCallback.cpp
Normal file
23
src/osgAnimation/ActionCallback.cpp
Normal 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);
|
||||
}
|
||||
|
||||
88
src/osgAnimation/ActionStripAnimation.cpp
Normal file
88
src/osgAnimation/ActionStripAnimation.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
184
src/osgAnimation/ActionVisitor.cpp
Normal file
184
src/osgAnimation/ActionVisitor.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
42
src/osgAnimation/BoneMapVisitor.cpp
Normal file
42
src/osgAnimation/BoneMapVisitor.cpp
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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;}
|
||||
|
||||
|
||||
87
src/osgAnimation/LinkVisitor.cpp
Normal file
87
src/osgAnimation/LinkVisitor.cpp
Normal 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));
|
||||
}
|
||||
277
src/osgAnimation/MorphGeometry.cpp
Normal file
277
src/osgAnimation/MorphGeometry.cpp
Normal 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;
|
||||
}
|
||||
@@ -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; }
|
||||
|
||||
272
src/osgAnimation/RigTransformHardware.cpp
Normal file
272
src/osgAnimation/RigTransformHardware.cpp
Normal 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());
|
||||
}
|
||||
144
src/osgAnimation/RigTransformSoftware.cpp
Normal file
144
src/osgAnimation/RigTransformSoftware.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
|
||||
40
src/osgAnimation/StackedMatrixElement.cpp
Normal file
40
src/osgAnimation/StackedMatrixElement.cpp
Normal 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();
|
||||
}
|
||||
53
src/osgAnimation/StackedQuaternionElement.cpp
Normal file
53
src/osgAnimation/StackedQuaternionElement.cpp
Normal 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();}
|
||||
55
src/osgAnimation/StackedRotateAxisElement.cpp
Normal file
55
src/osgAnimation/StackedRotateAxisElement.cpp
Normal 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)); }
|
||||
56
src/osgAnimation/StackedScaleElement.cpp
Normal file
56
src/osgAnimation/StackedScaleElement.cpp
Normal 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();
|
||||
}
|
||||
66
src/osgAnimation/StackedTransform.cpp
Normal file
66
src/osgAnimation/StackedTransform.cpp
Normal 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;
|
||||
}
|
||||
50
src/osgAnimation/StackedTranslateElement.cpp
Normal file
50
src/osgAnimation/StackedTranslateElement.cpp
Normal 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();
|
||||
}
|
||||
722
src/osgAnimation/StatsHandler.cpp
Normal file
722
src/osgAnimation/StatsHandler.cpp
Normal 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.");
|
||||
}
|
||||
|
||||
}
|
||||
86
src/osgAnimation/StatsVisitor.cpp
Normal file
86
src/osgAnimation/StatsVisitor.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
54
src/osgAnimation/UpdateBone.cpp
Normal file
54
src/osgAnimation/UpdateBone.cpp
Normal 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);
|
||||
}
|
||||
63
src/osgAnimation/UpdateMaterial.cpp
Normal file
63
src/osgAnimation/UpdateMaterial.cpp
Normal 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;
|
||||
}
|
||||
67
src/osgAnimation/UpdateMatrixTransform.cpp
Normal file
67
src/osgAnimation/UpdateMatrixTransform.cpp
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
51
src/osgPlugins/osgAnimation/Matrix.cpp
Normal file
51
src/osgPlugins/osgAnimation/Matrix.cpp
Normal 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;
|
||||
}
|
||||
|
||||
13
src/osgPlugins/osgAnimation/Matrix.h
Normal file
13
src/osgPlugins/osgAnimation/Matrix.h
Normal 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
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
228
src/osgPlugins/osgAnimation/StackedTransform.cpp
Normal file
228
src/osgPlugins/osgAnimation/StackedTransform.cpp
Normal 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
|
||||
);
|
||||
47
src/osgPlugins/osgAnimation/UpdateMaterial.cpp
Normal file
47
src/osgPlugins/osgAnimation/UpdateMaterial.cpp
Normal 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
|
||||
);
|
||||
70
src/osgPlugins/osgAnimation/UpdateMatrixTransform.cpp
Normal file
70
src/osgPlugins/osgAnimation/UpdateMatrixTransform.cpp
Normal 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
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user