Hi Robert,

I just sent you the files by mail, here again on the mailing. Those changes are not critical, so it's not a problem if not for the 2.8

Cheers,
Cedric

Robert Osfield wrote:
Hi Guys,

If we have a quicker turn around on review on these changes I would
have considered them for the 2.8.0 release, but given that lots of
people are now testing the 2.8 branch as is, without these changes I
feel it'd be best to just apply these changes to svn/trunk.  None of
these changes address bugs so there shouldn't be a risk in not merging
for 2.8.

Robert.
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

--
+33 (0) 6 63 20 03 56  Cedric Pinson mailto:[email protected] 
http://www.plopbyte.net


/*  -*-c++-*- 
 *  Copyright (C) 2008 Cedric Pinson <[email protected]>
 *
 * 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 <iostream>
#include <osg/Geometry>
#include <osg/MatrixTransform>
#include <osg/Geode>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osgUtil/SmoothingVisitor>
#include <osg/io_utils>

#include <osgAnimation/Bone>
#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/Skinning>
#include <osgAnimation/BasicAnimationManager>

osg::Geode* createAxis()
{
    osg::Geode* geode (new osg::Geode());  
    osg::Geometry* geometry (new osg::Geometry());

    osg::Vec3Array* vertices (new osg::Vec3Array());
    vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
    vertices->push_back (osg::Vec3 ( 1.0, 0.0, 0.0));
    vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
    vertices->push_back (osg::Vec3 ( 0.0, 1.0, 0.0));
    vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
    vertices->push_back (osg::Vec3 ( 0.0, 0.0, 1.0));
    geometry->setVertexArray (vertices);

    osg::Vec4Array* colors (new osg::Vec4Array());
    colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
    colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
    colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
    colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
    colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
    colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
    geometry->setColorArray (colors);

    geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX);    
    geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,6));

    geode->addDrawable( geometry );
    return geode;
}

osgAnimation::RigGeometry* createTesselatedBox(int nsplit, float size)
{
    osgAnimation::RigGeometry* geometry = new osgAnimation::RigGeometry;

    osg::ref_ptr<osg::Vec3Array> vertices (new osg::Vec3Array());
    osg::ref_ptr<osg::Vec3Array> colors (new osg::Vec3Array());
    geometry->setVertexArray (vertices.get());
    geometry->setColorArray (colors.get());
    geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX);    
  
    float step = size / nsplit;
    float s = 0.5/4.0;
    for (int i = 0; i < nsplit; i++) 
    {
        float x = -1 + i * step;
        std::cout << x << std::endl;
        vertices->push_back (osg::Vec3 ( x, s, s));
        vertices->push_back (osg::Vec3 ( x, -s, s));
        vertices->push_back (osg::Vec3 ( x, -s, -s));
        vertices->push_back (osg::Vec3 ( x, s, -s));
        osg::Vec3 c (0,0,0);
        c[i%3] = 1;
        colors->push_back (c);
        colors->push_back (c);
        colors->push_back (c);
        colors->push_back (c);
    }

    osg::ref_ptr<osg::UIntArray> array = new osg::UIntArray;
    for (int i = 0; i < nsplit - 1; i++) 
    {
        int base = i * 4;
        array->push_back(base);
        array->push_back(base+1);
        array->push_back(base+4);
        array->push_back(base+1);
        array->push_back(base+5);
        array->push_back(base+4);

        array->push_back(base+3);
        array->push_back(base);
        array->push_back(base+4);
        array->push_back(base+7);
        array->push_back(base+3);
        array->push_back(base+4);

        array->push_back(base+5);
        array->push_back(base+1);
        array->push_back(base+2);
        array->push_back(base+2);
        array->push_back(base+6);
        array->push_back(base+5);

        array->push_back(base+2);
        array->push_back(base+3);
        array->push_back(base+7);
        array->push_back(base+6);
        array->push_back(base+2);
        array->push_back(base+7);
    }
  
    geometry->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, array->size(), &array->front()));
    geometry->setUseDisplayList( false );
    return geometry;
}


void initVertexMap(osgAnimation::Bone* b0,
                   osgAnimation::Bone* b1,
                   osgAnimation::Bone* b2,
                   osgAnimation::RigGeometry* geom,
                   osg::Vec3Array* array)
{
    osgAnimation::VertexInfluenceSet vertexesInfluences;
    osgAnimation::VertexInfluenceMap* vim = new osgAnimation::VertexInfluenceMap;

    (*vim)[b0->getName()].setName(b0->getName());
    (*vim)[b1->getName()].setName(b1->getName());
    (*vim)[b2->getName()].setName(b2->getName());

    for (int i = 0; i < (int)array->size(); i++) 
    {
        float val = (*array)[i][0];
        std::cout << val << std::endl;
        if (val >= -1 && val <= 0)
            (*vim)[b0->getName()].push_back(osgAnimation::VertexIndexWeight(i,1));
        else if ( val > 0 && val <= 1)
            (*vim)[b1->getName()].push_back(osgAnimation::VertexIndexWeight(i,1));
        else if ( val > 1)
            (*vim)[b2->getName()].push_back(osgAnimation::VertexIndexWeight(i,1));
    }

    geom->setInfluenceMap(vim);
}



int main (int argc, char* argv[])
{
    osg::ArgumentParser arguments(&argc, argv);
    osgViewer::Viewer viewer(arguments);

    viewer.setCameraManipulator(new osgGA::TrackballManipulator());

    osg::ref_ptr<osgAnimation::Skeleton> skelroot = new osgAnimation::Skeleton;
    skelroot->setDefaultUpdateCallback();
    osg::ref_ptr<osgAnimation::Bone> root = new osgAnimation::Bone;
    {
        root->setBindMatrixInBoneSpace(osg::Matrix::identity());
        root->setBindMatrixInBoneSpace(osg::Matrix::translate(-1,0,0));
        root->setName("root");
        root->setDefaultUpdateCallback();
    }

    osg::ref_ptr<osgAnimation::Bone> right0 = new osgAnimation::Bone;
    right0->setBindMatrixInBoneSpace(osg::Matrix::translate(1,0,0));
    right0->setName("right0");
    right0->setDefaultUpdateCallback("right0");

    osg::ref_ptr<osgAnimation::Bone> right1 = new osgAnimation::Bone;
    right1->setBindMatrixInBoneSpace(osg::Matrix::translate(1,0,0));
    right1->setName("right1");
    right1->setDefaultUpdateCallback("right1");

    root->addChild(right0.get());
    right0->addChild(right1.get());
    skelroot->addChild(root.get());

    osg::Group* scene = new osg::Group;
    osg::ref_ptr<osgAnimation::BasicAnimationManager> manager = new osgAnimation::BasicAnimationManager;
    scene->setUpdateCallback(manager.get());

    osgAnimation::Animation* anim = new osgAnimation::Animation;
    {
        osgAnimation::QuatKeyframeContainer* keys0 = new osgAnimation::QuatKeyframeContainer;
        osg::Quat rotate;
        rotate.makeRotate(osg::PI_2, osg::Vec3(0,0,1));
        keys0->push_back(osgAnimation::QuatKeyframe(0,osg::Quat(0,0,0,1)));
        keys0->push_back(osgAnimation::QuatKeyframe(3,rotate));
        keys0->push_back(osgAnimation::QuatKeyframe(6,rotate));
        osgAnimation::QuatSphericalLinearSampler* sampler = new osgAnimation::QuatSphericalLinearSampler;
        sampler->setKeyframeContainer(keys0);
        // osgAnimation::AnimationUpdateCallback* cb = dynamic_cast<osgAnimation::AnimationUpdateCallback*>(right0->getUpdateCallback());
        osgAnimation::QuatSphericalLinearChannel* channel = new osgAnimation::QuatSphericalLinearChannel(sampler);
        channel->setName("quaternion");
        channel->setTargetName("right0");
        anim->addChannel(channel);
    }

    {
        osgAnimation::QuatKeyframeContainer* keys1 = new osgAnimation::QuatKeyframeContainer;
        osg::Quat rotate;
        rotate.makeRotate(osg::PI_2, osg::Vec3(0,0,1));
        keys1->push_back(osgAnimation::QuatKeyframe(0,osg::Quat(0,0,0,1)));
        keys1->push_back(osgAnimation::QuatKeyframe(3,osg::Quat(0,0,0,1)));
        keys1->push_back(osgAnimation::QuatKeyframe(6,rotate));
        osgAnimation::QuatSphericalLinearSampler* sampler = new osgAnimation::QuatSphericalLinearSampler;
        sampler->setKeyframeContainer(keys1);
        osgAnimation::QuatSphericalLinearChannel* channel = new osgAnimation::QuatSphericalLinearChannel(sampler);
        //osgAnimation::AnimationUpdateCallback* cb = dynamic_cast<osgAnimation::AnimationUpdateCallback*>(right1->getUpdateCallback());
        channel->setName("quaternion");
        channel->setTargetName("right1");
        anim->addChannel(channel);
    }
    manager->registerAnimation(anim);
    manager->buildTargetReference();
  
    // let's start !
    manager->playAnimation(anim);

    // we will use local data from the skeleton
    osg::MatrixTransform* rootTransform = new osg::MatrixTransform;
    rootTransform->setMatrix(osg::Matrix::rotate(osg::PI_2,osg::Vec3(1,0,0)));
    right0->addChild(createAxis());
    right0->setDataVariance(osg::Object::DYNAMIC);
    right1->addChild(createAxis());
    right1->setDataVariance(osg::Object::DYNAMIC);
    osg::MatrixTransform* trueroot = new osg::MatrixTransform;
    trueroot->setMatrix(osg::Matrix(root->getMatrixInBoneSpace().ptr()));
    trueroot->addChild(createAxis());
    trueroot->addChild(skelroot.get());
    trueroot->setDataVariance(osg::Object::DYNAMIC);
    rootTransform->addChild(trueroot);
    scene->addChild(rootTransform);
  
    osgAnimation::RigGeometry* geom = createTesselatedBox(4, 4.0);
    osg::Geode* geode = new osg::Geode;
    geode->addDrawable(geom);
    skelroot->addChild(geode);
    osg::ref_ptr<osg::Vec3Array> src = dynamic_cast<osg::Vec3Array*>(geom->getVertexArray());
    geom->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
    geom->setDataVariance(osg::Object::DYNAMIC);

    initVertexMap(root.get(), right0.get(), right1.get(), geom, src.get());

    // let's run !
    viewer.setSceneData( scene );
    viewer.realize();

    while (!viewer.done())
    {
        viewer.frame();
    }

    return 0;
}


/*  -*-c++-*- 
 *  Copyright (C) 2008 Cedric Pinson <[email protected]>
 *
 * 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.
*/

