00001 #include "global.h"
00002 #include "MercuryObjectCommands.h"
00003 #include "MercuryObject.h"
00004 #include "MercuryUtil.h"
00005 #include "MercuryMath.h"
00006 #include "MercuryLog.h"
00007
00008 using namespace std;
00009
00010
00011 AutoCommandRegisterer CommandRegisterer;
00012
00013 map< MString, vector< MercuryTween * > > MercuryTweenState::m_GlobalTweens;
00014
00015 MercuryTweenFunction AutoCommandRegisterer::GetFunction( const MString &name )
00016 {
00017 if ((sMapFunctions == NULL) || (sMapFunctions->find( name ) == sMapFunctions->end() ))
00018 return NULL;
00019
00020 return (*sMapFunctions)[name];
00021 }
00022
00023 int AutoCommandRegisterer::RegisterFunction( MercuryTweenFunction fnct, const MString & name )
00024 {
00025 if ( sMapFunctions == NULL )
00026 sMapFunctions = new map< MString, MercuryTweenFunction >;
00027
00028 (*sMapFunctions)[name] = fnct;
00029
00030 sNumFunctions++;
00031
00032 return sNumFunctions;
00033 }
00034
00035 MercuryTweenType AutoCommandRegisterer::GetTweenType( const MString &name )
00036 {
00037 if ((sMapTweens == NULL) || (sMapTweens->find( name ) == sMapTweens->end() ))
00038 return NULL;
00039
00040 return (*sMapTweens)[name];
00041 }
00042
00043 int AutoCommandRegisterer::RegisterTweenType( MercuryTweenType fnct, const MString & name )
00044 {
00045 if ( sMapTweens == NULL )
00046 sMapTweens = new map< MString, MercuryTweenType >;
00047
00048 (*sMapTweens)[name] = fnct;
00049
00050 sNumFunctions++;
00051
00052 return sNumFunctions;
00053 }
00054
00055
00056 #define STD_COMMAND( x, y, z ) \
00057 static void CMD##x( const float fPercent, const float fLastPercent, MercuryObject * pObject, MercuryTweenOperation * pOperation ) \
00058 { \
00059 float newloc; \
00060 if ( pOperation->Parameters.PeekItem().GetType() == PSElement::PARAMETER ) {\
00061 newloc = pObject->Tweening.m_pCurrentTween->pKArgs.PeekItem( pOperation->Parameters.PeekItem().GetValueI() ).GetValueF(); \
00062 } else \
00063 newloc = pOperation->Parameters.PeekItem().GetValueF(); \
00064 float oldloc = pObject->Get##x(); \
00065 float diffloc = newloc-oldloc; \
00066 float totalmove = diffloc/(1-fLastPercent); \
00067 float fToMove = totalmove * ( fPercent - fLastPercent ); \
00068 pObject->Set##x( (z)( fToMove + oldloc ) ); \
00069 } \
00070 \
00071 static int FunctionNumberCMD##x = CommandRegisterer.RegisterFunction( CMD##x, y );
00072
00073 #define STD_FLOAT_COMMAND( x, y ) STD_COMMAND( x, y, float )
00074
00075 STD_FLOAT_COMMAND( X, "x" )
00076 STD_FLOAT_COMMAND( Y, "y" )
00077 STD_FLOAT_COMMAND( Z, "z" )
00078 STD_FLOAT_COMMAND( RotX, "rotationx" )
00079 STD_FLOAT_COMMAND( RotY, "rotationy" )
00080 STD_FLOAT_COMMAND( RotZ, "rotationz" )
00081 STD_FLOAT_COMMAND( ScaleX, "scalex" )
00082 STD_FLOAT_COMMAND( ScaleY, "scaley" )
00083 STD_FLOAT_COMMAND( ScaleZ, "scalez" )
00084 STD_COMMAND( DrawOrder, "draworder", int )
00085
00086
00087
00088 static void ExecuteObjectCommand( const float fPercent, const float fLastPercent, MercuryObject * pObject, MercuryTweenOperation * pOperation )
00089 {
00090 if ( fPercent == 1 )
00091 {
00092 PStack ret;
00093 pObject->Command( ret, pOperation->Command, pOperation->Parameters );
00094 }
00095 }
00096
00097 static int FunctionNumberExecCommand = CommandRegisterer.RegisterFunction( ExecuteObjectCommand, "cmd" );
00098
00099
00100 #define ADD_COLOR_COMMAND( x, y ) \
00101 static void ADDCCMD##x( const float fPercent, const float fLastPercent, MercuryObject * pObject, MercuryTweenOperation * pOperation ) \
00102 { \
00103 MercuryColor newloc; \
00104 if ( pOperation->Parameters.PeekItem(0).GetType() == PSElement::PARAMETER ) \
00105 newloc.SetR( pObject->Tweening.m_pCurrentTween->pKArgs.PeekItem( pOperation->Parameters.PeekItem(0).GetValueI() ).GetValueF() ); \
00106 else \
00107 newloc.SetR( pOperation->Parameters.PeekItem(0).GetValueF() ); \
00108 if ( pOperation->Parameters.PeekItem(1).GetType() == PSElement::PARAMETER ) \
00109 newloc.SetG( pObject->Tweening.m_pCurrentTween->pKArgs.PeekItem( pOperation->Parameters.PeekItem(1).GetValueI() ).GetValueF() ); \
00110 else \
00111 newloc.SetG( pOperation->Parameters.PeekItem(1).GetValueF() ); \
00112 if ( pOperation->Parameters.PeekItem(2).GetType() == PSElement::PARAMETER ) \
00113 newloc.SetB( pObject->Tweening.m_pCurrentTween->pKArgs.PeekItem( pOperation->Parameters.PeekItem(2).GetValueI() ).GetValueF() ); \
00114 else \
00115 newloc.SetB( pOperation->Parameters.PeekItem(2).GetValueF() ); \
00116 if ( pOperation->Parameters.PeekItem(3).GetType() == PSElement::PARAMETER ) \
00117 newloc.SetA( pObject->Tweening.m_pCurrentTween->pKArgs.PeekItem( pOperation->Parameters.PeekItem(3).GetValueI() ).GetValueF() ); \
00118 else \
00119 newloc.SetA( pOperation->Parameters.PeekItem(3).GetValueF() ); \
00120 \
00121 MercuryColor oldloc = pObject->Get##x(); \
00122 MercuryColor diffloc = newloc-oldloc; \
00123 MercuryColor totalmove = diffloc*(1/(1-fLastPercent)); \
00124 MercuryColor fToMove = totalmove * ( fPercent - fLastPercent ); \
00125 \
00126 pObject->Set##x( fToMove + oldloc ); \
00127 } \
00128 \
00129 static int FunctionADDCCMD##x = CommandRegisterer.RegisterFunction( ADDCCMD##x, y );
00130
00131 ADD_COLOR_COMMAND( Diffuse, "diffuse" )
00132 ADD_COLOR_COMMAND( Ambient, "ambient" )
00133 ADD_COLOR_COMMAND( Emissive, "emissive" )
00134 ADD_COLOR_COMMAND( Specular, "specular" )
00135
00136 #define ADD_COMMAND( x, y ) \
00137 static void ADDCMD##x( const float fPercent, const float fLastPercent, MercuryObject * pObject, MercuryTweenOperation * pOperation ) \
00138 { \
00139 float diffloc = pOperation->Parameters.PeekItem().GetValueF(); \
00140 float oldloc = pObject->Get##x(); \
00141 float totalmove = diffloc*(fPercent-fLastPercent); \
00142 float fToMove = totalmove; \
00143 pObject->Set##x( fToMove + oldloc ); \
00144 } \
00145 \
00146 static int FunctionNumberADDCMD##x = CommandRegisterer.RegisterFunction( ADDCMD##x, y );
00147
00148 ADD_COMMAND( X, "addx" )
00149 ADD_COMMAND( Y, "addy" )
00150 ADD_COMMAND( Z, "addz" )
00151 ADD_COMMAND( RotX, "addrotationx" )
00152 ADD_COMMAND( RotY, "addrotationy" )
00153 ADD_COMMAND( RotZ, "addrotationz" )
00154
00155 static void CommandHide( const float fPercent, const float fLastPercent, MercuryObject * pObject, MercuryTweenOperation * pOperation )
00156 {
00157 bool hideON = (pOperation->Parameters.PeekItem().GetValueF() > 0.5f );
00158 if ( fPercent > 0.5f )
00159 pObject->SetHide( hideON );
00160 }
00161 static int FunctionHideNumber = CommandRegisterer.RegisterFunction( CommandHide, "hide" );
00162
00163
00164 static float TweenLinear( const float fPercent, PStack & pArgs )
00165 {
00166 return fPercent;
00167 }
00168
00169 static float TweenSleep( const float fPercent, PStack & pArgs )
00170 {
00171 if ( fPercent == 1 )
00172 return 1;
00173 else
00174 return 0;
00175 }
00176
00177 static float TweenQuadratic( const float fPercent, PStack & pArgs )
00178 {
00179 return powf(fPercent,pArgs.PeekItem().GetValueF());
00180 }
00181
00182 static int FunctionNumberCMDlinear = CommandRegisterer.RegisterTweenType( TweenLinear, "linear" );
00183 static int FunctionNumberCMDsleep = CommandRegisterer.RegisterTweenType( TweenSleep, "sleep" );
00184 static int FunctionNumberCMDquadratic = CommandRegisterer.RegisterTweenType( TweenQuadratic, "quadratic" );
00185
00186
00187
00188
00189 MercuryTween::MercuryTween() :
00190 fStart(0), fEnd(0)
00191 {
00192
00193 bDeleteChildren = true;
00194 iEndBase = -1;
00195 }
00196
00197 MercuryTween::MercuryTween( const MercuryTween & rhs )
00198 {
00199 for( unsigned i = 0; i < rhs.Operations.size(); i++ )
00200 Operations.push_back( new MercuryTweenOperation( *rhs.Operations[i] ) );
00201 fStart = rhs.fStart;
00202 fEnd = rhs.fEnd;
00203 pTT = rhs.pTT;
00204 pTArgs = rhs.pTArgs;
00205 pKArgs = rhs.pKArgs;
00206 bAutoDelete = rhs.bAutoDelete;
00207 bDeleteChildren = rhs.bDeleteChildren;
00208 iEndBase = rhs.iEndBase;
00209 }
00210
00211 MercuryTween & MercuryTween::operator = ( const MercuryTween & rhs )
00212 {
00213 for( unsigned i = 0; i < rhs.Operations.size(); i++ )
00214 Operations.push_back( new MercuryTweenOperation( *rhs.Operations[i] ) );
00215 fStart = rhs.fStart;
00216 fEnd = rhs.fEnd;
00217 pTT = rhs.pTT;
00218 pTArgs = rhs.pTArgs;
00219 pKArgs = rhs.pKArgs;
00220 bAutoDelete = rhs.bAutoDelete;
00221 bDeleteChildren = rhs.bDeleteChildren;
00222 iEndBase = rhs.iEndBase;
00223 return *this;
00224 }
00225
00226 MercuryTween::~MercuryTween()
00227 {
00228 if ( bDeleteChildren )
00229 for( unsigned i = 0; i < Operations.size(); i++ )
00230 SAFE_DELETE( Operations[i] );
00231 }
00232
00233 void MercuryTween::Operate( const float fPercent, const float fLastPercent, MercuryObject * pObject )
00234 {
00235 for ( unsigned i = 0; i < Operations.size(); i++ )
00236 Operations[i]->Function( fPercent, fLastPercent, pObject, Operations[i] );
00237 }
00238
00239 MercuryTweenState::MercuryTweenState( )
00240 :m_fCurTime(0), m_bPauseTweening(false), m_bCloned( false )
00241 {
00242
00243 m_fRunningEnd = 0;
00244 m_pCurrentTween = NULL;
00245 }
00246
00247 MercuryTweenState::MercuryTweenState( const MercuryTweenState & rhs ) :
00248 m_fCurTime(rhs.m_fCurTime),
00249 m_bPauseTweening(rhs.m_bPauseTweening),
00250 m_fRunningEnd(rhs.m_fRunningEnd), m_LocalTweens(rhs.m_LocalTweens),
00251 m_bCloned( true )
00252 {
00253 MDequeIterator< MercuryTween *> i;
00254 for( i = m_qTweens.begin(); i != m_qTweens.end(); ++i )
00255 m_qTweens.push_back( new MercuryTween( *i.Data() ) );
00256 m_pCurrentTween = NULL;
00257 }
00258
00259 MercuryTweenState & MercuryTweenState::operator = ( const MercuryTweenState & rhs )
00260 {
00261 m_bCloned = true;
00262 m_bPauseTweening = rhs.m_bPauseTweening;
00263 m_fCurTime = rhs.m_fCurTime;
00264 m_fRunningEnd = rhs.m_fRunningEnd;
00265 m_LocalTweens = rhs.m_LocalTweens;
00266 MDequeIterator< MercuryTween *> i;
00267 for( i = rhs.m_qTweens.begin(); i != rhs.m_qTweens.end(); ++i )
00268 m_qTweens.push_back( new MercuryTween( *i.Data() ) );
00269 m_pCurrentTween = NULL;
00270 return *this;
00271 }
00272
00273 MercuryTweenState::~MercuryTweenState()
00274 {
00275 StopTweening();
00276 if( !m_bCloned )
00277 {
00278 map< MString, vector< MercuryTween * > >::iterator g = m_LocalTweens.begin();
00279 for( ; g != m_LocalTweens.end(); g++ )
00280 {
00281 for ( unsigned i = 0; i < (g->second).size(); i++ )
00282 SAFE_DELETE( (g->second)[i] );
00283 }
00284 }
00285 }
00286
00287 void MercuryTweenState::AttachToObject( MercuryObject * object )
00288 {
00289 m_pObject = object;
00290 }
00291
00292 void MercuryTweenState::Update( float fDeltaTime )
00293 {
00294 if ( !m_bPauseTweening )
00295 m_fCurTime += fDeltaTime;
00296
00297 InternalUpdate( fDeltaTime );
00298 }
00299
00300 void MercuryTweenState::FinishTweening()
00301 {
00302 InternalUpdate( 0, true );
00303 }
00304
00305 void MercuryTweenState::StopTweening()
00306 {
00307 m_pCurrentTween = NULL;
00308
00309 while ( !m_qTweens.empty() )
00310 {
00311 if ( m_qTweens.front()->bAutoDelete )
00312 SAFE_DELETE( m_qTweens.front() );
00313 m_qTweens.pop_front();
00314 }
00315 }
00316
00317 void MercuryTweenState::InternalUpdate( float fDeltaTime, bool bFinish )
00318 {
00319 while ( !m_qTweens.empty() )
00320 {
00321 if ( !m_pCurrentTween && (m_qTweens.front()->fStart <= m_fCurTime) )
00322 m_pCurrentTween = m_qTweens.front();
00323
00324 if ( bFinish )
00325 if ( m_pCurrentTween->fEnd > m_fCurTime )
00326 {
00327
00328
00329
00330 fDeltaTime += ( m_pCurrentTween->fEnd - m_fCurTime );
00331 m_fCurTime = m_pCurrentTween->fEnd;
00332 }
00333
00334 if ( m_pCurrentTween->fEnd <= m_fCurTime )
00335 {
00336 float curPercent = 1;
00337 float lastPercent = CalculateRemainingPercent( fDeltaTime );
00338
00339 lastPercent = Clamp( lastPercent, 0.0f, 1.0f);
00340 m_pCurrentTween->Operate( curPercent, lastPercent, m_pObject );
00341
00342
00343 m_qTweens.pop_front();
00344 if ( m_pCurrentTween->bAutoDelete )
00345 SAFE_DELETE( m_pCurrentTween );
00346 m_pCurrentTween = NULL;
00347 } else {
00348 float curPercent = CalculateCurrentPercent( fDeltaTime );
00349 float lastPercent = CalculateRemainingPercent( fDeltaTime );
00350
00351
00352 lastPercent = Clamp( lastPercent, 0.0f, 1000.0f );
00353 m_pCurrentTween->Operate( m_pCurrentTween->pTT(curPercent,m_pCurrentTween->pTArgs),
00354 m_pCurrentTween->pTT(lastPercent,m_pCurrentTween->pTArgs), m_pObject );
00355 break;
00356 }
00357 }
00358 }
00359
00360 float MercuryTweenState::CalculateRemainingPercent( float fDeltaTime )
00361 {
00362 float percent, fDeltaTweenTime;
00363 percent = 0;
00364 fDeltaTweenTime = m_pCurrentTween->fEnd - m_pCurrentTween->fStart;
00365 if (fDeltaTweenTime > 0)
00366 percent = ( m_fCurTime - fDeltaTime - m_pCurrentTween->fStart ) / fDeltaTweenTime ;
00367 return percent;
00368 }
00369
00370 float MercuryTweenState::CalculateCurrentPercent( float fDeltaTime )
00371 {
00372 float percent, fDeltaTweenTime;
00373 percent = 0;
00374 fDeltaTweenTime = m_pCurrentTween->fEnd - m_pCurrentTween->fStart;
00375 if (fDeltaTweenTime > 0)
00376 percent = ( m_fCurTime - m_pCurrentTween->fStart ) / fDeltaTweenTime ;
00377 return percent;
00378 }
00379
00380 void MercuryTweenState::ExecuteCommand( const MString & sName, const PStack & pKArgs )
00381 {
00382 vector< MercuryTween * > * AllTweens = NULL;
00383 if ( m_LocalTweens.find( sName ) == m_LocalTweens.end() )
00384 {
00385 if ( m_GlobalTweens.find( sName ) == m_GlobalTweens.end() )
00386 AllTweens = NULL;
00387 else
00388 AllTweens = &m_GlobalTweens[sName];
00389 } else
00390 AllTweens = &m_LocalTweens[sName];
00391
00392 if ( AllTweens == NULL )
00393 return;
00394
00395 vector< MercuryTween * >::iterator g = AllTweens->begin();
00396 for ( ; g != AllTweens->end(); g++ )
00397 {
00398 MercuryTween * Copied = new MercuryTween;
00399
00400 if ( (*g)->iEndBase >= 0 )
00401 Copied->fEnd = pKArgs.PeekItem( (*g)->iEndBase ).GetValueF();
00402 else
00403 Copied->fEnd = (*g)->fEnd;
00404 Copied->fStart = 0;
00405 Copied->pTT = (*g)->pTT;
00406 Copied->pTArgs = (*g)->pTArgs;
00407 Copied->Operations = (*g)->Operations;
00408 Copied->pKArgs = pKArgs;
00409 Copied->bAutoDelete = true;
00410 Copied->bDeleteChildren = false;
00411 AddCommand( Copied );
00412 }
00413 }
00414
00415 void MercuryTweenState::AddCommand( MercuryTween * ToPush, float fFuture, SPACE iWhichPlace, MString sTweenName )
00416 {
00417 if ( m_qTweens.size() > 0 )
00418 {
00419 ToPush->fStart += m_fRunningEnd;
00420 ToPush->fEnd += m_fRunningEnd;
00421 } else if ( fFuture >= 0 )
00422 {
00423 ToPush->fStart += m_fCurTime;
00424 ToPush->fEnd += ToPush->fStart;
00425 }
00426
00427 switch ( iWhichPlace )
00428 {
00429 case CURRENT:
00430 ToPush->bAutoDelete = true;
00431 m_qTweens.push_back( ToPush );
00432 break;
00433 case LOCAL:
00434 ToPush->bAutoDelete = false;
00435 m_LocalTweens[sTweenName].push_back( ToPush );
00436 break;
00437 case GLOBAL:
00438 ToPush->bAutoDelete = false;
00439 m_GlobalTweens[sTweenName].push_back( ToPush );
00440 break;
00441 default:
00442 LOG.Warn( "Requested AddCommand to non-existant tween 'place'. This tween will leak." );
00443 break;
00444 };
00445
00446 m_fRunningEnd = ToPush->fEnd;
00447
00448
00449
00450
00451
00452 if ( (m_qTweens.size() == 1) && (fFuture <= 0.0f) )
00453 InternalUpdate( 0 );
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463 void MercuryTweenState::AddCommand( const MString & command, SPACE iWhichPlace, MString sTweenName )
00464 {
00465 const char *sCmd = command.c_str();
00466 const char *sEnd = sCmd + command.length();
00467 const char *sNext = 0;
00468 const char *sCur = sCmd;
00469 const char *sNextComma = 0;
00470 char * sTmp;
00471 unsigned int iTmp;
00472 bool bHasNextPart;
00473 MString sBaseCmd;
00474 MercuryTween * cs = new MercuryTween;
00475 cs->fEnd = -1;
00476
00477
00478 switch ( iWhichPlace )
00479 {
00480 case LOCAL:
00481 for ( iTmp = 0; iTmp < m_LocalTweens[sTweenName].size(); ++iTmp )
00482 SAFE_DELETE( m_LocalTweens[sTweenName][iTmp] );
00483 m_LocalTweens[sTweenName].clear();
00484 break;
00485 case GLOBAL:
00486 for ( iTmp = 0; iTmp < m_GlobalTweens[sTweenName].size(); ++iTmp )
00487 SAFE_DELETE( m_GlobalTweens[sTweenName][iTmp] );
00488 m_GlobalTweens[sTweenName].clear();
00489 break;
00490 default:
00491 break;
00492 }
00493
00494
00495 while ( sCur < sEnd && sCur[0] != '\0' )
00496 {
00497
00498 sNext = strchr( sCur, ';' );
00499 if ( !sNext )
00500 sNext = sEnd;
00501
00502
00503
00504 sNextComma = strchr( sCur, ',' );
00505 if ( sNextComma > sNext || !sNextComma )
00506 {
00507 bHasNextPart = false;
00508 sNextComma = sNext;
00509 } else
00510 bHasNextPart = true;
00511
00512
00513 sBaseCmd.assign( sCur, sNextComma - sCur );
00514
00515
00516
00517 sCur = sNextComma+1;
00518
00519
00520 MercuryTweenFunction fnct = CommandRegisterer.GetFunction( sBaseCmd );
00521 MercuryTweenType typ = CommandRegisterer.GetTweenType( sBaseCmd );
00522
00523
00524
00525
00526
00527
00528 if ( typ == NULL && cs->fEnd < 0 )
00529 {
00530 cs->fEnd = 0;
00531 cs->pTT = CommandRegisterer.GetTweenType( "sleep" );
00532 cs->fStart = 0;
00533 }
00534
00535 if ( typ != NULL )
00536 {
00537
00538
00539
00540 if ( cs->fEnd >= 0 )
00541 {
00542
00543 AddCommand( cs, 0, iWhichPlace, sTweenName );
00544 cs = new MercuryTween;
00545 }
00546
00547
00548 cs->pTT = typ;
00549
00550
00551 if ( !bHasNextPart )
00552 {
00553 cs->fEnd = 0;
00554 cs->pTArgs.Clear();
00555 } else {
00556
00557 sNextComma = strchr( sCur, ',' );
00558 if ( sNextComma > sNext || !sNextComma )
00559 sNextComma = sNext;
00560
00561 iTmp = sNextComma - sCur;
00562 sTmp = (char*)malloc( sNextComma - sCur + 1 );
00563 strncpy( sTmp, sCur, iTmp );
00564 sTmp[iTmp] = '\0';
00565 cs->fEnd = float(atof( sTmp ));
00566 if ( sTmp[0] == '%' )
00567 cs->iEndBase = atoi( sTmp+1 );
00568 free( sTmp );
00569 sCur = sNextComma+1;
00570
00571
00572 cs->pTArgs = PStack( sCur, sNext - sCur );
00573
00574 if( sCur < sNext )
00575 sCur = sNext + 1;
00576 }
00577 } else if ( fnct != NULL ) {
00578 MercuryTweenOperation * k = new MercuryTweenOperation;
00579 k->Function = fnct;
00580
00581
00582 k->Parameters = PStack( sCur, sNext - sCur );
00583
00584
00585 if ( sCur <= sNext )
00586 sCur = sNext + 1;
00587 cs->Operations.push_back(k);
00588 } else {
00589 fnct = CommandRegisterer.GetFunction( "cmd" );
00590 if ( fnct == NULL )
00591 LOG.Warn( "The object commands function \"cmd\" has not been registered! Your compile may be bad" );
00592 else
00593 {
00594 MercuryTweenOperation *k = new MercuryTweenOperation;
00595 k->Function = fnct;
00596 k->Command = sBaseCmd;
00597 k->Parameters = PStack( sCur, sNext - sCur );
00598 if ( sCur <= sNext )
00599 sCur = sNext + 1;
00600 cs->Operations.push_back(k);
00601 }
00602 }
00603 }
00604 if ( cs->fEnd < 0 )
00605 cs->fEnd = 0;
00606 if ( ( cs->Operations.size() > 0 ) || (cs->fEnd > 0) )
00607 AddCommand( cs, 0, iWhichPlace, sTweenName );
00608 else
00609 SAFE_DELETE( cs );
00610 }
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639