Torque3D Documentation / _generateds / VController.cpp

VController.cpp

Engine/source/Verve/Core/VController.cpp

More...

Public Functions

DefineEngineMethod(VController , clear , void , () , "( void ) - Detaches and deletes all of the child <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n</a>" "@return No return value." )
DefineEngineMethod(VController , getDataFieldCount , S32 , () , "( void ) - Get the number of data elements in the Data <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Table.\n</a>" "@return Returns the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the Data Table." )
DefineEngineMethod(VController , getDataFieldName , const char * , (S32 index) , (0) , "( int pIndex ) - Get the name of the field given by the passed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n</a>" "@param pIndex The index of the data field you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">check.\n</a>" "@return Returns the name of the field corresponding <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given index." )
DefineEngineMethod(VController , getDataFieldType , const char * , (String fieldName) , ("") , "( string pFieldName ) - Get the type of data <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@param pFieldName The name of the field you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">check.\n</a>" "@return Returns the data type." )
DefineEngineMethod(VController , getDataFieldValue , const char * , (String fieldName) , ("") , "( string pFieldName ) - Get the evaluated data from the data <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@param pFieldName The name of the field you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">evaluate.\n</a>" "@return Returns the evaluated data from the field." )
DefineEngineMethod(VController , getTimeScale , F32 , () , "( void ) - Get the playback speed. A value, 0.0 will enable the Controller <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play forwards)
DefineEngineMethod(VController , isDataField , bool , (String fieldName) , ("") , "( string pFieldName ) - Is the field <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> member of the Data Table?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param pFieldName The name of the dynamic field you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">check.\n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the field is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> member of the Data Table." )
DefineEngineMethod(VController , isPaused , bool , () , "( void ) - Is the sequence currently paused?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the Controller is paused." )
DefineEngineMethod(VController , isPlaying , bool , () , "( void ) - Is the sequence currently playing?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the Controller is playing." )
DefineEngineMethod(VController , isStopped , bool , () , "( void ) - Is the sequence currently stopped?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the Controller is stopped." )
DefineEngineMethod(VController , pause , void , () , "( void ) - Pause the sequence. Playback can resume by calling <a href="/coding/class/classvcontroller/#classvcontroller_1ab7f64c3e1fb02310bce1d55d74ae6fff">VController::play</a>().\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return No return value." )
DefineEngineMethod(VController , play , void , (S32 time) , (-1) , "( [int pTime] ) - Play the sequence. If <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> pTime is specified, the Controller is reset and played from that <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">time.\n</a>" " @param pTime The time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> start playing the sequence <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">from.\n</a>" " @return No return value." )
DefineEngineMethod(VController , readFile , bool , (String fileName) , ("") , "( string pFileName ) - Clears the object and loads the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> data from the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">filename.\n</a>" "@param pFileName The target <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> read <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">from.\n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the read was successful." )
DefineEngineMethod(VController , reset , void , (S32 time) , (-1) , "( [int pTime] ) - Reset the Controller's and child object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">state.\n</a>" "@param pTime The target time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> reset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n</a>" "@return No return value." )
DefineEngineMethod(VController , setTimeScale , void , (float timeScale) , (1) , "( float pTimeScale ) - Set the playback speed. A value, 0.0 will enable the Controller <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play forwards, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a0e48c1f64b558d03d870367324920354">while</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a>< 0.0 will play backwards. If|pTimeScale|> 1. 0, then playback will be faster than normal)
DefineEngineMethod(VController , step , void , () , "( void ) - Step forward one <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">frame.\n</a>" "@return No return value." )
DefineEngineMethod(VController , stop , void , (bool reset) , (true) , "( [bool pReset] ) - Stop the sequence and optionally reset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it.\n</a>" "@param pReset Reset the Controller after <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">stopping.\n</a>" "@return No return value." )

Detailed Description

Public Functions

DefineEngineMethod(VController , clear , void , () , "( void ) - Detaches and deletes all of the child <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n</a>" "@return No return value." )

DefineEngineMethod(VController , getDataFieldCount , S32 , () , "( void ) - Get the number of data elements in the Data <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Table.\n</a>" "@return Returns the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the Data Table." )

DefineEngineMethod(VController , getDataFieldName , const char * , (S32 index) , (0) , "( int pIndex ) - Get the name of the field given by the passed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">index.\n</a>" "@param pIndex The index of the data field you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">check.\n</a>" "@return Returns the name of the field corresponding <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given index." )

DefineEngineMethod(VController , getDataFieldType , const char * , (String fieldName) , ("") , "( string pFieldName ) - Get the type of data <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@param pFieldName The name of the field you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">check.\n</a>" "@return Returns the data type." )

DefineEngineMethod(VController , getDataFieldValue , const char * , (String fieldName) , ("") , "( string pFieldName ) - Get the evaluated data from the data <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">field.\n</a>" "@param pFieldName The name of the field you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">evaluate.\n</a>" "@return Returns the evaluated data from the field." )

DefineEngineMethod(VController , getTimeScale , F32 , () , "( void ) - Get the playback speed. A value, 0.0 will enable the Controller <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play forwards)

DefineEngineMethod(VController , isDataField , bool , (String fieldName) , ("") , "( string pFieldName ) - Is the field <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> member of the Data Table?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param pFieldName The name of the dynamic field you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">check.\n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the field is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> member of the Data Table." )

DefineEngineMethod(VController , isPaused , bool , () , "( void ) - Is the sequence currently paused?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the Controller is paused." )

DefineEngineMethod(VController , isPlaying , bool , () , "( void ) - Is the sequence currently playing?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the Controller is playing." )

DefineEngineMethod(VController , isStopped , bool , () , "( void ) - Is the sequence currently stopped?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the Controller is stopped." )

DefineEngineMethod(VController , pause , void , () , "( void ) - Pause the sequence. Playback can resume by calling <a href="/coding/class/classvcontroller/#classvcontroller_1ab7f64c3e1fb02310bce1d55d74ae6fff">VController::play</a>().\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return No return value." )

DefineEngineMethod(VController , play , void , (S32 time) , (-1) , "( [int pTime] ) - Play the sequence. If <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> pTime is specified, the Controller is reset and played from that <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">time.\n</a>" " @param pTime The time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> start playing the sequence <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">from.\n</a>" " @return No return value." )

DefineEngineMethod(VController , readFile , bool , (String fileName) , ("") , "( string pFileName ) - Clears the object and loads the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> data from the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">filename.\n</a>" "@param pFileName The target <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> read <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">from.\n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the read was successful." )

DefineEngineMethod(VController , reset , void , (S32 time) , (-1) , "( [int pTime] ) - Reset the Controller's and child object's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">state.\n</a>" "@param pTime The target time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> reset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n</a>" "@return No return value." )

DefineEngineMethod(VController , setTimeScale , void , (float timeScale) , (1) , "( float pTimeScale ) - Set the playback speed. A value, 0.0 will enable the Controller <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play forwards, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a0e48c1f64b558d03d870367324920354">while</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a>< 0.0 will play backwards. If|pTimeScale|> 1. 0, then playback will be faster than normal)

DefineEngineMethod(VController , step , void , () , "( void ) - Step forward one <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">frame.\n</a>" "@return No return value." )

DefineEngineMethod(VController , stop , void , (bool reset) , (true) , "( [bool pReset] ) - Stop the sequence and optionally reset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it.\n</a>" "@param pReset Reset the Controller after <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">stopping.\n</a>" "@return No return value." )

IMPLEMENT_CONOBJECT(VController )

   1
   2//-----------------------------------------------------------------------------
   3// Verve
   4// Copyright (C) 2014 - Violent Tulip
   5//
   6// Permission is hereby granted, free of charge, to any person obtaining a copy
   7// of this software and associated documentation files (the "Software"), to
   8// deal in the Software without restriction, including without limitation the
   9// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10// sell copies of the Software, and to permit persons to whom the Software is
  11// furnished to do so, subject to the following conditions:
  12//
  13// The above copyright notice and this permission notice shall be included in
  14// all copies or substantial portions of the Software.
  15//
  16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22// IN THE SOFTWARE.
  23//-----------------------------------------------------------------------------
  24#include "Verve/Core/VController.h"
  25#include "Verve/Core/VObject.h"
  26#include "Verve/Core/VGroup.h"
  27#include "Verve/Core/VTrack.h"
  28
  29#include "Verve/Extension/Director/VDirectorGroup.h"
  30
  31#include "console/consoleObject.h"
  32#include "console/consoleTypes.h"
  33#include "math/mMathFn.h"
  34
  35//-----------------------------------------------------------------------------
  36IMPLEMENT_CONOBJECT( VController );
  37//-----------------------------------------------------------------------------
  38
  39VController::VController( void ) :
  40        mStatus( ( k_StatusInit | k_StatusStopped ) ),
  41        mTime( 0 ),
  42        mLastTime( 0 ),
  43        mTimeScale( 1.f ),
  44        mDuration( 5000 ),
  45        mLoop( false ),
  46        mLoopBackwards( false ),
  47        mLoopCount( -1 ),
  48        mLoopIndex( 0 ),
  49        mLoopDelay( 0 ),
  50        mLoopDelayTime( 0 ),
  51        mJump( k_JumpInvalid ),
  52        mJumpTime( 0 ),
  53        mResetOnCompletion( true )
  54{
  55    // Don't Process Ticks.
  56    setProcessTicks( false );
  57}
  58
  59VController::~VController( void )
  60{
  61    // Void.
  62}
  63
  64void VController::initPersistFields( void )
  65{
  66    addGroup( "Controller" );
  67        addProtectedField( "Time",      TypeS32,  Offset( mTime,              VController ), &setTime,      &defaultProtectedGetFn, "Current position of the Controller (in milliseconds)." );
  68        addProtectedField( "Duration",  TypeS32,  Offset( mDuration,          VController ), &setDuration,  &defaultProtectedGetFn, "Total length of the sequence (in milliseconds)." );
  69        addProtectedField( "TimeScale", TypeF32,  Offset( mTimeScale,         VController ), &setTimeScale, &defaultProtectedGetFn, "Speed of playback. A value > 0.0 will enable the Controller to play forwards, while a value < 0.0 will play backwards. If |TimeScale| > 1.0, then playback will be faster than normal, while |TimeScale| < 1.0 will be slower." );
  70
  71        addField( "Loop",               TypeBool, Offset( mLoop,              VController ), "Instead of stopping once playback is complete, the Controller will reset and resume play." );
  72        addField( "LoopBackwards",      TypeBool, Offset( mLoopBackwards,     VController ), "When the sequence loops, reverse the direction of play." );
  73        addField( "LoopCount",          TypeS32,  Offset( mLoopCount,         VController ), "The number of times the sequence loops before stopping. -1 will cause the sequence to loop indefinitely." );
  74        addField( "LoopDelay",          TypeS32,  Offset( mLoopDelay,         VController ), "When the sequence loops, delay playback by this value (in milliseconds)." );
  75
  76        addField( "ResetOnCompletion",  TypeBool, Offset( mResetOnCompletion, VController ), "When the sequence is completed, reset the state of the Controller." );
  77    endGroup( "Controller" );
  78
  79    // Parent Call.
  80    Parent::initPersistFields();
  81}
  82
  83//-----------------------------------------------------------------------------
  84//
  85// ITickable Methods.
  86//
  87//-----------------------------------------------------------------------------
  88
  89//-----------------------------------------------------------------------------
  90// 
  91// VController::processTick();
  92// 
  93// This method controls the playback of the entire sequence. It integrates all
  94// of the groups and handles sequence looping and jumping.
  95// 
  96//-----------------------------------------------------------------------------
  97void VController::processTick( void )
  98{
  99    if ( mTimeScale == 0.f )
 100    {
 101        // Pause.
 102        pause();
 103
 104        // Exit.
 105        return;
 106    }
 107
 108    // Calculate Delta.
 109    const S32 time  = Sim::getCurrentTime();
 110    S32 delta = ( time - mLastTime );
 111    mLastTime = time;
 112
 113    // Reverse?
 114    if ( mTimeScale < 0.f )
 115    {
 116        // Negative Delta.
 117        delta *= -1;
 118    }
 119
 120    if ( mLoopDelayTime > 0 )
 121    {
 122        // Update Delay Time.
 123        mLoopDelayTime -= getMin( mAbs( delta ), mLoopDelayTime );
 124
 125        // Exit.
 126        return;
 127    }
 128
 129    // Jump Delta?
 130    if ( mJump == k_JumpDelta )
 131    {
 132        // Jump.
 133        delta = mJumpTime;
 134
 135        // Clear.
 136        mJump     = k_JumpInvalid;
 137        mJumpTime = 0;
 138    }
 139
 140    if ( ( isPlayingForward()  && ( mTime + delta ) > mDuration )
 141         || ( !isPlayingForward() && ( mTime + delta ) < 0 ) )
 142    {
 143        // Clamp Delta.
 144        delta = ( ( mTimeScale > 0.f ) * mDuration ) - mTime;
 145
 146        // Note: If we are playing forwards, we're at the end of the
 147        //       sequence and we want to loop/reset the Controller, then we
 148        //       need to handle that now.
 149        if ( delta == 0 )
 150        {
 151            onPostTick();
 152        }
 153    }
 154
 155    // Valid Delta?
 156    if ( delta == 0 )
 157    {
 158        // Exit.
 159        return;
 160    }
 161
 162    // Trigger Update.
 163    mControllerUpdateSignal.trigger( mTime, delta );
 164
 165    // Update Time.
 166    mTime += delta;
 167
 168    // Perform Post Tick.
 169    onPostTick();
 170}
 171
 172//-----------------------------------------------------------------------------
 173// 
 174// VController::onPostTick();
 175// 
 176// This method is called onces a tick has been processed. It will perform the
 177// the right checks to see if the Controller has finished playing. It also 
 178// handles special cases like Looping or Resetting the Controller.
 179// 
 180//-----------------------------------------------------------------------------
 181void VController::onPostTick( void )
 182{
 183    // Jump Time?
 184    if ( mJump == k_JumpTime )
 185    {
 186        // Jump Post Update.
 187        reset( mJumpTime );
 188
 189        // Clear.
 190        mJump     = k_JumpInvalid;
 191        mJumpTime = 0;
 192    }
 193
 194    // Sequence Completed?
 195    if ( isPlayingForward() && mTime >= mDuration 
 196        || !isPlayingForward() && mTime <= 0 )
 197    {
 198        bool stopPlaying = true;
 199        if ( mLoop )
 200        {
 201            // Don't Stop.
 202            stopPlaying = false;
 203
 204            if ( mLoopBackwards )
 205            {
 206                // Change Direction.
 207                setTimeScale( -1.f * mTimeScale );
 208            }
 209            else
 210            {
 211                // Reset Time.
 212                reset();
 213            }
 214
 215            if ( mLoopDelay > 0 )
 216            {
 217                // Resume After Delay.
 218                mLoopDelayTime = mLoopDelay;
 219            }
 220
 221            // At the Start of the Sequence?
 222            if ( mTime <= 0 && mLoopCount >= 0 )
 223            {
 224                // Stop Looping?
 225                stopPlaying = ( ++mLoopIndex >= mLoopCount );
 226            }
 227
 228            // Callback.
 229            Con::executef( this, "onLoop" );
 230
 231            // Loop Signal.
 232            postEvent( k_EventLoop );
 233        }
 234
 235        // Stop?
 236        if ( stopPlaying )
 237        {
 238            // Stop Only.
 239            stop( mResetOnCompletion );
 240        }
 241    }
 242}
 243
 244//-----------------------------------------------------------------------------
 245//
 246// Controller Methods.
 247//
 248//-----------------------------------------------------------------------------
 249
 250//-----------------------------------------------------------------------------
 251// 
 252// VController::reset();
 253// 
 254// Reset the Controller to the start of the sequence.
 255// 
 256//-----------------------------------------------------------------------------
 257void VController::reset( void )
 258{
 259    // Reset.
 260    reset( ( isPlayingForward() ) ? 0 : mDuration );
 261}
 262
 263//-----------------------------------------------------------------------------
 264// 
 265// VController::reset( pTime );
 266// 
 267// Reset the Controller to the target time. This is a very important method as
 268// it allows tracks and events to reset their state as well as prepare
 269// themselves for playback.
 270// 
 271//-----------------------------------------------------------------------------
 272void VController::reset( const S32 &pTime )
 273{
 274    // Reset Time.
 275    mTime     = pTime;
 276    mLastTime = Sim::getCurrentTime();
 277
 278    // Reset Delay Time.
 279    mLoopDelayTime = 0;
 280
 281    // Post Event.
 282    postEvent( k_EventReset );
 283}
 284
 285//-----------------------------------------------------------------------------
 286// 
 287// VController::play();
 288// 
 289// Start playing the sequence from the current time and execute a number of
 290// callbacks.
 291// 
 292//-----------------------------------------------------------------------------
 293void VController::play( void )
 294{
 295    if ( isPlaying() || mTime < 0 || mTime > mDuration )
 296    {
 297        // Sanity!
 298        return;
 299    }
 300
 301    // Reset Time.
 302    mLastTime = Sim::getCurrentTime();
 303
 304    // Start Updating.
 305    setProcessTicks( true );
 306
 307    if ( mStatus & k_StatusInit )
 308    {
 309        // Init Signal.
 310        postEvent( k_EventInit );
 311
 312        // Clear Init Status.
 313        mStatus &= ~<a href="/coding/class/classvcontroller/#classvcontroller_1aca00be95e4e090086219319cac0bee74a914a6ba9b1853cd0b4ea252035a7ac57">k_StatusInit</a>;
 314    }
 315
 316    // Update Status.
 317    updateStatus( k_StatusPlaying );
 318
 319    // Play Signal.
 320    postEvent( k_EventPlay );
 321
 322    // Callback.
 323    Con::executef( this, "onPlay" );
 324}
 325
 326//-----------------------------------------------------------------------------
 327// 
 328// VController::play( pTime );
 329// 
 330// Start playing the sequence from the desired time.
 331// 
 332//-----------------------------------------------------------------------------
 333void VController::play( const S32 &pTime )
 334{
 335    // Reset.
 336    reset( pTime );
 337
 338    // Play.
 339    play();
 340}
 341
 342//-----------------------------------------------------------------------------
 343// 
 344// VController::pause();
 345// 
 346// Cease playback of the sequence, but maintain the current time.
 347// 
 348//-----------------------------------------------------------------------------
 349void VController::pause( void )
 350{
 351    // Stop Updating.
 352    setProcessTicks( false );
 353
 354    // Update Status.
 355    updateStatus( k_StatusPaused );
 356
 357    // Pause Signal.
 358    postEvent( k_EventPause );
 359
 360    // Callback.
 361    Con::executef( this, "onPause" );
 362}
 363
 364//-----------------------------------------------------------------------------
 365// 
 366// VController::stop( pReset );
 367// 
 368// Stop playback altogether and reset the Controller to the start of the
 369// sequence.
 370// 
 371//-----------------------------------------------------------------------------
 372void VController::stop( const bool &pReset )
 373{
 374    // Stop Updating.
 375    setProcessTicks( false );
 376
 377    // Reset Loop Index.
 378    mLoopIndex = 0;
 379
 380    // Update Status.
 381    updateStatus( ( k_StatusInit | k_StatusStopped ) );
 382
 383    // Reset?
 384    if ( pReset )
 385    {
 386        // Reset.
 387        reset();
 388    }
 389
 390    // Stop Signal.
 391    postEvent( k_EventStop );
 392
 393    // Callback.
 394    Con::executef( this, "onStop" );
 395}
 396
 397//-----------------------------------------------------------------------------
 398// 
 399// VController::jump();
 400// 
 401// Jump the Controller time forward 1 tick (32ms).
 402// 
 403//-----------------------------------------------------------------------------
 404void VController::jump( void )
 405{
 406    // Jump 1 tick.
 407    jump( k_JumpDelta, ( isPlayingForward() ) ? TickMs : -TickMs );
 408}
 409
 410//-----------------------------------------------------------------------------
 411// 
 412// VController::jump( pType, pDelta );
 413// 
 414// Jump the Controller time by the target Delta.
 415// 
 416//-----------------------------------------------------------------------------
 417void VController::jump( const eControllerJumpType &pType, const S32 &pDelta )
 418{
 419    // Jump.
 420    mJump     = pType;
 421    mJumpTime = pDelta;
 422}
 423
 424//-----------------------------------------------------------------------------
 425// 
 426// VController::updateStatus( pStatus );
 427// 
 428// Clear the regular playback states and add the updated state.
 429// 
 430//-----------------------------------------------------------------------------
 431void VController::updateStatus( const S32 &pStatus )
 432{
 433    // Clear Playback Status.
 434    mStatus &= ~( k_StatusPlaying | k_StatusPaused | k_StatusStopped );
 435
 436    // Add New Status.
 437    mStatus |= pStatus;
 438}
 439
 440//-----------------------------------------------------------------------------
 441//
 442// Reference Methods.
 443//
 444//-----------------------------------------------------------------------------
 445
 446//-----------------------------------------------------------------------------
 447// 
 448// VController::getObject( pLabel );
 449// 
 450// Returns the group with the given name. If no group belongs to the Controller
 451// with that name, then a NULL value is returned.
 452// 
 453//-----------------------------------------------------------------------------
 454VGroup *VController::getObject( const String &pLabel )
 455{
 456    VGroup *node = ( VGroup* )mChildNode;
 457    while ( node )
 458    {
 459        // Compare Names.
 460        if ( node->getLabel().equal( pLabel, String::NoCase ) )
 461        {
 462            // Valid.
 463            return node;
 464        }
 465
 466        // Next Sibling.
 467        node = ( VGroup* )node->mSiblingNextNode;
 468    }
 469
 470    // Invalid.
 471    return NULL;
 472}
 473
 474//-----------------------------------------------------------------------------
 475// 
 476// VController::getDirectorGroup();
 477// 
 478// Returns the DirectorGroup reference if the Controller has a one.
 479// 
 480//-----------------------------------------------------------------------------
 481VDirectorGroup *VController::getDirectorGroup( void )
 482{
 483    for ( ITreeNode *node = mChildNode; node != NULL; node = node->mSiblingNextNode )
 484    {
 485        if ( VDirectorGroup *group = dynamic_cast<VDirectorGroup*>( node ) )
 486        {
 487            // Return Group.
 488            return group;
 489        }
 490    }
 491
 492    // Invalid Group.
 493    return NULL;
 494}
 495
 496//-----------------------------------------------------------------------------
 497// 
 498// VController::getDirectorTrack();
 499// 
 500// Returns the DirectorTrack reference if the DirectorGroup has one.
 501// 
 502//-----------------------------------------------------------------------------
 503VDirectorTrack *VController::getDirectorTrack( void )
 504{
 505    VDirectorGroup *group = getDirectorGroup();
 506    if ( !group )
 507    {
 508        // Invalid Track.
 509        return NULL;
 510    }
 511
 512    // Return Track.
 513    return group->getDirectorTrack();
 514}
 515
 516//-----------------------------------------------------------------------------
 517// 
 518// VController::getDataValue( pFieldName, *pValue );
 519// 
 520// Returns true if the field is a DataTable member and can be correctly
 521// evaluated. If this is the case, then pValue will contain the result.
 522// 
 523//-----------------------------------------------------------------------------
 524bool VController::getDataValue( const String &pFieldName, String &pValue )
 525{
 526    return mDataTable.getValue( this, pFieldName, pValue );
 527}
 528
 529//-----------------------------------------------------------------------------
 530// 
 531// VController::clearData();
 532// 
 533// Clear the contents of the DataTable entirely.
 534// 
 535//-----------------------------------------------------------------------------
 536void VController::clearData( void )
 537{
 538    while ( mDataTable.getCount() > 0 )
 539    {
 540        // Clear Item.
 541        clearData( 0 );
 542    }
 543}
 544
 545//-----------------------------------------------------------------------------
 546// 
 547// VController::clearData( pIndex );
 548// 
 549// Clear the DataTable entry with the given index.
 550// 
 551//-----------------------------------------------------------------------------
 552void VController::clearData( const S32 &pIndex )
 553{
 554    VDataTable::sDataItem data;
 555    if ( mDataTable.getItem( pIndex, &data ) )
 556    {
 557        // Clear Data.
 558        clearData( data.FieldName );
 559    }
 560}
 561
 562//-----------------------------------------------------------------------------
 563// 
 564// VController::clearData( pIndex );
 565// 
 566// Clear the DataTable entry with the given field name.
 567// 
 568//-----------------------------------------------------------------------------
 569void VController::clearData( const String &pFieldName )
 570{
 571    // Clear Dynamic Field.
 572    setDataField( pFieldName, NULL, "" );
 573
 574    // Clear Item.
 575    mDataTable.clear( pFieldName );
 576}
 577
 578//-----------------------------------------------------------------------------
 579// 
 580// VController::sort();
 581// 
 582// Sort each track in each of the child groups.
 583// 
 584//-----------------------------------------------------------------------------
 585void VController::sort( void )
 586{
 587    for ( ITreeNode *group = mChildNode; group != NULL; group = group->mSiblingNextNode )
 588    {
 589        for ( ITreeNode *track = group->mChildNode; track != NULL; track = track->mSiblingNextNode )
 590        {
 591            // Sort Track.
 592            ( ( VTrack* )track )->sort();
 593        }
 594    }
 595}
 596
 597//-----------------------------------------------------------------------------
 598//
 599// Write Methods.
 600//
 601//-----------------------------------------------------------------------------
 602
 603//-----------------------------------------------------------------------------
 604// 
 605// VController::writeDataTable( pElement );
 606// 
 607// Write the DataTable out to a TinyXML document.
 608// 
 609//-----------------------------------------------------------------------------
 610bool VController::writeDataTable( TiXmlElement *pElement )
 611{
 612    // Create Data Table Root.
 613    TiXmlElement *dataTableRoot = new TiXmlElement( "DataTable" );
 614    pElement->LinkEndChild( dataTableRoot );
 615
 616    for ( VDataTable::VDataMap::Iterator itr = mDataTable.mDataMap.begin(); itr != mDataTable.mDataMap.end(); ++itr )
 617    {
 618        // Fetch Data.
 619        VDataTable::sDataItem *data = &itr->value;
 620
 621        // Create Element.
 622        TiXmlElement *dataElement = new TiXmlElement( "DataItem" );  
 623
 624        // Apply Attributes.
 625        dataElement->SetAttribute( "Type",  VDataTable::getDataTypeDescription( data->Type ) );
 626        dataElement->SetAttribute( "Name",  data->FieldName );
 627        dataElement->SetAttribute( "Value", getDataField( StringTable->insert( data->FieldName.c_str() ), NULL ) );
 628
 629        // Add.
 630        dataTableRoot->LinkEndChild( dataElement );
 631    }
 632
 633    return true;
 634}
 635
 636//-----------------------------------------------------------------------------
 637//
 638// Read Methods.
 639//
 640//-----------------------------------------------------------------------------
 641
 642//-----------------------------------------------------------------------------
 643// 
 644// VController::readDataTable( pElement );
 645// 
 646// Read the DataTable from a TinyXML document.
 647// 
 648//-----------------------------------------------------------------------------
 649bool VController::readDataTable( TiXmlElement *pElement )
 650{
 651    TiXmlElement *dataTableRoot = pElement->FirstChildElement( "DataTable" );
 652    if ( dataTableRoot )
 653    {
 654        for ( TiXmlElement *child = dataTableRoot->FirstChildElement(); child != NULL; child = child->NextSiblingElement() )
 655        {
 656            // Get Field Data.
 657            const char *fieldType  = child->Attribute( "Type" );
 658            const char *fieldName  = child->Attribute( "Name" );
 659            const char *fieldValue = child->Attribute( "Value" );
 660
 661            // Add Data Item.
 662            mDataTable.insert( VDataTable::getDataTypeEnum( fieldType ), fieldName );
 663
 664            // Set Field Value.
 665            setDataField( StringTable->insert( fieldName ), NULL, fieldValue );
 666        }
 667    }
 668    
 669    // Valid Read.
 670    return true;
 671}
 672
 673//-----------------------------------------------------------------------------
 674//
 675// Property Methods.
 676//
 677//-----------------------------------------------------------------------------
 678
 679//-----------------------------------------------------------------------------
 680// 
 681// VController::postEvent( pEvent );
 682// 
 683// Process an event signal to all event subscribers. This method is used to
 684// signal changes in the Controller's status.
 685// 
 686// For a full list of possible events, see the 'eControllerEventType'
 687// declaration in VController.h.
 688// 
 689//-----------------------------------------------------------------------------
 690void VController::postEvent( const eControllerEventType &pEvent )
 691{
 692    // Signal Event.
 693    mControllerEventSignal.trigger( pEvent );
 694}
 695
 696//-----------------------------------------------------------------------------
 697// 
 698// VController::setTimeScale( pTimeScale );
 699// 
 700// Set the speed of playback. In effect, a value of 0.5 will double the real
 701// time taken to complete the playback of the sequence, while a value of 2.0
 702// will halve the time needed.
 703// 
 704//-----------------------------------------------------------------------------
 705void VController::setTimeScale( const F32 &pTimeScale )
 706{
 707    // Need an Update?
 708    const bool update = ( pTimeScale != 0.f && ( mTimeScale == 0.f || ( ( mTimeScale > 0.f ) != ( pTimeScale > 0.f ) ) ) );
 709
 710    // Store.
 711    mTimeScale = pTimeScale;
 712
 713    // Update $timeScale Variable.
 714    Con::setFloatVariable( "timeScale", mFabs( mTimeScale ) );
 715
 716    if ( update )
 717    {
 718        // Reset.
 719        reset( mTime );
 720    }
 721}
 722
 723//-----------------------------------------------------------------------------
 724//
 725// Console Methods.
 726//
 727//-----------------------------------------------------------------------------
 728
 729DefineEngineMethod( VController, readFile, bool, (String fileName), (""), "( string pFileName ) - Clears the object and loads the new data from the given filename.\n"
 730                                                  "@param pFileName The target file to read from.\n"
 731                                                  "@return Returns true if the read was successful." )
 732{
 733    // Clear Sequence Lists.
 734    object->clear();
 735
 736    // Clear Data Table.
 737    object->clearData();
 738
 739    // Read Target File.
 740    if ( !VPersistence::readFile( fileName, object ) )
 741    {
 742        // Re-Clear.
 743        object->clear();
 744
 745        // Invalid Read.
 746        return false;
 747    }
 748
 749    // Initial Sort.
 750    object->sort();
 751
 752    // Reset.
 753    object->reset();
 754
 755    // Valid Read.
 756    return true;
 757}
 758
 759DefineEngineMethod( VController, clear, void, (), , "( void ) - Detaches and deletes all of the child objects.\n"
 760                                               "@return No return value." )
 761{
 762    // Clear Sequence Lists.
 763    object->clear();
 764
 765    // Clear Data Table.
 766    object->clearData();
 767}
 768
 769DefineEngineMethod( VController, reset, void, (S32 time), (-1), "( [int pTime] ) - Reset the Controller's and child object's state.\n"
 770                                               "@param pTime The target time to reset to.\n"
 771                                               "@return No return value." )
 772{
 773   if (time != -1)
 774   {
 775      // Reset Sequence.
 776      object->reset(time);
 777      return;
 778   }
 779
 780    // Default Reset.
 781    object->reset();
 782}
 783
 784DefineEngineMethod( VController, isPlaying, bool, (), , "( void ) - Is the sequence currently playing?\n"
 785                                                   "@return Returns true if the Controller is playing." )
 786{
 787    // Is Playing?
 788    return ( object->isPlaying() );
 789}
 790
 791DefineEngineMethod( VController, play, void, (S32 time), (-1), "( [int pTime] ) - Play the sequence. If a value for pTime is specified, the Controller is reset and played from that time.\n"
 792                                              "@param pTime The time to start playing the sequence from.\n"
 793                                              "@return No return value." )
 794{
 795    S32 startTime = object->getTime();
 796    if (time != -1)
 797    {
 798        startTime = time;
 799    }
 800
 801    // Play From Specified Time.
 802    object->play( startTime );
 803}
 804
 805DefineEngineMethod( VController, step, void, (),, "( void ) - Step forward one frame.\n"
 806                                              "@return No return value." )
 807{
 808    if ( object->isPlaying() )
 809    {
 810        // Sanity!
 811        return;
 812    }
 813
 814    // Play.
 815    object->play( object->getTime() );
 816
 817    // Jump.
 818    object->jump();
 819
 820    // Step Forward One Frame.
 821    object->processTick();
 822
 823    // Stop.
 824    object->stop( false );
 825}
 826
 827DefineEngineMethod( VController, isPaused, bool, (), , "( void ) - Is the sequence currently paused?\n"
 828                                                  "@return Returns true if the Controller is paused." )
 829{
 830    // Is Paused?
 831    return ( object->isPaused() );
 832}
 833
 834DefineEngineMethod( VController, pause, void, (), , "( void ) - Pause the sequence. Playback can resume by calling VController::play().\n"
 835                                               "@return No return value." )
 836{
 837    // Pause Sequence.
 838    object->pause();
 839}
 840
 841DefineEngineMethod( VController, isStopped, bool, (), , "( void ) - Is the sequence currently stopped?\n"
 842                                                   "@return Returns true if the Controller is stopped." )
 843{
 844    // Is Stopped?
 845    return ( object->isStopped() );
 846}
 847
 848DefineEngineMethod( VController, stop, void, (bool reset), (true), "( [bool pReset] ) - Stop the sequence and optionally reset it.\n"
 849                                              "@param pReset Reset the Controller after stopping.\n"
 850                                              "@return No return value." )
 851{
 852    // Stop Sequence.
 853    object->stop(reset);
 854}
 855
 856DefineEngineMethod( VController, getTimeScale, F32, (), , "( void ) - Get the playback speed. A value > 0.0 will enable the Controller to play forwards, while a value < 0.0 will play backwards.\n"
 857                                                     "@return Playback Speed." )
 858{
 859    // Get Time Scale.
 860    return object->getTimeScale();
 861}
 862
 863DefineEngineMethod( VController, setTimeScale, void, (float timeScale), (1), "( float pTimeScale ) - Set the playback speed. A value > 0.0 will enable the Controller to play forwards, while a value < 0.0 will play backwards. If |pTimeScale| > 1.0, then playback will be faster than normal, while |pTimeScale| < 1.0 will be slower.\n"
 864                                                      "@param pTimeScale Playback speed.\n"
 865                                                      "@return No return value." )
 866{
 867    // Set Time Scale.
 868    object->setTimeScale(timeScale);
 869}
 870
 871DefineEngineMethod( VController, isDataField, bool, (String fieldName), (""), "( string pFieldName ) - Is the field a member of the Data Table?\n"
 872                                                     "@param pFieldName The name of the dynamic field you wish to check.\n"
 873                                                     "@return Returns true if the field is a member of the Data Table." )
 874{
 875    if (fieldName.isEmpty())
 876    {
 877        return false;
 878    }
 879
 880    // Is Field.
 881    return object->getDataTable().getItem(fieldName);
 882}
 883
 884DefineEngineMethod( VController, getDataFieldCount, S32, (), , "( void ) - Get the number of data elements in the Data Table.\n"
 885                                                          "@return Returns the size of the Data Table." )
 886{
 887    // Return Count.
 888    return object->getDataTable().getCount();
 889}
 890
 891DefineEngineMethod( VController, getDataFieldName, const char *, (S32 index), (0), "( int pIndex ) - Get the name of the field given by the passed index.\n"
 892                                                                  "@param pIndex The index of the data field you wish to check.\n"
 893                                                                  "@return Returns the name of the field corresponding to the given index." )
 894{
 895    VDataTable::sDataItem data;
 896    if ( !object->getDataTable().getItem(index, &data ) || data.Type == VDataTable::k_TypeInvalid )
 897    {
 898        // Invalid Field.
 899        return "";
 900    }
 901
 902    // Return Field Name.
 903    return data.FieldName;
 904}
 905
 906DefineEngineMethod( VController, getDataFieldValue, const char *, (String fieldName), (""), "( string pFieldName ) - Get the evaluated data from the data field.\n"
 907                                                                   "@param pFieldName The name of the field you wish to evaluate.\n"
 908                                                                   "@return Returns the evaluated data from the field." )
 909{
 910    String fieldValue;
 911    if ( object->getDataValue(fieldName, fieldValue ) )
 912    {
 913        // Create Buffer.
 914        char *buffer = Con::getReturnBuffer( 256 );
 915        dStrcpy( buffer, fieldValue.c_str(), 256 );
 916
 917        // Return Value.
 918        return buffer;
 919    }
 920
 921    // Return NULL.
 922    return "0";
 923}
 924
 925DefineEngineMethod( VController, getDataFieldType, const char *, (String fieldName), (""), "( string pFieldName ) - Get the type of data for the given field.\n"
 926                                                                  "@param pFieldName The name of the field you wish to check.\n"
 927                                                                  "@return Returns the data type." )
 928{
 929    VDataTable::sDataItem data;
 930    if ( !object->getDataTable().getItem(fieldName, &data ) || data.Type == VDataTable::k_TypeInvalid )
 931    {
 932        // Invalid Field.
 933        return "";
 934    }
 935
 936    // Return Field Type.
 937    return VDataTable::getDataTypeDescription( data.Type );
 938}
 939
 940#ifdef VT_EDITOR
 941//-----------------------------------------------------------------------------
 942//
 943// Debug Methods.
 944//
 945//-----------------------------------------------------------------------------
 946
 947DefineEngineMethod( VController, writeFile, bool, (String fileName), (""), "( string pFileName ) - Save to a given filename.\n"
 948                                                   "@param pFileName The target file to write to.\n"
 949                                                   "@return Returns true if the write was successful." )
 950{
 951    // Write Target File.
 952    return VPersistence::writeFile(fileName.c_str(), object );
 953}
 954
 955DefineEngineMethod( VController, readTemplate, bool, (String fileName), (""), "( string pFileName ) - Load data from given filename.\n"
 956                                                      "@param pFileName The target file to read from.\n"
 957                                                      "@return Returns true if the read was successful." )
 958{
 959    // Read Target File.
 960    return VPersistence::readFile(fileName.c_str(), object );
 961}
 962
 963DefineEngineMethod( VController, getCount, S32, (),, "( void ) - Get the number of child objects.\n"
 964                                                 "@return Returns the number of child objects." )
 965{
 966    // Size.
 967    return object->size();
 968}
 969
 970DefineEngineMethod( VController, getObject, S32, (S32 index), (0), "( int pIndex ) - Get the object corresponding to the given index.\n"
 971                                                  "@param pIndex The index of the object you wish to retrieve.\n"
 972                                                  "@return Returns the SimObjectID for the object." )
 973{
 974    // Fetch Object.
 975    VObject *objectRef  = ( VObject* )object->at(index);
 976
 977    // Return Group ID.
 978    return ( objectRef ) ? objectRef->getId() : 0;
 979}
 980
 981DefineEngineMethod( VController, addObject, void, (SimObject* simObj), (nullAsType<SimObject*>()), "( SimObject pObject ) - Add a child object to this node.\n"
 982                                                   "@param pObject The SimObjectID of the object to be added to this node.\n"
 983                                                   "@return No return value." )
 984{
 985   if (simObj == nullptr)
 986      return;
 987
 988    VObject *child = dynamic_cast<VObject*>(simObj);
 989    if ( child )
 990    {
 991        // Add Child.
 992        child->addTo( object );
 993    }
 994}
 995
 996DefineEngineMethod( VController, removeObject, void, (SimObject* simObj), (nullAsType<SimObject*>()), "( SimObject pObject ) - Remove the target object from this node.\n"
 997                                                      "@param pObject The SimObjectID of the object to be removed from this node.\n"
 998                                                      "@return No return value." )
 999{
1000   if (simObj == nullptr)
1001      return;
1002
1003    VObject *child = dynamic_cast<VObject*>(simObj);
1004    if ( child && child->getParent() == object )
1005    {
1006        child->remove();
1007    }
1008}
1009
1010DefineEngineMethod( VController, sortGroups, void, (),, "( void ) - Sort Groups by their Labels.\n"
1011                                                    "@return No return value." )
1012{
1013    // Ensure that the Director Group is the First Group.
1014    VDirectorGroup *directorGroup = object->getDirectorGroup();
1015    if ( directorGroup && directorGroup != object->mChildNode )
1016    {
1017        // Detach.
1018        directorGroup->remove();
1019
1020        // Add to the Front of the Controller.
1021        directorGroup->addToFront( object );
1022    }
1023
1024    const S32 count = object->size();
1025    for ( S32 j = 0; j < count; j++ )
1026    {
1027        ITreeNode *node = object->mChildNode;
1028        if ( dynamic_cast<VDirectorGroup*>( node ) != NULL )
1029        {
1030            // Skip Director Group.
1031            node = node->mSiblingNextNode;
1032        }
1033
1034        for ( ; node != NULL; node = node->mSiblingNextNode )
1035        {
1036            VGroup *groupA = ( VGroup* )node;
1037            VGroup *groupB = ( VGroup* )node->mSiblingNextNode;
1038            if ( !groupB )
1039            {
1040                // No Node.
1041                break;
1042            }
1043
1044            // Swap?
1045            if ( groupA->getLabel().compare(groupB->getLabel()) > 0 )
1046            {
1047                // Get Outer Siblings.
1048                ITreeNode *prevNode = groupA->mSiblingPrevNode;
1049                ITreeNode *nextNode = groupB->mSiblingNextNode;
1050                
1051                if ( groupA->mParentNode && groupA->mParentNode->mChildNode == groupA )
1052                {
1053                    // New Child Node.
1054                    groupA->mParentNode->mChildNode = groupB;
1055                }
1056
1057                //
1058                // Move A.
1059
1060                groupA->mSiblingPrevNode = groupB;
1061                groupA->mSiblingNextNode = nextNode;
1062
1063                if ( nextNode )
1064                {
1065                    // Update Outer Sibling.
1066                    nextNode->mSiblingPrevNode = groupA;
1067                }
1068
1069                //
1070                // Move B.
1071
1072                groupB->mSiblingPrevNode = prevNode;
1073                groupB->mSiblingNextNode = groupA;
1074
1075                if ( prevNode )
1076                {
1077                    // Update Outer Sibling.
1078                    prevNode->mSiblingNextNode = groupB;
1079                }
1080            }
1081        }
1082    }
1083}
1084
1085DefineEngineMethod( VController, sortTracks, void, (),, "( void ) - Sort Tracks by their Labels.\n"
1086                                                    "@return No return value." )
1087{
1088    for ( ITreeNode *group = object->mChildNode; group != NULL; group = group->mSiblingNextNode )
1089    {
1090        const S32 count = ( ( VGroup* )group )->size();
1091        for ( S32 j = 0; j < count; j++ )
1092        {
1093            for ( ITreeNode *node = group->mChildNode; node != NULL; node = node->mSiblingNextNode )
1094            {
1095                VTrack *trackA = ( VTrack* )node;
1096                VTrack *trackB = ( VTrack* )node->mSiblingNextNode;
1097                if ( !trackB )
1098                {
1099                    // No Node.
1100                    break;
1101                }
1102
1103                // Swap?
1104                if ( trackA->getLabel().compare(trackB->getLabel()) > 0 )
1105                {
1106                    // Get Outer Siblings.
1107                    ITreeNode *prevNode = trackA->mSiblingPrevNode;
1108                    ITreeNode *nextNode = trackB->mSiblingNextNode;
1109                    
1110                    if ( trackA->mParentNode && trackA->mParentNode->mChildNode == trackA )
1111                    {
1112                        // New Child Node.
1113                        trackA->mParentNode->mChildNode = trackB;
1114                    }
1115
1116                    //
1117                    // Move A.
1118
1119                    trackA->mSiblingPrevNode = trackB;
1120                    trackA->mSiblingNextNode = nextNode;
1121
1122                    if ( nextNode )
1123                    {
1124                        // Update Outer Sibling.
1125                        nextNode->mSiblingPrevNode = trackA;
1126                    }
1127
1128                    //
1129                    // Move B.
1130
1131                    trackB->mSiblingPrevNode = prevNode;
1132                    trackB->mSiblingNextNode = trackA;
1133
1134                    if ( prevNode )
1135                    {
1136                        // Update Outer Sibling.
1137                        prevNode->mSiblingNextNode = trackB;
1138                    }
1139                }
1140            }
1141        }
1142    }
1143}
1144
1145DefineEngineMethod( VController, addDataField, void, (String fieldType, String fieldName), ("", ""), "( string pFieldType, string pFieldName ) - Add a new data entry to the Data Table.\n"
1146                                                      "@param pFieldType The method of evaluating the field's data.\n"
1147                                                      "@param pFieldName The name of the field to be added to the Data Table.\n"
1148                                                      "@return No return value." )
1149{
1150    // Insert Data.
1151    object->getDataTable().insert( VDataTable::getDataTypeEnum(fieldType), fieldName);
1152}
1153
1154DefineEngineMethod( VController, removeDataField, void, (String fieldName), (""), "( string pFieldName ) - Remove a data entry from the Data Table.\n"
1155                                                         "@param pFieldName The name of the field to be removed from the Data Table.\n"
1156                                                         "@return No return value." )
1157{
1158    // Clear Data Item.
1159    object->clearData(fieldName);
1160}
1161#endif
1162