#ifndef OSGANIMATION_RIGGEOMETRY_H
#define OSGANIMATION_RIGGEOMETRY_H

#include <osgAnimation/Export>
#include <osgAnimation/Skinning>
#include <osgAnimation/Skeleton>
#include <osg/Geometry>

namespace osgAnimation 
{

    class OSGANIMATION_EXPORT RigGeometry : public osg::Geometry
    {
    public:

        RigGeometry();
        RigGeometry(const osg::Geometry& b);
        RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop = 
osg::CopyOp::SHALLOW_COPY);

        META_Object(osgAnimation, RigGeometry);

        void setInfluenceMap(osgAnimation::VertexInfluenceMap* 
vertexInfluenceMap) { _vertexInfluenceMap = vertexInfluenceMap; }
        const osgAnimation::VertexInfluenceMap* getInfluenceMap() const { 
return _vertexInfluenceMap.get();}
        osgAnimation::VertexInfluenceMap* getInfluenceMap() { return 
_vertexInfluenceMap.get();}
 
        const Skeleton* getSkeleton() const;
        Skeleton* getSkeleton();
        
        void setNeedToComputeMatrix(bool state) { _needToComputeMatrix = state;}
        bool getNeedToComputeMatrix() const { return _needToComputeMatrix;}
        
