include/cinder/Tween.h
Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2011, The Cinder Project, All rights reserved.
00003  This code is intended for use with the Cinder C++ library: http://libcinder.org
00004 
00005  Based on the sc-Choreograph CinderBlock by David Wicks: http://sansumbrella.com/
00006 
00007  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00008  the following conditions are met:
00009 
00010     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00011     the following disclaimer.
00012     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00013     the following disclaimer in the documentation and/or other materials provided with the distribution.
00014 
00015  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00016  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00017  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00018  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00019  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00020  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00021  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00022  POSSIBILITY OF SUCH DAMAGE.
00023 */
00024 
00025 #pragma once
00026 
00027 #include "cinder/Cinder.h"
00028 #include "cinder/TimelineItem.h"
00029 #include "cinder/CinderMath.h"
00030 #include "cinder/Easing.h"
00031 #include "cinder/Function.h"
00032 
00033 #include <list>
00034 #include <boost/utility.hpp>
00035 
00036 namespace cinder {
00037 
00038 class Timeline;
00039 typedef std::shared_ptr<Timeline>       TimelineRef;
00040 
00041 template<typename T>
00042 class Tween;
00043 typedef std::function<float (float)> EaseFn;
00044 
00045 template<typename T>
00046 class Anim;
00047 
00048 template<typename T>
00049 T tweenLerp( const T &start, const T &end, float time )
00050 {
00051     return start * ( 1 - time ) + end * time;
00052 }
00053 
00054 class TweenBase : public TimelineItem {
00055   public:
00056     typedef std::function<void ()>      StartFn;
00057     typedef std::function<void ()>      FinishFn;
00058     typedef std::function<void ()>      UpdateFn;
00059 
00060     TweenBase( void *target, bool copyStartValue, float startTime, float duration, EaseFn easeFunction = easeNone );
00061     virtual ~TweenBase() {}
00062 
00064     void    setEaseFn( EaseFn easeFunction ) { mEaseFunction = easeFunction; }
00065     EaseFn  getEaseFn() const { return mEaseFunction; }
00066 
00067     void            setStartFn( StartFn startFunction ) { mStartFunction = startFunction; }
00068     StartFn         getStartFn() const { return mStartFunction; }
00069 
00070     void            setReverseStartFn( StartFn reverseStartFunction ) { mReverseStartFunction = reverseStartFunction; }
00071     StartFn         getReverseStartFn() const { return mReverseStartFunction; }
00072     
00073     void            setUpdateFn( UpdateFn updateFunction ) { mUpdateFunction = updateFunction; }                                    
00074     UpdateFn        getUpdateFn() const { return mUpdateFunction; }
00075                                                                                                                                                     
00076     void            setFinishFn( FinishFn finishFn ) { mFinishFunction = finishFn; }
00077     FinishFn        getFinishFn() const { return mFinishFunction; }
00078 
00079     void            setReverseFinishFn( FinishFn reverseFinishFn ) { mReverseFinishFunction = reverseFinishFn; }
00080     FinishFn        getReverseFinishFn() const { return mReverseFinishFunction; }
00081     
00082     class Options {
00083       protected:
00084         Options( TimelineRef timeline )
00085             : mTimeline( timeline )
00086         {}
00087 
00088         void    appendTo( TweenBase &tweenBase, void *target, float offset );
00089         void    timelineEnd( TweenBase &tweenBase, float offset );
00090       
00091         TimelineRef     mTimeline;
00092     };
00093     
00094   protected:
00095     virtual void reset( bool unsetStarted )
00096     {
00097         TimelineItem::reset( unsetStarted );
00098     }
00099 
00100     virtual void complete( bool reverse )
00101     {
00102         if( reverse && mReverseFinishFunction )
00103             mReverseFinishFunction();
00104         else if( ( ! reverse ) && mFinishFunction )
00105             mFinishFunction();
00106     }
00107 
00108   
00109     StartFn         mStartFunction, mReverseStartFunction;
00110     UpdateFn        mUpdateFunction;    
00111     FinishFn        mFinishFunction, mReverseFinishFunction;
00112   
00113     EaseFn      mEaseFunction;
00114     float       mDuration;
00115     bool        mCopyStartValue;
00116 };
00117 
00118 template<typename T>
00119 class TweenRef : public std::shared_ptr<Tween<T> > {
00120   public:
00121     TweenRef( const std::shared_ptr<Tween<T> > &sp )
00122         : std::shared_ptr<Tween<T> >( sp )
00123     {}
00124     TweenRef( Tween<T> *tween )
00125         : std::shared_ptr<Tween<T> >( tween )
00126     {}
00127     TweenRef()
00128         : std::shared_ptr<Tween<T> >()
00129     {}
00130 };
00131         
00132 template<typename T>
00133 class Tween : public TweenBase {
00134   public:
00135     typedef std::function<T (const T&, const T&, float)>    LerpFn;
00136 
00137     // build a tween with a target, target value, duration, and optional ease function
00138     Tween( T *target, T endValue, float startTime, float duration,
00139             EaseFn easeFunction = easeNone, LerpFn lerpFunction = &tweenLerp<T> )
00140         : TweenBase( target, true, startTime, duration, easeFunction ), mStartValue( *target ), mEndValue( endValue ), mLerpFunction( lerpFunction )
00141     {
00142     }
00143     
00144     Tween( T *target, T startValue, T endValue, float startTime, float duration,
00145             EaseFn easeFunction = easeNone, LerpFn lerpFunction = &tweenLerp<T> )
00146         : TweenBase( target, false, startTime, duration, easeFunction ), mStartValue( startValue ), mEndValue( endValue ), mLerpFunction( lerpFunction )
00147     {
00148     }
00149     
00150     virtual ~Tween() {}
00151     
00153     T   getStartValue() const { return mStartValue; }
00154     T   getEndValue() const { return mEndValue; }           
00155     T*  getTarget() const { return reinterpret_cast<T*>( mTarget ); }
00156     
00158     bool    isCopyStartValue() { return mCopyStartValue; }
00159 
00160     void    setLerpFn( const LerpFn &lerpFn ) { mLerpFunction = lerpFn; }
00161 
00163     TweenRef<T>     getThisRef(){ return TweenRef<T>( std::static_pointer_cast<Tween<T> >( shared_from_this() ) ); }
00164 
00165 
00166     class Options : public TweenBase::Options {
00167       public:
00168         Options&    startFn( const TweenBase::StartFn &startFn ) { mTweenRef->setStartFn( startFn ); return *this; }
00169         Options&    reverseStartFn( const TweenBase::StartFn &reverseStartFn ) { mTweenRef->setReverseStartFn( reverseStartFn ); return *this; }
00170         Options&    updateFn( const TweenBase::UpdateFn &updateFn ) { mTweenRef->setUpdateFn( updateFn ); return *this; }
00171         Options&    finishFn( const TweenBase::FinishFn &finishFn ) { mTweenRef->setFinishFn( finishFn ); return *this; }
00172         Options&    reverseFinishFn( const TweenBase::FinishFn &reverseFinishFn ) { mTweenRef->setReverseFinishFn( reverseFinishFn ); return *this; }
00173         Options&    easeFn( const EaseFn &easeFunc ) { mTweenRef->setEaseFn( easeFunc ); return *this; }
00174         Options&    delay( float delayAmt ) { mTweenRef->setStartTime( mTweenRef->getStartTime() + delayAmt ); return *this; }
00175         Options&    autoRemove( bool remove = true ) { mTweenRef->setAutoRemove( remove ); return *this; }
00176         Options&    loop( bool doLoop = true ) { mTweenRef->setLoop( doLoop ); return *this; }
00177         Options&    pingPong( bool doPingPong = true ) { mTweenRef->setPingPong( doPingPong ); return *this; }
00178         Options&    timelineEnd( float offset = 0 ) { TweenBase::Options::timelineEnd( *mTweenRef, offset ); return *this; }
00179         template<typename Y>
00180         Options&    appendTo( Anim<Y> *endTarget, float offset = 0 ) { TweenBase::Options::appendTo( *mTweenRef, endTarget->ptr(), offset ); return *this; }    
00181         Options&    appendTo( void *endTarget, float offset = 0 ) { TweenBase::Options::appendTo( *mTweenRef, endTarget, offset ); return *this; }  
00182         Options&    lerpFn( const typename Tween<T>::LerpFn &lerpFn ) { mTweenRef->setLerpFn( lerpFn ); return *this; }
00183         
00184         operator TweenRef<T>() { return mTweenRef; }
00185 
00186       protected:
00187         Options( TweenRef<T> tweenRef, TimelineRef timeline )
00188             : TweenBase::Options( timeline ), mTweenRef( tweenRef )
00189         {}
00190                 
00191         TweenRef<T>     mTweenRef;
00192         
00193         friend class Timeline;
00194     };
00195 
00196 
00197   protected:
00198     virtual void reverse()
00199     {
00200         std::swap( mStartValue, mEndValue );
00201     }
00202 
00203     virtual TimelineItemRef clone() const
00204     {
00205         std::shared_ptr<Tween<T> > result( new Tween<T>( *this ) );
00206         result->mCopyStartValue = false;
00207         return result;
00208     }
00209     
00210     virtual TimelineItemRef cloneReverse() const
00211     {
00212         std::shared_ptr<Tween<T> > result( new Tween<T>( *this ) );
00213         std::swap( result->mStartValue, result->mEndValue );
00214         result->mCopyStartValue = false;
00215         return result;
00216     }
00217     
00218     virtual void start( bool reverse )
00219     {
00220         if( mCopyStartValue )
00221             mStartValue = *(reinterpret_cast<T*>( mTarget ) );
00222         if( reverse && mReverseStartFunction )
00223             mReverseStartFunction();
00224         else if( ( ! reverse ) && mStartFunction )
00225             mStartFunction();
00226     }
00227     
00228     virtual void update( float relativeTime )
00229     {
00230         *reinterpret_cast<T*>(mTarget) = mLerpFunction( mStartValue, mEndValue, mEaseFunction( relativeTime ) );
00231         if( mUpdateFunction )
00232             mUpdateFunction();
00233     }
00234     
00235 
00236     T   mStartValue, mEndValue; 
00237     
00238     LerpFn              mLerpFunction;
00239 };
00240 
00241 template<typename T>
00242 class FnTween : public Tween<T> {
00243   public:
00244     FnTween( std::function<void (T)> fn, T startValue, T endValue, float startTime, float duration, EaseFn easeFunction = easeNone, typename Tween<T>::LerpFn lerpFunction = &tweenLerp<T> )
00245         : Tween<T>( &mValue, startValue, endValue, startTime, duration, easeFunction, lerpFunction ), mFn( fn ), mValue( startValue )
00246     {
00247     }
00248     
00249     virtual void update( float relativeTime )
00250     {
00251         Tween<T>::update( relativeTime );
00252         if( mFn )
00253             mFn( mValue );
00254     }   
00255     
00256     std::function<void (T)>     mFn;
00257     T                           mValue;
00258 };
00259 
00260 template<typename T>
00261 class FnTweenRef : public TweenRef<T> {
00262   public:
00263     FnTweenRef( const std::shared_ptr<FnTween<T> > &sp )
00264         : TweenRef<T>( sp )
00265     {}
00266     FnTweenRef( FnTween<T> *fnTween )
00267         : TweenRef<T>( fnTween )
00268     {}
00269     FnTweenRef()
00270         : TweenRef<T>()
00271     {}
00272 };
00273 
00274 class AnimBase {
00275   public:
00277     void    stop();
00278     
00280     TimelineRef getParent() const { return mParentTimeline; }
00281 
00282   protected:
00283     AnimBase( void *voidPtr ) : mVoidPtr( voidPtr ) {}
00284     AnimBase( const AnimBase &rhs, void *voidPtr );
00285     ~AnimBase();
00286     
00287     void    set( const AnimBase &rhs );
00288     void    setReplace( const AnimBase &rhs );
00289     
00290     void        setParentTimeline( TimelineRef parentTimeline );
00291 
00292     void            *mVoidPtr;  
00293     TimelineRef     mParentTimeline;
00294 };
00295 
00296 template<typename T>
00297 class Anim : public AnimBase {
00298   public:
00299     Anim()
00300         : AnimBase( &mValue )
00301     {}
00302     Anim( T value ) 
00303         : AnimBase( &mValue), mValue( value )
00304     {}
00305     Anim( const Anim<T> &rhs ) // normal copy constructor
00306         : AnimBase( rhs, &mValue ), mValue( rhs.mValue )
00307     {}
00308     
00309     const T&    operator()() const { return mValue; }
00310     T&          operator()() { return mValue; } 
00311     
00312     operator const T&() const { return mValue; }    
00313     Anim<T>& operator=( const Anim &rhs ) { // copy assignment
00314         if( this != &rhs ) {
00315             set( rhs );
00316             mValue = rhs.mValue;
00317         }
00318         return *this;
00319     }
00320 
00321 #if defined( CINDER_RVALUE_REFERENCES )
00322     Anim( Anim &&rhs ) // move constructor
00323         : AnimBase( &mValue )
00324     {
00325         setReplace( rhs );
00326         rhs.mParentTimeline.reset(); // blow away rhs's tweens due to move semantics
00327         mValue = rhs.mValue;
00328     }
00329     Anim<T>& operator=( Anim &&rhs ) { // move assignment
00330         if( this != &rhs ) {
00331             setReplace( rhs );
00332             rhs.mParentTimeline.reset(); // blow away rhs's tweens due to move semantics
00333             mValue = rhs.mValue;
00334         }
00335         return *this;
00336     }
00337 #endif
00338 
00339     Anim<T>& operator=( T value ) { mValue = value; return *this; }
00340 
00341     const T&    value() const { return mValue; }
00342     T&          value() { return mValue; }
00343     
00344     const T*        ptr() const { return &mValue; }
00345     T*              ptr() { return &mValue; }
00346 
00347   protected:
00348 
00349     friend class Timeline;
00350 
00351     T               mValue;
00352 };
00353 
00354 //typedef boost::instrusive_ptr<TweenBase>  TweenBaseRef;
00355 
00356 /*class TweenScope {
00357   public:
00358     TweenScope() {}
00359     TweenScope( const TweenScope &rhs ) {}  // do nothing for copy; these are our tweens alone
00360     TweenScope& operator=( const TweenScope &rhs ) { return *this; }    // do nothing for copy; these are our tweens alone  
00361     ~TweenScope();
00362     
00363     TweenScope& operator+=( TimelineItemRef item );
00364     void add( TimelineItemRef item );
00365 
00366   private:
00367     std::list<std::weak_ptr<TimelineItem> >     mItems;
00368 };*/
00369 
00370 } //namespace cinder