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

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

Fixed osgWrappers for osgAnimation library

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 Status
156        {
157            Play,
158            Stop
159        };
160       
161        Status _state;
162    };
163
164
165    class Timeline : public osg::Object
166    {
167    public:
168
169        META_Object(osgAnimation, Timeline);
170
171        Timeline();
172        Timeline(const Timeline& nc,const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY);
173
174        enum Status
175        {
176            Play,
177            Stop
178        };
179
180        Status getStatus() const { return _state; }
181
182        typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
183        typedef std::vector<FrameAction> ActionList;
184        typedef std::map<int, ActionList> ActionLayers;
185
186        const ActionList& getActionLayer(int i)
187        {
188            return _actions[i];
189        }
190        unsigned int getCurrentFrame() const { return _currentFrame;}
191        double getCurrentTime() const { return _currentFrame * 1.0 / _fps;}
192
193        void play() { _state = Play; }
194        void gotoFrame(unsigned int frame) { _currentFrame = frame; }
195        void stop() { _state = Stop; }
196        bool getEvaluating() const { return _evaluating;}
197
198        bool isActive(Action* activeAction)
199        {
200            // update from high priority to low priority
201            for( ActionLayers::iterator iterAnim = _actions.begin(); iterAnim != _actions.end(); ++iterAnim )
202            {
203                // update all animation
204                ActionList& list = iterAnim->second;
205                for (unsigned int i = 0; i < list.size(); i++)
206                {
207                    Action* action = list[i].second.get();
208                    if (action == activeAction)
209                    {
210                        unsigned int firstFrame = list[i].first;
211                        // check if current frame of timeline hit an action interval
212                        if (_currentFrame >= firstFrame &&
213                            _currentFrame < (firstFrame + action->getNumFrames()) )
214                            return true;
215                    }
216                }
217            }
218            return false;
219        }
220
221        void removeAction(Action* action)
222        {
223            if (getEvaluating())
224                _removeActionOperations.push_back(FrameAction(0, action));
225            else
226                internalRemoveAction(action);
227        }
228
229        virtual void addActionAt(unsigned int frame, Action* action, int priority = 0)
230        {
231            if (getEvaluating())
232                _addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
233            else
234                internalAddAction(priority, FrameAction(frame, action));
235        }
236        virtual void addActionAt(double t, Action* action, int priority = 0)
237        {
238            unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
239            addActionAt(frame, action, priority);
240        }
241
242        virtual void evaluate(unsigned int frame)
243        {
244            setEvaluating(true);
245            osg::notify(osg::DEBUG_INFO) << getName() << " evaluate frame " << _currentFrame << std::endl;
246
247            // update from high priority to low priority
248            for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
249            {
250                // update all animation
251                ActionList& list = iterAnim->second;
252                for (unsigned int i = 0; i < list.size(); i++)
253                {
254                    unsigned int firstFrame = list[i].first;
255                    Action* action = list[i].second.get();
256                    // check if current frame of timeline hit an action interval
257                    if (frame >= firstFrame &&
258                        frame < (firstFrame + action->getNumFrames()) )
259                        action->evaluate(frame - firstFrame);
260                }
261            }
262            setEvaluating(false);
263
264            // evaluate callback after updating all animation
265            evaluateCallback(frame);
266            _previousFrameEvaluated = frame;
267        }
268
269        virtual void evaluateCallback(unsigned int frame)
270        {
271            // update from high priority to low priority
272            for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
273            {
274                // update all animation
275                ActionList& list = iterAnim->second;
276                for (unsigned int i = 0; i < list.size(); i++)
277                {
278                    unsigned int firstFrame = list[i].first;
279                    Action* action = list[i].second.get();
280                    // check if current frame of timeline hit an action interval
281                    if (frame >= firstFrame &&
282                        frame < (firstFrame + action->getNumFrames()) )
283                        action->evaluateCallback(frame - firstFrame);
284                }
285            }
286            processPendingOperation();
287        }
288
289        virtual void update(double simulationTime)
290        {
291            // first time we call update we generate one frame
292            if (!_initFirstFrame)
293            {
294                _lastUpdate = simulationTime;
295                _initFirstFrame = true;
296                evaluate(_currentFrame);
297            }
298
299            // find the number of frame pass since the last update
300            double delta = (simulationTime - _lastUpdate);
301            double nbframes = delta * _fps * _speed;
302            unsigned int nb = static_cast<unsigned int>(floor(nbframes));
303
304            for (unsigned int i = 0; i < nb; i++)
305            {
306                if (_state == Play)
307                    _currentFrame++;
308                evaluate(_currentFrame);
309            }
310            if (nb)
311            {
312                _lastUpdate += ((double)nb) / _fps;
313            }
314        }
315
316    protected:
317
318
319        ActionLayers _actions;
320        double _lastUpdate;
321        double _speed;
322        unsigned int _currentFrame;
323        unsigned int _fps;
324        unsigned int _numberFrame;
325        unsigned int _previousFrameEvaluated;
326        bool _loop;
327        bool _initFirstFrame;
328
329        Status _state;
330
331        // to manage pending operation
332        bool _evaluating;
333
334        struct Command
335        {
336            Command():_priority(0) {}
337            Command(int priority, const FrameAction& action) : _priority(priority), _action(action) {}
338            int _priority;
339            FrameAction _action;
340        };
341
342        typedef std::vector<Command> CommandList;
343        CommandList _addActionOperations;
344        ActionList _removeActionOperations;
345
346        void setEvaluating(bool state) { _evaluating = state;}
347        void processPendingOperation()
348        {
349            // process all pending add action operation
350            while( !_addActionOperations.empty())
351            {
352                internalAddAction(_addActionOperations.back()._priority, _addActionOperations.back()._action);
353                _addActionOperations.pop_back();
354            }
355
356            // process all pending remove action operation
357            while( !_removeActionOperations.empty())
358            {
359                internalRemoveAction(_removeActionOperations.back().second.get());
360                _removeActionOperations.pop_back();
361            }
362        }
363
364        void internalRemoveAction(Action* action)
365        {
366            for (ActionLayers::iterator it = _actions.begin(); it != _actions.end(); it++)
367            {
368                ActionList& fa = it->second;
369                for (unsigned int i = 0; i < fa.size(); i++)
370                    if (fa[i].second.get() == action)
371                    {
372                        fa.erase(fa.begin() + i);
373                        return;
374                    }
375            }
376        }
377        void internalAddAction(int priority, const FrameAction& ftl)
378        {
379            _actions[priority].push_back(ftl);
380        }
381       
382    };
383
384
385
386    // blend in from 0 to weight in duration
387    class BlendIn : public Action
388    {
389        double _weight;
390        osg::ref_ptr<Animation> _animation;
391
392    public:
393        BlendIn(Animation* animation, double duration, double weight)
394        {
395            _animation = animation;
396            _weight = weight;
397            float d = duration * _fps;
398            setNumFrames(static_cast<unsigned int>(floor(d)) + 1);
399            setName("BlendIn");
400        }
401        double getWeight() const { return _weight;}
402        virtual void evaluate(unsigned int frame)
403        {
404            Action::evaluate(frame);
405            // frame + 1 because the start is 0 and we want to start the blend in at the first
406            // frame.
407            double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
408            double w = _weight;
409            if (frame < getNumFrames() -1 ) // the last frame we set the target weight the user asked
410                w = _weight * ratio;
411            _animation->setWeight(w);
412        }
413    };
414
415    // blend in from 0 to weight in duration
416    class BlendOut : public Action
417    {
418        double _weight;
419        osg::ref_ptr<Animation> _animation;
420    public:
421        BlendOut(Animation* animation, double duration)
422        {
423            _animation = animation;
424            float d = duration * _fps;
425            setNumFrames(static_cast<unsigned int>(floor(d) + 1));
426            _weight = 1.0;
427            setName("BlendOut");
428        }
429        double getWeight() const { return _weight;}
430        virtual void evaluate(unsigned int frame)
431        {
432            Action::evaluate(frame);
433            // frame + 1 because the start is 0 and we want to start the blend in at the first
434            // frame.
435            double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
436            double w = 0.0;
437            if (frame < getNumFrames() -1 ) // the last frame we set the target weight the user asked
438                w = _weight * (1.0-ratio);
439            _animation->setWeight(w);
440        }
441    };
442
443
444    class ActionAnimation : public Action
445    {
446    public:
447        ActionAnimation(Animation* animation) : _animation(animation)
448        {
449            setDuration(animation->getDuration());
450            setName(animation->getName());
451        }
452        virtual void evaluate(unsigned int frame)
453        {
454            Action::evaluate(frame);
455            _animation->update(frame * 1.0/_fps);
456        }
457        Animation* getAnimation() { return _animation.get(); }
458    protected:
459        osg::ref_ptr<Animation> _animation;
460    };
461
462
463    // encapsulate animation with blend in blend out for classic usage
464    class StripAnimation : public Action
465    {
466    protected:
467        typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
468
469    public:
470        StripAnimation(Animation* animation, double blendInDuration, double blendOutDuration, double blendInWeightTarget = 1.0  )
471        {
472            _blendIn = new BlendIn(animation, blendInDuration, blendInWeightTarget);
473            _animation = new ActionAnimation(animation);
474            unsigned int start = static_cast<unsigned int>(floor((_animation->getDuration() - blendOutDuration) * _fps));
475            _blendOut = FrameAction(start, new BlendOut(animation, blendOutDuration));
476            setName(animation->getName() + "_Strip");
477            _blendIn->setName(_animation->getName() + "_" + _blendIn->getName());
478            _blendOut.second->setName(_animation->getName() + "_" + _blendOut.second->getName());
479            setDuration(animation->getDuration());
480        }
481
482        ActionAnimation* getActionAnimation() { return _animation.get(); }
483        BlendIn* getBlendIn() { return _blendIn.get(); }
484        BlendOut* getBlendOut() { return dynamic_cast<BlendOut*>(_blendOut.second.get()); }
485        const ActionAnimation* getActionAnimation() const { return _animation.get(); }
486        const BlendIn* getBlendIn() const { return _blendIn.get(); }
487        const BlendOut* getBlendOut() const { return dynamic_cast<BlendOut*>(_blendOut.second.get()); }
488
489        unsigned int getLoop() const { return _animation->getLoop(); }
490        void setLoop(unsigned int loop)
491        {
492            _animation->setLoop(loop);
493            if (!loop)
494                setDuration(-1);
495            else
496                setDuration(loop * _animation->getDuration());
497
498            // duration changed re evaluate the blendout duration
499            unsigned int start = static_cast<unsigned int>(floor((getDuration() - _blendOut.second->getDuration()) * _fps));
500            _blendOut = FrameAction(start, _blendOut.second);
501        }
502
503        virtual void evaluate(unsigned int frame)
504        {
505            if (frame > getNumFrames() - 1)
506                return;
507
508            Action::evaluate(frame);
509            if (frame < _blendIn->getNumFrames())
510                _blendIn->evaluate(frame);
511            if (frame >= _blendOut.first)
512                _blendOut.second->evaluate(frame - _blendOut.first);
513            _animation->evaluate(frame);
514        }
515
516    protected:
517        osg::ref_ptr<BlendIn> _blendIn;
518        FrameAction _blendOut;
519        osg::ref_ptr<ActionAnimation> _animation;
520    };
521
522
523    class RunAction : public Action::Callback
524    {
525    protected:
526        osg::ref_ptr<Timeline> _tm;
527        osg::ref_ptr<Action> _action;
528       
529    public:
530        RunAction(Timeline* tm, Action* a) : _tm(tm), _action(a) {}
531        virtual void operator()(Action* /*action*/)
532        {
533            _tm->addActionAt(_tm->getCurrentFrame(), _action.get()); // warning we are trsversing the vector
534        }
535    };
536
537
538
539}
540
541#endif
Note: See TracBrowser for help on using the browser.