        void buildVertexSet();
        void buildTransformer(Skeleton* root);
        void computeMatrixFromRootSkeleton();

        virtual void transformSoftwareMethod();
        const osgAnimation::VertexInfluenceSet& getVertexInfluenceSet() const { 
return _vertexInfluenceSet;}

        const std::vector<osg::Vec3>& getPositionSource() const { return 
_positionSource;}
        const std::vector<osg::Vec3>& getNormalSource() const { return 
_normalSource;}

    protected:

        std::vector<osg::Vec3> _positionSource;
        std::vector<osg::Vec3> _normalSource;

        osgAnimation::VertexInfluenceSet _vertexInfluenceSet;
        osg::ref_ptr<osgAnimation::VertexInfluenceMap> _vertexInfluenceMap;
        osgAnimation::TransformVertexFunctor _transformVertexes;

        osg::Matrix _matrixFromSkeletonToGeometry;
        osg::Matrix _invMatrixFromSkeletonToGeometry;
        osg::observer_ptr<Skeleton> _root;
        bool _needToComputeMatrix;

 
        struct FindNearestParentSkeleton : public osg::NodeVisitor
        {
            osg::ref_ptr<osgAnimation::Skeleton> _root;
            FindNearestParentSkeleton() : 
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {}
            void apply(osg::Transform& node) 
            {
                if (_root.valid())
                    return;
                _root = dynamic_cast<osgAnimation::Skeleton*>(&node);
                traverse(node);
            }
        };


