Browse Source

Merge branch 'development' of https://github.com/doodaddy64/Torque2D into development

Charlie Patterson 12 years ago
parent
commit
82eea09
28 changed files with 691 additions and 198 deletions
  1. 21 0
      engine/source/2d/assets/AnimationAsset.cc
  2. 1 0
      engine/source/2d/assets/AnimationAsset.h
  3. 51 0
      engine/source/2d/assets/ImageAsset.cc
  4. 1 0
      engine/source/2d/assets/ImageAsset.h
  5. 68 10
      engine/source/2d/controllers/PointForceController.cc
  6. 20 0
      engine/source/2d/controllers/PointForceController.h
  7. 52 0
      engine/source/2d/controllers/PointForceController_ScriptBinding.h
  8. 2 2
      engine/source/2d/core/SpriteBatch.h
  9. 2 1
      engine/source/2d/core/Vector2.h
  10. 11 5
      engine/source/2d/sceneobject/ParticlePlayer.cc
  11. 6 1
      engine/source/2d/sceneobject/ParticlePlayer.h
  12. 21 0
      engine/source/assets/assetBase.cc
  13. 1 0
      engine/source/assets/assetBase.h
  14. 13 13
      engine/source/assets/assetManager.cc
  15. 29 4
      engine/source/assets/assetManager.h
  16. 37 18
      engine/source/assets/assetManager_ScriptBinding.h
  17. 21 0
      engine/source/audio/AudioAsset.cc
  18. 1 0
      engine/source/audio/AudioAsset.h
  19. 1 0
      modules/AppCore/1/scripts/defaultPreferences.cs
  20. 36 38
      modules/BuoyancyControllerToy/1/main.cs
  21. 0 1
      modules/CollisionToy/1/main.cs
  22. 233 104
      modules/PointForceControllerToy/1/main.cs
  23. 1 1
      modules/PointForceControllerToy/1/module.taml
  24. 3 0
      modules/ToyAssets/1/assets/images/Planetoid.asset.taml
  25. BIN
      modules/ToyAssets/1/assets/images/Planetoid.png
  26. 49 0
      modules/ToyAssets/1/assets/particles/forceBubble.asset.taml
  27. 4 0
      modules/ToyAssets/1/assets/particles/impactExplosion.asset.taml
  28. 6 0
      tools/VisualStudioVisualizer/VS2012/T2D_Vector2.natvis

+ 21 - 0
engine/source/2d/assets/AnimationAsset.cc

@@ -143,6 +143,27 @@ void AnimationAsset::onAssetRefresh( void )
 
 //------------------------------------------------------------------------------
 
+void AnimationAsset::copyTo(SimObject* object)
+{
+    // Call to parent.
+    Parent::copyTo(object);
+
+    // Cast to asset.
+    AnimationAsset* pAsset = static_cast<AnimationAsset*>(object);
+
+    // Sanity!
+    AssertFatal(pAsset != NULL, "AnimationAsset::copyTo() - Object is not the correct type.");
+
+    // Copy state.
+    pAsset->setImage( getImage().getAssetId() );
+    pAsset->setAnimationFrames( Con::getData( TypeS32Vector, (void*)&getSpecifiedAnimationFrames(), 0 ) );
+    pAsset->setAnimationTime( getAnimationTime() );
+    pAsset->setAnimationCycle( getAnimationCycle() );
+    pAsset->setRandomStart( getRandomStart() );
+}
+
+//------------------------------------------------------------------------------
+
 void AnimationAsset::setImage( const char* pAssetId )
 {
     // Ignore no change.

+ 1 - 0
engine/source/2d/assets/AnimationAsset.h

@@ -58,6 +58,7 @@ public:
     static void initPersistFields();
     virtual bool onAdd();
     virtual void onRemove();
+    virtual void copyTo(SimObject* object);
 
     void            setImage( const char* pAssetId );
     const AssetPtr<ImageAsset>& getImage( void ) const     { return mImageAsset; }

+ 51 - 0
engine/source/2d/assets/ImageAsset.cc

@@ -264,6 +264,57 @@ void ImageAsset::setImageFile( const char* pImageFile )
 
 //------------------------------------------------------------------------------
 
+void ImageAsset::copyTo(SimObject* object)
+{
+    // Call to parent.
+    Parent::copyTo(object);
+
+    // Cast to asset.
+    ImageAsset* pAsset = static_cast<ImageAsset*>(object);
+
+    // Sanity!
+    AssertFatal(pAsset != NULL, "ImageAsset::copyTo() - Object is not the correct type.");
+
+    // Copy state.
+    pAsset->setImageFile( getImageFile() );
+    pAsset->setForce16Bit( getForce16Bit() );
+    pAsset->setFilterMode( getFilterMode() );
+    pAsset->setExplicitMode( getExplicitMode() );
+    pAsset->setCellRowOrder( getCellRowOrder() );
+    pAsset->setCellOffsetX( getCellCountX() );
+    pAsset->setCellOffsetY( getCellCountY() );
+    pAsset->setCellStrideX( getCellStrideX() );
+    pAsset->setCellStrideY( getCellStrideY() );
+    pAsset->setCellCountX( getCellCountX() );
+    pAsset->setCellCountY( getCellCountY() );
+    pAsset->setCellWidth( getCellWidth() );
+    pAsset->setCellHeight( getCellHeight() );
+
+    // Finish if not in explicit mode.
+    if ( !getExplicitMode() )
+        return;
+
+    // Fetch the explicit cell count.
+    const S32 explicitCellCount = getExplicitCellCount();
+
+    // Finish if no explicit cells exist.
+    if ( explicitCellCount == 0 )
+        return;
+
+    // Copy explicit cells.
+    pAsset->clearExplicitCells();
+    for( S32 index = 0; index < explicitCellCount; ++index )
+    {
+        // Fetch the cell pixel area.
+        const FrameArea::PixelArea& pixelArea = getImageFrameArea( index ).mPixelArea;
+
+        // Add the explicit cell.
+        pAsset->addExplicitCell( pixelArea.mPixelOffset.x, pixelArea.mPixelOffset.y, pixelArea.mPixelWidth, pixelArea.mPixelHeight );
+    }
+}
+
+//------------------------------------------------------------------------------
+
 void ImageAsset::setForce16Bit( const bool force16Bit )
 {
     // Ignore no change,

+ 1 - 0
engine/source/2d/assets/ImageAsset.h

@@ -165,6 +165,7 @@ public:
     static void initPersistFields();
     virtual bool onAdd();
     virtual void onRemove();
+    virtual void copyTo(SimObject* object);
 
     void                    setImageFile( const char* pImageFile );
     inline StringTableEntry getImageFile( void ) const                      { return mImageFile; };

+ 68 - 10
engine/source/2d/controllers/PointForceController.cc

@@ -39,6 +39,9 @@ PointForceController::PointForceController()
     mPosition.SetZero();
     mRadius = 1.0f;
     mForce = 0.0f;
+    mNonLinear = true;
+    mLinearDrag = 0.0f;
+    mAngularDrag = 0.0f;
 }
 
 //------------------------------------------------------------------------------
@@ -56,9 +59,12 @@ void PointForceController::initPersistFields()
     Parent::initPersistFields();
 
     // Force.
-    addProtectedField("Position", TypeVector2, Offset( mPosition, PointForceController), &defaultProtectedSetFn, &defaultProtectedGetFn, "The position of the attractor controller.");
-    addProtectedField("Radius", TypeF32, Offset( mRadius, PointForceController), &defaultProtectedSetFn, &defaultProtectedGetFn, "The radius of the attractor circle centered on the attractors position.");
-    addProtectedField("Force", TypeF32, Offset( mForce, PointForceController), &defaultProtectedSetFn, &defaultProtectedGetFn, "The force to apply to attact to the controller position.");
+    addField( "Position", TypeVector2, Offset( mPosition, PointForceController), "The position of the attractor controller.");
+    addField( "Radius", TypeF32, Offset( mRadius, PointForceController), "The radius of the attractor circle centered on the attractors position.");
+    addField( "Force", TypeF32, Offset( mForce, PointForceController), "The force to apply to attact to the controller position.");
+    addField( "NonLinear", TypeBool, Offset( mNonLinear, PointForceController), "Whether to apply the force non-linearly (using the inverse square law) or linearly.");
+    addField( "LinearDrag", TypeF32, Offset(mLinearDrag, PointForceController), "The linear drag co-efficient for the fluid." );
+    addField( "AngularDrag", TypeF32, Offset(mAngularDrag, PointForceController), "The angular drag co-efficient for the fluid." );
 }
 
 //------------------------------------------------------------------------------
