/* -*-c++-*- * Copyright (C) 2009 Cedric Pinson * * 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::Action() { _numberFrame = 25; _fps = 25; _speed = 1.0; _loop = 1; } osgAnimation::Action::Action(const Action&,const osg::CopyOp&) {} osgAnimation::Action::Callback* osgAnimation::Action::getFrameCallback(unsigned int frame) { if (_framesCallback.find(frame) != _framesCallback.end()) { return _framesCallback[frame].get(); } return 0; } osgAnimation::Action::Callback* osgAnimation::Action::getFrameCallback(double time) { unsigned int frame = static_cast(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; } osgAnimation::BlendIn::BlendIn(Animation* animation, double duration, double weight) { _animation = animation; _weight = weight; float d = duration * _fps; setNumFrames(static_cast(floor(d)) + 1); setName("BlendIn"); } void osgAnimation::BlendIn::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); } osgAnimation::BlendOut::BlendOut(Animation* animation, double duration) { _animation = animation; float d = duration * _fps; setNumFrames(static_cast(floor(d) + 1)); _weight = 1.0; setName("BlendOut"); } void osgAnimation::BlendOut::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); } osgAnimation::ActionAnimation::ActionAnimation(Animation* animation) : _animation(animation) { Action::setDuration(animation->getDuration()); setName(animation->getName()); } void osgAnimation::ActionAnimation::updateAnimation(unsigned int frame) { _animation->update(frame * 1.0/_fps); } osgAnimation::StripAnimation::StripAnimation(const StripAnimation& a, const osg::CopyOp& c) : Action(a,c) { _animation = a._animation; _blendIn = a._blendIn; _blendOut = a._blendOut; } osgAnimation::StripAnimation::StripAnimation(Animation* animation, double blendInDuration, double blendOutDuration, double blendInWeightTarget) { _blendIn = new BlendIn(animation, blendInDuration, blendInWeightTarget); _animation = new ActionAnimation(animation); unsigned int start = static_cast(floor((_animation->getDuration() - blendOutDuration) * _fps)); _blendOut = FrameBlendOut(start, new BlendOut(animation, blendOutDuration)); setName(animation->getName() + "_Strip"); _blendIn->setName(_animation->getName() + "_" + _blendIn->getName()); _blendOut.second->setName(_animation->getName() + "_" + _blendOut.second->getName()); setDuration(animation->getDuration()); } void osgAnimation::StripAnimation::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(floor((getDuration() - _blendOut.second->getDuration()) * _fps)); _blendOut = FrameBlendOut(start, _blendOut.second); } void osgAnimation::StripAnimation::traverse(ActionVisitor& visitor) { if (_blendIn.valid()) { unsigned int f = visitor._stackFrameAction.back().first; visitor.pushFrameActionOnStack(FrameAction(f,_blendIn.get())); _blendIn->accept(visitor); visitor.popFrameAction(); } if (_blendOut.second.valid()) { unsigned int f = visitor._stackFrameAction.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._stackFrameAction.back().first; visitor.pushFrameActionOnStack(FrameAction(f,_animation.get())); _animation->accept(visitor); visitor.popFrameAction(); } } void osgAnimation::StripAnimation::computeWeightAndUpdateAnimation(unsigned int frame) { if (frame < _blendIn->getNumFrames()) _blendIn->computeWeight(frame); if (frame >= _blendOut.first) _blendOut.second->computeWeight(frame - _blendOut.first); _animation->updateAnimation(frame); }