        struct UpdateVertex : public osg::Drawable::UpdateCallback
        {
            virtual void update(osg::NodeVisitor*, osg::Drawable* drw)
            {
                RigGeometry* geom = dynamic_cast<RigGeometry*>(drw);
                if (!geom)
                    return;
                if (!geom->getSkeleton() && !geom->getParents().empty()) 
                {
                    FindNearestParentSkeleton finder;
                    if (geom->getParents().size() > 1)
                        osg::notify(osg::WARN) << "A RigGeometry should not 
have multi parent ( " << geom->getName() << " )" << std::endl;
                    geom->getParents()[0]->accept(finder);

                    if (!finder._root.valid())
                        return;
                    geom->buildVertexSet();
                    geom->buildTransformer(finder._root.get());
                }

                if (!geom->getSkeleton())
                    return;

                if (geom->getNeedToComputeMatrix())
                    geom->computeMatrixFromRootSkeleton();
                geom->transformSoftwareMethod();
            }
        };

        /** BuildVertexTransformerVisitor is used to setup RigGeometry drawable
         *  throw a subgraph. 
         */
        struct BuildVertexTransformerVisitor : public osg::NodeVisitor
        {
            osg::ref_ptr<Skeleton> _root;
            BuildVertexTransformerVisitor(Skeleton* root): 
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { _root = root;}

            META_NodeVisitor("osgAnimation","BuildVertexTransformerVisitor")

            void apply(osg::Geode& node) 
            { 
                int num = node.getNumDrawables();
                for (int i = 0; i < num; i++) {
                    RigGeometry* geom = 
dynamic_cast<RigGeometry*>(node.getDrawable(i));
                    if (geom) 
                    {
                        geom->buildVertexSet();
                        geom->buildTransformer(_root.get());
                    }
                }
            }
        };

   };

}

#endif
/*  -*-c++-*- 
 *  Copyright (C) 2008 Cedric Pinson <[email protected]>
 *
 * 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.
*/

#ifndef OSGANIMATION_TIMELINE_H
#define OSGANIMATION_TIMELINE_H

