TuttleOFX  1
TuttleOFX/libraries/tuttle/src/tuttle/host/attribute/AnimatedParam.hpp
Go to the documentation of this file.
00001 #ifndef _TUTTLE_HOST_CORE_ATTRIBUTE_ANIMATED_PARAM_HPP_
00002 #define _TUTTLE_HOST_CORE_ATTRIBUTE_ANIMATED_PARAM_HPP_
00003 
00004 /* Template class for an animated parameter.
00005 
00006 Used for ParamDouble and ParamInteger */
00007 
00008 #include "Param.hpp"
00009 #include "expression.hpp"
00010 
00011 #include <tuttle/host/INode.hpp>
00012 #include <tuttle/host/ofx/attribute/OfxhParamDouble.hpp>
00013 #include <tuttle/host/ofx/attribute/OfxhParamInteger.hpp>
00014 #include <tuttle/host/attribute/ValueInterpolator.hpp>
00015 
00016 #include <boost/scoped_ptr.hpp>
00017 #include <boost/functional/hash.hpp>
00018 
00019 #include <vector>
00020 #include <algorithm>
00021 
00022 namespace tuttle {
00023 namespace host {
00024 namespace attribute {
00025 
00026 template<typename T, typename OFX_PARAM>
00027 class AnimatedParam : public Param, public OFX_PARAM
00028 {
00029 protected:
00030         T _value;
00031 
00032         /* An ordered list of key frames. Used when this param is
00033            animated.  This must stay sorted */
00034         std::vector< TimeValue<T> > _key_frames;
00035 
00036         /* The class that interpolates key frames when animating this param
00037            All transitions yare animated with the same interpolator. A more
00038            advanced version of this class might allow any of the interpolators
00039            in ValueInterpolator.hpp to be used between any adjacent key frames. */
00040         boost::scoped_ptr< Interpolator<T> > _interpolator;
00041 
00042 public:
00043         typedef AnimatedParam<T, OFX_PARAM> This;
00044         typedef typename std::vector< TimeValue<T> >::iterator TimeValueTIterator;
00045         typedef typename std::vector< TimeValue<T> >::const_iterator TimeValueTConstIterator;
00046 
00047         AnimatedParam(
00048                 INode& effect,
00049                 const std::string& name,
00050                 const ofx::attribute::OfxhParamDescriptor& descriptor,
00051                 const std::size_t index,
00052                 const T value )
00053         : Param( effect )
00054         , OFX_PARAM( descriptor, name, effect.getParamSet( ), index )
00055         , _value( value )
00056         , _interpolator( new LinearInterpolator<T>() )
00057         {
00058         }
00059 
00060         AnimatedParam( const AnimatedParam<T, OFX_PARAM>& other )
00061         : Param( other )
00062         , OFX_PARAM( other )
00063         , _value( other._value )
00064         , _interpolator( other._interpolator->clone() )
00065         {
00066         }
00067         
00068         ~AnimatedParam( )
00069         {
00070         }
00071 
00072         void setInterpolator( const ofx::attribute::EInterpolatorType interpolatorType ) OFX_EXCEPTION_SPEC
00073         {
00074                 switch( interpolatorType )
00075                 {
00076                         case ofx::attribute::eSmoothInterpolator:
00077                                 _interpolator.reset( new SmoothInterpolator<T>() );
00078                                 break;
00079                         case ofx::attribute::eFastInterpolator:
00080                                 _interpolator.reset( new FastInterpolator<T>() );
00081                                 break;
00082                         case ofx::attribute::eSlowInterpolator:
00083                                 _interpolator.reset( new SlowInterpolator<T>() );
00084                                 break;
00085                         case ofx::attribute::eLinearInterpolator:
00086                                 _interpolator.reset( new LinearInterpolator<T>() );
00087                                 break;
00088                 }
00089         }
00090 
00091         void getValue( T& v ) const OFX_EXCEPTION_SPEC
00092         {
00093                 v = _value;
00094         }
00095 
00096         void getValueAtTime( const OfxTime time, T& v ) const OFX_EXCEPTION_SPEC
00097         {
00098                 if( _key_frames.size( ) == 0 )
00099                         v = _value;
00100                 else
00101                 {
00102 
00103                         /* Find the key frames surrounding this time
00104     
00105                            Set prev to the first key frame before "time" or the first one
00106                            after "time" if there's not one before.
00107     
00108                            Set next to the first key frame after "time" or the first one
00109                            before "time" if there's not one after */
00110 
00111                         TimeValue<T> temp, prev, next;
00112                         TimeValueTConstIterator it;
00113 
00114                         // Find the first item at or before time
00115                         temp.time = time;
00116                         it = std::lower_bound( _key_frames.begin( ), _key_frames.end( ), temp );
00117 
00118                         if( it->time == time || it == _key_frames.begin( ) )
00119                         {
00120                                 // There's a key frame at exactly this time
00121                                 // or this is the first key frame. Return this key frame value
00122                                 v = it->value;
00123                                 return;
00124                         }
00125                         else if( it == _key_frames.end( ) )
00126                         {
00127                                 // There's no key frame at or after this time
00128                                 // Return the last key frame value
00129                                 it--;
00130                                 v = it->value;
00131                                 return;
00132                         }
00133                         else
00134                         {
00135                                 // The time is between two values.
00136                                 // Get the previous key frame and interpolate
00137                                 next = *it;
00138                                 it--;
00139                                 prev = *it;
00140                                 _interpolator->getValue( prev, next, ( const OfxTime ) time, v );
00141                         }
00142                 }
00143         }
00144 
00145         void setValue( const T& v, const ofx::attribute::EChange change ) OFX_EXCEPTION_SPEC
00146         {
00147                 /* Setting a single value for this param clears the animation */
00148                 _key_frames.clear( );
00149                 _value = v;
00150                 this->paramChanged( change );
00151         }
00152 
00153         void setValueAtTime( const OfxTime time, const T& v, const ofx::attribute::EChange change ) OFX_EXCEPTION_SPEC
00154         {
00155                 TimeValue<T> new_tv;
00156                 TimeValueTIterator it;
00157 
00158                 new_tv.time = time;
00159                 new_tv.value = v;
00160                 it = find( _key_frames.begin( ), _key_frames.end( ), new_tv );
00161                 if( it == _key_frames.end( ) )
00162                 {
00163                         _key_frames.push_back( new_tv );
00164                         std::sort( _key_frames.begin( ), _key_frames.end( ) );
00165                 }
00166                 else
00167                 {
00168                         ( *it ).value = v;
00169                 }
00170                 this->paramChanged( change );
00171         }
00172 
00173         void setValueFromExpression( const std::string& value, const ofx::attribute::EChange change ) OFX_EXCEPTION_SPEC
00174         {
00175                 _value = extractValueFromExpression<T>( value );
00176                 this->paramChanged( change );
00177         }
00178 
00179         void derive( const OfxTime time, T& ) const OFX_EXCEPTION_SPEC
00180         {
00181                 BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatErrMissingHostFeature ) );
00182         }
00183 
00184         void integrate( const OfxTime time1, const OfxTime time2, T& ) const OFX_EXCEPTION_SPEC
00185         {
00186                 BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatErrMissingHostFeature ) );
00187         }
00188 
00189         void copy( const AnimatedParam<T, OFX_PARAM>& p ) OFX_EXCEPTION_SPEC
00190         {
00191                 _value = p._value;
00192                 _key_frames = p._key_frames;
00193                 //      paramChanged( ofx::attribute::eChangeUserEdited );
00194         }
00195 
00196         void copy( const ofx::attribute::OfxhParam& p ) OFX_EXCEPTION_SPEC
00197         {
00198                 const AnimatedParam<T, OFX_PARAM>& param = dynamic_cast < const AnimatedParam<T, OFX_PARAM>& > ( p );
00199 
00200                 copy( param );
00201         }
00202 
00203         This* clone() const
00204         {
00205                 return new This( *this );
00206         }
00207 
00208         /* ======= BEGIN OfxhKeyframeParam functions =======
00209 
00210         Since this implementation is backed by a set, indexes may change and
00211         they are no longer valid after a key frame is set or deleted.  */
00212         void getNumKeys( unsigned int& outNumKeys ) const OFX_EXCEPTION_SPEC
00213         {
00214                 outNumKeys = _key_frames.size( );
00215         }
00216 
00217         void getKeyTime( const int nth, OfxTime& outTime ) const OFX_EXCEPTION_SPEC
00218         {
00219                 if( nth >= 0 && ( size_t ) nth < _key_frames.size( ) )
00220                         outTime = _key_frames[nth].time;
00221                 else
00222                         BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatErrBadIndex ) );
00223         }
00224 
00225         void getKeyIndex( const OfxTime time, const int direction, int& outIndex ) const OFX_EXCEPTION_SPEC
00226         {
00227                 TimeValue<T> temp;
00228                 TimeValueTConstIterator it;
00229 
00230                 // Find the first item at or before time
00231                 temp.time = time;
00232                 it = std::lower_bound( _key_frames.begin( ), _key_frames.end( ), temp );
00233 
00234                 if( it == _key_frames.end( ) )
00235                         BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatFailed ) );
00236 
00237                 if( direction == 0 )
00238                 {
00239                         // Find an exact match or fail
00240                         if( it->time == time )
00241                         {
00242                                 outIndex = it - _key_frames.begin( );
00243                         }
00244                         else
00245                         {
00246                                 BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatFailed ) );
00247                         }
00248 
00249                 }
00250                 else if( direction < 0 )
00251                 {
00252                         // Find the key frame directly before the match. If the match is the first element, fail.
00253                         if( it == _key_frames.begin( ) )
00254                                 BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatFailed ) );
00255                         else
00256                         {
00257                                 outIndex = it - _key_frames.begin( ) - 1;
00258 
00259                         }
00260 
00261                 }
00262                 else
00263                 { // direction > 0
00264                         if( it->time > time )
00265                         {
00266                                 // The match is greater than time. Success.
00267                                 outIndex = it - _key_frames.begin( );
00268                         }
00269                         else
00270                         { // (it->time == time)
00271                                 // The match is exact. If there's a next element, use that.
00272                                 it++;
00273                                 if( it != _key_frames.end( ) )
00274                                         outIndex = it - _key_frames.begin( );
00275                                 else
00276                                         BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatFailed ) );
00277                         }
00278                 }
00279         }
00280 
00281         void deleteKey( const OfxTime time ) OFX_EXCEPTION_SPEC
00282         {
00283                 TimeValue<T> temp;
00284                 TimeValueTIterator it;
00285 
00286                 temp.time = time;
00287                 it = find( _key_frames.begin( ), _key_frames.end( ), temp );
00288                 if( it != _key_frames.end( ) )
00289                         _key_frames.erase( it );
00290                 else
00291                         BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatErrBadIndex ) );
00292         }
00293 
00294         void deleteAllKeys( ) OFX_EXCEPTION_SPEC
00295         {
00296                 _key_frames.clear( );
00297         }
00298 
00299         /* ======= END OfxhKeyframeParam functions ======= */
00300 
00301         bool paramTypeHasData() const { return true; }
00302 
00303         std::size_t getHash() const
00304         {
00305                 std::size_t seed = 0;
00306                 BOOST_FOREACH( const TimeValue<T>& tv, _key_frames )
00307                 {
00308                         boost::hash_combine( seed, tv.time );
00309                         boost::hash_combine( seed, tv.value );
00310                 }
00311                 return seed;
00312         }
00313 
00314         std::size_t getHashAtTime_valueChangeToEnd( const OfxTime time ) const
00315         {
00316                 T valueAtTime = 0;
00317                 getValueAtTime( time, valueAtTime );
00318                 std::size_t seed = 0;
00319                 BOOST_FOREACH( const TimeValue<T>& tv, _key_frames )
00320                 {
00321                         if( tv.time >= time )
00322                         {
00323                                 boost::hash_combine( seed, tv.time );
00324                                 boost::hash_combine( seed, tv.value );
00325                         }
00326                 }
00327                 return seed;
00328         }
00329         
00330         std::size_t getHashAtTime( const OfxTime time ) const
00331         {
00332                 const std::string cacheInvalidation = getCacheInvalidation();
00333                 if( cacheInvalidation == kOfxParamInvalidateAll )
00334                 {
00335                         std::size_t seed = getHash();
00336                         boost::hash_combine( seed, time );
00337                         return seed;
00338                 }
00339                 else if( cacheInvalidation == kOfxParamInvalidateValueChangeToEnd )
00340                 {
00341                         return getHashAtTime_valueChangeToEnd( time );
00342                 }
00343                 else
00344                 {
00345                         BOOST_ASSERT( cacheInvalidation == kOfxParamInvalidateValueChange );
00346                         
00347                         // Standard case
00348                         T valueAtTime = 0;
00349                         getValueAtTime( time, valueAtTime );
00350                         return boost::hash_value( valueAtTime );
00351                 }
00352         }
00353 };
00354 
00355 }
00356 }
00357 }
00358 
00359 #endif