root/OpenSceneGraph/trunk/include/osgAnimation/Timeline @ 9737

Revision 9737, 18.1 kB (checked in by robert, 6 years ago)

From Fabien Lavignotte, "Here is some various small fixes i have done while playing with
osgAnimation.

  • Animation : removed the _name attribute that is never used.
  • BasicAnimationManager? : fix a crash on Windows with the example

osganimationviewer. The _lastUpdate attribute was not initialized when
using copy constructor.

Line 
1/*  -*-c++-*-
2 *  Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
3 *
4 * This library is open source and may be redistributed and/or modified under 
5 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
6 * (at your option) any later version.  The full license is in LICENSE file
7 * included with this distribution, and on the openscenegraph.org website.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * OpenSceneGraph Public License for more details.
13*/
14
15#ifndef OSGANIMATION_TIMELINE_H
16#define OSGANIMATION_TIMELINE_H
17
18#include <osgAnimation/Export>
19#include <osg/Object>
20#include <map>
21#include <vector>
22#include <osg/Notify>
23#include <osg/Group>
24#include <osgAnimation/Animation>
25#include <osgAnimation/AnimationManagerBase>
26
27namespace osgAnimation
28{
29
30    class Action : public osg::Object
31    {
32    public:
33
34        class Callback : public osg::Object
35        {
36        public:
37            Callback(){}
38            Callback(const Callback&,const osg::CopyOp&) {}
39
40            META_Object(osgAnimation,Callback);
41       
42            virtual void operator()(Action* /*action*/) {}
43           
44            void addNestedCallback(Callback* callback)
45            {
46                if (_nested.valid())
47                    _nested->addNestedCallback(callback);
48                else
49                    _nested = callback;
50            }
51
52        protected:
53            osg::ref_ptr<Callback> _nested;
54        };
55
56
57        typedef std::map<unsigned int, osg::ref_ptr<Callback> > FrameCallback;
58
59        META_Object(osgAnimation, Action);
60       
61        Action()
62        {
63            _numberFrame = 25;
64            _fps = 25;
65            _speed = 1.0;
66            _loop = 1;
67        }
68
69        Action(const Action&,const osg::CopyOp&) {}
70
71        void setCallback(double when, Callback* callback)
72        {
73            setCallback(static_cast<unsigned int>(floor(when*_fps)), callback);
74        }
75
76        void setCallback(unsigned int frame, Callback* callback)
77        {
78            if (_framesCallback[frame].valid())
79                _framesCallback[frame]->addNestedCallback(callback);
80            else
81                _framesCallback[frame] = callback;
82        }
83        Callback* getCallback(unsigned int frame)
84        {
85            if (_framesCallback.find(frame) == _framesCallback.end())
86                return 0;
87            return _framesCallback[frame].get();
88        }
89
90        void setNumFrames(unsigned int numFrames) { _numberFrame = numFrames;}
91        void setDuration(double duration) { _numberFrame = static_cast<unsigned int>(floor(duration * _fps)); }
92
93        unsigned int getNumFrames() const { return _numberFrame;}
94        double getDuration() const { return _numberFrame * 1.0 / _fps; }
95
96        // 0 means infini else it's the number of loop
97        virtual void setLoop(int nb) { _loop = nb; }
98        virtual unsigned int getLoop() const { return _loop;}
99
100        // get the number of loop, the frame relative to loop.
101        // return true if in range, and false if out of range.
102        bool evaluateFrame(unsigned int frame, unsigned int& resultframe, unsigned int& nbloop )
103        {
104            nbloop = frame / getNumFrames();
105            resultframe = frame;
106
107            if (frame > getNumFrames()-1)
108            {
109                if (!getLoop())
110                    resultframe = frame % getNumFrames();
111                else
112                {
113                    if (nbloop >= getLoop())
114                        return false;
115                    else
116                        resultframe = frame % getNumFrames();
117                }
118            }
119            return true;
120        }
121
122        virtual void evaluate(unsigned int frame)
123        {
124            unsigned int frameInAction;
125            unsigned int loopDone;
126            if (!evaluateFrame(frame, frameInAction, loopDone))
127                osg::notify(osg::DEBUG_INFO) << getName() << " Action frame " << frameInAction  << " finished" << std::endl;
128            else
129                osg::notify(osg::DEBUG_INFO) << getName() << " Action frame " << frame  << " relative to loop " << frameInAction  << " no loop " << loopDone<< std::endl;
130        }
131
132        virtual void evaluateCallback(unsigned int frame)
133        {
134            unsigned int frameInAction;
135            unsigned int loopDone;
136            if (!evaluateFrame(frame, frameInAction, loopDone))
137                return;
138
139            frame = frameInAction;
140            if (_framesCallback.find(frame) != _framesCallback.end())
141            {
142                std::cout << getName() << " evaluate callback " << _framesCallback[frame]->getName() << " at " << frame << std::endl;
143                (*_framesCallback[frame])(this);
144            }
145        }
146
147    protected:
148        FrameCallback _framesCallback;
149
150        double _speed;
151        unsigned int _fps;
152        unsigned int _numberFrame;
153        unsigned int _loop;
154
155        enum State
156        {
157            Play,
158            Stop
159        };
160       
161        State _state;
162    };
163
164
165    class Timeline : public osg::Object
166    {
167    protected:
168        typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
169        typedef std::vector<FrameAction> ActionList;
170        typedef std::map<int, ActionList> ActionLayers;
171        enum State
172        {
173            Play,
174            Stop
175        };
176       
177
178        ActionLayers _actions;
179        double _lastUpdate;
180        double _speed;
181        unsigned int _currentFrame;
182        unsigned int _fps;
183        unsigned int _numberFrame;
184        unsigned int _previousFrameEvaluated;
185        bool _loop;
186        bool _initFirstFrame;
187
188        State _state;
189
190        // to manage pending operation
191        bool _evaluating;
192
193        struct Command
194        {
195            Command():_priority(0) {}
196            Command(int priority, const FrameAction& action) : _priority(priority), _action(action) {}
197            int _priority;
198            FrameAction _action;
199        };
200
201        typedef std::vector<Command> CommandList;
202        CommandList _addActionOperations;
203        ActionList _removeActionOperations;
204
205        void setEvaluating(bool state) { _evaluating = state;}
206        void processPendingOperation()
207        {
208            // process all pending add action operation
209            while( !_addActionOperations.empty())
210            {
211                internalAddAction(_addActionOperations.back()._priority, _addActionOperations.back()._action);
212                _addActionOperations.pop_back();
213            }
214
215            // process all pending remove action operation
216            while( !_removeActionOperations.empty())
217            {
218                internalRemoveAction(_removeActionOperations.back().second.get());
219                _removeActionOperations.pop_back();
220            }
221        }
222
223        void internalRemoveAction(Action* action)
224        {
225            for (ActionLayers::iterator it = _actions.begin(); it != _actions.end(); it++)
226            {
227                ActionList& fa = it->second;
228                for (unsigned int i = 0; i < fa.size(); i++)
229                    if (fa[i].second.get() == action)
230                    {
231                        fa.erase(fa.begin() + i);
232                        return;
233                    }
234            }
235        }
236        void internalAddAction(int priority, const FrameAction& ftl)
237        {
238            _actions[priority].push_back(ftl);
239        }
240       
241    public:
242
243        META_Object(osgAnimation, Timeline);
244
245        Timeline();
246        Timeline(const Timeline& nc,const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY);
247        State getStatus() const { return _state; }
248        const ActionList& getActionLayer(int i)
249        {
250            return _actions[i];
251        }
252        unsigned int getCurrentFrame() const { return _currentFrame;}
253        double getCurrentTime() const { return _currentFrame * 1.0 / _fps;}
254
255        void play() { _state = Play; }
256        void gotoFrame(unsigned int frame) { _currentFrame = frame; }
257        void stop() { _state = Stop; }
258        bool getEvaluating() const { return _evaluating;}
259
260        bool isActive(Action* activeAction)
261        {
262            // update from high priority to low priority
263            for( ActionLayers::iterator iterAnim = _actions.begin(); iterAnim != _actions.end(); ++iterAnim )
264            {
265                // update all animation
266                ActionList& list = iterAnim->second;
267                for (unsigned int i = 0; i < list.size(); i++)
268                {
269                    Action* action = list[i].second.get();
270                    if (action == activeAction)
271                    {
272                        unsigned int firstFrame = list[i].first;
273                        // check if current frame of timeline hit an action interval
274                        if (_currentFrame >= firstFrame &&
275                            _currentFrame < (firstFrame + action->getNumFrames()) )
276                            return true;
277                    }
278                }
279            }
280            return false;
281        }
282
283        void removeAction(Action* action)
284        {
285            if (getEvaluating())
286                _removeActionOperations.push_back(FrameAction(0, action));
287            else
288                internalRemoveAction(action);
289        }
290
291        virtual void addActionAt(unsigned int frame, Action* action, int priority = 0)
292        {
293            if (getEvaluating())
294                _addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
295            else
296                internalAddAction(priority, FrameAction(frame, action));
297        }
298        virtual void addActionAt(double t, Action* action, int priority = 0)
299        {
300            unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
301            addActionAt(frame, action, priority);
302        }
303
304        virtual void evaluate(unsigned int frame)
305        {
306            setEvaluating(true);
307            osg::notify(osg::DEBUG_INFO) << getName() << " evaluate frame " << _currentFrame << std::endl;
308
309            // update from high priority to low priority
310            for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
311            {
312                // update all animation
313                ActionList& list = iterAnim->second;
314                for (unsigned int i = 0; i < list.size(); i++)
315                {
316                    unsigned int firstFrame = list[i].first;
317                    Action* action = list[i].second.get();
318                    // check if current frame of timeline hit an action interval
319                    if (frame >= firstFrame &&
320                        frame < (firstFrame + action->getNumFrames()) )
321                        action->evaluate(frame - firstFrame);
322                }
323            }
324            setEvaluating(false);
325
326            // evaluate callback after updating all animation
327            evaluateCallback(frame);
328            _previousFrameEvaluated = frame;
329        }
330
331        virtual void evaluateCallback(unsigned int frame)
332        {
333            // update from high priority to low priority
334            for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
335            {
336                // update all animation
337                ActionList& list = iterAnim->second;
338                for (unsigned int i = 0; i < list.size(); i++)
339                {
340                    unsigned int firstFrame = list[i].first;
341                    Action* action = list[i].second.get();
342                    // check if current frame of timeline hit an action interval
343                    if (frame >= firstFrame &&
344                        frame < (firstFrame + action->getNumFrames()) )
345                        action->evaluateCallback(frame - firstFrame);
346                }
347            }
348            processPendingOperation();
349        }
350
351        virtual void update(double simulationTime)
352        {
353            // first time we call update we generate one frame
354            if (!_initFirstFrame)
355            {
356                _lastUpdate = simulationTime;
357                _initFirstFrame = true;
358                evaluate(_currentFrame);
359            }
360
361            // find the number of frame pass since the last update
362            double delta = (simulationTime - _lastUpdate);
363            double nbframes = delta * _fps * _speed;
364            unsigned int nb = static_cast<unsigned int>(floor(nbframes));
365
366            for (unsigned int i = 0; i < nb; i++)
367            {
368                if (_state == Play)
369                    _currentFrame++;
370                evaluate(_currentFrame);
371            }
372            if (nb)
373            {
374                _lastUpdate += ((double)nb) / _fps;
375            }
376        }
377    };
378
379
380
381    // blend in from 0 to weight in duration
382    class BlendIn : public Action
383    {
384        double _weight;
385        osg::ref_ptr<Animation> _animation;
386
387    public:
388        BlendIn(Animation* animation, double duration, double weight)
389        {
390            _animation = animation;
391            _weight = weight;
392            float d = duration * _fps;
393            setNumFrames(static_cast<unsigned int>(floor(d)) + 1);
394            setName("BlendIn");
395        }
396        double getWeight() const { return _weight;}
397        virtual void evaluate(unsigned int frame)
398        {
399            Action::evaluate(frame);
400            // frame + 1 because the start is 0 and we want to start the blend in at the first
401            // frame.
402            double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
403            double w = _weight;
404            if (frame < getNumFrames() -1 ) // the last frame we set the target weight the user asked
405                w = _weight * ratio;
406            _animation->setWeight(w);
407        }
408    };
409
410    // blend in from 0 to weight in duration
411    class BlendOut : public Action
412    {
413        double _weight;
414        osg::ref_ptr<Animation> _animation;
415    public:
416        BlendOut(Animation* animation, double duration)
417        {
418            _animation = animation;
419            float d = duration * _fps;
420            setNumFrames(static_cast<unsigned int>(floor(d) + 1));
421            _weight = 1.0;
422            setName("BlendOut");
423        }
424        double getWeight() const { return _weight;}
425        virtual void evaluate(unsigned int frame)
426        {
427            Action::evaluate(frame);
428            // frame + 1 because the start is 0 and we want to start the blend in at the first
429            // frame.
430            double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
431            double w = 0.0;
432            if (frame < getNumFrames() -1 ) // the last frame we set the target weight the user asked
433                w = _weight * (1.0-ratio);
434            _animation->setWeight(w);
435        }
436    };
437
438
439    class ActionAnimation : public Action
440    {
441    public:
442        ActionAnimation(Animation* animation) : _animation(animation)
443        {
444            setDuration(animation->getDuration());
445            setName(animation->getName());
446        }
447        virtual void evaluate(unsigned int frame)
448        {
449            Action::evaluate(frame);
450            _animation->update(frame * 1.0/_fps);
451        }
452        Animation* getAnimation() { return _animation.get(); }
453    protected:
454        osg::ref_ptr<Animation> _animation;
455    };
456
457
458    // encapsulate animation with blend in blend out for classic usage
459    class StripAnimation : public Action
460    {
461    protected:
462        typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
463
464    public:
465        StripAnimation(Animation* animation, double blendInDuration, double blendOutDuration, double blendInWeightTarget = 1.0  )
466        {
467            _blendIn = new BlendIn(animation, blendInDuration, blendInWeightTarget);
468            _animation = new ActionAnimation(animation);
469            unsigned int start = static_cast<unsigned int>(floor((_animation->getDuration() - blendOutDuration) * _fps));
470            _blendOut = FrameAction(start, new BlendOut(animation, blendOutDuration));
471            setName(animation->getName() + "_Strip");
472            _blendIn->setName(_animation->getName() + "_" + _blendIn->getName());
473            _blendOut.second->setName(_animation->getName() + "_" + _blendOut.second->getName());
474            setDuration(animation->getDuration());
475        }
476
477        ActionAnimation* getActionAnimation() { return _animation.get(); }
478        BlendIn* getBlendIn() { return _blendIn.get(); }
479        BlendOut* getBlendOut() { return dynamic_cast<BlendOut*>(_blendOut.second.get()); }
480        const ActionAnimation* getActionAnimation() const { return _animation.get(); }
481        const BlendIn* getBlendIn() const { return _blendIn.get(); }
482        const BlendOut* getBlendOut() const { return dynamic_cast<BlendOut*>(_blendOut.second.get()); }
483
484        unsigned int getLoop() const { return _animation->getLoop(); }
485        void setLoop(unsigned int loop)
486        {
487            _animation->setLoop(loop);
488            if (!loop)
489                setDuration(-1);
490            else
491                setDuration(loop * _animation->getDuration());
492
493            // duration changed re evaluate the blendout duration
494            unsigned int start = static_cast<unsigned int>(floor((getDuration() - _blendOut.second->getDuration()) * _fps));
495            _blendOut = FrameAction(start, _blendOut.second);
496        }
497
498        virtual void evaluate(unsigned int frame)
499        {
500            if (frame > getNumFrames() - 1)
501                return;
502
503            Action::evaluate(frame);
504            if (frame < _blendIn->getNumFrames())
505                _blendIn->evaluate(frame);
506            if (frame >= _blendOut.first)
507                _blendOut.second->evaluate(frame - _blendOut.first);
508            _animation->evaluate(frame);
509        }
510
511    protected:
512        osg::ref_ptr<BlendIn> _blendIn;
513        FrameAction _blendOut;
514        osg::ref_ptr<ActionAnimation> _animation;
515    };
516
517
518    class RunAction : public Action::Callback
519    {
520    protected:
521        osg::ref_ptr<Timeline> _tm;
522        osg::ref_ptr<Action> _action;
523       
524    public:
525        RunAction(Timeline* tm, Action* a) : _tm(tm), _action(a) {}
526        virtual void operator()(Action* /*action*/)
527        {
528            _tm->addActionAt(_tm->getCurrentFrame(), _action.get()); // warning we are trsversing the vector
529        }
530    };
531
532
533
534}
535
536#endif
Note: See TracBrowser for help on using the browser.