1 /*  -*-c++-*-
2  *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@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 #include <osgAnimation/Timeline>
16 #include <osgAnimation/StatsVisitor>
17 #include <limits.h>
18 
19 using namespace osgAnimation;
20 
21 
Timeline()22 Timeline::Timeline()
23 {
24     _lastUpdate = 0;
25     _currentFrame = 0;
26     _fps = 25;
27     _speed = 1.0;
28     _state = Stop;
29     _initFirstFrame = false;
30     _previousFrameEvaluated = 0;
31     _evaluating = 0;
32     _numberFrame = UINT_MAX; // something like infinity
33     _collectStats = false;
34     _stats = new osg::Stats("Timeline");
35     setName("Timeline");
36 }
37 
Timeline(const Timeline & nc,const osg::CopyOp & op)38 Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op)
39     : Action(nc, op),
40       _actions(nc._actions)
41 {
42     _lastUpdate = 0;
43     _currentFrame = 0;
44     _fps = 25;
45     _speed = 1.0;
46     _state = Stop;
47     _initFirstFrame = false;
48     _previousFrameEvaluated = 0;
49     _evaluating = 0;
50     _numberFrame = UINT_MAX; // something like infinity
51     _collectStats = false;
52     _stats = new osg::Stats("Timeline");
53     setName("Timeline");
54 }
55 
setAnimationManager(AnimationManagerBase * manager)56 void Timeline::setAnimationManager(AnimationManagerBase* manager)
57 {
58     _animationManager = manager;
59 }
60 
traverse(ActionVisitor & visitor)61 void Timeline::traverse(ActionVisitor& visitor)
62 {
63     int layer = visitor.getCurrentLayer();
64     visitor.pushTimelineOnStack(this);
65     // update from high priority to low priority
66     for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
67     {
68         visitor.setCurrentLayer(iterAnim->first);
69         ActionList& list = iterAnim->second;
70         for (unsigned int i = 0; i < list.size(); i++)
71         {
72             visitor.pushFrameActionOnStack(list[i]);
73             if (list[i].second) list[i].second->accept(visitor);
74             visitor.popFrameAction();
75         }
76     }
77     visitor.popTimeline();
78     visitor.setCurrentLayer(layer);
79 }
80 
81 
setStats(osg::Stats * stats)82 void Timeline::setStats(osg::Stats* stats) { _stats = stats;}
getStats()83 osg::Stats* Timeline::getStats() { return _stats.get();}
collectStats(bool state)84 void Timeline::collectStats(bool state) { _collectStats = state;}
getStatsVisitor()85 StatsActionVisitor* Timeline::getStatsVisitor() { return _statsVisitor.get(); }
86 
clearActions()87 void Timeline::clearActions()
88 {
89     _actions.clear();
90     _addActionOperations.clear();
91     _removeActionOperations.clear();
92 }
93 
update(double simulationTime)94 void Timeline::update(double simulationTime)
95 {
96     // first time we call update we generate one frame
97     UpdateActionVisitor updateTimeline;
98     if (!_initFirstFrame)
99     {
100         _lastUpdate = simulationTime;
101         _initFirstFrame = true;
102 
103 
104         _animationManager->clearTargets();
105         updateTimeline.setFrame(_currentFrame);
106         accept(updateTimeline);
107 
108         if (_collectStats)
109         {
110             if (!_statsVisitor)
111                 _statsVisitor = new StatsActionVisitor();
112             _statsVisitor->setStats(_stats.get());
113             _statsVisitor->setFrame(_currentFrame);
114             _statsVisitor->reset();
115             accept(*_statsVisitor);
116         }
117 
118         processPendingOperation();
119     }
120 
121     // find the number of frame pass since the last update
122     double delta = (simulationTime - _lastUpdate);
123     double nbframes = delta * _fps * _speed;
124     unsigned int nb = static_cast<unsigned int>(floor(nbframes));
125 
126     for (unsigned int i = 0; i < nb; i++)
127     {
128         if (_state == Play)
129             _currentFrame++;
130 
131         _animationManager->clearTargets();
132         updateTimeline.setFrame(_currentFrame);
133         accept(updateTimeline);
134         if (_collectStats)
135         {
136             if (!_statsVisitor)
137                 _statsVisitor = new StatsActionVisitor;
138             _statsVisitor->setStats(_stats.get());
139             _statsVisitor->setFrame(_currentFrame);
140             _statsVisitor->reset();
141             accept(*_statsVisitor);
142         }
143 
144         processPendingOperation();
145     }
146     if (nb)
147     {
148         _lastUpdate += ((double)nb) / _fps;
149     }
150 }
151 
removeAction(Action * action)152 void Timeline::removeAction(Action* action)
153 {
154     if (getEvaluating())
155         _removeActionOperations.push_back(FrameAction(0, action));
156     else
157         internalRemoveAction(action);
158 }
159 
addActionAt(unsigned int frame,Action * action,int priority)160 void Timeline::addActionAt(unsigned int frame, Action* action, int priority)
161 {
162     // skip if this action has already been added this frame
163     for (CommandList::iterator it = _addActionOperations.begin(); it != _addActionOperations.end(); ++it)
164     {
165         Command& command = *it;
166         if (command._action.second.get() == action) {
167             OSG_INFO << "Timeline::addActionAt command " << action->getName() << " already added this frame, declined" << std::endl;
168             return;
169         }
170     }
171 
172     if (isActive(action))
173     {
174         OSG_INFO << "Timeline::addActionAt command " << action->getName() << " already active, remove the old" << std::endl;
175         removeAction(action);
176     }
177 
178     if (getEvaluating())
179         _addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
180     else
181         internalAddAction(priority, FrameAction(frame, action));
182 }
addActionAt(double t,Action * action,int priority)183 void Timeline::addActionAt(double t, Action* action, int priority)
184 {
185     unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
186     addActionAt(frame, action, priority);
187 }
188 
addActionNow(Action * action,int priority)189 void Timeline::addActionNow(Action* action, int priority)
190 {
191     addActionAt(getCurrentFrame()+1, action, priority);
192 }
193 
processPendingOperation()194 void Timeline::processPendingOperation()
195 {
196     // process all pending add action operation
197     while( !_addActionOperations.empty())
198     {
199         internalAddAction(_addActionOperations.back()._priority, _addActionOperations.back()._action);
200         _addActionOperations.pop_back();
201     }
202 
203     // process all pending remove action operation
204     while( !_removeActionOperations.empty())
205     {
206         internalRemoveAction(_removeActionOperations.back().second.get());
207         _removeActionOperations.pop_back();
208     }
209 }
210 
internalRemoveAction(Action * action)211 void Timeline::internalRemoveAction(Action* action)
212 {
213     for (ActionLayers::iterator it = _actions.begin(); it != _actions.end(); ++it)
214     {
215         ActionList& fa = it->second;
216         for (unsigned int i = 0; i < fa.size(); i++)
217             if (fa[i].second.get() == action)
218             {
219                 fa.erase(fa.begin() + i);
220                 return;
221             }
222     }
223 }
224 
internalAddAction(int priority,const FrameAction & ftl)225 void Timeline::internalAddAction(int priority, const FrameAction& ftl)
226 {
227     _actions[priority].insert(_actions[priority].begin(), ftl);
228 }
229 
isActive(Action * activeAction)230 bool Timeline::isActive(Action* activeAction)
231 {
232     // update from high priority to low priority
233     for( ActionLayers::iterator iterAnim = _actions.begin(); iterAnim != _actions.end(); ++iterAnim )
234     {
235         // update all animation
236         ActionList& list = iterAnim->second;
237         for (unsigned int i = 0; i < list.size(); i++)
238         {
239             Action* action = list[i].second.get();
240             if (action == activeAction)
241             {
242                 unsigned int firstFrame = list[i].first;
243                 // check if current frame of timeline hit an action interval
244                 if (_currentFrame >= firstFrame &&
245                     _currentFrame < (firstFrame + action->getNumFrames()) )
246                     return true;
247             }
248         }
249     }
250     return false;
251 }
252