1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12  */
13 
14 #include <osg/Sequence>
15 #include <osg/Notify>
16 
17 using namespace osg;
18 
19 /**
20  * Sequence constructor.
21  */
Sequence()22 Sequence::Sequence() :
23     Group(),
24     _value(-1),
25     _now(0.0),
26     _start(-1.0),
27     _totalTime(0.),
28     _resetTotalTime(true),
29     _loopMode(LOOP),
30     _begin(0),
31     _end(-1),
32     _speed(0),
33     _nreps(-1),
34     _nrepsRemain(-1),
35     _step(0),
36     _defaultTime(1.),
37     _lastFrameTime(0.),
38     _saveRealLastFrameTime(-1.),
39     _saveRealLastFrameValue(0),
40     _mode(STOP),
41     _sync(false),
42     _clearOnStop(false)
43 
44 {
45     setNumChildrenRequiringUpdateTraversal(1);
46 }
47 
Sequence(const Sequence & seq,const CopyOp & copyop)48 Sequence::Sequence(const Sequence& seq, const CopyOp& copyop) :
49     Group(seq, copyop),
50     _value(seq._value),
51     _now(seq._now),
52     _start(seq._start),
53     _frameTime(seq._frameTime),
54     _totalTime(seq._totalTime),
55     _resetTotalTime(seq._resetTotalTime),
56     _loopMode(seq._loopMode),
57     _begin(seq._begin),
58     _end(seq._end),
59     _speed(seq._speed),
60     _nreps(seq._nreps),
61     _nrepsRemain(seq._nrepsRemain),
62     _step(seq._step),
63     _defaultTime(seq._defaultTime),
64     _lastFrameTime(seq._lastFrameTime),
65     _saveRealLastFrameTime(seq._saveRealLastFrameTime),
66     _saveRealLastFrameValue(seq._saveRealLastFrameValue),
67     _mode(seq._mode),
68     _sync(seq._sync),
69     _clearOnStop(seq._clearOnStop)
70 {
71     setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1);
72 }
73 
addChild(Node * child)74 bool Sequence::addChild( Node *child)
75 {
76     return Sequence::insertChild( _children.size(), child, _defaultTime);
77 }
78 
addChild(Node * child,double t)79 bool Sequence::addChild( Node *child, double t)
80 {
81     return Sequence::insertChild( _children.size(), child, t);
82 }
83 
insertChild(unsigned int index,Node * child)84 bool Sequence::insertChild( unsigned int index, Node *child)
85 {
86     return Sequence::insertChild(index, child, _defaultTime);
87 }
88 
insertChild(unsigned int index,Node * child,double t)89 bool Sequence::insertChild( unsigned int index, Node *child, double t)
90 {
91     if (Group::insertChild(index,child))
92     {
93         if (index>=_frameTime.size())
94         {
95             Sequence::setTime(index, t);
96         }
97         _resetTotalTime = true;
98         return true;
99     }
100     return false;
101 }
102 
removeChild(Node * child)103 bool Sequence::removeChild( Node *child )
104 {
105     if (Group::removeChild(child ))
106     {
107         unsigned int pos = getChildIndex(child);
108         if (pos < _children.size())
109             return Sequence::removeChildren(pos,1);
110         else
111             return false;
112     }
113     else
114         return false;
115 }
116 
removeChildren(unsigned int pos,unsigned int numChildrenToRemove)117 bool Sequence::removeChildren(unsigned int pos,unsigned int numChildrenToRemove)
118 {
119     if (pos<_frameTime.size())
120         _frameTime.erase(_frameTime.begin()+pos,
121                          osg::minimum(_frameTime.begin()+(pos+numChildrenToRemove),
122                                       _frameTime.end()) );
123     _resetTotalTime = true;
124     return Group::removeChildren(pos,numChildrenToRemove);
125 }
126 
127 
128 // if frame >= _frameTime.size() then extend _frameTime to have frame-1 items
129 // a time <0 will get set to 0
setTime(unsigned int frame,double t)130 void Sequence::setTime(unsigned int frame, double t)
131 {
132     if (t<0.) t = 0.0;
133     unsigned int sz = _frameTime.size();
134     if (frame < sz)
135     {
136         _frameTime[frame] = t;
137     }
138     else
139     {
140         for (unsigned int i = sz; i <= frame; i++)
141         {
142             _frameTime.push_back(t);
143         }
144     }
145 
146 }
147 
148 // returns a frame time of -1 if frame is out of range
getTime(unsigned int frame) const149 double Sequence::getTime(unsigned int frame) const
150 {
151     if (frame < _frameTime.size())
152         return _frameTime[frame];
153     else
154         return -1.0f;
155 }
156 
setInterval(LoopMode mode,int begin,int end)157 void Sequence::setInterval(LoopMode mode, int begin, int end)
158 {
159     _loopMode = mode;
160     _end = end;
161     _begin = begin;
162 
163     // _value based on _begin & _end
164     _value = -1;
165 
166     _resetTotalTime = true;
167 
168 }
169 
setDuration(float speed,int nreps)170 void Sequence::setDuration(float speed, int nreps)
171 {
172     _speed = speed;
173     // -1 means loop forever
174     _nreps = (nreps < 0 ? -1:nreps);
175     // countdown of laps around the track
176     _nrepsRemain = _nreps;
177 }
178 
setMode(SequenceMode mode)179 void Sequence::setMode(SequenceMode mode)
180 {
181     int ubegin, uend;
182 
183     switch (mode)
184     {
185     case START:
186         // restarts sequence from beginning
187         _value = -1;
188 
189         // Figure out which direction to start stepping the sequence
190         ubegin = (_begin < 0 ?  (int)_frameTime.size()-1: _begin);
191         uend = (_end < 0 ? (int)_frameTime.size()-1: _end);
192         _step = (ubegin > uend ? -1 : 1);
193 
194         _start = -1.0;
195         _mode = mode;
196         if (_saveRealLastFrameTime>=0.)
197         {
198             _frameTime[_saveRealLastFrameValue] = _saveRealLastFrameTime;
199             _saveRealLastFrameTime = -1.;
200         }
201         break;
202     case STOP:
203         _mode = mode;
204         break;
205     case PAUSE:
206         if (_mode == START)
207             _mode = PAUSE;
208         break;
209     case RESUME:
210         if (_mode == PAUSE)
211             _mode = START;
212         break;
213     }
214 }
215 
traverse(NodeVisitor & nv)216 void Sequence::traverse(NodeVisitor& nv)
217 {
218     if (getNumChildren()==0) return;
219 
220     const FrameStamp* framestamp = nv.getFrameStamp();
221     if (framestamp)
222     {
223         _now = framestamp->getSimulationTime();
224     }
225 
226 
227     if (nv.getVisitorType()==NodeVisitor::UPDATE_VISITOR &&
228         _mode == START &&
229         !_frameTime.empty() && getNumChildren()!=0)
230     {
231 
232         // if begin or end < 0, make it last frame
233         int _ubegin = (_begin < 0 ?  (int)_frameTime.size()-1: _begin);
234         int _uend = (_end < 0 ? (int)_frameTime.size()-1: _end);
235 
236         int _sbegin = osg::minimum(_ubegin,_uend);
237         int _send = osg::maximum(_ubegin,_uend);
238 
239         if (framestamp)
240         {
241             // hack for last frame time
242             if (_lastFrameTime>0. && _nrepsRemain==1 && _saveRealLastFrameTime<0.)
243             {
244                 if ( _loopMode == LOOP)
245                 {
246                     if ((_step>0 && _value!=_send) || (_step<0 && _value!=_sbegin))
247                     {
248                         _saveRealLastFrameTime=_frameTime[_uend];
249                         _saveRealLastFrameValue = _uend;
250                         _frameTime[_uend] = _lastFrameTime;
251                         _resetTotalTime = true;
252                     }
253                 }
254                 else
255                 {
256                     if (_step>0 && _value!=_sbegin)
257                     {
258                         _saveRealLastFrameTime=_frameTime[_send];
259                         _saveRealLastFrameValue = _send;
260                         _frameTime[_send] = _lastFrameTime;
261                         _resetTotalTime = true;
262                     }
263                     else if (_step<0 && _value!=_send)
264                     {
265                         _saveRealLastFrameTime=_frameTime[_sbegin];
266                         _saveRealLastFrameValue = _sbegin;
267                         _frameTime[_sbegin] = _lastFrameTime;
268                         _resetTotalTime = true;
269                     }
270                 }
271             }
272 
273             // I never know when to stop!
274             // more fun for last frame time
275             if (_nrepsRemain==0)
276             {
277                 if (!_clearOnStop)
278                 {
279                     _mode = STOP;
280                 }
281                 else
282                 {
283                     if ( (_loopMode == LOOP) &&
284                          ( (_step>0 && _value!=_send) ||
285                            (_step<0 && _value!=_sbegin)))
286                     {
287                         _mode = STOP;
288                     }
289                     else if ( (_loopMode == SWING) &&
290                               ( (_step<0 && _value!=_send) ||
291                                 (_step>0 && _value!=_sbegin)))
292                     {
293                         _mode = STOP;
294                     }
295 
296                 }
297             }
298 
299             // update local variables
300             _update();
301 
302 
303             // now for the heavy lifting! three options
304             // 1) still in the same frame, so have nothing to do
305             // 2) just in the next frame
306             // 3) need to calculate everything based on elapsed time
307             if ((_now - _start) > _frameTime[_value]*osg::absolute(_speed))
308             { // case 2 or case 3
309                 // most of the time it's just the next frame in the sequence
310                 int nextValue = _getNextValue();
311                 if (!_sync ||
312                     ((_now - _start) <= (_frameTime[_value]+_frameTime[nextValue])*osg::absolute(_speed)) )
313                 {
314                     _start += _frameTime[_value]*osg::absolute(_speed);
315                     // repeat or change directions?
316                     if ( (_step>0 && nextValue==_send) ||
317                          (_step<0 && nextValue==_sbegin))
318                     {
319                         if (_nreps>0)
320                             _nrepsRemain--;
321 
322                         // change direction
323                         if  (_loopMode == SWING)
324                             _step = -_step;
325 
326                     }
327                     _value = nextValue;
328                 }
329                 else // case 3
330         {
331             // recalculate everything based on elapsed time
332 
333             // elapsed time from start of the frame
334             double deltaT = _now - _start;
335 
336             // factors _speed into account
337             double adjTotalTime = _totalTime*osg::absolute(_speed);
338 
339             // how many laps?
340             int loops = (int)(deltaT/adjTotalTime);
341 
342 
343             // adjust reps & quick check to see if done because reps used up
344 
345             if (_nreps>0)
346             {
347             if (_loopMode == LOOP)
348                 _nrepsRemain -= loops;
349             else
350                 _nrepsRemain -= 2*loops;
351 
352             if (_nrepsRemain<=0)
353             {
354                 _nrepsRemain = 0;
355                 _mode = STOP;
356                 OSG_WARN << "stopping because elapsed time greater or equal to time remaining to repeat the sequence\n";
357             }
358             }
359 
360             // deduct off time for laps- _value shouldn't change as it's modulo the total time
361             double jumpStart = ((double)loops * adjTotalTime);
362 
363             // step through frames one at a time until caught up
364             while (deltaT-jumpStart > _frameTime[_value]*osg::absolute(_speed))
365             {
366             jumpStart +=  _frameTime[_value]*osg::absolute(_speed );
367             _value = _getNextValue();
368             }
369 
370             // set start time
371             _start += jumpStart;
372         }
373             }
374         }
375         else
376             OSG_WARN << "osg::Sequence::traverse(NodeVisitor&) requires a valid FrameStamp to function, sequence not updated.\n";
377 
378     }
379 
380     // now do the traversal
381     if (nv.getTraversalMode()==NodeVisitor::TRAVERSE_ACTIVE_CHILDREN)
382     {
383         if ( !((_mode == STOP) && _clearOnStop) &&
384              (getValue()>=0 && getValue()<(int)_children.size()) )
385         {
386             _children[getValue()]->accept(nv);
387         }
388     }
389     else
390     {
391         Group::traverse(nv);
392     }
393 
394 }
395 
_getNextValue()396 int Sequence::_getNextValue()
397 {
398     if (_frameTime.empty() || getNumChildren()==0) return 0;
399 
400     // if begin or end < 0, make it last frame
401     int _ubegin = (_begin < 0 ?  (int)_frameTime.size()-1: _begin);
402     int _uend = (_end < 0 ? (int)_frameTime.size()-1: _end);
403 
404     int _sbegin = osg::minimum(_ubegin,_uend);
405     int _send = osg::maximum(_ubegin,_uend);
406 
407     int v = _value + _step * static_cast<int>(osg::sign(_speed));
408 
409     if (_sbegin==_send)
410     {
411         return _sbegin;
412     }
413     else if (v<=_send && v>=_sbegin)
414     {
415         return v;
416     }
417     else
418     {
419         int vs = _send - _sbegin + 1;
420         if (_loopMode == LOOP)
421         {
422             v = ((v-_sbegin)%vs) + _sbegin;
423             if (v<_sbegin)
424             {
425                 v+=vs;
426             }
427 
428             return v;
429         }
430         else // SWING
431         {
432             if (v>_send)
433                 return (2*_send-v);
434             else
435                 return (2*_sbegin-v);
436 
437         }
438     }
439 
440 }
441 
_update()442 void Sequence::_update()
443 {
444     if (_frameTime.empty()) return;
445 
446     // if begin or end < 0, make it last frame
447     int _ubegin = (_begin < 0 ?  (int)_frameTime.size()-1: _begin);
448     int _uend = (_end < 0 ? (int)_frameTime.size()-1: _end);
449 
450     int _sbegin = osg::minimum(_ubegin,_uend);
451     int _send = osg::maximum(_ubegin,_uend);
452 
453     // if _value<0, new or restarted
454     if (_value<0)
455     {
456         _value = (_begin < 0 ?  (int)_frameTime.size()-1: _begin);
457         _resetTotalTime = true;
458     }
459 
460     // if _start<0, new or restarted
461     if (_start<0)
462     {
463         _start = _now;
464         _resetTotalTime = true;
465     }
466 
467     // need to calculate time of a complete sequence?
468     // time is different depending on loop mode
469     if (_resetTotalTime)
470     {
471         if (_loopMode == LOOP)
472         {
473             _totalTime = 0.0;
474             for (int i=_sbegin; i<=_send; i++)
475             {
476                 _totalTime += _frameTime[i];
477             }
478         }
479         else //SWING
480         {
481             _totalTime = _frameTime[_sbegin];
482             // ones in the middle get counted twice: 0 1 2 3 4 3 2 1 0
483             for (int i=_sbegin+1; i<_send; i++)
484             {
485                 _totalTime += 2*_frameTime[i];
486             }
487             if (_sbegin != _send)
488             {
489                 _totalTime += _frameTime[_send];
490             }
491         }
492 
493         _resetTotalTime = false;
494     }
495 
496 }
497