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 #include "cinder/Quaternion.h"
00033 
00034 #include <list>
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 // Specialization of tweenLerp for Quaternions to use slerping
00055 template<>
00056 inline Quatf tweenLerp( const Quatf &start, const Quatf &end, float time )
00057 {
00058     Quatf val = start.slerp( time, end ).normalized();
00059     if( std::isfinite( val.getAxis().x ) && std::isfinite( val.getAxis().y ) && std::isfinite( val.getAxis().z ) )
00060         return val;
00061     else
00062         return Quatf::identity();
00063 }
00064 
00065 template<>
00066 inline Quatd tweenLerp( const Quatd &start, const Quatd &end, float time )
00067 {
00068     Quatd val = start.slerp( time, end ).normalized();
00069     if( std::isfinite( val.getAxis().x ) && std::isfinite( val.getAxis().y ) && std::isfinite( val.getAxis().z ) )
00070         return val;
00071     else
00072         return Quatd::identity();
00073 }
00074 
00075 
00076 class TweenBase : public TimelineItem {
00077   public:
00078     typedef std::function<void ()>      StartFn;
00079     typedef std::function<void ()>      FinishFn;
00080     typedef std::function<void ()>      UpdateFn;
00081 
00082     TweenBase( void *target, bool copyStartValue, float startTime, float duration, EaseFn easeFunction = easeNone );
00083     virtual ~TweenBase() {}
00084 
00086     void    setEaseFn( EaseFn easeFunction ) { mEaseFunction = easeFunction; }
00087     EaseFn  getEaseFn() const { return mEaseFunction; }
00088 
00089     void            setStartFn( StartFn startFunction ) { mStartFunction = startFunction; }
00090     StartFn         getStartFn() const { return mStartFunction; }
00091 
00092     void            setReverseStartFn( StartFn reverseStartFunction ) { mReverseStartFunction = reverseStartFunction; }
00093     StartFn         getReverseStartFn() const { return mReverseStartFunction; }
00094     
00095     void            setUpdateFn( UpdateFn updateFunction ) { mUpdateFunction = updateFunction; }                                    
00096     UpdateFn        getUpdateFn() const { return mUpdateFunction; }
00097                                                                                                                                                     
00098     void            setFinishFn( FinishFn finishFn ) { mFinishFunction = finishFn; }
00099     FinishFn        getFinishFn() const { return mFinishFunction; }
00100 
00101     void            setReverseFinishFn( FinishFn reverseFinishFn ) { mReverseFinishFunction = reverseFinishFn; }
00102     FinishFn        getReverseFinishFn() const { return mReverseFinishFunction; }
00103     
00104     class Options {
00105       protected:
00106         Options( TimelineRef timeline )
00107             : mTimeline( timeline )
00108         {}
00109 
00110         void    appendTo( TweenBase &tweenBase, void *target, float offset );
00111         void    timelineEnd( TweenBase &tweenBase, float offset );
00112       
00113         TimelineRef     mTimeline;
00114     };
00115     
00116   protected:
00117     virtual void reset( bool unsetStarted )
00118     {
00119         TimelineItem::reset( unsetStarted );
00120     }
00121 
00122     virtual void complete( bool reverse )
00123     {
00124         if( reverse && mReverseFinishFunction )
00125             mReverseFinishFunction();
00126         else if( ( ! reverse ) && mFinishFunction )
00127             mFinishFunction();
00128     }
00129 
00130   
00131     StartFn         mStartFunction, mReverseStartFunction;
00132     UpdateFn        mUpdateFunction;    
00133     FinishFn        mFinishFunction, mReverseFinishFunction;
00134   
00135     EaseFn      mEaseFunction;
00136     float       mDuration;
00137     bool        mCopyStartValue;
00138 };
00139 
00140 template<typename T>
00141 class TweenRef : public std::shared_ptr<Tween<T> > {
00142   public:
00143     TweenRef( const std::shared_ptr<Tween<T> > &sp )
00144         : std::shared_ptr<Tween<T> >( sp )
00145     {}
00146     TweenRef( Tween<T> *tween )
00147         : std::shared_ptr<Tween<T> >( tween )
00148     {}
00149     TweenRef()
00150         : std::shared_ptr<Tween<T> >()
00151     {}
00152 };
00153         
00154 template<typename T>
00155 class Tween : public TweenBase {
00156   public:
00157     typedef std::function<T (const T&, const T&, float)>    LerpFn;
00158 
00159     // build a tween with a target, target value, duration, and optional ease function
00160     Tween( T *target, T endValue, float startTime, float duration,
00161             EaseFn easeFunction = easeNone, LerpFn lerpFunction = &tweenLerp<T> )
00162         : TweenBase( target, true, startTime, duration, easeFunction ), mStartValue( *target ), mEndValue( endValue ), mLerpFunction( lerpFunction )
00163     {
00164     }
00165     
00166     Tween( T *target, T startValue, T endValue, float startTime, float duration,
00167             EaseFn easeFunction = easeNone, LerpFn lerpFunction = &tweenLerp<T> )
00168         : TweenBase( target, false, startTime, duration, easeFunction ), mStartValue( startValue ), mEndValue( endValue ), mLerpFunction( lerpFunction )
00169     {
00170     }
00171     
00172     virtual ~Tween() {}
00173     
00175     T   getStartValue() const { return mStartValue; }
00176     T   getEndValue() const { return mEndValue; }           
00177     T*  getTarget() const { return reinterpret_cast<T*>( mTarget ); }
00178     
00180     bool    isCopyStartValue() { return mCopyStartValue; }
00181 
00182     void    setLerpFn( const LerpFn &lerpFn ) { mLerpFunction = lerpFn; }
00183 
00185     TweenRef<T>     getThisRef(){ return TweenRef<T>( std::static_pointer_cast<Tween<T> >( shared_from_this() ) ); }
00186 
00187 
00188     class Options : public TweenBase::Options {
00189       public:
00190         Options&    startFn( const TweenBase::StartFn &startFn ) { mTweenRef->setStartFn( startFn ); return *this; }
00191         Options&    reverseStartFn( const TweenBase::StartFn &reverseStartFn ) { mTweenRef->setReverseStartFn( reverseStartFn ); return *this; }
00192         Options&    updateFn( const TweenBase::UpdateFn &updateFn ) { mTweenRef->setUpdateFn( updateFn ); return *this; }
00193         Options&    finishFn( const TweenBase::FinishFn &finishFn ) { mTweenRef->setFinishFn( finishFn ); return *this; }
00194         Options&    reverseFinishFn( const TweenBase::FinishFn &reverseFinishFn ) { mTweenRef->setReverseFinishFn( reverseFinishFn ); return *this; }
00195         Options&    easeFn( const EaseFn &easeFunc ) { mTweenRef->setEaseFn( easeFunc ); return *this; }
00196         Options&    delay( float delayAmt ) { mTweenRef->setStartTime( mTweenRef->getStartTime() + delayAmt ); return *this; }
00197         Options&    startTime( float time ) { mTweenRef->setStartTime( time ); return *this; }
00198         Options&    autoRemove( bool remove = true ) { mTweenRef->setAutoRemove( remove ); return *this; }
00199         Options&    loop( bool doLoop = true ) { mTweenRef->setLoop( doLoop ); return *this; }
00200         Options&    pingPong( bool doPingPong = true ) { mTweenRef->setPingPong( doPingPong ); return *this; }
00201         Options&    infinite( bool doInfinite = true ) { mTweenRef->setInfinite( doInfinite ); return *this; }
00202         Options&    timelineEnd( float offset = 0 ) { TweenBase::Options::timelineEnd( *mTweenRef, offset ); return *this; }
00203         template<typename Y>
00204         Options&    appendTo( Anim<Y> *endTarget, float offset = 0 ) { TweenBase::Options::appendTo( *mTweenRef, endTarget->ptr(), offset ); return *this; }    
00205         Options&    appendTo( void *endTarget, float offset = 0 ) { TweenBase::Options::appendTo( *mTweenRef, endTarget, offset ); return *this; }  
00206         Options&    lerpFn( const typename Tween<T>::LerpFn &lerpFn ) { mTweenRef->setLerpFn( lerpFn ); return *this; }
00207         
00208         operator TweenRef<T>() { return mTweenRef; }
00209 
00210       protected:
00211         Options( TweenRef<T> tweenRef, TimelineRef timeline )
00212             : TweenBase::Options( timeline ), mTweenRef( tweenRef )
00213         {}
00214                 
00215         TweenRef<T>     mTweenRef;
00216         
00217         friend class Timeline;
00218     };
00219 
00220 
00221   protected:
00222     virtual void reverse()
00223     {
00224         std::swap( mStartValue, mEndValue );
00225     }
00226 
00227     virtual TimelineItemRef clone() const
00228     {
00229         std::shared_ptr<Tween<T> > result( new Tween<T>( *this ) );
00230         result->mCopyStartValue = false;
00231         return result;
00232     }
00233     
00234     virtual TimelineItemRef cloneReverse() const
00235     {
00236         std::shared_ptr<Tween<T> > result( new Tween<T>( *this ) );
00237         std::swap( result->mStartValue, result->mEndValue );
00238         result->mCopyStartValue = false;
00239         return result;
00240     }
00241     
00242     virtual void start( bool reverse )
00243     {
00244         if( mCopyStartValue )
00245             mStartValue = *(reinterpret_cast<T*>( mTarget ) );
00246         if( reverse && mReverseStartFunction )
00247             mReverseStartFunction();
00248         else if( ( ! reverse ) && mStartFunction )
00249             mStartFunction();
00250     }
00251     
00252     virtual void update( float relativeTime )
00253     {
00254         *reinterpret_cast<T*>(mTarget) = mLerpFunction( mStartValue, mEndValue, mEaseFunction( relativeTime ) );
00255         if( mUpdateFunction )
00256             mUpdateFunction();
00257     }
00258     
00259 
00260     T   mStartValue, mEndValue; 
00261     
00262     LerpFn              mLerpFunction;
00263 };
00264 
00265 template<typename T>
00266 class FnTween : public Tween<T> {
00267   public:
00268     FnTween( std::function<void (T)> fn, T startValue, T endValue, float startTime, float duration, EaseFn easeFunction = easeNone, typename Tween<T>::LerpFn lerpFunction = &tweenLerp<T> )
00269         : Tween<T>( &mValue, startValue, endValue, startTime, duration, easeFunction, lerpFunction ), mFn( fn ), mValue( startValue )
00270     {
00271     }
00272     
00273     virtual void update( float relativeTime )
00274     {
00275         Tween<T>::update( relativeTime );
00276         if( mFn )
00277             mFn( mValue );
00278     }   
00279     
00280     std::function<void (T)>     mFn;
00281     T                           mValue;
00282 };
00283 
00284 template<typename T>
00285 class FnTweenRef : public TweenRef<T> {
00286   public:
00287     FnTweenRef( const std::shared_ptr<FnTween<T> > &sp )
00288         : TweenRef<T>( sp )
00289     {}
00290     FnTweenRef( FnTween<T> *fnTween )
00291         : TweenRef<T>( fnTween )
00292     {}
00293     FnTweenRef()
00294         : TweenRef<T>()
00295     {}
00296 };
00297 
00298 class AnimBase {
00299   public:
00301     void    stop();
00302 
00304     bool isComplete() const;
00305     
00307     TimelineRef getParent() const { return mParentTimeline; }
00308 
00309   protected:
00310     AnimBase( void *voidPtr ) : mVoidPtr( voidPtr ) {}
00311     AnimBase( const AnimBase &rhs, void *voidPtr );
00312     ~AnimBase();
00313     
00314     void    set( const AnimBase &rhs );
00315     void    setReplace( const AnimBase &rhs );
00316     
00317     void        setParentTimeline( TimelineRef parentTimeline );
00318 
00319     void            *mVoidPtr;  
00320     TimelineRef     mParentTimeline;
00321 };
00322 
00323 template<typename T>
00324 class Anim : public AnimBase {
00325   public:
00326     Anim()
00327         : AnimBase( &mValue )
00328     {}
00329     Anim( T value ) 
00330         : AnimBase( &mValue), mValue( value )
00331     {}
00332     Anim( const Anim<T> &rhs ) // normal copy constructor
00333         : AnimBase( rhs, &mValue ), mValue( rhs.mValue )
00334     {}
00335     
00336     const T&    operator()() const { return mValue; }
00337     T&          operator()() { return mValue; } 
00338     
00339     operator const T&() const { return mValue; }    
00340     Anim<T>& operator=( const Anim &rhs ) { // copy assignment
00341         if( this != &rhs ) {
00342             set( rhs );
00343             mValue = rhs.mValue;
00344         }
00345         return *this;
00346     }
00347 
00348     Anim( Anim &&rhs ) // move constructor
00349         : AnimBase( &mValue )
00350     {
00351         setReplace( rhs );
00352         rhs.mParentTimeline.reset(); // blow away rhs's tweens due to move semantics
00353         mValue = rhs.mValue;
00354     }
00355     Anim<T>& operator=( Anim &&rhs ) { // move assignment
00356         if( this != &rhs ) {
00357             setReplace( rhs );
00358             rhs.mParentTimeline.reset(); // blow away rhs's tweens due to move semantics
00359             mValue = rhs.mValue;
00360         }
00361         return *this;
00362     }
00363 
00364     Anim<T>& operator=( T value ) { mValue = value; return *this; }
00365 
00366     const T&    value() const { return mValue; }
00367     T&          value() { return mValue; }
00368     
00369     const T*        ptr() const { return &mValue; }
00370     T*              ptr() { return &mValue; }
00371 
00372   protected:
00373 
00374     friend class Timeline;
00375 
00376     T               mValue;
00377 };
00378 
00379 //typedef boost::instrusive_ptr<TweenBase>  TweenBaseRef;
00380 
00381 /*class TweenScope {
00382   public:
00383     TweenScope() {}
00384     TweenScope( const TweenScope &rhs ) {}  // do nothing for copy; these are our tweens alone
00385     TweenScope& operator=( const TweenScope &rhs ) { return *this; }    // do nothing for copy; these are our tweens alone  
00386     ~TweenScope();
00387     
00388     TweenScope& operator+=( TimelineItemRef item );
00389     void add( TimelineItemRef item );
00390 
00391   private:
00392     std::list<std::weak_ptr<TimelineItem> >     mItems;
00393 };*/
00394 
00395 } //namespace cinder