/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #ifndef OSGSIM_BLINKSQUENCE #define OSGSIM_BLINKSQUENCE 1 #include #include #include #include #include #include #include namespace osgSim { /** sequence group which can be used to synchronize related blink sequences.*/ class OSGSIM_EXPORT SequenceGroup : public osg::Object { public: SequenceGroup(); SequenceGroup(const SequenceGroup& bs, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); SequenceGroup(double baseTime); META_Object(osgSim,SequenceGroup); double _baseTime; }; class OSGSIM_EXPORT BlinkSequence : public osg::Object { public: BlinkSequence(); BlinkSequence(const BlinkSequence& bs, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); META_Object(osgSim,BlinkSequence); /** add a pulse of specified color and duration to the BlinkSequence.*/ inline void addPulse(double length,const osg::Vec4& color); /** return the number of pulses. */ inline int getNumPulses() const { return _pulseData.size(); } /** return the pulse data at position i. */ inline void getPulse(unsigned int i, double& length,osg::Vec4& color) const; /** set pulse of specified color and duration to the BlinkSequence.*/ inline void setPulse(unsigned int i,double length,const osg::Vec4& color); /** get the total pulse period of the blink sequence, which is equal to the sum of all the pulse periods.*/ inline double getPulsePeriod() const { return _pulsePeriod; } /** set the sequence group which can be used to synchronize related blink sequences.*/ inline void setSequenceGroup(SequenceGroup* sg) { _sequenceGroup = sg; } /** get the non const sequence group.*/ inline SequenceGroup* getSequenceGroup() { return _sequenceGroup.get(); } /** get the const sequence group.*/ inline const SequenceGroup* getSequenceGroup() const { return _sequenceGroup.get(); } /** set the phase shift of the blink sequence, this would be used to shift a sequence within a sequence group.*/ inline void setPhaseShift(double ps) { _phaseShift = ps; } /** get the pahse shift.*/ inline double getPhaseShift() const { return _phaseShift; } /** compute the local time clamped to this BlinkSequences period, and accounting for the phase shift and sequence group.*/ inline double localTime(double time) const; /** compute the color for the time interval sepecifed. Averages the colors if the length is greater than the current pulse.*/ inline osg::Vec4 color(double time,double length) const; protected: typedef std::pair IntervalColor; typedef std::vector PulseData; double _pulsePeriod; double _phaseShift; PulseData _pulseData; osg::ref_ptr _sequenceGroup; }; inline double BlinkSequence::localTime(double time) const { if (_sequenceGroup.valid()) time -= _sequenceGroup->_baseTime; time -= _phaseShift; return time - floor(time/_pulsePeriod)*_pulsePeriod; } inline void BlinkSequence::addPulse(double length,const osg::Vec4& color) { _pulseData.push_back(IntervalColor(length,color)); _pulsePeriod += length; } inline void BlinkSequence::getPulse(unsigned int i, double& length, osg::Vec4& color) const { const IntervalColor& ic = _pulseData[i]; length = ic.first; color = ic.second; } inline void BlinkSequence::setPulse(unsigned int i,double length,const osg::Vec4& color) { if( i >= _pulseData.size() ) return; IntervalColor& ic = _pulseData[i]; ic.first = length; ic.second = color; } inline osg::Vec4 BlinkSequence::color(double time,double length) const { if (_pulseData.empty()) return osg::Vec4(1.0f,1.0f,1.0f,1.0f); double lt = localTime(time); PulseData::const_iterator itr = _pulseData.begin(); // find the first sample at this time point. while (lt>itr->first) { lt -= itr->first; ++itr; if (itr==_pulseData.end()) itr = _pulseData.begin(); } // if time interval fits inside the current pulse // then simply return this pulses color value. if (lt+length<=itr->first) { return itr->second; } // time length exceeds the current pulse therefore // we have to average out the pules to get the correct // results... // accumulate final part of the first active pulses. osg::Vec4 color(itr->second*(itr->first-lt)); double len = length-(itr->first-lt); ++itr; if (itr==_pulseData.end()) itr = _pulseData.begin(); // accumulate all the whole pluses pulses. while (len>itr->first) { len -= itr->first; color += itr->second*itr->first; ++itr; if (itr==_pulseData.end()) itr = _pulseData.begin(); } // add remaining part of the final pulse. color += itr->second*len; // normalise the time waited color. color /= length; return color; } } #endif