BlinkSequence 5.86 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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 <osgSim/Export>

#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Object>
#include <osg/ref_ptr>

#include <vector>

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);
       
       inline void setBaseTime( double t ) { _baseTime = t; }
       inline double getBaseTime() const { return _baseTime; }

       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<double,osg::Vec4> IntervalColor;
        typedef std::vector<IntervalColor>  PulseData;
        
        double                      _pulsePeriod;
        double                      _phaseShift;
        PulseData                   _pulseData;
        osg::ref_ptr<SequenceGroup> _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