#include <osgAnimation/Export>
#include <osg/Object>
#include <map>
#include <vector>
#include <osg/Notify>
#include <osg/Group>
#include <osgAnimation/Animation>
#include <osgAnimation/AnimationManagerBase>

namespace osgAnimation
{

    class Action : public osg::Object
    {
    public:

        class Callback : public osg::Object
        {
        public:
            Callback(){}
            Callback(const Callback&,const osg::CopyOp&) {}

            META_Object(osgAnimation,Callback);
        
            virtual void operator()(Action* /*action*/) {}
            
            void addNestedCallback(Callback* callback) 
            { 
                if (_nested.valid())
                    _nested->addNestedCallback(callback);
                else
                    _nested = callback;
            }

        protected:
            osg::ref_ptr<Callback> _nested;
        };


        typedef std::map<unsigned int, osg::ref_ptr<Callback> > FrameCallback;

        META_Object(osgAnimation, Action);
        
        Action()
        {
            _numberFrame = 25;
            _fps = 25;
            _speed = 1.0;
            _loop = 1;
        }

        Action(const Action&,const osg::CopyOp&) {}

        void setCallback(double when, Callback* callback)
        {
            setCallback(static_cast<unsigned int>(floor(when*_fps)), callback);
        }

        void setCallback(unsigned int frame, Callback* callback)
        {
            if (_framesCallback[frame].valid())
                _framesCallback[frame]->addNestedCallback(callback);
            else
                _framesCallback[frame] = callback;
        }
        Callback* getCallback(unsigned int frame)
        {
            if (_framesCallback.find(frame) == _framesCallback.end())
                return 0;
            return _framesCallback[frame].get();
        }

        void setNumFrames(unsigned int numFrames) { _numberFrame = numFrames;}
        void setDuration(double duration) { _numberFrame = static_cast<unsigned 
int>(floor(duration * _fps)); }

        unsigned int getNumFrames() const { return _numberFrame;}
        double getDuration() const { return _numberFrame * 1.0 / _fps; }

        // 0 means infini else it's the number of loop
        virtual void setLoop(int nb) { _loop = nb; }
        virtual unsigned int getLoop() const { return _loop;}

        // get the number of loop, the frame relative to loop.
        // return true if in range, and false if out of range.
        bool 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;
        }

        virtual void evaluate(unsigned int frame)
        {
            unsigned int frameInAction;
            unsigned int loopDone;
            if (!evaluateFrame(frame, frameInAction, loopDone))
                osg::notify(osg::DEBUG_INFO) << getName() << " Action frame " 
<< frameInAction  << " finished" << std::endl;
            else
                osg::notify(osg::DEBUG_INFO) << getName() << " Action frame " 
<< frame  << " relative to loop " << frameInAction  << " no loop " << 
loopDone<< std::endl;
        }

        virtual void evaluateCallback(unsigned int frame)
        {
            unsigned int frameInAction;
            unsigned int loopDone;
            if (!evaluateFrame(frame, frameInAction, loopDone))
                return;

            frame = frameInAction;
            if (_framesCallback.find(frame) != _framesCallback.end())
            {
                std::cout << getName() << " evaluate callback " << 
_framesCallback[frame]->getName() << " at " << frame << std::endl;
                (*_framesCallback[frame])(this);
            }
        }

    protected:
        FrameCallback _framesCallback;

        double _speed;
        unsigned int _fps;
        unsigned int _numberFrame;
        unsigned int _loop;

        enum State
        {
            Play,
            Stop
        };
        
