Files
OpenSceneGraph/src/osg/Sequence.cpp
Robert Osfield 4a3cc5c182 Implemented OpenFlight style switches so that each child of a switch can now
be individually turned on or off.  Moved the OpenFlight code across to use the
new scheme, removing the old hack of using node masks to achieve the same end
result.
2002-10-04 14:50:33 +00:00

176 lines
4.2 KiB
C++

#include <osg/Sequence>
using namespace osg;
/**
* Sequence constructor.
*/
Sequence::Sequence() :
Switch(),
_last(-1.0f),
_step(1),
_loopMode(LOOP),
_begin(0),
_end(-1),
_speed(0),
_nreps(0),
_nrepsremain(0),
_mode(STOP)
{
setNumChildrenRequiringAppTraversal(1);
}
Sequence::Sequence(const Sequence& seq, const CopyOp& copyop) :
Switch(seq, copyop),
_last(seq._last),
_step(seq._step),
_loopMode(seq._loopMode),
_begin(seq._begin),
_end(seq._end),
_speed(seq._speed),
_nreps(seq._nreps),
_nrepsremain(seq._nrepsremain),
_mode(seq._mode)
{
setNumChildrenRequiringAppTraversal(getNumChildrenRequiringAppTraversal()+1);
}
void Sequence::setTime(int frame, float t)
{
int sz = _frameTime.size();
//cerr << "sz=" << sz << " frame=" << frame << endl;
if (frame < sz)
_frameTime[frame] = t;
else
for (int i = sz; i < (frame+1); i++) {
_frameTime.push_back(t);
}
}
float Sequence::getTime(int frame) const
{
if (frame >= 0 && frame < (int) _frameTime.size())
return _frameTime[frame];
else
return -1.0f;
}
void Sequence::setInterval(LoopMode mode, int begin, int end)
{
_loopMode = mode;
_begin = begin;
_end = end;
// switch to beginning of interval
unsigned int nch = getNumChildren();
begin = (_begin < 0 ? nch + _begin : _begin);
end = (_end < 0 ? nch + _end : _end);
setValue(begin);
_step = (begin < end ? 1 : -1);
}
void Sequence::setDuration(float speed, int nreps)
{
_speed = (speed <= 0.0f ? 0.0f : speed);
_nreps = (nreps < 0 ? -1 : nreps);
_nrepsremain = _nreps;
}
void Sequence::setMode(SequenceMode mode)
{
switch (mode) {
case START:
// restarts sequence in 'traverse'
setValue(ALL_CHILDREN_OFF);
_mode = mode;
break;
case STOP:
_mode = mode;
break;
case PAUSE:
if (_mode == START)
_mode = PAUSE;
break;
case RESUME:
if (_mode == PAUSE)
_mode = START;
break;
}
}
void Sequence::traverse(NodeVisitor& nv)
{
if (nv.getVisitorType()==NodeVisitor::APP_VISITOR && _mode == START && _nrepsremain)
{
double t = nv.getFrameStamp()->getReferenceTime();
if (_last == -1.0)
_last = t;
// first and last frame of interval
unsigned int nch = getNumChildren();
int begin = (_begin < 0 ? nch + _begin : _begin);
int end = (_end < 0 ? nch + _end : _end);
int sw = getValue();
if (sw == ALL_CHILDREN_OFF ||
sw == ALL_CHILDREN_ON ||
sw == MULTIPLE_CHILDREN_ON ) {
sw = begin;
_step = (begin < end ? 1 : -1);
}
// default timeout for unset values
if (sw >= (int) _frameTime.size()) {
setTime(sw, 1.0f);
}
// frame time-out?
float dur = _frameTime[sw] * _speed;
if ((t - _last) > dur) {
sw += _step;
// check interval
int ibegin = (begin < end ? begin : end);
int iend = (end > begin ? end : begin);
//cerr << this << " interval " << ibegin << "," << iend << endl;
if (sw < ibegin || sw > iend) {
// stop at last frame
if (sw < ibegin)
sw = ibegin;
else
sw = iend;
// repeat counter
if (_nrepsremain > 0)
_nrepsremain--;
if (_nrepsremain == 0) {
// stop
setMode(STOP);
}
else {
// wrap around
switch (_loopMode) {
case LOOP:
//cerr << this << " loop" << endl;
sw = begin;
break;
case SWING:
//cerr << this << " swing" << endl;
_step = -_step;
break;
}
}
}
_last = t;
}
//cerr << this << " child=" << sw << endl;
setValue(sw);
}
Switch::traverse(nv);
}