Hi Max,

Could you please supply a test .osg file that reproduces the problem,
and full source files of any files you've modified.

Emails like the one you just posted are very hard to follow, and often
lead to confusion, so the above files would help avoid ambiguities and
let me go straight to the issues.

Thanks,
Robert.

On Mon, Oct 27, 2008 at 3:44 PM, Max Bandazian <[EMAIL PROTECTED]> wrote:
> Hi,
> It looks like osg::Sequence has a bug in the way it ends a run through its
> frames. Instead of stopping at the last frame, it wraps around and displays
> the first frame once before stopping. You can test this by loading a
> sequence and setting it to play exactly once, with a long enough time per
> frame that each is clearly visible. It looks like the culprit is an
> inconsistency in two boolean tests that determine whether or not to do last
> frame related things:
> 314                    if ( (_step>0 && nextValue==_send) ||
> 315                         (_step<0 && nextValue==_sbegin))
> 316                    {
> 317                        if (_nreps>0)
> 318                            _nrepsRemain--;
> 319
> 320                        // change direction
> 321                        if  (_loopMode == SWING)
> 322                            _step = -_step;
> 323
> 324                    }
> 325                    _value = nextValue;
> And
> 281                    if ( (_loopMode == LOOP) &&
> 282                         ( (_step>0 && _value!=_send) ||
> 283                           (_step<0 && _value!=_sbegin)))
> 284                    {
> 285                        _mode = STOP;
> 286                    }
> The first piece of code is in the regular (_nrepsRemain > 0) portion, and
> does something like "if the next frame is the last one, decrement
> _nrepsRemain and go to the next frame". So far so good. The second snippet
> is from the code that handles the _nrepsRemain == 0 case, and based on
> comments and functionality appears intended to run when the current frame is
> the last one. However, the tests _value!=_send and _value!=_sbegin won't
> pass until the current frame is *not* the last frame, so the sequence will
> wrap around to the first frame before stopping. The simple fix is to just
> change != to ==. The entire sequence.cpp file with change is pasted below.
> Note that I have not changed the != tests for the code handling the last
> frame when _nrepsRemain > 0, because I haven't tested it. It might not
> matter in that case, since the animation isn't stopping anyway.
> Thanks,
> Max Bandazian
> virtual void traverse(osg::NodeVisitor& nv)
> {
>    if (getNumChildren()==0) return;
>    const osg::FrameStamp* framestamp = nv.getFrameStamp();
>    if (framestamp)
>    {
>       _now = framestamp->getSimulationTime();
>    }
>
>    if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR &&
>       _mode == START &&
>       !_frameTime.empty() && getNumChildren()!=0)
>    {
>       // if begin or end < 0, make it last frame
>       int _ubegin = (_begin < 0 ?  (int)_frameTime.size()-1: _begin);
>       int _uend = (_end < 0 ? (int)_frameTime.size()-1: _end);
>       int _sbegin = osg::minimum(_ubegin,_uend);
>       int _send = osg::maximum(_ubegin,_uend);
>       if (framestamp)
>       {
>          // hack for last frame time
>          if (_lastFrameTime>0. && _nrepsRemain==1 &&
> _saveRealLastFrameTime<0.)
>          {
>             if ( _loopMode == LOOP)
>             {
>                if ((_step>0 && _value!=_send) || (_step<0 &&
> _value!=_sbegin))
>                {
>                   _saveRealLastFrameTime=_frameTime[_uend];
>                   _saveRealLastFrameValue = _uend;
>                   _frameTime[_uend] = _lastFrameTime;
>                   _resetTotalTime = true;
>                }
>             }
>             else
>             {
>                if (_step>0 && _value!=_sbegin)
>                {
>                   _saveRealLastFrameTime=_frameTime[_send];
>                   _saveRealLastFrameValue = _send;
>                   _frameTime[_send] = _lastFrameTime;
>                   _resetTotalTime = true;
>                }
>                else if (_step<0 && _value!=_send)
>                {
>                   _saveRealLastFrameTime=_frameTime[_sbegin];
>                   _saveRealLastFrameValue = _sbegin;
>                   _frameTime[_sbegin] = _lastFrameTime;
>                   _resetTotalTime = true;
>                }
>             }
>          }
>          // I never know when to stop!
>          // more fun for last frame time
>          if (_nrepsRemain==0)
>          {
>             if (!_clearOnStop)
>             {
>                _mode = STOP;
>             }
>             else
>             {
>                if ( (_loopMode == LOOP) &&
>                   ( (_step>0 && _value==_send) ||
>                   (_step<0 && _value==_sbegin)))
>                {
>                   _mode = STOP;
>                }
>                else if ( (_loopMode == SWING) &&
>                   ( (_step<0 && _value==_send) ||
>                   (_step>0 && _value==_sbegin)))
>                {
>                   _mode = STOP;
>                }
>             }
>          }
>          // update local variables
>          _update();
>
>          // now for the heavy lifting! three options
>          // 1) still in the same frame, so have nothing to do
>          // 2) just in the next frame
>          // 3) need to calculate everything based on elapsed time
>          if ((_now - _start) > _frameTime[_value]*osg::absolute(_speed))
>          { // case 2 or case 3
>             // most of the time it's just the next frame in the sequence
>             int nextValue = _getNextValue();
>             if (!_sync ||
>                ((_now - _start) <=
> (_frameTime[_value]+_frameTime[nextValue])*osg::absolute(_speed)) )
>             {
>                _start += _frameTime[_value]*osg::absolute(_speed);
>                // repeat or change directions?
>                if ( (_step>0 && nextValue==_send) ||
>                   (_step<0 && nextValue==_sbegin))
>                {
>                   if (_nreps>0)
>                      _nrepsRemain--;
>                   // change direction
>                   if  (_loopMode == SWING)
>                      _step = -_step;
>                }
>                _value = nextValue;
>             }
>             else // case 3
>             {
>                // recalculate everything based on elapsed time
>                // elapsed time from start of the frame
>                double deltaT = _now - _start;
>                // factors _speed into account
>                double adjTotalTime = _totalTime*osg::absolute(_speed);
>                // how many laps?
>                int loops = (int)(deltaT/adjTotalTime);
>
>                // adjust reps & quick check to see if done becuase reps used
> up
>                if (_nreps>0)
>                {
>                   if (_loopMode == LOOP)
>                      _nrepsRemain -= loops;
>                   else
>                      _nrepsRemain -= 2*loops;
>                   if (_nrepsRemain<=0)
>                   {
>                      _nrepsRemain = 0;
>                      _mode = STOP;
>                      osg::notify(osg::WARN) << "stopping because elapsed
> time greater or equal to time remaining to repeat the sequence\n";
>                   }
>                }
>                // deduct off time for laps- _value shouldn't change as it's
> modulo the total time
>                double jumpStart = ((double)loops * adjTotalTime);
>                // step through frames one at a time until caught up
>                while (deltaT-jumpStart >
> _frameTime[_value]*osg::absolute(_speed))
>                {
>                   jumpStart +=  _frameTime[_value]*osg::absolute(_speed );
>                   _value = _getNextValue();
>                }
>                // set start time
>                _start += jumpStart;
>             }
>          }
>       }
>       else
>          osg::notify(osg::WARN) << "osg::Sequence::traverse(NodeVisitor&)
> requires a valid FrameStamp to function, sequence not updated.\n";
>    }
>    // now do the traversal
>    if (nv.getTraversalMode()==osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN)
>    {
>       if ( !((_mode == STOP) && _clearOnStop) &&
>          (getValue()>=0 && getValue()<(int)_children.size()) )
>       {
>          _children[getValue()]->accept(nv);
>       }
>    }
>    else
>    {
>       osg::Group::traverse(nv);
>    }
> }
> _______________________________________________
> osg-submissions mailing list
> [email protected]
> http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
>
>
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to