@@ -100,8 +106,25 @@ void PointForceController::integrate( Scene* pScene, const F32 totalTime, const
     // Fetch results.
     typeWorldQueryResultVector& queryResults = pWorldQuery->getQueryResults();
 
+    // Fetch result count.
+    const U32 resultCount = (U32)queryResults.size();
+
+    // Finish if nothing to process.
+    if ( resultCount == 0 )
+        return;
+
+    // Calculate the radius squared.
+    const F32 radiusSqr = mRadius * mRadius;
+
+    // Calculate the force squared in-case we need it.
+    const F32 forceSqr = mForce * mForce * (( mForce < 0.0f ) ? -1.0f : 1.0f);
+
+    // Calculate drag coefficients (time-integrated).
+    const F32 linearDrag = mClampF( mLinearDrag, 0.0f, 1.0f ) * elapsedTime;
+    const F32 angularDrag = mClampF( mAngularDrag, 0.0f, 1.0f ) * elapsedTime;
+
     // Iterate the results.
-    for ( U32 n = 0; n < (U32)queryResults.size(); n++ )
+    for ( U32 n = 0; n < resultCount; n++ )
     {
         // Fetch the scene object.
         SceneObject* pSceneObject = queryResults[n].mpSceneObject;
@@ -110,18 +133,53 @@ void PointForceController::integrate( Scene* pScene, const F32 totalTime, const
         if ( pSceneObject->getBodyType() == b2_staticBody )
             continue;
 
-        // Calculate the force direction to the controllers position.
-        Vector2 forceDirection = mPosition - pSceneObject->getPosition();
+        // Calculate the force distance to the controllers position.
+        Vector2 distanceForce = mPosition - pSceneObject->getPosition();
 
         // Skip if the position is outside the radius.
-        if ( forceDirection.Length() > mRadius )
+        if ( distanceForce.LengthSquared() > radiusSqr )
             continue;
 
-        // Normalize to the specified force.
-        forceDirection.Normalize( mForce );
+        // Non-Linear force?
+        if ( mNonLinear )
+        {
+            // Yes, so use an approximation of the inverse-square law.
+            distanceForce *= (1.0f / distanceForce.LengthSquared()) * forceSqr;
+        }
+        else
+        {
+            // No, so normalize to the specified force (linear).
+            distanceForce.Normalize( mForce );
+        }
 
         // Apply the force.
-        pSceneObject->applyForce( forceDirection, true );
+        pSceneObject->applyForce( distanceForce, true );
+
+        // Linear drag?
+        if ( linearDrag > 0.0f )
+        {
+            // Yes, so fetch linear velocity.
+            Vector2 linearVelocity = pSceneObject->getLinearVelocity();
+
+            // Calculate linear velocity change.
+            const Vector2 linearVelocityDelta = linearVelocity * linearDrag;
+
+            // Set linear velocity.
+            pSceneObject->setLinearVelocity( linearVelocity - linearVelocityDelta );
+        }
+
+        // Angular drag?
+        if ( angularDrag > 0.0f )
+        {
+            // Yes, so fetch angular velocity.
+            F32 angularVelocity = pSceneObject->getAngularVelocity();
+
+            // Calculate angular velocity change.
+            const F32 angularVelocityDelta = angularVelocity * angularDrag;
+
+            // Set angular velocity.
+            pSceneObject->setAngularVelocity( angularVelocity - angularVelocityDelta );
+        }
     }
 }
 

+ 20 - 0
engine/source/2d/controllers/PointForceController.h

@@ -38,10 +38,24 @@ class PointForceController : public PickingSceneController
 private:
     typedef PickingSceneController Parent;
 
+    /// Controller position.
     Vector2 mPosition;
+
+    /// Controller radius.
     F32 mRadius;
+
+    /// Controller force.
     F32 mForce;
 
+    /// Whether to apply the force non-linearly (using the inverse square law) or linearly.
+    bool mNonLinear;
+
+	/// Linear drag co-efficient.
+	F32 mLinearDrag;
+
+	/// Linear drag co-efficient.
+	F32 mAngularDrag;
+
 public:
     PointForceController();
     virtual ~PointForceController();
@@ -55,6 +69,12 @@ public:
     inline F32 getRadius( void ) const { return mRadius; }
     inline void setForce( const F32 force ) { mForce = force; }
     inline F32 getForce( void ) const { return mForce; }
+    inline void setNonLinear( const bool nonLinear ) { mNonLinear = nonLinear; }
+    inline bool getNonLinear( void ) const { return mNonLinear; }
+    inline void setLinearDrag( const F32 linearDrag ) { mLinearDrag = linearDrag; }
+    inline F32 getLinearDrag( void ) const { return mLinearDrag; }
+    inline void setAngularDrag( const F32 angularDrag ) { mAngularDrag = angularDrag; }
+    inline F32 getAngularDrag( void ) const { return mAngularDrag; }
 
     /// Integration.
     virtual void integrate( Scene* pScene, const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats );

+ 52 - 0
engine/source/2d/controllers/PointForceController_ScriptBinding.h

@@ -92,3 +92,55 @@ ConsoleMethod(PointForceController, getForce, F32, 2, 2,        "() Gets the poi
 {
     return object->getForce();
 }
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(PointForceController, setLinearDrag, void, 3, 3,  "(linearDrag) - Sets the linear drag coefficient (0.0 to 1.0).\n"
+                                                                "@param linearDrag The linear drag coefficient\n"
+                                                                "@return No return value.")
+{
+    object->setLinearDrag( dAtof(argv[2]) );
+} 
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(PointForceController, getLinearDrag, F32, 2, 2,   "() Gets the linear drag coefficient.\n"
+                                                                "@return The linear drag coefficient.")
+{
+    return object->getLinearDrag();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(PointForceController, setAngularDrag, void, 3, 3, "(angularDrag) - Sets the angular drag coefficient (0.0 to 1.0).\n"
+                                                                "@param angularDrag The angular drag coefficient\n"
+                                                                "@return No return value.")
+{
+    object->setAngularDrag( dAtof(argv[2]) );
+} 
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(PointForceController, getAngularDrag, F32, 2, 2,  "() Gets the angular drag coefficient.\n"
+                                                                "@return The angular drag coefficient.")
+{
+    return object->getAngularDrag();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(PointForceController, setNonLinear, void, 3, 3,   "(nonLinear) - Sets whether to apply the force non-linearly (using the inverse square law) or linearly.\n"
+                                                                "@param nonLinear whether to apply the force non-linearly (using the inverse square law) or linearly.\n"
+                                                                "@return No return value.")
+{
+    object->setNonLinear( dAtob(argv[2]) );
+} 
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(PointForceController, getNonLinear, bool, 2, 2,  "() Gets whether to apply the force non-linearly (using the inverse square law) or linearly.\n"
+                                                                "@return Whether to apply the force non-linearly (using the inverse square law) or linearly.")
+{
+    return object->getNonLinear();
+}
+

+ 2 - 2
engine/source/2d/core/SpriteBatch.h

@@ -105,10 +105,10 @@ public:
     inline bool getBatchCulling( void ) const { return mBatchCulling; }
 
     inline void setDefaultSpriteStride( const Vector2& defaultStride ) { mDefaultSpriteStride = defaultStride; }
-    inline Vector2 getDefaultSpriteStride( void ) const { return mDefaultSpriteStride; }
+    inline const Vector2& getDefaultSpriteStride( void ) const { return mDefaultSpriteStride; }
 
     inline void setDefaultSpriteSize( const Vector2& defaultSize ) { mDefaultSpriteSize = defaultSize; }
-    inline Vector2 getDefaultSpriteSize( void ) const { return mDefaultSpriteSize; }
+    inline const Vector2& getDefaultSpriteSize( void ) const { return mDefaultSpriteSize; }
 
     inline void setDefaultSpriteAngle( const F32 defaultAngle ) { mDefaultSpriteAngle = defaultAngle; }
     inline F32 getDefaultSpriteAngle( void ) const { return mDefaultSpriteAngle; }

+ 2 - 1
engine/source/2d/core/Vector2.h

@@ -127,6 +127,7 @@ struct Vector2 : b2Vec2
     inline F32 Normalize(const F32 s)                                   { const F32 length = Length(); if ( length > 0.0f ) m_point2F_normalize_f((F32*)this, s); return length; }
     inline Vector2& absolute(void)                                      { if (x < 0.0f) x = -x; if (y < 0.0f) y = -y; return *this; }
     inline Vector2& receiprocate(void)                                  { x = 1.0f/x; y = 1.0f/y; return *this; }
+    inline Vector2 getReceiprocate(void) const                          { Vector2 temp = *this; temp.receiprocate();return temp; }
     inline Vector2& add(const Vector2& v)                               { x += v.x; y += v.y; return *this; }
     inline Vector2& sub(const Vector2& v)                               { x -= v.x; y -= v.y; return *this; }
     inline Vector2& mult(const Vector2& v)                              { x *= v.x; y *= v.y; return *this; }
@@ -145,7 +146,7 @@ struct Vector2 : b2Vec2
     inline Vector2& clampMin(const Vector2& min)                        { if (x < min.x) x = min.x; if (y < min.y) y = min.y;  return *this; }
     inline Vector2& clampMax(const Vector2& max)                        { if (x > max.x) x = max.x; if (y > max.y) y = max.y;  return *this; }
     inline void rand(const Vector2& min, const Vector2& max)            { x = CoreMath::mGetRandomF(min.x, max.x), y = CoreMath::mGetRandomF(min.y,max.y); }
-    inline void round(const F32 epsilon = FLT_EPSILON)                  { F32 recip = 1.0f/epsilon; x = mFloor(x * recip + 0.5f) * epsilon; y = mFloor(y * recip + 0.5f) * epsilon; }
+    inline void round(const F32 epsilon = FLT_EPSILON)                  { x = mRound(x, epsilon); y = mRound(y, epsilon); }
 
     inline StringTableEntry stringThis(void) const                      { char buffer[32]; dSprintf(buffer, 32, "%g %g", x, y ); return StringTable->insert(buffer); }
     inline const char* scriptThis(void) const                           { char* pBuffer = Con::getReturnBuffer(32); dSprintf(pBuffer, 32, "%.5g %.5g", x, y ); return pBuffer; }

+ 11 - 5
engine/source/2d/sceneobject/ParticlePlayer.cc

@@ -97,7 +97,8 @@ ParticlePlayer::ParticlePlayer() :
     mEmissionRateScale = Con::getFloatVariable( PARTICLE_PLAYER_EMISSION_RATE_SCALE, 1.0f );
     mSizeScale         = Con::getFloatVariable( PARTICLE_PLAYER_SIZE_SCALE, 1.0f );
     mForceScale        = Con::getFloatVariable( PARTICLE_PLAYER_FORCE_SCALE, 1.0f );
-
+    mTimeScale         = Con::getFloatVariable( PARTICLE_PLAYER_TIME_SCALE, 1.0f );
+     
     // Register for refresh notifications.
     mParticleAsset.registerRefreshNotify( this );
 }
@@ -123,6 +124,7 @@ void ParticlePlayer::initPersistFields()
     addProtectedField( "EmissionRateScale", TypeF32, Offset(mEmissionRateScale, ParticlePlayer), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeEmissionRateScale, "" );
     addProtectedField( "SizeScale", TypeF32, Offset(mSizeScale, ParticlePlayer), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeSizeScale, "" );
     addProtectedField( "ForceScale", TypeF32, Offset(mForceScale, ParticlePlayer), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeForceScale, "" );
+    addProtectedField( "TimeScale", TypeF32, Offset(mTimeScale, ParticlePlayer), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeTimeScale, "" );
 }
 
 //------------------------------------------------------------------------------
@@ -145,6 +147,7 @@ void ParticlePlayer::copyTo(SimObject* object)
    pParticlePlayer->setEmissionRateScale( getEmissionRateScale() );
    pParticlePlayer->setSizeScale( getSizeScale() );
    pParticlePlayer->setForceScale( getForceScale() );
+   pParticlePlayer->setTimeScale( getTimeScale() );
 }
 
 //------------------------------------------------------------------------------
@@ -265,6 +268,9 @@ void ParticlePlayer::integrateObject( const F32 totalTime, const F32 elapsedTime
             mEmitters.size() == 0 )
         return;
 
+    // Calculate scaled time.
+    const F32 scaledTime = elapsedTime * mTimeScale;
+
     // Fetch particle asset.
     ParticleAsset* pParticleAsset = mParticleAsset;
 
@@ -279,7 +285,7 @@ void ParticlePlayer::integrateObject( const F32 totalTime, const F32 elapsedTime
     if ( !mCameraIdle )
     {
         // No, so update the particle player age.
-        mAge += elapsedTime;
+        mAge += scaledTime;
 
         // Iterate the emitters.
         for( typeEmitterVector::iterator emitterItr = mEmitters.begin(); emitterItr != mEmitters.end(); ++emitterItr )
@@ -300,7 +306,7 @@ void ParticlePlayer::integrateObject( const F32 totalTime, const F32 elapsedTime
             while ( pParticleNode != pParticleNodeHead )
             {
                 // Update the particle age.
-                pParticleNode->mParticleAge += elapsedTime;
+                pParticleNode->mParticleAge += scaledTime;
 
                 // Has the particle expired?
                 // NOTE:-   If we're in single-particle mode then the particle lives as long as the particle player does.
@@ -317,7 +323,7 @@ void ParticlePlayer::integrateObject( const F32 totalTime, const F32 elapsedTime
                 else
                 {
                     // No, so integrate the particle.
-                    integrateParticle( pEmitterNode, pParticleNode, pParticleNode->mParticleAge / pParticleNode->mParticleLifetime, elapsedTime );
+                    integrateParticle( pEmitterNode, pParticleNode, pParticleNode->mParticleAge / pParticleNode->mParticleLifetime, scaledTime );
 
                     // Move to the next particle node.
                     pParticleNode = pParticleNode->mNextNode;
@@ -347,7 +353,7 @@ void ParticlePlayer::integrateObject( const F32 totalTime, const F32 elapsedTime
                 //
                 // NOTE:    We need to do this if there's an emission target but the time-integration is so small
                 //          that rounding results in no emission.  Downside to good FPS!
-                pEmitterNode->setTimeSinceLastGeneration( pEmitterNode->getTimeSinceLastGeneration() + elapsedTime );
+                pEmitterNode->setTimeSinceLastGeneration( pEmitterNode->getTimeSinceLastGeneration() + scaledTime );
 
                 // Fetch the particle player age.
                 const F32 particlePlayerAge = mAge;

+ 6 - 1
engine/source/2d/sceneobject/ParticlePlayer.h

@@ -44,6 +44,7 @@
 #define PARTICLE_PLAYER_EMISSION_RATE_SCALE     "$pref::T2D::ParticlePlayerEmissionRateScale"
 #define PARTICLE_PLAYER_SIZE_SCALE              "$pref::T2D::ParticlePlayerSizeScale"
 #define PARTICLE_PLAYER_FORCE_SCALE             "$pref::T2D::ParticlePlayerForceScale"
+#define PARTICLE_PLAYER_TIME_SCALE              "$pref::T2D::ParticlePlayerTimeScale"
 
 //-----------------------------------------------------------------------------
 
@@ -134,7 +135,7 @@ private:
     F32                         mEmissionRateScale;
     F32                         mSizeScale;
     F32                         mForceScale;
-
+    F32                         mTimeScale;
 
     bool                        mWaitingForParticles;
     bool                        mWaitingForDelete;
@@ -174,6 +175,9 @@ public:
     inline void setForceScale( const F32 scale ) { mForceScale = scale; }
     inline F32 getForceScale( void  ) const { return mForceScale; }
 
+    inline void setTimeScale( const F32 scale ) { mTimeScale = scale; }
+    inline F32 getTimeScale( void  ) const { return mTimeScale; }
+
     inline const U32 getEmitterCount( void ) const { return (U32)mEmitters.size(); }
 
     void setEmitterPaused( const bool paused, const U32 emitterIndex );
@@ -207,6 +211,7 @@ protected:
     static bool     writeEmissionRateScale( void* obj, StringTableEntry pFieldName )        { return !mIsOne( static_cast<ParticlePlayer*>( obj )->getEmissionRateScale() ); }
     static bool     writeSizeScale( void* obj, StringTableEntry pFieldName )                { return !mIsOne( static_cast<ParticlePlayer*>( obj )->getSizeScale() ); }
     static bool     writeForceScale( void* obj, StringTableEntry pFieldName )               { return !mIsOne( static_cast<ParticlePlayer*>( obj )->getForceScale() ); }
+    static bool     writeTimeScale( void* obj, StringTableEntry pFieldName )                { return !mIsOne( static_cast<ParticlePlayer*>( obj )->getTimeScale() ); }
 
 private:
     virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );

+ 21 - 0
engine/source/assets/assetBase.cc

@@ -79,6 +79,27 @@ void AssetBase::initPersistFields()
     addProtectedField( ASSET_BASE_ASSETPRIVATE_FIELD, TypeBool, 0, &defaultProtectedNotSetFn, &getAssetPrivate, &defaultProtectedNotWriteFn, "Whether the asset is private or not." );
 }
 
+//------------------------------------------------------------------------------
+
+void AssetBase::copyTo(SimObject* object)
+{
+    // Call to parent.
+    Parent::copyTo(object);
+
+    // Cast to asset.
+    AssetBase* pAsset = static_cast<AssetBase*>(object);
+
+    // Sanity!
+    AssertFatal(pAsset != NULL, "AssetBase::copyTo() - Object is not the correct type.");
+
+    // Copy state.
+    pAsset->setAssetName( getAssetName() );
+    pAsset->setAssetDescription( getAssetDescription() );
+    pAsset->setAssetCategory( getAssetCategory() );
+    pAsset->setAssetAutoUnload( getAssetAutoUnload() );
+    pAsset->setAssetInternal( getAssetInternal() );
+}
+
 //-----------------------------------------------------------------------------
 
 void AssetBase::setAssetDescription( const char* pAssetDescription )

+ 1 - 0
engine/source/assets/assetBase.h

@@ -67,6 +67,7 @@ public:
 
     /// Engine.
     static void initPersistFields();
+    virtual void copyTo(SimObject* object);
 
     /// Asset configuration.
     inline void             setAssetName( const char* pAssetName )              { if ( mpOwningAssetManager == NULL ) mpAssetDefinition->mAssetName = StringTable->insert(pAssetName); }

+ 13 - 13
engine/source/assets/assetManager.cc

@@ -157,7 +157,7 @@ bool AssetManager::compileReferencedAssets( ModuleDefinition* pModuleDefinition
 
 //-----------------------------------------------------------------------------
 
-bool AssetManager::addDeclaredAssets( ModuleDefinition* pModuleDefinition )
+bool AssetManager::addModuleDeclaredAssets( ModuleDefinition* pModuleDefinition )
 {
     // Debug Profiling.
     PROFILE_SCOPE(AssetManager_AddDeclaredAssets);
@@ -191,7 +191,7 @@ bool AssetManager::addDeclaredAssets( ModuleDefinition* pModuleDefinition )
         if ( !scanDeclaredAssets( filePathBuffer, pDeclaredAssets->getExtension(), pDeclaredAssets->getRecurse(), pModuleDefinition ) )
         {
             // Warn.
-            Con::warnf( "AssetManager::addDeclaredAssets() - Could not scan for declared assets at location '%s' with extension '%s'.", filePathBuffer, pDeclaredAssets->getExtension() );
+            Con::warnf( "AssetManager::addModuleDeclaredAssets() - Could not scan for declared assets at location '%s' with extension '%s'.", filePathBuffer, pDeclaredAssets->getExtension() );
         }
     }  
 
@@ -200,7 +200,7 @@ bool AssetManager::addDeclaredAssets( ModuleDefinition* pModuleDefinition )
 
 //-----------------------------------------------------------------------------
 
-bool AssetManager::addSingleDeclaredAsset( ModuleDefinition* pModuleDefinition, const char* pAssetFilePath )
+bool AssetManager::addDeclaredAsset( ModuleDefinition* pModuleDefinition, const char* pAssetFilePath )
 {
     // Debug Profiling.
     PROFILE_SCOPE(AssetManager_AddSingleDeclaredAsset);
@@ -220,7 +220,7 @@ bool AssetManager::addSingleDeclaredAsset( ModuleDefinition* pModuleDefinition,
     if ( pFileStart == NULL )
     {
         // No, so warn.
-        Con::warnf( "AssetManager::addSingleDeclaredAsset() - Could not add single declared asset file '%s' as file-path '%s' is not valid.",
+        Con::warnf( "AssetManager::addDeclaredAsset() - Could not add single declared asset file '%s' as file-path '%s' is not valid.",
             assetFilePathBuffer,
             pModuleDefinition->getModulePath() );
         return false;
@@ -236,7 +236,7 @@ bool AssetManager::addSingleDeclaredAsset( ModuleDefinition* pModuleDefinition,
     if ( !scanDeclaredAssets( assetFilePathBuffer, pFileStart, false, pModuleDefinition ) )
     {
         // Warn.
-        Con::warnf( "AssetManager::addSingleDeclaredAsset() - Could not scan declared assets at location '%s' with extension '%s'.", assetFilePathBuffer, pFileStart );
+        Con::warnf( "AssetManager::addDeclaredAsset() - Could not scan declared assets at location '%s' with extension '%s'.", assetFilePathBuffer, pFileStart );
         return false;
     }
 
@@ -273,10 +273,10 @@ StringTableEntry AssetManager::addPrivateAsset( AssetBase* pAssetBase )
     pAssetDefinition->mpAssetBase = pAssetBase;
     pAssetDefinition->mAssetDescription = pSourceAssetDefinition->mAssetDescription;
     pAssetDefinition->mAssetCategory = pSourceAssetDefinition->mAssetCategory;
-    pAssetDefinition->mAssetAutoUnload = false;
+    pAssetDefinition->mAssetAutoUnload = true;
     pAssetDefinition->mAssetRefreshEnable = false;
     pAssetDefinition->mAssetType = StringTable->insert( pAssetBase->getClassName() );
-    pAssetDefinition->mAssetLoadedCount = 1;
+    pAssetDefinition->mAssetLoadedCount = 0;
     pAssetDefinition->mAssetInternal = false;
     pAssetDefinition->mAssetPrivate = true;
 
@@ -326,7 +326,7 @@ bool AssetManager::removeDeclaredAssets( ModuleDefinition* pModuleDefinition )
         AssetDefinition* pAssetDefinition = *moduleAssets.begin();
 
         // Remove this asset.
-        removeSingleDeclaredAsset( pAssetDefinition->mAssetId );
+        removeDeclaredAsset( pAssetDefinition->mAssetId );
     }
 
     // Info.
@@ -338,7 +338,7 @@ bool AssetManager::removeDeclaredAssets( ModuleDefinition* pModuleDefinition )
 
 //-----------------------------------------------------------------------------
 
-bool AssetManager::removeSingleDeclaredAsset( const char* pAssetId )
+bool AssetManager::removeDeclaredAsset( const char* pAssetId )
 {
     // Debug Profiling.
     PROFILE_SCOPE(AssetManager_RemoveSingleDeclaredAsset);
@@ -1250,7 +1250,7 @@ bool AssetManager::deleteAsset( const char* pAssetId, const bool deleteLooseFile
     pAssetDefinition = NULL;
 
     // Remove asset.
-    removeSingleDeclaredAsset( pAssetId );
+    removeDeclaredAsset( pAssetId );
 
     // Delete the asset definition file.
     if ( !Platform::fileDelete( assetDefinitionFile ) )
@@ -3106,7 +3106,7 @@ void AssetManager::unloadAsset( AssetDefinition* pAssetDefinition )
         mLoadedPrivateAssetsCount--;
 
         // Remove it completely.
-        removeSingleDeclaredAsset( pAssetDefinition->mAssetId );
+        removeDeclaredAsset( pAssetDefinition->mAssetId );
     }
 }
 
@@ -3117,8 +3117,8 @@ void AssetManager::onModulePreLoad( ModuleDefinition* pModuleDefinition )
     // Debug Profiling.
     PROFILE_SCOPE(AssetManager_OnModulePreLoad);
 
-    // Add declared assets.
-    addDeclaredAssets( pModuleDefinition );
+    // Add module declared assets.
+    addModuleDeclaredAssets( pModuleDefinition );
 
     // Is an asset tags manifest specified?
     if ( pModuleDefinition->getAssetTagsManifest() != StringTable->EmptyString )

+ 29 - 4
engine/source/assets/assetManager.h

@@ -125,11 +125,11 @@ public:
     static void initPersistFields();
 
     /// Declared assets.
-    bool addDeclaredAssets( ModuleDefinition* pModuleDefinition );
-    bool addSingleDeclaredAsset( ModuleDefinition* pModuleDefinition, const char* pAssetFilePath );
+    bool addModuleDeclaredAssets( ModuleDefinition* pModuleDefinition );
+    bool addDeclaredAsset( ModuleDefinition* pModuleDefinition, const char* pAssetFilePath );
     StringTableEntry addPrivateAsset( AssetBase* pAssetBase );
     bool removeDeclaredAssets( ModuleDefinition* pModuleDefinition );
-    bool removeSingleDeclaredAsset( const char* pAssetId );
+    bool removeDeclaredAsset( const char* pAssetId );
     bool renameDeclaredAsset( const char* pAssetIdFrom, const char* pAssetIdTo );
     StringTableEntry getAssetName( const char* pAssetId );
     StringTableEntry getAssetDescription( const char* pAssetId );
@@ -151,7 +151,7 @@ public:
     bool isReferencedAsset( const char* pAssetId );
     bool renameReferencedAsset( const char* pAssetIdFrom, const char* pAssetIdTo );
 
-    /// Asset acquisition.
+    /// Public asset acquisition.
     template<typename T> T* acquireAsset( const char* pAssetId )
     {
         // Sanity!
@@ -298,6 +298,31 @@ public:
         return pAcquiredAsset;
     }
 
+    /// Private asset acquisition.
+    template<typename T> T* acquireAsPrivateAsset( const char* pAssetId )
+    {
+        // Acquire the asset normally.
+        T* pAsset = acquireAsset<T>( pAssetId );
+
+        // Finish if the asset was not acquired.
+        if ( pAsset == NULL )
+            return NULL;
+
+        // Clone the asset.
+        T* pAssetClone = dynamic_cast<T*>( pAsset->clone( true ) );
+
+        // Sanity!
+        AssertFatal( pAssetClone != NULL, "acquireAsPrivateAsset() - Failed to clone asset type." );
+
+        // Release the public asset.
+        releaseAsset( pAssetId );
+
+        // Add as a private asset.
+        addPrivateAsset( pAssetClone );
+
+        return pAssetClone;
+    }
+
     bool releaseAsset( const char* pAssetId );
     void purgeAssets( void );
 

+ 37 - 18
engine/source/assets/assetManager_ScriptBinding.h

@@ -41,9 +41,9 @@ ConsoleMethod( AssetManager, compileReferencedAssets, bool, 3, 3,  "(moduleDefin
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod( AssetManager, addDeclaredAssets, bool, 3, 3,     "(moduleDefinition) - Add any the declared assets specified by the module definition.\n"
-                                                                "@param moduleDefinition The module definition specifies the asset manifest.\n"
-                                                                "@return Whether adding declared assets was successful or not." )
+ConsoleMethod( AssetManager, addModuleDeclaredAssets, bool, 3, 3,   "(moduleDefinition) - Add any the declared assets specified by the module definition.\n"
+                                                                    "@param moduleDefinition The module definition specifies the asset manifest.\n"
+                                                                    "@return Whether adding declared assets was successful or not." )
 {
     // Fetch module definition.
     ModuleDefinition* pModuleDefinition = Sim::findObject<ModuleDefinition>( argv[2] );
@@ -56,15 +56,15 @@ ConsoleMethod( AssetManager, addDeclaredAssets, bool, 3, 3,     "(moduleDefiniti
         return false;
     }
 
-    // Add declared assets.
-    return object->addDeclaredAssets( pModuleDefinition );
+    // Add module declared assets.
+    return object->addModuleDeclaredAssets( pModuleDefinition );
 }
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod( AssetManager, addSingleDeclaredAsset, bool, 4, 4,    "(moduleDefinition, assetFilePath) - Add the specified asset against the specified module definition.\n"
-                                                                    "@param moduleDefinition The module definition that may contain declared assets.\n"
-                                                                    "@return Whether adding declared assets was successful or not." )
+ConsoleMethod( AssetManager, addDeclaredAsset, bool, 4, 4,  "(moduleDefinition, assetFilePath) - Add the specified asset against the specified module definition.\n"
+                                                            "@param moduleDefinition The module definition that may contain declared assets.\n"
+                                                            "@return Whether adding declared assets was successful or not." )
 {
     // Fetch module definition.
     ModuleDefinition* pModuleDefinition = Sim::findObject<ModuleDefinition>( argv[2] );
@@ -73,15 +73,15 @@ ConsoleMethod( AssetManager, addSingleDeclaredAsset, bool, 4, 4,    "(moduleDefi
     if ( pModuleDefinition == NULL )
     {
         // No, so warn.
-        Con::warnf( "AssetManager::addSingleDeclaredAsset() - Could not find the module definition '%s'.", argv[2] );        
+        Con::warnf( "AssetManager::addDeclaredAsset() - Could not find the module definition '%s'.", argv[2] );        
         return false;
     }
 
     // Fetch asset file-path.
     const char* pAssetFilePath = argv[3];
 
-    // Add single declared assets.
-    return object->addSingleDeclaredAsset( pModuleDefinition, pAssetFilePath );
+    // Add declared asset.
+    return object->addDeclaredAsset( pModuleDefinition, pAssetFilePath );
 }
 
 //-----------------------------------------------------------------------------
@@ -128,12 +128,12 @@ ConsoleMethod( AssetManager, removeDeclaredAssets, bool, 3, 3,  "(moduleDefiniti
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod( AssetManager, removeSingleDeclaredAsset, bool, 3, 3, "(assetId) - Remove the specified declared asset Id.\n"
-                                                                    "@param assetId The selected asset Id.\n"
-                                                                    "@return Whether removing the declared asset was successful or not." )
+ConsoleMethod( AssetManager, removeDeclaredAsset, bool, 3, 3,   "(assetId) - Remove the specified declared asset Id.\n"
+                                                                "@param assetId The selected asset Id.\n"
+                                                                "@return Whether removing the declared asset was successful or not." )
 {
     // Remove the declared asset Id.
-    return object->removeSingleDeclaredAsset( argv[2] );
+    return object->removeDeclaredAsset( argv[2] );
 }
 
 //-----------------------------------------------------------------------------
@@ -278,13 +278,32 @@ ConsoleMethod( AssetManager, renameReferencedAsset, bool, 4, 4,     "(assetIdFro
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod( AssetManager, acquireAsset, const char*, 3, 3,   "(assetId) - Acquire the specified asset Id.\n"
+ConsoleMethod( AssetManager, acquireAsset, const char*, 3, 4,   "(assetId, [asPrivate?]) - Acquire the specified asset Id.\n"
                                                                 "You must release the asset once you're finish with it using 'releaseAsset'.\n"
                                                                 "@param assetId The selected asset Id.\n"
+                                                                "@param asPrivate Whether to acquire the asset Id as a private asset.\n"
                                                                 "@return The acquired asset or NULL if not acquired.")
 {
-    // Acquire asset.
-    AssetBase* pAssetBase = object->acquireAsset<AssetBase>( argv[2] );
+    // Fetch asset Id.
+    const char* pAssetId = argv[2];
+
+    // Fetch private asset flag.
+    const bool asPrivate = argc >= 4 ? dAtob(argv[3]) : false;
+
+    // Reset asset reference.
+    AssetBase* pAssetBase = NULL;
+
+    // Acquire private asset?
+    if ( asPrivate )
+    {
+        // Acquire private asset.
+        pAssetBase = object->acquireAsPrivateAsset<AssetBase>( pAssetId );
+    }
+    else
+    {
+        // Acquire public asset.
+        pAssetBase = object->acquireAsset<AssetBase>( pAssetId );
+    }
 
     return pAssetBase != NULL ? pAssetBase->getIdString() : StringTable->EmptyString;
 }

+ 21 - 0
engine/source/audio/AudioAsset.cc

@@ -122,6 +122,27 @@ void AudioAsset::initPersistFields()
    //addField("environmentLevel",  TypeF32,     Offset(mDescription.mEnvironmentLevel, AudioAsset));
 }
 
+//------------------------------------------------------------------------------
+
+void AudioAsset::copyTo(SimObject* object)
+{
+    // Call to parent.
+    Parent::copyTo(object);
+
+    // Cast to asset.
+    AudioAsset* pAsset = static_cast<AudioAsset*>(object);
+
+    // Sanity!
+    AssertFatal(pAsset != NULL, "AudioAsset::copyTo() - Object is not the correct type.");
+
+    // Copy state.
+    pAsset->setAudioFile( getAudioFile() );
+    pAsset->setVolume( getVolume() );
+    pAsset->setVolumeChannel( getVolumeChannel() );
+    pAsset->setLooping( getLooping() );
+    pAsset->setStreaming( getStreaming() );
+}
+
 //--------------------------------------------------------------------------
 
 void AudioAsset::initializeAsset( void )

+ 1 - 0
engine/source/audio/AudioAsset.h

@@ -63,6 +63,7 @@ private:
 public:
    AudioAsset();
    static void initPersistFields();
+   virtual void copyTo(SimObject* object);
 
    void setAudioFile( const char* pAudioFile );
    inline StringTableEntry getAudioFile( void ) const { return mAudioFile; }

+ 1 - 0
modules/AppCore/1/scripts/defaultPreferences.cs

@@ -50,6 +50,7 @@ $pref::Audio::musicVolume = 1.0;
 $pref::T2D::ParticlePlayerEmissionRateScale = 1.0;
 $pref::T2D::ParticlePlayerSizeScale = 1.0;
 $pref::T2D::ParticlePlayerForceScale = 1.0;
+$pref::T2D::ParticlePlayerTimeScale = 1.0;
 $pref::T2D::warnFileDeprecated = 1;
 $pref::T2D::warnSceneOccupancy = 1;
 $pref::T2D::imageAssetGlobalFilterMode = Bilinear;

+ 36 - 38
modules/BuoyancyControllerToy/1/main.cs

@@ -40,8 +40,7 @@ function BuoyancyControllerToy::create( %this )
     BuoyancyControllerToy.FluidGravity = "0 -29.8";    
     BuoyancyControllerToy.UseShapeDensity = false;
 
-    BuoyancyControllerToy.FlowAngle = 90;
-    BuoyancyControllerToy.FlowMagnitude = 0;
+    BuoyancyControllerToy.FlowMagnitude = 13;
     
     BuoyancyControllerToy.MaxDebrisCount = 50;
     BuoyancyControllerToy.MinDebrisDensity = 1;
@@ -51,7 +50,6 @@ function BuoyancyControllerToy::create( %this )
 
     // Add options.    
     addNumericOption("Fluid Density", 0, 10, 0.1, "setFluidDensity", BuoyancyControllerToy.FluidDensity, false, "The fluid density.");   
-    addNumericOption("Fluid Flow Angle", -359, 359, 1, "setFluidFlowAngle", BuoyancyControllerToy.FlowAngle, true, "The angle of the constant force.");   
     addNumericOption("Fluid Flow Magnitude", 0, 1000, 10, "setFluidFlowMagnitude", BuoyancyControllerToy.FlowMagnitude, true, "The magnitude of the constant force.");      
     addNumericOption("Linear Drag", 0, 10, 0.1, "setLinearDrag", BuoyancyControllerToy.LinearDrag, false, "The linear drag co-efficient for the fluid.");
     addNumericOption("Angular Drag", 0, 10, 0.1, "setAngularDrag", BuoyancyControllerToy.AngularDrag, false, "The angular drag co-efficient for the fluid.");
@@ -87,16 +85,17 @@ function BuoyancyControllerToy::reset( %this )
     %this.createBackground();
    
     // Create fluid.
-    %this.createFluid("-45 -30 -30 -20");
-    %this.createFluid("-35 5 10 20");
-    %this.createFluid("-25 -25 15 -5");
-    %this.createFluid("25 -25 45 10");
+    %this.createFluid( "-50 20 30 30", "1 0", Navy );
+    %this.createFluid( "-10 2 50 12", "-1 0", Cyan );
+    %this.createFluid("-40 -16 30 -6", "1 0", LightBlue );
+    %this.createFluid( "-50 -34 50 -24", "-1 0", Green );
+    %this.createFluid( "-50 -34 -40 30", "0 0", Blue );
+
+    // Update the buoyancy controllers.
+    %this.updateBuoyancyControllers();     
     
     // Create debris.    
     %this.createDebris();   
-    
-    // Update the buoyancy controllers.
-    %this.updateBuoyancyControllers();     
 }
 
 //-----------------------------------------------------------------------------
@@ -112,11 +111,17 @@ function BuoyancyControllerToy::createBackground( %this )
     %object.Image = "ToyAssets:highlightBackground";
     %object.BlendColor = SlateGray;
     SandboxScene.add( %object );
+
+    %object.setDefaultFriction( 0 );    
     
     // Create border collisions.
-    %object.createEdgeCollisionShape( -50, -37.5, -50, 37.5 );
-    %object.createEdgeCollisionShape( 50, -37.5, 50, 37.5 );
+    %object.createEdgeCollisionShape( -50, -37.5, -50, 100 );
+    %object.createEdgeCollisionShape( 50, -37.5, 50, 100 );
     %object.createEdgeCollisionShape( -50, -34, 50, -34 );
+    
+    // Vertical fluid edge.
+    %object.createEdgeCollisionShape( -39.8, -16.2, -39.8, 20 );    
+    %object.createEdgeCollisionShape( -39.8, -16.2, -20, -16.2 );    
                 
     // Add the sprite to the scene.
     SandboxScene.add( %object );    
@@ -165,7 +170,7 @@ function BuoyancyControllerToy::createDebris( %this )
             %size = 2;
             
             // Create some sprites.
-            %sprite = %this.createSprite( "ToyAssets:football", getRandom(-40,40) SPC getRandom(50,70), %size, getRandom(0,360) );
+            %sprite = %this.createSprite( "ToyAssets:football", getRandom(-45,20) SPC getRandom(40,50), %size, getRandom(0,360) );
             %sprite.setDefaultFriction( 0.5 );
             %sprite.setDefaultDensity( getRandom(%this.MinDebrisDensity, %this.MaxDebrisDensity) );
             %sprite.createCircleCollisionShape( %size * 0.5 );
@@ -178,7 +183,7 @@ function BuoyancyControllerToy::createDebris( %this )
             %size = %sizeX SPC %sizeY;
             
             // Create some sprites.
-            %sprite = %this.createSprite( "ToyAssets:Blocks", getRandom(-40,40) SPC getRandom(50,70), %size, getRandom(0,360) );
+            %sprite = %this.createSprite( "ToyAssets:Blocks", getRandom(-45,20) SPC getRandom(40,50), %size, getRandom(0,360) );
             %sprite.Frame = getRandom( 0, 55 );
             %sprite.setDefaultFriction( 0.5 );
             %sprite.setDefaultDensity( getRandom(%this.MinDebrisDensity, %this.MaxDebrisDensity) );
@@ -191,22 +196,28 @@ function BuoyancyControllerToy::createDebris( %this )
 
 //-----------------------------------------------------------------------------
 
-function BuoyancyControllerToy::createFluid( %this, %area )
+function BuoyancyControllerToy::createFluid( %this, %area, %flowVelocity, %color )
 {
     %areaLeft = %area._0;
     %areaBottom = %area._1;
     %areaRight = %area._2;
     %areaTop = %area._3;
 
-    %crestHeight = 0.2;
-    %crestY = %areaTop - ((%areaTop - %areaBottom) * %crestHeight);
+    %crestY = %areaTop - 3;
+    %width = %areaRight - %areaLeft;
+    
+    // Create a new controller.
+    %controller = new BuoyancyController();
+    %controller.FluidArea = %area;
+    %controller.FlowVelocity = %flowVelocity;
+    SandboxScene.Controllers.add( %controller );     
     
     // Add the water.
     %water = new Sprite();
     %water.BodyType = static;
     %water.setArea( %areaLeft SPC %areaBottom SPC %areaRight SPC %crestY);
     %water.Image = "ToyAssets:Blank";
-    %water.BlendColor = Navy;    
+    %water.BlendColor = %color;    
     %water.SetBlendAlpha( 0.5 );
     SandboxScene.add( %water );
 
@@ -214,36 +225,23 @@ function BuoyancyControllerToy::createFluid( %this, %area )
     %crests1 = new Scroller();   
     %crests1.setArea( %areaLeft SPC %crestY SPC %areaRight SPC %areaTop );
     %crests1.Image = "BuoyancyControllerToy:WaveCrests";
-    %crests1.BlendColor = Navy;    
+    %crests1.BlendColor = %color;    
     %crests1.SetBlendAlpha( 0.3 );
+    %crests1.RepeatX = %width / 50;
     %crests1.ScrollX = getRandom(5,10);
-    %crests2.ScrollPositionX = getRandom(0,50);
+    %crests1.ScrollPositionX = getRandom(0,50);
     SandboxScene.add( %crests1 );
     
     // Create some wave crests.
     %crests2 = new Scroller();   
     %crests2.setArea( %areaLeft SPC %crestY SPC %areaRight SPC %areaTop );
     %crests2.Image = "BuoyancyControllerToy:WaveCrests";
-    %crests2.BlendColor = Navy;    
+    %crests2.BlendColor = %color;    
     %crests2.SetBlendAlpha( 0.3 );
+    %crests2.RepeatX = %width / 50;
     %crests2.ScrollX = getRandom(-5,-10);
     %crests2.ScrollPositionX = getRandom(0,50);
-    SandboxScene.add( %crests2 );    
-        
-    // Create a new controller.
-    %controller = new BuoyancyController();
-    %controller.FluidArea = %area;
-    SandboxScene.Controllers.add( %controller );    
-}
-
-//-----------------------------------------------------------------------------
-
-function BuoyancyControllerToy::setFluidFlowAngle(%this, %value)
-{
-    %this.FlowAngle = %value;
-    
-    // Update the controllers.
-    %this.updateBuoyancyControllers();   
+    SandboxScene.add( %crests2 );         
 }
 
 //-----------------------------------------------------------------------------
@@ -346,7 +344,7 @@ function BuoyancyControllerToy::updateBuoyancyControllers( %this )
 
         // Update the controllers.
         %controller.FluidDensity = BuoyancyControllerToy.FluidDensity;
-        %controller.FlowVelocity = Vector2Direction( %this.FlowAngle, %this.FlowMagnitude );
+        %controller.FlowVelocity = Vector2Direction( Vector2AngleToPoint("0 0",%controller.FlowVelocity), %this.FlowMagnitude );
         %controller.LinearDrag = BuoyancyControllerToy.LinearDrag;
         %controller.AngularDrag = BuoyancyControllerToy.AngularDrag;
         %controller.FluidGravity = BuoyancyControllerToy.FluidGravity;

+ 0 - 1
modules/CollisionToy/1/main.cs

@@ -185,7 +185,6 @@ function CollisionToyBall::onCollision(%this, %object, %collisionDetails)
     // Create a marker sprite with a limited lifetime.
     // Also set this so that it can't be picked so you can't drag it via the Sandbox "pull" feature.
     %object = new Sprite();
-    //%object.BodyType = static;
     %object.Position = %contactPosition;
     %object.Layer = 10;   
     %object.Size = 3;

+ 233 - 104
modules/PointForceControllerToy/1/main.cs

@@ -22,23 +22,45 @@
 
 function PointForceControllerToy::create( %this )
 {
+    // Activate the package.
+    activatePackage( PointForceControllerToyPackage );    
+    
     // Set the sandbox drag mode availability.
-    Sandbox.allowManipulation( pan );
     Sandbox.allowManipulation( pull );
     
     // Set the manipulation mode.
     Sandbox.useManipulation( pull );
     
-    // Configure settings.
-    PointForceControllerToy.ForceRadius = 20;
-    PointForceControllerToy.ForceMagnitude = 50;
-    PointForceControllerToy.DebrisCount = 100;
-
-    // Add options.    
-    addNumericOption("Force Radius", 1, 200, 1, "setForceRadius", PointForceControllerToy.ForceRadius, false, "The radius of the point force.");   
-    addNumericOption("Force Magnitude", -1000, 1000, 10, "setForceMagnitude", PointForceControllerToy.ForceMagnitude, false, "The magnitude of the point force.");   
-    addNumericOption("Debris Count", 10, 1000, 10, "setDebrisCount", PointForceControllerToy.DebrisCount, true, "The amount of debris to use.");
+    // Initialize the toys settings.
+    PointForceControllerToy.autoSpawnAsteroids = false;
+    PointForceControllerToy.showPlanetoid = true;
+    PointForceControllerToy.showExplosions = true;    
+    PointForceControllerToy.nonLinearController = true;
+    PointForceControllerToy.controllerForce = 35;
+    PointForceControllerToy.controllerRadius = 36;
+    PointForceControllerToy.controllerLinearDrag = 0.1;
+    PointForceControllerToy.controllerAngularDrag = 0;
+    PointForceControllerToy.planetoidSize = 26;
+    PointForceControllerToy.asteroidSize = 4;
+    PointForceControllerToy.asteroidDensity = 0.2;
+    PointForceControllerToy.asteroidLifetime = 10;
+    PointForceControllerToy.asteroidSpeed = 30;
     
+    // Add the custom controls.
+    addFlagOption("Auto Spawn Asteroids", "setAutoSpawnAsteroids", PointForceControllerToy.autoSpawnAsteroids, true, "Whether to auto-spawn asteroids or not." );
+    addFlagOption("Show Planetoid", "setShowPlanetoid", PointForceControllerToy.showPlanetoid, true, "Whether to show the planetoid or not or not." );
+    addFlagOption("Show Explosions", "setShowExplosions", PointForceControllerToy.showExplosions, false, "Whether to show the explosions or not or not." );
+    addFlagOption("Controller Non-Linear", "setNonLinearController", PointForceControllerToy.nonLinearController, true, " Whether to apply the controller force non-linearly (using the inverse square law) or linearly" );
+    addNumericOption("Controller Force", -1000, 1000, 10, "setControllerForce", PointForceControllerToy.controllerForce, true, "Sets the controller force.");
+    addNumericOption("Controller Radius", 1, 30, 1, "setControllerRadius", PointForceControllerToy.controllerRadius, true, "Sets the controller radius.");
+    addNumericOption("Controller Linear Drag", 0, 1, 0.1, "setControllerLinearDrag", PointForceControllerToy.controllerLinearDrag, true, "Sets the controller linear drag.");
+    addNumericOption("Controller Angular Drag", 0, 1, 0.1, "setControllerAngularDrag", PointForceControllerToy.controllerAngularDrag, true, "Sets the controller angular drag.");
+    addNumericOption("Planetoid Size", 1, 30, 1, "setPlanetoidSize", PointForceControllerToy.planetoidSize, true, "Sets the planetoid size.");
+    addNumericOption("Asteroid Size", 1, 10, 1, "setAsteroidSize", PointForceControllerToy.asteroidSize, true, "Sets the asteroid size.");
+    addNumericOption("Asteroid Density", 0.1, 10, 0.1, "setAsteroidDensity", PointForceControllerToy.asteroidDensity, true, "Sets the asteroid density.");
+    addNumericOption("Asteroid Lifetime", 1, 10, 1, "setAsteroidLifetime", PointForceControllerToy.asteroidLifetime, true, "Sets the asteroid lifetime.");
+    addNumericOption("Asteroid Speed", 1, 100, 1, "setAsteroidSpeed", PointForceControllerToy.asteroidSpeed, true, "Sets the asteroid speed.");
+      
     // Reset the toy.
     PointForceControllerToy.reset();
 }
@@ -48,6 +70,8 @@ function PointForceControllerToy::create( %this )
 
 function PointForceControllerToy::destroy( %this )
 {
+    // Deactivate the package.
+    deactivatePackage( PointForceControllerToyPackage );    
 }
 
 //-----------------------------------------------------------------------------
@@ -60,8 +84,14 @@ function PointForceControllerToy::reset( %this )
     // Create background.
     %this.createBackground();
     
-    // Create point force controller.
-    %this.createPointForceController();
+    // Create the planetoid.
+    %this.createPlanetoid();
+    
+    // Start a timer throwing asteroids.
+    if ( PointForceControllerToy.autoSpawnAsteroids )
+        %this.startTimer( "createAsteroid", 1000 );
+    else
+        %this.stopTimer();        
 }
 
 //-----------------------------------------------------------------------------
@@ -69,136 +99,235 @@ function PointForceControllerToy::reset( %this )
 function PointForceControllerToy::createBackground( %this )
 {    
     // Create the sprite.
-    %object = new Sprite();
-    
-    // Set the sprite as "static" so it is not affected by gravity.
-    %object.setBodyType( static );
-       
-    // Always try to configure a scene-object prior to adding it to a scene for best performance.
+    %object = new Scroller();
+    %object.BodyType = static;
+    %object.Size = "200 150";
+    %object.SceneLayer = 31;
+    %object.Image = "ToyAssets:SkyBackground";  
+    %object.ScrollX = 2;
+    SandboxScene.add( %object );    
+}
 
-    // Set the position.
-    %object.Position = "0 0";
+//-----------------------------------------------------------------------------
 
-    // Set the size.        
-    %object.Size = "100 75";
-    
-    // Set to the furthest background layer.
-    %object.SceneLayer = 31;
+function PointForceControllerToy::createPlanetoid( %this )
+{
+    if ( PointForceControllerToy.showPlanetoid )
+    {
+        // Create the planetoid.
+        %object = new Sprite()
+        {
+            class = "Planetoid";
+        };
+        //%object.BodyType = static;
+        %object.Size = PointForceControllerToy.planetoidSize;
+        %object.Image = "ToyAssets:Planetoid";
+        %object.AngularVelocity = -5;
+        %object.setDefaultDensity( 10000 );
+        %object.createCircleCollisionShape( PointForceControllerToy.planetoidSize * 0.48 );
+        %object.CollisionCallback = true;
+        SandboxScene.add( %object );
+    }
     
-    // Set the scroller to use an animation!
-    %object.Image = "ToyAssets:highlightBackground";
+    // Create planetoid bubble.
+    %player = new ParticlePlayer();
+    %player.BodyType = static;
+    %player.Particle = "ToyAssets:ForceBubble";
+    %player.SceneLayer = 0;
+    SandboxScene.add( %player );
+        
+    // Create a new controller.
+    %controller = new PointForceController();
+    %controller.setControlLayers( 10 ); // Only affect asteroids.
+    %controller.Radius = PointForceControllerToy.controllerRadius;
+    %controller.Force = PointForceControllerToy.ControllerForce;
+    %controller.NonLinear = PointForceControllerToy.nonLinearController;
+    %controller.LinearDrag = PointForceControllerToy.controllerLinearDrag;
+    %controller.AngularDrag = PointForceControllerToy.controllerAngularDrag;
+    SandboxScene.Controllers.add( %controller );
     
-    // Set the blend color.
-    %object.BlendColor = SlateGray;
+    // This is so we can reference it in the toy, no other reason.
+    PointForceControllerToy.Controller = %controller;
+}
+
+//-----------------------------------------------------------------------------
+
+function Planetoid::onCollision( %this, %object, %collisionDetails )
+{
+    // Are we showing explosions?
+    if ( PointForceControllerToy.showExplosions )
+    {
+        // Yes, so calculate position angle.
+        %positionDelta = Vector2Sub( %object.Position, %this.Position );
+        %angle = -mRadToDeg( mAtan( %positionDelta._0, %positionDelta._1 ) );
+        
+        // Fetch contact position.
+        %contactPosition = %collisionDetails._4 SPC %collisionDetails._5;
+        
+        // Calculate total impact force.
+        %impactForce = mAbs(%collisionDetails._6 / 100) + mAbs(%collisionDetails._7 / 20);
+        
+        // Create explosion.
+        %player = new ParticlePlayer();
+        %player.BodyType = static;
+        %player.Particle = "ToyAssets:impactExplosion";
+        %player.Position = %contactPosition;
+        %player.Angle = %angle;
+        %player.SizeScale = mClamp( %impactForce, 0.1, 10 );
+        %player.SceneLayer = 0;
+        SandboxScene.add( %player );            
+    }
     
-    // Create border collisions.
-    %object.createEdgeCollisionShape( -50, -37.5, -50, 37.5 );
-    %object.createEdgeCollisionShape( 50, -37.5, 50, 37.5 );
-    %object.createEdgeCollisionShape( -50, 37.5, 50, 37.5 );
-    %object.createEdgeCollisionShape( -50, -34.5, 50, -34.5 );
-           
-    // Add the sprite to the scene.
-    SandboxScene.add( %object );    
+    // Delete the asteroid.
+    %object.Trail.LinearVelocity = 0;
+    %object.Trail.AngularVelocity = 0;
+    %object.Trail.safeDelete();
+    %object.safeDelete();  
 }
 
 //-----------------------------------------------------------------------------
 
-function PointForceControllerToy::createSprite( %this, %asset, %position, %size, %angle, %blendColor )
-{    
-    // Create the sprite.
+function PointForceControllerToy::createAsteroid( %this, %position )
+{
+    // Create an asteroid.
     %object = new Sprite();
+    %object.Position = %position !$= "" ? %position : -40 SPC getRandom(-35,35);
+    %object.Size = PointForceControllerToy.asteroidSize;
+    %object.Image = "ToyAssets:Asteroids";
+    %object.ImageFrame = getRandom(0,3);
+    %object.SceneLayer = 10;
+    %object.setDefaultDensity( PointForceControllerToy.asteroidDensity );
+    %object.createCircleCollisionShape( PointForceControllerToy.asteroidSize * 0.4 );
+    %object.setLinearVelocity( PointForceControllerToy.asteroidSpeed, 0 );
+    %object.setAngularVelocity( getRandom(-90,90) );
+    %object.setLifetime( PointForceControllerToy.asteroidLifetime );  
+    SandboxScene.add( %object ); 
     
-    // Set the position.
-    %object.Position = %position;
+    // Create fire trail.
+    %player = new ParticlePlayer();
+    %player.Particle = "ToyAssets:bonfire";
+    %player.Position = %object.Position;
+    %player.EmissionRateScale = 3;
+    %player.SizeScale = 2;
+    %player.SceneLayer = 11;
+    %player.setLifetime( PointForceControllerToy.asteroidLifetime );  
+    SandboxScene.add( %player );
+    %jointId = SandboxScene.createRevoluteJoint( %object, %player );
+    SandboxScene.setRevoluteJointLimit( %jointId, 0, 0 );    
 
-    // Set the size.        
-    %object.Size = %size;
-    
-    // Set the angle.
-    %object.Angle = %angle;
-       
-    // Set the scroller to use an animation!
-    %object.Image = %asset;
-    
-    // Set the blend color.
-    %object.BlendColor = %blendColor $= "" ? White : %blendColor;
+    %object.Trail = %player;
             
-    // Add the sprite to the scene.
-    SandboxScene.add( %object );    
-    
     return %object;
 }
 
 //-----------------------------------------------------------------------------
 
-function PointForceControllerToy::createPointForceController( %this )
+function PointForceControllerToy::setAutoSpawnAsteroids( %this, %value )
 {
-    // Create a new controller.
-    %controller = new PointForceController();
-    
-    // Set scene controller.
-    PointForceControllerToy.SceneController = %controller;
+    %this.autoSpawnAsteroids = %value;
+}
 
-    // Update the point force controller.
-    %this.updatePointForceController();
-    
-    // Add the controller.
-    SandboxScene.Controllers.add( %controller );
-   
-    // Create some sprites used by the controller.
-    for( %n = 0; %n < PointForceControllerToy.DebrisCount; %n++ )
-    {    
-        %sizeX = getRandom(1,4);
-        %sizeY = getRandom(1,4);
-        %size = %sizeX SPC %sizeY;
-        
-        // Create some sprites.
-        %sprite = %this.createSprite( "ToyAssets:blocks", getRandom(-40,40) SPC getRandom(-30,30), %size, getRandom(0,360), White );
-        %sprite.Frame = getRandom( 0, 55 );
-        %sprite.createPolygonBoxCollisionShape( %sizeX, %sizeY );
-        %sprite.setAngularVelocity(getRandom(-180,180));
-        
-        // Add to the controller.
-        %controller.add( %sprite );
-    }   
-    
+//-----------------------------------------------------------------------------
+
+function PointForceControllerToy::setShowPlanetoid( %this, %value )
+{
+    %this.showPlanetoid = %value;
 }
 
 //-----------------------------------------------------------------------------
 
-function PointForceControllerToy::updatePointForceController( %this )
+function AngryBirdsSpaceToy::setShowExplosions( %this, %value )
 {
-    // Fetch the controller.
-    %controller = PointForceControllerToy.SceneController;
-    
-    // Update the controller.
-    %controller.Radius = %this.ForceRadius;
-    %controller.Force = %this.ForceMagnitude;
+    %this.showExplosions = %value;
 }
 
 //-----------------------------------------------------------------------------
 
-function PointForceControllerToy::setForceRadius(%this, %value)
+function PointForceControllerToy::setNonLinearController( %this, %value )
 {
-    %this.ForceRadius = %value;
-    
-    // Update the controller.
-    %this.updatePointForceController();   
+    %this.nonLinearController = %value;
 }
 
 //-----------------------------------------------------------------------------
 
-function PointForceControllerToy::setForceMagnitude(%this, %value)
+function PointForceControllerToy::setControllerForce( %this, %value )
 {
-    %this.ForceMagnitude = %value;
-    
-    // Update the controller.
-    %this.updatePointForceController();   
+    %this.controllerForce = %value;
+}
+
+//-----------------------------------------------------------------------------
+
+function PointForceControllerToy::setControllerRadius( %this, %value )
+{
+    %this.controllerRadius = %value;
+}
+
+//-----------------------------------------------------------------------------
+
+function PointForceControllerToy::setControllerLinearDrag( %this, %value )
+{
+    %this.controllerLinearDrag = %value;
+}
+
+//-----------------------------------------------------------------------------
+
+function PointForceControllerToy::setControllerAngularDrag( %this, %value )
+{
+    %this.controllerAngularDrag = %value;
+}
+
+//-----------------------------------------------------------------------------
+
+function PointForceControllerToy::setPlanetoidSize( %this, %value )
+{
+    %this.planetoidSize = %value;
+}
+
+//-----------------------------------------------------------------------------
+
+function PointForceControllerToy::setAsteroidSize( %this, %value )
+{
+    %this.asteroidSize = %value;
+}
+
+//-----------------------------------------------------------------------------
+
+function PointForceControllerToy::setAsteroidDensity( %this, %value )
+{
+    %this.asteroidDensity = %value;
 }
 
 //-----------------------------------------------------------------------------
 
-function PointForceControllerToy::setDebrisCount(%this, %value)
+function PointForceControllerToy::setAsteroidLifetime( %this, %value )
 {
-    %this.DebrisCount = %value;
+    %this.asteroidLifetime = %value;
 }
+
+//-----------------------------------------------------------------------------
+
+function PointForceControllerToy::setAsteroidSpeed( %this, %value )
+{
+    %this.asteroidSpeed = %value;
+}
+
+//-----------------------------------------------------------------------------
+
+package PointForceControllerToyPackage
+{
+
+function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
+{
+    // Call parent.
+    Parent::onTouchDown(%this, %touchID, %worldPosition );
+
+    // Create an asteroid.
+    %object = PointForceControllerToy.createAsteroid( %worldPosition );
+    
+    if ( %worldPosition.x < PointForceControllerToy.Controller.Position.x )
+        %object.setLinearVelocity( PointForceControllerToy.asteroidSpeed, 0 );
+    else
+        %object.setLinearVelocity( -PointForceControllerToy.asteroidSpeed, 0 );    
+}
+    
+};

+ 1 - 1
modules/PointForceControllerToy/1/module.taml

@@ -1,7 +1,7 @@
 <ModuleDefinition
 	ModuleId="PointForceControllerToy"
 	VersionId="1"
-	Description="Demonstrates using a point-force controller."
+	Description="Demonstrates the point-force controller."
 	Dependencies="ToyAssets=1"
 	Type="toy"
 	ToyCategoryIndex="3"

+ 3 - 0
modules/ToyAssets/1/assets/images/Planetoid.asset.taml

@@ -0,0 +1,3 @@
+<ImageAsset
+    AssetName="Planetoid"
+    ImageFile="Planetoid.png" />

BIN
modules/ToyAssets/1/assets/images/Planetoid.png


+ 49 - 0
modules/ToyAssets/1/assets/particles/forceBubble.asset.taml

@@ -0,0 +1,49 @@
+<ParticleAsset
+    AssetName="ForceBubble">
+    <ParticleAssetEmitter
+        EmitterName="PermanentBubble"
+        Image="@asset=ToyAssets:Particles5"
+        Frame="1"
+		SingleParticle="1">
+        <ParticleAssetEmitter.Fields>
+            <SizeX>
+				<Key Time="0" Value="72"/>
+            </SizeX>
+            <AlphaChannel>
+				<Key Time="0" Value="0.2"/>
+			</AlphaChannel>
+        </ParticleAssetEmitter.Fields>
+    </ParticleAssetEmitter>
+    <ParticleAssetEmitter
+        EmitterName="MovingBubbles"
+        Image="@asset=ToyAssets:Particles5"
+        Frame="1">
+        <ParticleAssetEmitter.Fields>
+            <Quantity>
+				<Key Time="0" Value="0.2"/>
+            </Quantity>
+            <QuantityVariation>
+				<Key Time="0" Value="0.1"/>
+            </QuantityVariation>			
+            <Lifetime>
+				<Key Time="0" Value="5"/>
+            </Lifetime>						
+            <Speed>
+				<Key Time="0" Value="0"/>
+            </Speed>			
+            <SizeX>
+				<Key Time="0" Value="72.0"/>
+            </SizeX>			
+            <SizeXLife>
+				<Key Time="0" Value="0.3"/>
+				<Key Time="1" Value="1.0"/>
+            </SizeXLife>			
+            <AlphaChannel>
+				<Key Time="0.0" Value="0.0"/>
+				<Key Time="0.3" Value="0.2"/>
+				<Key Time="0.9" Value="0.1"/>
+				<Key Time="1.0" Value="0.0"/>				
+			</AlphaChannel>
+        </ParticleAssetEmitter.Fields>
+    </ParticleAssetEmitter>	
+</ParticleAsset>

+ 4 - 0
modules/ToyAssets/1/assets/particles/impactExplosion.asset.taml

@@ -7,6 +7,8 @@
         EmitterType="BOX"
         EmitterAngle="90"
         EmitterSize="2 1"
+		AttachPositionToEmitter="1"
+		AttachRotationToEmitter="1"
         FixedForceAngle="-90"
         OldestInFront="1"
         Image="@asset=ToyAssets:Asteroids"
@@ -44,6 +46,8 @@
         EmitterName="flames"
         EmitterType="LINE"
         EmitterSize="1 0"
+		AttachPositionToEmitter="1"
+		AttachRotationToEmitter="1"		
         IntenseParticles="1"
         OldestInFront="1"
         Animation="@asset=ToyAssets:Impact_ExplosionAnimation">

+ 6 - 0
tools/VisualStudioVisualizer/VS2012/T2D_Vector2.natvis

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+    <Type Name="b2Vec2">
+		<DisplayString>{{ X = {x}, Y = {y} }}</DisplayString>
+    </Type>
+</AutoVisualizer>