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