Hi Robert,

In principle I agree with you.

In that special case, I think it is OSG itself, which is breaking it's interface, as the renaming done in the trunk breaks compatibility with version 2.8.

Also I think one should differentiate between "yet another 3rd party library" and the X windowing system, which on Unix systems is more or less an essential part of the operating system.

Regards,

Paul

Robert Osfield wrote:
Hi Paul,

I don't feel this change is appropriate, one can't keep breaking OSG
interfaces each time a 3rd party C headers introduces a problem
define.  Rather end user code that includes both the offending X
headers should include osgAnimatiom headers first.

Robert.

On Sat, May 16, 2009 at 9:39 PM, p...@tcl3d <[email protected]> wrote:
Hello Robert,

I would recommend to rename the 2 enumerations called "Status" back to their
previous name "State".

I got strange compile errors when trying to compile my code (which ran fine
with 2.8) with the current head on Linux.
After some investigation I found out, that in several X header files, there
are statements like this:

#define Status int

which causes the preprocessor to change the enum definitions:
enum Status
{
   Play,
   Stop
};

to
enum int
{
   Play,
   Stop
};

I know, that's not the fault of OSG, but bad design in the X code.

Regards,

Paul Obermeier

/*  -*-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 OSGANIMATION_EXPORT Timeline : public osg::Object
   {
   public:

       META_Object(osgAnimation, Timeline);

       Timeline();
       Timeline(const Timeline& nc,const osg::CopyOp& op =
osg::CopyOp::SHALLOW_COPY);

       enum State
       {
           Play,
           Stop
       };

       State getStatus() const { return _state; }

       typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
       typedef std::vector<FrameAction> ActionList;
       typedef std::map<int, ActionList> ActionLayers;

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

   protected:


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

   };



   // 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


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


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

Reply via email to