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