        State _state;
    };


    class Timeline : public osg::Object
    {
    protected:
        typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
        typedef std::vector<FrameAction> ActionList;
        typedef std::map<int, ActionList> ActionLayers;
        enum State
        {
            Play,
            Stop
        };
        

        ActionLayers _actions;
        double _lastUpdate;
        double _speed;
        unsigned int _currentFrame;
        unsigned int _fps;
        unsigned int _numberFrame;
        unsigned int _previousFrameEvaluated;
        bool _loop;
        bool _initFirstFrame;

        State _state;

        // to manage pending operation
        bool _evaluating;

        struct Command
        {
            Command():_priority(0) {}
            Command(int priority, const FrameAction& action) : 
_priority(priority), _action(action) {}
            int _priority;
            FrameAction _action;
        };

        typedef std::vector<Command> CommandList;
        CommandList _addActionOperations;
        ActionList _removeActionOperations;

        void setEvaluating(bool state) { _evaluating = state;}
        void 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 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 internalAddAction(int priority, const FrameAction& ftl)
        {
            _actions[priority].push_back(ftl);
        }
        
    public:

        META_Object(osgAnimation, Timeline);

        Timeline();
        Timeline(const Timeline& nc,const osg::CopyOp& op = 
osg::CopyOp::SHALLOW_COPY);
        State getStatus() const { return _state; }
        const ActionList& getActionLayer(int i)
        {
            return _actions[i];
        }
        unsigned int getCurrentFrame() const { return _currentFrame;}
        double getCurrentTime() const { return _currentFrame * 1.0 / _fps;}

        void play() { _state = Play; }
        void gotoFrame(unsigned int frame) { _currentFrame = frame; }
        void stop() { _state = Stop; }
        bool getEvaluating() const { return _evaluating;}

        bool 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;
        }

        void removeAction(Action* action)
        {
            if (getEvaluating())
                _removeActionOperations.push_back(FrameAction(0, action));
            else
                internalRemoveAction(action);
        }

        virtual void addActionAt(unsigned int frame, Action* action, int 
priority = 0)
        {
            if (getEvaluating())
                
_addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
            else
                internalAddAction(priority, FrameAction(frame, action));
        }
        virtual void addActionAt(double t, Action* action, int priority = 0)
        {
            unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
            addActionAt(frame, action, priority);
        }

        virtual void evaluate(unsigned int frame)
        {
            setEvaluating(true);
            osg::notify(osg::DEBUG_INFO) << getName() << " evaluate frame " << 
_currentFrame << std::endl;

            // update from high priority to low priority
            for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); 
iterAnim != _actions.rend(); ++iterAnim )
            {
                // update all animation
                ActionList& list = iterAnim->second;
                for (unsigned int i = 0; i < list.size(); i++)
                {
                    unsigned int firstFrame = list[i].first;
                    Action* action = list[i].second.get();
                    // check if current frame of timeline hit an action interval
                    if (frame >= firstFrame && 
                        frame < (firstFrame + action->getNumFrames()) )
                        action->evaluate(frame - firstFrame);
                }
            }
            setEvaluating(false);

            // evaluate callback after updating all animation
            evaluateCallback(frame);
            _previousFrameEvaluated = frame;
        }

        virtual void evaluateCallback(unsigned int frame)
        {
            // update from high priority to low priority
            for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); 
