TuttleOFX  1
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         : Param( effect )
00053         , OFX_PARAM( descriptor, name, effect.getParamSet( ), index )
00054         , _interpolator( new LinearInterpolator<T>() )
00055         {
00056         }
00057 
00058         AnimatedParam( const AnimatedParam<T, OFX_PARAM>& other )
00059         : Param( other )
00060         , OFX_PARAM( other )
00061         , _interpolator( other._interpolator->clone() )
00062         {
00063         }
00064         
00065         ~AnimatedParam( )
00066         {
00067         }
00068 
00069         void setInterpolator( const ofx::attribute::EInterpolatorType interpolatorType ) OFX_EXCEPTION_SPEC
00070         {
00071                 switch( interpolatorType )
00072                 {
00073                         case ofx::attribute::eSmoothInterpolator:
00074                                 _interpolator.reset( new SmoothInterpolator<T>() );
00075                                 break;
00076                         case ofx::attribute::eFastInterpolator:
00077                                 _interpolator.reset( new FastInterpolator<T>() );
00078                                 break;
00079                         case ofx::attribute::eSlowInterpolator:
00080                                 _interpolator.reset( new SlowInterpolator<T>() );
00081                                 break;
00082                         case ofx::attribute::eLinearInterpolator:
00083                                 _interpolator.reset( new LinearInterpolator<T>() );
00084                                 break;
00085                 }
00086         }
00087 
00088         void getValue( T& v ) const OFX_EXCEPTION_SPEC
00089         {
00090                 v = _value;
00091         }
00092 
00093         void getValueAtTime( const OfxTime time, T& v ) const OFX_EXCEPTION_SPEC
00094         {
00095                 if( _key_frames.size( ) == 0 )
00096                         v = _value;
00097                 else
00098                 {
00099 
00100                         /* Find the key frames surrounding this time
00101     
00102                            Set prev to the first key frame before "time" or the first one
00103                            after "time" if there's not one before.
00104     
00105                            Set next to the first key frame after "time" or the first one
00106                            before "time" if there's not one after */
00107 
00108                         TimeValue<T> temp, prev, next;
00109                         TimeValueTConstIterator it;
00110 
00111                         // Find the first item at or before time
00112                         temp.time = time;
00113                         it = std::lower_bound( _key_frames.begin( ), _key_frames.end( ), temp );
00114 
00115                         if( it->time == time || it == _key_frames.begin( ) )
00116                         {
00117                                 // There's a key frame at exactly this time
00118                                 // or this is the first key frame. Return this key frame value
00119                                 v = it->value;
00120                                 return;
00121                         }
00122                         else if( it == _key_frames.end( ) )
00123                         {
00124                                 // There's no key frame at or after this time
00125                                 // Return the last key frame value
00126                                 it--;
00127                                 v = it->value;
00128                                 return;
00129                         }
00130                         else
00131                         {
00132                                 // The time is between two values.
00133                                 // Get the previous key frame and interpolate
00134                                 next = *it;
00135                                 it--;
00136                                 prev = *it;
00137                                 _interpolator->getValue( prev, next, ( const OfxTime ) time, v );
00138                         }
00139                 }
00140         }
00141 
00142         void setValue( const T& v, const ofx::attribute::EChange change ) OFX_EXCEPTION_SPEC
00143         {
00144                 /* Setting a single value for this param clears the animation */
00145                 _key_frames.clear( );
00146                 _value = v;
00147                 this->paramChanged( change );
00148         }
00149 
00150         void setValueAtTime( const OfxTime time, const T& v, const ofx::attribute::EChange change ) OFX_EXCEPTION_SPEC
00151         {
00152                 TimeValue<T> new_tv;
00153                 TimeValueTIterator it;
00154 
00155                 new_tv.time = time;
00156                 new_tv.value = v;
00157                 it = find( _key_frames.begin( ), _key_frames.end( ), new_tv );
00158                 if( it == _key_frames.end( ) )
00159                 {
00160                         _key_frames.push_back( new_tv );
00161                         std::sort( _key_frames.begin( ), _key_frames.end( ) );
00162                 }
00163                 else
00164                 {
00165                         ( *it ).value = v;
00166                 }
00167                 this->paramChanged( change );
00168         }
00169 
00170         void setValueFromExpression( const std::string& value, const ofx::attribute::EChange change ) OFX_EXCEPTION_SPEC
00171         {
00172                 _value = extractValueFromExpression<T>( value );
00173                 this->paramChanged( change );
00174         }
00175 
00176         void derive( const OfxTime time, T& ) const OFX_EXCEPTION_SPEC
00177         {
00178                 BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatErrMissingHostFeature ) );
00179         }
00180 
00181         void integrate( const OfxTime time1, const OfxTime time2, T& ) const OFX_EXCEPTION_SPEC
00182         {
00183                 BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatErrMissingHostFeature ) );
00184         }
00185 
00186         void copy( const AnimatedParam<T, OFX_PARAM>& p ) OFX_EXCEPTION_SPEC
00187         {
00188                 _value = p._value;
00189                 _key_frames = p._key_frames;
00190                 //      paramChanged( ofx::attribute::eChangeUserEdited );
00191         }
00192 
00193         void copy( const ofx::attribute::OfxhParam& p ) OFX_EXCEPTION_SPEC
00194         {
00195                 const AnimatedParam<T, OFX_PARAM>& param = dynamic_cast < const AnimatedParam<T, OFX_PARAM>& > ( p );
00196 
00197                 copy( param );
00198         }
00199 
00200         This* clone() const
00201         {
00202                 return new This( *this );
00203         }
00204 
00205         /* ======= BEGIN OfxhKeyframeParam functions =======
00206 
00207         Since this implementation is backed by a set, indexes may change and
00208         they are no longer valid after a key frame is set or deleted.  */
00209         void getNumKeys( unsigned int& outNumKeys ) const OFX_EXCEPTION_SPEC
00210         {
00211                 outNumKeys = _key_frames.size( );
00212         }
00213 
00214         void getKeyTime( const int nth, OfxTime& outTime ) const OFX_EXCEPTION_SPEC
00215         {
00216                 if( nth >= 0 && ( size_t ) nth < _key_frames.size( ) )
00217                         outTime = _key_frames[nth].time;
00218                 else
00219                         BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatErrBadIndex ) );
00220         }
00221 
00222         void getKeyIndex( const OfxTime time, const int direction, int& outIndex ) const OFX_EXCEPTION_SPEC
00223         {
00224                 TimeValue<T> temp;
00225                 TimeValueTConstIterator it;
00226 
00227                 // Find the first item at or before time
00228                 temp.time = time;
00229                 it = std::lower_bound( _key_frames.begin( ), _key_frames.end( ), temp );
00230 
00231                 if( it == _key_frames.end( ) )
00232                         BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatFailed ) );
00233 
00234                 if( direction == 0 )
00235                 {
00236                         // Find an exact match or fail
00237                         if( it->time == time )
00238                         {
00239                                 outIndex = it - _key_frames.begin( );
00240                         }
00241                         else
00242                         {
00243                                 BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatFailed ) );
00244                         }
00245 
00246                 }
00247                 else if( direction < 0 )
00248                 {
00249                         // Find the key frame directly before the match. If the match is the first element, fail.
00250                         if( it == _key_frames.begin( ) )
00251                                 BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatFailed ) );
00252                         else
00253                         {
00254                                 outIndex = it - _key_frames.begin( ) - 1;
00255 
00256                         }
00257 
00258                 }
00259                 else
00260                 { // direction > 0
00261                         if( it->time > time )
00262                         {
00263                                 // The match is greater than time. Success.
00264                                 outIndex = it - _key_frames.begin( );
00265                         }
00266                         else
00267                         { // (it->time == time)
00268                                 // The match is exact. If there's a next element, use that.
00269                                 it++;
00270                                 if( it != _key_frames.end( ) )
00271                                         outIndex = it - _key_frames.begin( );
00272                                 else
00273                                         BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatFailed ) );
00274                         }
00275                 }
00276         }
00277 
00278         void deleteKey( const OfxTime time ) OFX_EXCEPTION_SPEC
00279         {
00280                 TimeValue<T> temp;
00281                 TimeValueTIterator it;
00282 
00283                 temp.time = time;
00284                 it = find( _key_frames.begin( ), _key_frames.end( ), temp );
00285                 if( it != _key_frames.end( ) )
00286                         _key_frames.erase( it );
00287                 else
00288                         BOOST_THROW_EXCEPTION( ofx::OfxhException( kOfxStatErrBadIndex ) );
00289         }
00290 
00291         void deleteAllKeys( ) OFX_EXCEPTION_SPEC
00292         {
00293                 _key_frames.clear( );
00294         }
00295 
00296         /* ======= END OfxhKeyframeParam functions ======= */
00297 
00298         bool paramTypeHasData() const { return true; }
00299 
00300         std::size_t getHash() const
00301         {
00302                 std::size_t seed = 0;
00303                 BOOST_FOREACH( const TimeValue<T>& tv, _key_frames )
00304                 {
00305                         boost::hash_combine( seed, tv.time );
00306                         boost::hash_combine( seed, tv.value );
00307                 }
00308                 return seed;
00309         }
00310 
00311         std::size_t getHashAtTime_valueChangeToEnd( const OfxTime time ) const
00312         {
00313                 T valueAtTime = 0;
00314                 getValueAtTime( time, valueAtTime );
00315                 std::size_t seed = 0;
00316                 BOOST_FOREACH( const TimeValue<T>& tv, _key_frames )
00317                 {
00318                         if( tv.time >= time )
00319                         {
00320                                 boost::hash_combine( seed, tv.time );
00321                                 boost::hash_combine( seed, tv.value );
00322                         }
00323                 }
00324                 return seed;
00325         }
00326         
00327         std::size_t getHashAtTime( const OfxTime time ) const
00328         {
00329                 const std::string cacheInvalidation = getCacheInvalidation();
00330                 if( cacheInvalidation == kOfxParamInvalidateAll )
00331                 {
00332                         std::size_t seed = getHash();
00333                         boost::hash_combine( seed, time );
00334                         return seed;
00335                 }
00336                 else if( cacheInvalidation == kOfxParamInvalidateValueChangeToEnd )
00337                 {
00338                         return getHashAtTime_valueChangeToEnd( time );
00339                 }
00340                 else
00341                 {
00342                         BOOST_ASSERT( cacheInvalidation == kOfxParamInvalidateValueChange );
00343                         
00344                         // Standard case
00345                         T valueAtTime = 0;
00346                         getValueAtTime( time, valueAtTime );
00347                         return boost::hash_value( valueAtTime );
00348                 }
00349         }
00350 };
00351 
00352 /**
00353  * @brief This class is just a re-implementation dedicated to Double Param.
00354  *        It allows implicit conversion from Int to Double.
00355  */
00356 class AnimatedParamDouble : public AnimatedParam<double, ofx::attribute::OfxhParamDouble>
00357 {
00358         typedef AnimatedParam<double, ofx::attribute::OfxhParamDouble> Parent;
00359         
00360 public:
00361         
00362         AnimatedParamDouble(
00363                 INode& effect,
00364                 const std::string& name,
00365                 const ofx::attribute::OfxhParamDescriptor& descriptor,
00366                 const std::size_t index )
00367         : Parent( effect, name, descriptor, index )
00368         {}
00369         
00370         inline void setValue( const double& v, const ofx::attribute::EChange change ) OFX_EXCEPTION_SPEC
00371         {
00372                 Parent::setValue( v, change );
00373         }
00374 
00375         inline void setValueAtTime( const OfxTime time, const double& v, const ofx::attribute::EChange change ) OFX_EXCEPTION_SPEC
00376         {
00377                 Parent::setValueAtTime( time, v, change );
00378         }
00379         
00380         inline void setValue( const int& v, const ofx::attribute::EChange change ) OFX_EXCEPTION_SPEC
00381         {
00382                 Parent::setValue( (double)v, change );
00383         }
00384 
00385         inline void setValueAtTime( const OfxTime time, const int& v, const ofx::attribute::EChange change ) OFX_EXCEPTION_SPEC
00386         {
00387                 Parent::setValueAtTime( time, (double)v, change );
00388         }
00389 
00390 };
00391 
00392 typedef AnimatedParam<int, ofx::attribute::OfxhParamInteger> AnimatedParamInteger;
00393 }
00394 }
00395 }
00396 
00397 #endif