iterAnim != _actions.rend(); ++iterAnim )
            {
                // update all animation
                ActionList& list = iterAnim->second;
                for (unsigned int i = 0; i < list.size(); i++)
                {
                    unsigned int firstFrame = list[i].first;
                    Action* action = list[i].second.get();
                    // check if current frame of timeline hit an action interval
                    if (frame >= firstFrame && 
                        frame < (firstFrame + action->getNumFrames()) )
                        action->evaluateCallback(frame - firstFrame);
                }
            }
            processPendingOperation();
        }

        virtual void update(double simulationTime)
        {
            // first time we call update we generate one frame
            if (!_initFirstFrame)
            {
                _lastUpdate = simulationTime;
                _initFirstFrame = true;
                evaluate(_currentFrame);
            }

            // 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++;
                evaluate(_currentFrame);
            }
            if (nb)
            {
                _lastUpdate += ((double)nb) / _fps;
            }
        }
    };



    // blend in from 0 to weight in duration
    class BlendIn : public Action
    {
        double _weight;
        osg::ref_ptr<Animation> _animation;

    public:
        BlendIn(Animation* animation, double duration, double weight)
        {
            _animation = animation;
            _weight = weight;
            float d = duration * _fps;
            setNumFrames(static_cast<unsigned int>(floor(d)) + 1);
            setName("BlendIn");
        }
        double getWeight() const { return _weight;}
        virtual void evaluate(unsigned int frame)
        {
            Action::evaluate(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;
            if (frame < getNumFrames() -1 ) // the last frame we set the target 
weight the user asked
                w = _weight * ratio;
            _animation->setWeight(w);
        }
    };

    // blend in from 0 to weight in duration
    class BlendOut : public Action
    {
        double _weight;
        osg::ref_ptr<Animation> _animation;
    public:
        BlendOut(Animation* animation, double duration)
        {
            _animation = animation;
            float d = duration * _fps;
            setNumFrames(static_cast<unsigned int>(floor(d) + 1));
            _weight = 1.0;
            setName("BlendOut");
        }
        double getWeight() const { return _weight;}
        virtual void evaluate(unsigned int frame)
        {
            Action::evaluate(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 = 0.0;
            if (frame < getNumFrames() -1 ) // the last frame we set the target 
weight the user asked
                w = _weight * (1.0-ratio);
            _animation->setWeight(w);
        }
    };


    class ActionAnimation : public Action
    {
    public:
        ActionAnimation(Animation* animation) : _animation(animation) 
        {
            setDuration(animation->getDuration()); 
            setName(animation->getName());
        }
        virtual void evaluate(unsigned int frame) 
        {
            Action::evaluate(frame);
            _animation->update(frame * 1.0/_fps); 
        }
        Animation* getAnimation() { return _animation.get(); }
    protected:
        osg::ref_ptr<Animation> _animation;
    };


    // encapsulate animation with blend in blend out for classic usage
    class StripAnimation : public Action
    {
    protected:
        typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;

    public:
        StripAnimation(Animation* animation, double blendInDuration, double 
blendOutDuration, double blendInWeightTarget = 1.0  )
        {
            _blendIn = new BlendIn(animation, blendInDuration, 
blendInWeightTarget);
            _animation = new ActionAnimation(animation);
            unsigned int start = static_cast<unsigned 
int>(floor((_animation->getDuration() - blendOutDuration) * _fps));
            _blendOut = FrameAction(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());
        }

        ActionAnimation* getActionAnimation() { return _animation.get(); }
        BlendIn* getBlendIn() { return _blendIn.get(); }
        BlendOut* getBlendOut() { return 
dynamic_cast<BlendOut*>(_blendOut.second.get()); }
        const ActionAnimation* getActionAnimation() const { return 
_animation.get(); }
        const BlendIn* getBlendIn() const { return _blendIn.get(); }
        const BlendOut* getBlendOut() const { return 
dynamic_cast<BlendOut*>(_blendOut.second.get()); }

        unsigned int getLoop() const { return _animation->getLoop(); }
        void 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 = FrameAction(start, _blendOut.second);
        }

        virtual void evaluate(unsigned int frame)
        {
            if (frame > getNumFrames() - 1)
                return;

            Action::evaluate(frame);
            if (frame < _blendIn->getNumFrames())
                _blendIn->evaluate(frame);
            if (frame >= _blendOut.first)
                _blendOut.second->evaluate(frame - _blendOut.first);
            _animation->evaluate(frame);
        }

    protected:
        osg::ref_ptr<BlendIn> _blendIn;
        FrameAction _blendOut;
        osg::ref_ptr<ActionAnimation> _animation;
    };


    class RunAction : public Action::Callback
    {
    protected:
        osg::ref_ptr<Timeline> _tm;
        osg::ref_ptr<Action> _action;
        
    public:
        RunAction(Timeline* tm, Action* a) : _tm(tm), _action(a) {}
        virtual void operator()(Action* /*action*/)
        {
            _tm->addActionAt(_tm->getCurrentFrame(), _action.get()); // warning 
we are trsversing the vector
        }
    };



}

#endif
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to