Browse Source

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

capnlove 12 years ago
parent
commit
8c8dad8
40 changed files with 1005 additions and 107 deletions
  1. 3 0
      engine/compilers/VisualStudio 2010/Torque 2D.vcxproj
  2. 15 0
      engine/compilers/VisualStudio 2010/Torque 2D.vcxproj.filters
  3. 3 0
      engine/compilers/VisualStudio 2012/Torque 2D.vcxproj
  4. 15 0
      engine/compilers/VisualStudio 2012/Torque 2D.vcxproj.filters
  5. 24 0
      engine/compilers/Xcode/Torque2D.xcodeproj/project.pbxproj
  6. 24 0
      engine/compilers/Xcode_iOS/Torque2D.xcodeproj/project.pbxproj
  7. 21 0
      engine/source/2d/assets/AnimationAsset.cc
  8. 1 0
      engine/source/2d/assets/AnimationAsset.h
  9. 51 0
      engine/source/2d/assets/ImageAsset.cc
  10. 1 0
      engine/source/2d/assets/ImageAsset.h
  11. 41 41
      engine/source/2d/controllers/BuoyancyController.cc
  12. 29 8
      engine/source/2d/controllers/PointForceController.cc
  13. 13 0
      engine/source/2d/controllers/PointForceController.h
  14. 23 0
      engine/source/2d/controllers/PointForceController_ScriptBinding.h
  15. 44 3
      engine/source/2d/core/SpriteBatch.cc
  16. 6 1
      engine/source/2d/core/SpriteBatch.h
  17. 5 2
      engine/source/2d/core/SpriteBatchItem.cc
  18. 6 0
      engine/source/2d/core/SpriteBatchItem.h
  19. 271 0
      engine/source/2d/experimental/composites/WaveComposite.cc
  20. 93 0
      engine/source/2d/experimental/composites/WaveComposite.h
  21. 22 0
      engine/source/2d/experimental/composites/WaveComposite_ScriptBinding.h
  22. 23 0
      engine/source/2d/sceneobject/CompositeSprite.cc
  23. 3 0
      engine/source/2d/sceneobject/CompositeSprite.h
  24. 11 5
      engine/source/2d/sceneobject/ParticlePlayer.cc
  25. 6 1
      engine/source/2d/sceneobject/ParticlePlayer.h
  26. 21 0
      engine/source/assets/assetBase.cc
  27. 1 0
      engine/source/assets/assetBase.h
  28. 13 13
      engine/source/assets/assetManager.cc
  29. 29 4
      engine/source/assets/assetManager.h
  30. 37 18
      engine/source/assets/assetManager_ScriptBinding.h
  31. 21 0
      engine/source/audio/AudioAsset.cc
  32. 1 0
      engine/source/audio/AudioAsset.h
  33. 9 8
      engine/source/gui/guiTypes.cc
  34. 1 1
      engine/source/module/moduleManager.cc
  35. 1 0
      modules/AppCore/1/scripts/defaultPreferences.cs
  36. 93 0
      modules/Experiments/WaveCompositeToy/1/main.cs
  37. 10 0
      modules/Experiments/WaveCompositeToy/1/module.taml
  38. 12 1
      modules/PointForceControllerToy/1/main.cs
  39. 2 1
      modules/Sandbox/1/scripts/toolbox.cs
  40. 0 0
      modules/ToyAssets/1/assets/images/skyBackground.asset.taml

+ 3 - 0
engine/compilers/VisualStudio 2010/Torque 2D.vcxproj

@@ -255,6 +255,7 @@
     <ClCompile Include="..\..\source\2d\core\SpriteProxyBase.cc" />
     <ClCompile Include="..\..\source\2d\core\Utility.cc" />
     <ClCompile Include="..\..\source\2d\core\Vector2.cc" />
+    <ClCompile Include="..\..\source\2d\experimental\composites\WaveComposite.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiImageButtonCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSceneObjectCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSpriteCtrl.cc" />
@@ -646,6 +647,8 @@
     <ClInclude Include="..\..\source\2d\core\Utility.h" />
     <ClInclude Include="..\..\source\2d\core\Vector2.h" />
     <ClInclude Include="..\..\source\2d\core\Vector2_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\2d\experimental\composites\WaveComposite.h" />
+    <ClInclude Include="..\..\source\2d\experimental\composites\WaveComposite_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\gui\guiImageButtonCtrl.h" />
     <ClInclude Include="..\..\source\2d\gui\guiImageButtonCtrl_ScriptBindings.h" />
     <ClInclude Include="..\..\source\2d\gui\guiSceneObjectCtrl.h" />

+ 15 - 0
engine/compilers/VisualStudio 2010/Torque 2D.vcxproj.filters

@@ -172,6 +172,12 @@
     <Filter Include="2d\controllers\core">
       <UniqueIdentifier>{6aeaed85-4546-4496-8415-72a392e830ba}</UniqueIdentifier>
     </Filter>
+    <Filter Include="2d\experimental">
+      <UniqueIdentifier>{de8d0673-dfd7-468d-b793-4b0488132183}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="2d\experimental\composites">
+      <UniqueIdentifier>{b250a30d-b6a9-48b5-9193-2b9bedf765ee}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\audio\audio.cc">
@@ -1299,6 +1305,9 @@
     <ClCompile Include="..\..\source\2d\core\SpriteBatchQuery.cc">
       <Filter>2d\core</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\source\2d\experimental\composites\WaveComposite.cc">
+      <Filter>2d\experimental\composites</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -2667,6 +2676,12 @@
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQueryResult.h">
       <Filter>2d\core</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\source\2d\experimental\composites\WaveComposite.h">
+      <Filter>2d\experimental\composites</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\experimental\composites\WaveComposite_ScriptBinding.h">
+      <Filter>2d\experimental\composites</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">

+ 3 - 0
engine/compilers/VisualStudio 2012/Torque 2D.vcxproj

@@ -262,6 +262,7 @@
     <ClCompile Include="..\..\source\2d\core\SpriteProxyBase.cc" />
     <ClCompile Include="..\..\source\2d\core\Utility.cc" />
     <ClCompile Include="..\..\source\2d\core\Vector2.cc" />
+    <ClCompile Include="..\..\source\2d\experimental\composites\WaveComposite.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiImageButtonCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSceneObjectCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSpriteCtrl.cc" />
@@ -653,6 +654,8 @@
     <ClInclude Include="..\..\source\2d\core\Utility.h" />
     <ClInclude Include="..\..\source\2d\core\Vector2.h" />
     <ClInclude Include="..\..\source\2d\core\Vector2_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\2d\experimental\composites\WaveComposite.h" />
+    <ClInclude Include="..\..\source\2d\experimental\composites\WaveComposite_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\gui\guiImageButtonCtrl.h" />
     <ClInclude Include="..\..\source\2d\gui\guiImageButtonCtrl_ScriptBindings.h" />
     <ClInclude Include="..\..\source\2d\gui\guiSceneObjectCtrl.h" />

+ 15 - 0
engine/compilers/VisualStudio 2012/Torque 2D.vcxproj.filters

@@ -172,6 +172,12 @@
     <Filter Include="2d\controllers\core">
       <UniqueIdentifier>{e11e344e-6418-4ed0-980a-77d66cd64d65}</UniqueIdentifier>
     </Filter>
+    <Filter Include="2d\experimental">
+      <UniqueIdentifier>{1eb9e730-583b-4aa4-ac25-b83960799ba4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="2d\experimental\composites">
+      <UniqueIdentifier>{30e1ec13-118b-4d50-8e04-76e76fcfdc01}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\audio\audio.cc">
@@ -1299,6 +1305,9 @@
     <ClCompile Include="..\..\source\2d\core\SpriteBatchQuery.cc">
       <Filter>2d\core</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\source\2d\experimental\composites\WaveComposite.cc">
+      <Filter>2d\experimental\composites</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -2664,6 +2673,12 @@
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQueryResult.h">
       <Filter>2d\core</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\source\2d\experimental\composites\WaveComposite.h">
+      <Filter>2d\experimental\composites</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\experimental\composites\WaveComposite_ScriptBinding.h">
+      <Filter>2d\experimental\composites</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">

+ 24 - 0
engine/compilers/Xcode/Torque2D.xcodeproj/project.pbxproj

@@ -25,6 +25,7 @@
 		2ACFC0A8166CE1AB00FE7370 /* platformMemoryTests.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2ACFC0A7166CE1AB00FE7370 /* platformMemoryTests.cc */; };
 		2ADCAC1516A41E5500E07619 /* ParticleAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2ADCAC1116A41E5500E07619 /* ParticleAsset.cc */; };
 		2ADCAC1716A41E5500E07619 /* ParticleAssetField.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2ADCAC1316A41E5500E07619 /* ParticleAssetField.cc */; };
+		2AE2938516EF4C220015E200 /* WaveComposite.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE2938316EF4C220015E200 /* WaveComposite.cc */; };
 		2AE2F55D16D6B08800B6A058 /* BuoyancyController.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE2F55B16D6B08800B6A058 /* BuoyancyController.cc */; };
 		2AE5B54216A6D860006908D5 /* ParticleAssetFieldCollection.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE5B54016A6D860006908D5 /* ParticleAssetFieldCollection.cc */; };
 		2AE851D21681E56E00193F17 /* color.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE851D11681E56E00193F17 /* color.cc */; };
@@ -496,6 +497,9 @@
 		2ADCAC1216A41E5500E07619 /* ParticleAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParticleAsset.h; sourceTree = "<group>"; };
 		2ADCAC1316A41E5500E07619 /* ParticleAssetField.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParticleAssetField.cc; sourceTree = "<group>"; };
 		2ADCAC1416A41E5500E07619 /* ParticleAssetField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParticleAssetField.h; sourceTree = "<group>"; };
+		2AE2938216EF4C220015E200 /* WaveComposite_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WaveComposite_ScriptBinding.h; path = experimental/composites/WaveComposite_ScriptBinding.h; sourceTree = "<group>"; };
+		2AE2938316EF4C220015E200 /* WaveComposite.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WaveComposite.cc; path = experimental/composites/WaveComposite.cc; sourceTree = "<group>"; };
+		2AE2938416EF4C220015E200 /* WaveComposite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WaveComposite.h; path = experimental/composites/WaveComposite.h; sourceTree = "<group>"; };
 		2AE2F55A16D6B08800B6A058 /* BuoyancyController_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BuoyancyController_ScriptBinding.h; path = controllers/BuoyancyController_ScriptBinding.h; sourceTree = "<group>"; };
 		2AE2F55B16D6B08800B6A058 /* BuoyancyController.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BuoyancyController.cc; path = controllers/BuoyancyController.cc; sourceTree = "<group>"; };
 		2AE2F55C16D6B08800B6A058 /* BuoyancyController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BuoyancyController.h; path = controllers/BuoyancyController.h; sourceTree = "<group>"; };
@@ -1407,6 +1411,24 @@
 			name = controllers;
 			sourceTree = "<group>";
 		};
+		2AE2938016EF4BFA0015E200 /* experimental */ = {
+			isa = PBXGroup;
+			children = (
+				2AE2938116EF4C070015E200 /* composites */,
+			);
+			name = experimental;
+			sourceTree = "<group>";
+		};
+		2AE2938116EF4C070015E200 /* composites */ = {
+			isa = PBXGroup;
+			children = (
+				2AE2938216EF4C220015E200 /* WaveComposite_ScriptBinding.h */,
+				2AE2938316EF4C220015E200 /* WaveComposite.cc */,
+				2AE2938416EF4C220015E200 /* WaveComposite.h */,
+			);
+			name = composites;
+			sourceTree = "<group>";
+		};
 		865A20BD1651589F00527C44 /* Resources */ = {
 			isa = PBXGroup;
 			children = (
@@ -1804,6 +1826,7 @@
 		86BC7E7516518D4600D96ADF /* 2d */ = {
 			isa = PBXGroup;
 			children = (
+				2AE2938016EF4BFA0015E200 /* experimental */,
 				2AB4F1CF16D55B7300C9A27B /* controllers */,
 				86BC7E7616518D4600D96ADF /* assets */,
 				86BC7E8016518D4600D96ADF /* core */,
@@ -3278,6 +3301,7 @@
 				2AB4C19F16DE9F0600B02479 /* PickingSceneController.cc in Sources */,
 				2AB4C1A316DE9F1100B02479 /* AmbientForceController.cc in Sources */,
 				2ACF5A2816E52D4B00F838D9 /* SpriteBatchQuery.cc in Sources */,
+				2AE2938516EF4C220015E200 /* WaveComposite.cc in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 24 - 0
engine/compilers/Xcode_iOS/Torque2D.xcodeproj/project.pbxproj

@@ -16,6 +16,7 @@
 		2AB97A2116B66BE50080F940 /* tamlCustom.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AB97A1F16B66BE50080F940 /* tamlCustom.cc */; };
 		2AC4404E16B0144500FC4091 /* ImageFont.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AC4404C16B0144500FC4091 /* ImageFont.cc */; };
 		2ACF5A2C16E52D6A00F838D9 /* SpriteBatchQuery.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF5A2916E52D6A00F838D9 /* SpriteBatchQuery.cc */; };
+		2AE2938B16EF4C480015E200 /* WaveComposite.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE2938916EF4C480015E200 /* WaveComposite.cc */; };
 		2AE2F55916D6B07200B6A058 /* BuoyancyController.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE2F55716D6B07200B6A058 /* BuoyancyController.cc */; };
 		2AED7D9316B70102003482CF /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AED7D9216B70102003482CF /* CoreText.framework */; };
 		2AF1C54B16B439D900C1CF3A /* declaredAssets.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AF1C54716B439D900C1CF3A /* declaredAssets.cc */; };
@@ -508,6 +509,9 @@
 		2ACF5A2A16E52D6A00F838D9 /* SpriteBatchQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteBatchQuery.h; sourceTree = "<group>"; };
 		2ACF5A2B16E52D6A00F838D9 /* SpriteBatchQueryResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteBatchQueryResult.h; sourceTree = "<group>"; };
 		2AD07B2716D15F8E0070DC79 /* simObjectTimerEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simObjectTimerEvent.h; sourceTree = "<group>"; };
+		2AE2938816EF4C480015E200 /* WaveComposite_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WaveComposite_ScriptBinding.h; path = experimental/composites/WaveComposite_ScriptBinding.h; sourceTree = "<group>"; };
+		2AE2938916EF4C480015E200 /* WaveComposite.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WaveComposite.cc; path = experimental/composites/WaveComposite.cc; sourceTree = "<group>"; };
+		2AE2938A16EF4C480015E200 /* WaveComposite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WaveComposite.h; path = experimental/composites/WaveComposite.h; sourceTree = "<group>"; };
 		2AE2F55616D6B07200B6A058 /* BuoyancyController_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BuoyancyController_ScriptBinding.h; path = controllers/BuoyancyController_ScriptBinding.h; sourceTree = "<group>"; };
 		2AE2F55716D6B07200B6A058 /* BuoyancyController.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BuoyancyController.cc; path = controllers/BuoyancyController.cc; sourceTree = "<group>"; };
 		2AE2F55816D6B07200B6A058 /* BuoyancyController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BuoyancyController.h; path = controllers/BuoyancyController.h; sourceTree = "<group>"; };
@@ -1477,6 +1481,24 @@
 			name = controllers;
 			sourceTree = "<group>";
 		};
+		2AE2938616EF4C310015E200 /* experimental */ = {
+			isa = PBXGroup;
+			children = (
+				2AE2938716EF4C3B0015E200 /* composites */,
+			);
+			name = experimental;
+			sourceTree = "<group>";
+		};
+		2AE2938716EF4C3B0015E200 /* composites */ = {
+			isa = PBXGroup;
+			children = (
+				2AE2938816EF4C480015E200 /* WaveComposite_ScriptBinding.h */,
+				2AE2938916EF4C480015E200 /* WaveComposite.cc */,
+				2AE2938A16EF4C480015E200 /* WaveComposite.h */,
+			);
+			name = composites;
+			sourceTree = "<group>";
+		};
 		867BAC9116AEC8BB0033868F /* platformiOS */ = {
 			isa = PBXGroup;
 			children = (
@@ -1556,6 +1578,7 @@
 		867BACF816AEC9050033868F /* 2d */ = {
 			isa = PBXGroup;
 			children = (
+				2AE2938616EF4C310015E200 /* experimental */,
 				2AB4F1D416D55B9F00C9A27B /* controllers */,
 				867BACF916AEC9050033868F /* assets */,
 				867BAD0C16AEC9050033868F /* core */,
@@ -3414,6 +3437,7 @@
 				2AB4C1B016DE9F6700B02479 /* GroupedSceneController.cc in Sources */,
 				2AB4C1B116DE9F6700B02479 /* PickingSceneController.cc in Sources */,
 				2ACF5A2C16E52D6A00F838D9 /* SpriteBatchQuery.cc in Sources */,
+				2AE2938B16EF4C480015E200 /* WaveComposite.cc in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 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; };

+ 41 - 41
engine/source/2d/controllers/BuoyancyController.cc

@@ -123,7 +123,7 @@ void BuoyancyController::integrate( Scene* pScene, const F32 totalTime, const F3
             continue;
 
         // Ignore if it's a static body.
-        if ( pSceneObject->getBodyType() == b2BodyType::b2_staticBody )
+        if ( pSceneObject->getBodyType() == b2_staticBody )
             continue;
 
         // Fetch the shape count.
@@ -136,10 +136,10 @@ void BuoyancyController::integrate( Scene* pScene, const F32 totalTime, const F3
         // Fetch the body transform.
         const b2Transform& bodyTransform = pSceneObject->getBody()->GetTransform();;
 
-		Vector2 areaCenter(0.0f, 0.0f);
-		Vector2 massCenter(0.0f, 0.0f);
-		F32 area = 0.0f;
-		F32 mass = 0.0f;
+        Vector2 areaCenter(0.0f, 0.0f);
+        Vector2 massCenter(0.0f, 0.0f);
+        F32 area = 0.0f;
+        F32 mass = 0.0f;
 
         // Yes, so iterate them.
         for( U32 i = 0; i < shapeCount; ++i )
@@ -150,9 +150,9 @@ void BuoyancyController::integrate( Scene* pScene, const F32 totalTime, const F3
             // Fetch the shape.
             const b2Shape* pShape = fixtureDef.shape;
 
-			Vector2 shapeCenter(0.0f, 0.0f);
+            Vector2 shapeCenter(0.0f, 0.0f);
             
-			F32 shapeArea = 0.0f;
+            F32 shapeArea = 0.0f;
 
             // Calculate the area for the shape type.
             if ( pShape->GetType() == b2Shape::e_circle )
@@ -174,36 +174,36 @@ void BuoyancyController::integrate( Scene* pScene, const F32 totalTime, const F3
             }
 
             // Calculate area.
-			area += shapeArea;
-			areaCenter.x += shapeArea * shapeCenter.x;
-			areaCenter.y += shapeArea * shapeCenter.y;
+            area += shapeArea;
+            areaCenter.x += shapeArea * shapeCenter.x;
+            areaCenter.y += shapeArea * shapeCenter.y;
 
             // Calculate mass.
-			const F32 shapeDensity = mUseShapeDensity ? fixtureDef.density : 1.0f;
-			mass += shapeArea*shapeDensity;
-			massCenter.x += shapeArea * shapeCenter.x * shapeDensity;
-			massCenter.y += shapeArea * shapeCenter.y * shapeDensity;
+            const F32 shapeDensity = mUseShapeDensity ? fixtureDef.density : 1.0f;
+            mass += shapeArea*shapeDensity;
+            massCenter.x += shapeArea * shapeCenter.x * shapeDensity;
+            massCenter.y += shapeArea * shapeCenter.y * shapeDensity;
         }
 
         // Skip not in water.
-		if( area < b2_epsilon )
-			continue;
+        if( area < b2_epsilon )
+            continue;
 
         // Calculate area/mass centers.
-		areaCenter.x /= area;
-		areaCenter.y /= area;
-		massCenter.x /= mass;
-		massCenter.y /= mass;
+        areaCenter.x /= area;
+        areaCenter.y /= area;
+        massCenter.x /= mass;
+        massCenter.y /= mass;
 
-		// Buoyancy
-		const Vector2 buoyancyForce = -mFluidDensity * area * mFluidGravity;
+        // Buoyancy
+        const Vector2 buoyancyForce = -mFluidDensity * area * mFluidGravity;
         pSceneObject->applyForce(buoyancyForce, massCenter);
 
-		// Linear drag
+        // Linear drag
         const Vector2 dragForce = (pSceneObject->getLinearVelocityFromWorldPoint(areaCenter) - mFlowVelocity) * (-mLinearDrag * area);
-		pSceneObject->applyForce(dragForce, areaCenter );
+        pSceneObject->applyForce(dragForce, areaCenter );
 
-		// Angular drag
+        // Angular drag
         pSceneObject->applyTorque( -pSceneObject->getInertia() / pSceneObject->getMass() * area * pSceneObject->getAngularVelocity()*mAngularDrag );
     }
 }
@@ -225,30 +225,30 @@ F32 BuoyancyController::ComputeCircleSubmergedArea( const b2Transform& bodyTrans
 
     // Submerged?
     if (l < - radius + FLT_MIN)
-	{
+    {
         // No, so return zero area submerged.
-		return 0.0f;
-	}
+        return 0.0f;
+    }
 
-	// Completely wet?
-	if (l > pShape->m_radius)
-	{
+    // Completely wet?
+    if (l > pShape->m_radius)
+    {
         // Yes!
-		center = worldShapeCenter;
-		return  b2_pi * radius * radius;
-	}
-		
-	// Partial submersion.
+        center = worldShapeCenter;
+        return  b2_pi * radius * radius;
+    }
+        
+    // Partial submersion.
     const F32 r2 = radius * radius;
     const F32 l2 = l * l;
     const F32 area = r2 *( mAsin(l / radius) + b2_pi / 2.0f) + l * mSqrt( r2 - l2 );
     const F32 com = -2.0f / 3.0f * mPow(r2 - l2, 1.5f) / area;
-	
+    
     // Calculate center.
-	center.x = worldShapeCenter.x + mSurfaceNormal.x * com;
-	center.y = worldShapeCenter.y + mSurfaceNormal.y * com;
-		
-	return area;
+    center.x = worldShapeCenter.x + mSurfaceNormal.x * com;
+    center.y = worldShapeCenter.y + mSurfaceNormal.y * com;
+        
+    return area;
 }
 
 //------------------------------------------------------------------------------

+ 29 - 8
engine/source/2d/controllers/PointForceController.cc

@@ -86,6 +86,14 @@ void PointForceController::copyTo(SimObject* object)
 
 //------------------------------------------------------------------------------
 
+void PointForceController::setTrackedObject( SceneObject* pSceneObject )
+{
+    // Set tracked object.
+    mTrackedObject = pSceneObject;
+}
+
+//------------------------------------------------------------------------------
+
 void PointForceController::integrate( Scene* pScene, const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats )
 {
     // Finish if the attractor would have no effect.
@@ -95,10 +103,13 @@ void PointForceController::integrate( Scene* pScene, const F32 totalTime, const
     // Prepare query filter.
     WorldQuery* pWorldQuery = prepareQueryFilter( pScene );
 
+    // Fetch the current position.
+    const Vector2 currentPosition = getCurrentPosition();
+
     // Calculate the AABB of the attractor.
     b2AABB aabb;
-    aabb.lowerBound.Set( mPosition.x - mRadius, mPosition.y - mRadius );
-    aabb.upperBound.Set( mPosition.x + mRadius, mPosition.y + mRadius );
+    aabb.lowerBound.Set( currentPosition.x - mRadius, currentPosition.y - mRadius );
+    aabb.upperBound.Set( currentPosition.x + mRadius, currentPosition.y + mRadius );
 
     // Query for candidate objects.
     pWorldQuery->anyQueryArea( aabb ); 
@@ -123,28 +134,38 @@ void PointForceController::integrate( Scene* pScene, const F32 totalTime, const
     const F32 linearDrag = mClampF( mLinearDrag, 0.0f, 1.0f ) * elapsedTime;
     const F32 angularDrag = mClampF( mAngularDrag, 0.0f, 1.0f ) * elapsedTime;
 
+    // Fetch the tracked object.
+    const SceneObject* pTrackedObject = mTrackedObject;
+
     // Iterate the results.
     for ( U32 n = 0; n < resultCount; n++ )
     {
         // Fetch the scene object.
         SceneObject* pSceneObject = queryResults[n].mpSceneObject;
 
+        // Ignore if it's the tracked object.
+        if ( pSceneObject == pTrackedObject )
+            continue;
+
         // Ignore if it's a static body.
         if ( pSceneObject->getBodyType() == b2_staticBody )
             continue;
 
-        // Calculate the force distance to the controllers position.
-        Vector2 distanceForce = mPosition - pSceneObject->getPosition();
+        // Calculate the force distance to the controllers current position.
+        Vector2 distanceForce = currentPosition - pSceneObject->getPosition();
+
+        // Fetch distance squared.
+        const F32 distanceSqr = distanceForce.LengthSquared();
 
-        // Skip if the position is outside the radius.
-        if ( distanceForce.LengthSquared() > radiusSqr )
+        // Skip if the position is outside the radius or is centered on the controller.
+        if ( distanceSqr > radiusSqr || distanceSqr < FLT_EPSILON )
             continue;
 
         // Non-Linear force?
         if ( mNonLinear )
         {
             // Yes, so use an approximation of the inverse-square law.
-            distanceForce *= (1.0f / distanceForce.LengthSquared()) * forceSqr;
+            distanceForce *= (1.0f / distanceSqr) * forceSqr;
         }
         else
         {
@@ -191,5 +212,5 @@ void PointForceController::renderOverlay( Scene* pScene, const SceneRenderState*
     Parent::renderOverlay( pScene, pSceneRenderState, pBatchRenderer );
 
     // Draw force radius.
-    pScene->mDebugDraw.DrawCircle( mPosition, mRadius, ColorF(1.0f, 1.0f, 0.0f ) );
+    pScene->mDebugDraw.DrawCircle( getCurrentPosition(), mRadius, ColorF(1.0f, 1.0f, 0.0f ) );
 }

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

@@ -56,6 +56,9 @@ private:
 	/// Linear drag co-efficient.
 	F32 mAngularDrag;
 
+    /// Tracked object.
+    SimObjectPtr<SceneObject> mTrackedObject;
+
 public:
     PointForceController();
     virtual ~PointForceController();
@@ -75,6 +78,16 @@ public:
     inline F32 getLinearDrag( void ) const { return mLinearDrag; }
     inline void setAngularDrag( const F32 angularDrag ) { mAngularDrag = angularDrag; }
     inline F32 getAngularDrag( void ) const { return mAngularDrag; }
+    void setTrackedObject( SceneObject* pSceneObject );
+    inline SceneObject* getTrackedObject( void ) { return mTrackedObject; }
+    inline Vector2 getCurrentPosition( void )
+    {
+        // Fetch the tracked object.
+        SceneObject* pSceneObject = mTrackedObject;
+
+        // Return the controller position if no tracked object else the tracked object position plus a tracked object local-space position.
+        return pSceneObject == NULL ? mPosition : b2Mul( pSceneObject->getTransform(), mPosition);
+    }
 
     /// Integration.
     virtual void integrate( Scene* pScene, const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats );

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

@@ -144,3 +144,26 @@ ConsoleMethod(PointForceController, getNonLinear, bool, 2, 2,  "() Gets whether
     return object->getNonLinear();
 }
 
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(PointForceController, setTrackedObject, void, 3, 3,   "(sceneObject) - Sets a scene object from which the position will be tracked.\n"
+                                                                    "@param sceneObject The scene object from which the position will be tracked.  An empty string will stop tracking.\n"
+                                                                    "@return No return value.")
+{
+    // Find the scene object.
+    SceneObject* pSceneObject = Sim::findObject<SceneObject>( argv[2] );
+
+    object->setTrackedObject( pSceneObject );
+} 
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(PointForceController, getTrackedObject, const char*, 2, 2,    "() - Gets the scene object from which the position will be tracked.\n"
+                                                                            "@return The scene object from which the position will be tracked or an empty string if nothing is being tracked.")
+{
+    // Fetch the scene object.
+    SceneObject* pSceneObject = object->getTrackedObject();
+
+    return pSceneObject == NULL ? NULL : pSceneObject->getIdString();
+} 
+

+ 44 - 3
engine/source/2d/core/SpriteBatch.cc

@@ -52,14 +52,28 @@ SpriteBatch::SpriteBatch() :
     // Reset local extents.
     mLocalExtents.SetZero();
     mLocalExtentsDirty = true;
-
-    // Create the sprite batch query if sprite clipping is on.
-    createSpriteBatchQuery();
 }
 
 //------------------------------------------------------------------------------
 
 SpriteBatch::~SpriteBatch()
+{
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpriteBatch::onAdd()
+{
+    // Create the sprite batch query if required.
+    if ( mBatchCulling )
+        createSpriteBatchQuery();
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void SpriteBatch::onRemove()
 {
     // Clear the sprites.
     clearSprites();
@@ -372,6 +386,9 @@ void SpriteBatch::setBatchCulling( const bool batchCulling )
     if ( mBatchCulling == batchCulling )
         return;
 
+    // Set batch culling.
+    mBatchCulling = batchCulling;
+
     // Create/destroy sprite batch query appropriately.
     if ( mBatchCulling )
         createSpriteBatchQuery();
@@ -925,6 +942,30 @@ SimObject* SpriteBatch::getSpriteDataObject( void ) const
 
 //------------------------------------------------------------------------------
 
+void SpriteBatch::setUserData( void* pUserData )
+{
+    // Finish if a sprite is not selected.
+    if ( !checkSpriteSelected() )
+        return;
+
+    // Set user data.
+    mSelectedSprite->setUserData( pUserData );
+}
+
+//------------------------------------------------------------------------------
+
+void* SpriteBatch::getUserData( void ) const
+{
+    // Finish if a sprite is not selected.
+    if ( !checkSpriteSelected() )
+        return NULL;
+
+    // Get user data.
+    return mSelectedSprite->getUserData();
+}
+
+//------------------------------------------------------------------------------
+
 void SpriteBatch::setSpriteName( const char* pName )
 {
     // Finish if a sprite is not selected.

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

@@ -72,6 +72,9 @@ public:
     SpriteBatch();
     virtual ~SpriteBatch();
 
+    virtual bool onAdd();
+    virtual void onRemove();
+
     void prepareRender( SceneRenderObject* pSceneRenderObject, const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue );
     void render( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer );
 
@@ -89,7 +92,6 @@ public:
     void moveQueryProxy( SpriteBatchItem* pSpriteBatchItem, const b2AABB& localAABB );    
     SpriteBatchQuery* getSpriteBatchQuery( const bool clearQuery = false );
 
-
     virtual void copyTo( SpriteBatch* pSpriteBatch ) const;
 
     inline U32 getSpriteCount( void ) { return (U32)mSprites.size(); }
@@ -171,6 +173,9 @@ public:
     void setSpriteDataObject( SimObject* pDataObject );
     SimObject* getSpriteDataObject( void ) const;
 
+    void setUserData( void* pUserData );
+    void* getUserData( void ) const;
+
     void setSpriteName( const char* pName );
     StringTableEntry getSpriteName( void ) const;
 

+ 5 - 2
engine/source/2d/core/SpriteBatchItem.cc

@@ -159,6 +159,8 @@ void SpriteBatchItem::resetState( void )
 
     mSpriteBatchQueryKey = 0;
 
+    mUserData = NULL;
+
     // Require self ticking.
     mSelfTick = true;
 }
@@ -310,10 +312,11 @@ void SpriteBatchItem::updateWorldTransform( const U32 batchTransformId )
 
     // Update the local transform if needed.
     if ( mLocalTransformDirty )
+    {
         updateLocalTransform();
-
+    }
     // Finish if the batch transform is up-to-date.
-    if ( batchTransformId == mLastBatchTransformId )
+    else if ( batchTransformId == mLastBatchTransformId )
         return;
 
     // Fetch world transform.

+ 6 - 0
engine/source/2d/core/SpriteBatchItem.h

@@ -225,6 +225,8 @@ protected:
 
     U32                 mSpriteBatchQueryKey;
 
+    void*               mUserData;
+
 public:
     SpriteBatchItem();
     virtual ~SpriteBatchItem();
@@ -284,6 +286,10 @@ public:
     inline void setDataObject( SimObject* pDataObject ) { mDataObject = pDataObject; }
     inline SimObject* getDataObject( void ) const { return mDataObject; }
 
+    inline void setUserData( void* pUserData ) { mUserData = pUserData; }
+    inline void* getUserData( void ) const { return mUserData; }
+    template<class T> T* getUserData( void ) const { return (T*)mUserData; }
+
     inline void setSpriteBatchQueryKey( const U32 key ) { mSpriteBatchQueryKey = key; }
     inline U32  getSpriteBatchQueryKey( void ) const { return mSpriteBatchQueryKey; }
 

+ 271 - 0
engine/source/2d/experimental/composites/WaveComposite.cc

@@ -0,0 +1,271 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _WAVE_COMPOSITE_H_
+#include "2d/experimental/composites/WaveComposite.h"
+#endif
+
+// Script bindings.
+#include "2d/experimental/composites/WaveComposite_ScriptBinding.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(WaveComposite);
+
+//------------------------------------------------------------------------------
+
+WaveComposite::WaveComposite() :
+    mPreTickTime( 0.0f ),
+    mPostTickTime( 0.0f ),
+    mImageFrame( 0 ),
+    mSpriteCount( 50 ),
+    mSpriteSize( 1.0f, 1.0f ),
+    mAmplitude( 30.0f ),
+    mFrequency( 10.0f )
+{
+    // Disable batch culling.
+    // NOTE:    This stops the batch-query dynamic-tree from being generated.
+    //          For smaller scale composites, this is more efficient and saves memory.
+    //          Do not turn this off for larger scale composites like tile-maps.
+    SpriteBatch::setBatchCulling( false );
+
+    // Turn-off layout.
+    setBatchLayout( NO_LAYOUT );
+}
+
+//------------------------------------------------------------------------------
+
+WaveComposite::~WaveComposite()
+{
+}
+
+//------------------------------------------------------------------------------
+
+void WaveComposite::initPersistFields()
+{
+    // Call parent.
+    Parent::initPersistFields();
+
+    addProtectedField( "Image", TypeImageAssetPtr, Offset(mImageAsset, WaveComposite), &setImage, &getImage, &writeImage, "The image asset Id used for the image." );
+    addProtectedField( "Frame", TypeS32, Offset(mImageFrame, WaveComposite), &setImageFrame, &defaultProtectedGetFn, &writeImageFrame, "The image frame used for the image." );
+    addProtectedField( "SpriteCount", TypeS32, Offset(mSpriteCount, WaveComposite), &setSpriteCount, &defaultProtectedGetFn, &defaultProtectedWriteFn, "The number of sprites to generate" );
+    addProtectedField( "SpriteSize", TypeVector2, Offset(mSpriteSize, WaveComposite),&setSpriteSize, &defaultProtectedGetFn, &defaultProtectedWriteFn, "The size of each sprite." );
+    addField( "Amplitude", TypeF32, Offset(mAmplitude, WaveComposite), "The amplitude of the sprite movement." );
+    addField( "Frequency", TypeF32, Offset(mFrequency, WaveComposite), "The frequency of the sprite movement." );
+}
+
+//-----------------------------------------------------------------------------
+
+void WaveComposite::preIntegrate( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats )
+{
+    // Note tick times.
+    mPreTickTime = mPostTickTime;
+    mPostTickTime = totalTime;
+
+    // Update composition at pre-tick time.
+    updateComposition( mPreTickTime );
+
+    // Call parent.
+    Parent::preIntegrate( totalTime, elapsedTime, pDebugStats );
+}
+
+//-----------------------------------------------------------------------------
+
+void WaveComposite::integrateObject( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats )
+{
+    // Call Parent.
+    Parent::integrateObject( totalTime, elapsedTime, pDebugStats );
+
+}
+
+//-----------------------------------------------------------------------------
+
+void WaveComposite::interpolateObject( const F32 timeDelta )
+{
+    // Call parent.
+    Parent::interpolateObject( timeDelta );
+
+    // Update composition time (interpolated).
+    updateComposition( (timeDelta * mPreTickTime) + ((1.0f-timeDelta) * mPostTickTime) );
+}
+
+//------------------------------------------------------------------------------
+
+void WaveComposite::copyTo(SimObject* object)
+{
+    // Call to parent.
+    Parent::copyTo(object); 
+
+    // Fetch object.
+    WaveComposite* pComposite = dynamic_cast<WaveComposite*>(object);
+
+    // Sanity!
+    AssertFatal(pComposite != NULL, "WaveComposite::copyTo() - Object is not the correct type.");
+
+    // Copy state.
+    pComposite->setImage( getImage() );
+    pComposite->setImageFrame( getImageFrame() );
+    pComposite->setSpriteCount( getSpriteCount() );
+    pComposite->setSpriteSize( getSpriteSize() );
+    pComposite->setAmplitude( getAmplitude() );
+}
+
+//-----------------------------------------------------------------------------
+
+bool WaveComposite::setImage( const char* pImageAssetId )
+{
+    // Sanity!
+    AssertFatal( pImageAssetId != NULL, "Cannot use a NULL asset Id." );
+
+    // Fetch the asset Id.
+    mImageAsset = pImageAssetId;
+
+    // Reset image frame.
+	mImageFrame = 0;
+
+    // Generate composition.
+    generateComposition();
+
+	return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool WaveComposite::setImageFrame( const U32 frame )
+{
+    // Check Existing Image.
+    if ( mImageAsset.isNull() )
+    {
+        // Warn.
+        Con::warnf("WaveComposite::setImageFrame() - Cannot set Frame without existing asset Id.");
+
+        // Return Here.
+        return false;
+    }
+
+    // Check Frame Validity.
+    if ( frame >= mImageAsset->getFrameCount() )
+    {
+        // Warn.
+        Con::warnf( "WaveComposite::setImageFrame() - Invalid Frame #%d for asset Id '%s'.", frame, mImageAsset.getAssetId() );
+        // Return Here.
+        return false;
+    }
+
+    // Set Frame.
+    mImageFrame = frame;
+
+    // Generate composition.
+    generateComposition();
+
+    // Return Okay.
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void WaveComposite::setSpriteCount( const U32 spriteCount )
+{
+    // Set sprite count.
+    mSpriteCount = spriteCount;
+
+    // Generate composition.
+    generateComposition();
+}
+
+//-----------------------------------------------------------------------------
+
+void WaveComposite::setSpriteSize( const Vector2& spriteSize )
+{
+    // Check Frame Validity.
+    if ( spriteSize.x <= 0.0f && spriteSize.y <= 0.0f )
+    {
+        // Warn.
+        Con::warnf( "WaveComposite::setSpriteSize() - Sprite sizes must be > 0." );
+
+        return;
+    }
+
+    // Set sprite size.
+    mSpriteSize = spriteSize;
+
+    // Generate composition.
+    generateComposition();
+}
+
+//-----------------------------------------------------------------------------
+
+void WaveComposite::generateComposition( void )
+{
+    // Clear all existing sprites.
+    clearSprites();
+    mWaveSprites.clear();
+
+    // Finish if image asset isn't available.
+    if ( mImageAsset.isNull() )
+        return;
+
+    // Fetch asset Id.
+    StringTableEntry assetId = mImageAsset.getAssetId();
+
+    // Generate sprites.
+    for( U32 n = 0; n < mSpriteCount; ++n )
+    {
+        // Create the sprite.
+        SpriteBatchItem* pSprite = SpriteBatch::createSprite();
+
+        // Configure the sprite.
+        pSprite->setImage( assetId );
+        pSprite->setImageFrame( mImageFrame );
+        pSprite->setSize( mSpriteSize );
+
+        // Store sprite reference.
+        mWaveSprites.push_back( pSprite );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void WaveComposite::updateComposition( const F32 time )
+{
+    // Scale time.
+    const F32 scaledTime = time * 100.0f;
+
+    // Calculate sprite start positin.
+    Vector2 spritePosition( mSpriteSize.x * mSpriteCount * -0.5f, 0.0f );
+
+    // Update sprite positions.
+    for( typeWaveSpritesVector::iterator spriteItr = mWaveSprites.begin(); spriteItr < mWaveSprites.end(); ++spriteItr )
+    {
+        // Fetch sprite,
+        SpriteBatchItem* pSprite = *spriteItr;
+
+        // Set y position.
+        spritePosition.y = mSin(mDegToRad(scaledTime + (spritePosition.x * mFrequency))) * mAmplitude;
+
+        // Set sprite position.
+        pSprite->setLocalPosition( spritePosition );
+
+        // Update the position.
+        spritePosition.x += mSpriteSize.x;
+    }
+}

+ 93 - 0
engine/source/2d/experimental/composites/WaveComposite.h

@@ -0,0 +1,93 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _WAVE_COMPOSITE_H_
+#define _WAVE_COMPOSITE_H_
+
+#ifndef _COMPOSITE_SPRITE_H_
+#include "2d/sceneObject/CompositeSprite.h"
+#endif
+
+//------------------------------------------------------------------------------  
+
+class WaveComposite : public CompositeSprite
+{
+protected:
+    typedef CompositeSprite Parent;
+
+private:
+    AssetPtr<ImageAsset>        mImageAsset;
+    U32                         mImageFrame;
+    U32                         mSpriteCount;
+    Vector2                     mSpriteSize;
+    F32                         mAmplitude;
+    F32                         mFrequency;
+
+    typedef Vector<SpriteBatchItem*> typeWaveSpritesVector;
+    typeWaveSpritesVector       mWaveSprites;
+    F32                         mPreTickTime;
+    F32                         mPostTickTime;
+
+public:
+    WaveComposite();
+    virtual ~WaveComposite();
+
+    static void initPersistFields();
+
+    virtual bool validRender( void ) const { return mImageAsset.notNull(); }
+    virtual void preIntegrate( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats );
+    virtual void integrateObject( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats );
+    virtual void interpolateObject( const F32 timeDelta );
+
+    virtual void copyTo( SimObject* object );
+
+    bool setImage( const char* pImageAssetId );
+    inline StringTableEntry getImage( void ) const { return mImageAsset.getAssetId(); }
+    bool setImageFrame( const U32 frame );
+    inline U32 getImageFrame( void ) const { return mImageFrame; }
+    void setSpriteCount( const U32 spriteCount );
+    inline U32 getSpriteCount( void ) const { return mSpriteCount; }
+    void setSpriteSize( const Vector2& spriteSize );
+    inline const Vector2& getSpriteSize( void ) const { return mSpriteSize; };
+    inline void setAmplitude( const F32 amplitude ) { mAmplitude = amplitude; }
+    inline F32 getAmplitude( void ) const { return mAmplitude; }
+    inline void setFrequency( const F32 frequency ) { mFrequency = frequency; }
+    inline F32 getFrequency( void ) const { return mFrequency; }
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( WaveComposite );
+
+protected:
+    void generateComposition( void );
+    void updateComposition( const F32 time );
+
+protected:
+    static bool setImage(void* obj, const char* data) { static_cast<WaveComposite*>(obj)->setImage( data ); return false; }
+    static const char* getImage(void* obj, const char* data) { return DYNAMIC_VOID_CAST_TO(WaveComposite, SpriteProxyBase, obj)->getImage(); }
+    static bool writeImage( void* obj, StringTableEntry pFieldName ) { return static_cast<WaveComposite*>(obj)->mImageAsset.notNull(); }
+    static bool setImageFrame(void* obj, const char* data) { static_cast<WaveComposite*>(obj)->setImageFrame( dAtoi(data) ); return false; }
+    static bool writeImageFrame( void* obj, StringTableEntry pFieldName ) { return static_cast<WaveComposite*>(obj)->getImageFrame() > 0; }
+    static bool setSpriteCount(void* obj, const char* data) { static_cast<WaveComposite*>(obj)->setSpriteCount( dAtoi(data) ); return false; }
+    static bool setSpriteSize(void* obj, const char* data) { static_cast<WaveComposite*>(obj)->setSpriteSize( Vector2(data) ); return false; }
+};
+
+#endif // _WAVE_COMPOSITE_H_

+ 22 - 0
engine/source/2d/experimental/composites/WaveComposite_ScriptBinding.h

@@ -0,0 +1,22 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+

+ 23 - 0
engine/source/2d/sceneobject/CompositeSprite.cc

@@ -119,6 +119,29 @@ void CompositeSprite::initPersistFields()
 
 //-----------------------------------------------------------------------------
 
+bool CompositeSprite::onAdd()
+{
+    // Call parent.
+    if ( !Parent::onAdd() )
+        return false;
+
+    // Call sprite batch.
+    return SpriteBatch::onAdd();
+}
+
+//-----------------------------------------------------------------------------
+
+void CompositeSprite::onRemove()
+{
+    // Call sprite batch.
+    SpriteBatch::onRemove();
+
+    // Call parent.
+    Parent::onRemove();
+}
+
+//-----------------------------------------------------------------------------
+
 void CompositeSprite::preIntegrate( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats )
 {
     // Are the spatials dirty?

+ 3 - 0
engine/source/2d/sceneobject/CompositeSprite.h

@@ -59,6 +59,9 @@ public:
 
     static void initPersistFields();
 
+    virtual bool onAdd();
+    virtual void onRemove();
+
     virtual void preIntegrate( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats );
     virtual void integrateObject( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats );
     virtual void interpolateObject( const F32 timeDelta );

+ 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; }

+ 9 - 8
engine/source/gui/guiTypes.cc

@@ -362,15 +362,16 @@ void GuiControlProfile::incRefCount()
       if (mFont.isNull())
          Con::errorf("Failed to load/create profile font (%s/%d)", mFontType, mFontSize);
        
-      //verify the bitmap
-      mTextureHandle = TextureHandle(mBitmapName, TextureHandle::BitmapKeepTexture);
-      if (!(bool)mTextureHandle)
-         Con::errorf("Failed to load profile bitmap (%s)",mBitmapName);
-
-      // If we've got a special border, make sure it's usable.
-      if( mBorder == -1 || mBorder == -2 )
-         constructBitmapArray();
+      if ( mBitmapName != NULL && mBitmapName != StringTable->EmptyString )
+      {
+          mTextureHandle = TextureHandle(mBitmapName, TextureHandle::BitmapKeepTexture);
+          if (!(bool)mTextureHandle)
+             Con::errorf("Failed to load profile bitmap (%s)",mBitmapName);
 
+          // If we've got a special border, make sure it's usable.
+          if( mBorder == -1 || mBorder == -2 )
+             constructBitmapArray();
+      }
    }
 }
 

+ 1 - 1
engine/source/module/moduleManager.cc

@@ -183,7 +183,7 @@ bool ModuleManager::scanModules( const char* pPath, const bool rootOnly )
     Vector<StringTableEntry> directories;
 
     // Find directories.
-    if ( !Platform::dumpDirectories( pathBuffer, directories, 1 ) )
+    if ( !Platform::dumpDirectories( pathBuffer, directories, rootOnly ? 1 : -1 ) )
     {
         // Failed so warn.
         Con::warnf( "Module Manager: Failed to scan module directories in path '%s'.", pathBuffer );

+ 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;

+ 93 - 0
modules/Experiments/WaveCompositeToy/1/main.cs

@@ -0,0 +1,93 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+function WaveCompositeToy::create( %this )
+{  
+    // Reset the toy.
+    WaveCompositeToy.reset();
+}
+
+
+//-----------------------------------------------------------------------------
+
+function WaveCompositeToy::destroy( %this )
+{
+}
+
+//-----------------------------------------------------------------------------
+
+function WaveCompositeToy::reset( %this )
+{
+    // Clear the scene.
+    SandboxScene.clear();
+       
+    // Create background.
+    %this.createBackground();
+       
+    // Create the composite.
+    %this.createComposite();
+}
+
+//-----------------------------------------------------------------------------
+
+function WaveCompositeToy::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.
+
+    // Set the position.
+    %object.Position = "0 0";
+
+    // Set the size.        
+    %object.Size = "100 75";
+    
+    // Set to the furthest background layer.
+    %object.SceneLayer = 31;
+    
+    // Set the scroller to use an animation!
+    %object.Image = "ToyAssets:highlightBackground";
+    
+    // Set the blend color.
+    %object.BlendColor = Navy;
+            
+    // Add the sprite to the scene.
+    SandboxScene.add( %object );    
+}
+
+//-----------------------------------------------------------------------------
+
+function WaveCompositeToy::createComposite( %this )
+{
+    %composite = new WaveComposite();
+    %composite.Image = "ToyAssets:football";
+    %composite.Frame = 0;
+    %composite.SpriteCount = 30;
+    %composite.SpriteSize = 3;
+    %composite.Amplitude = 20;
+    %composite.Frequency = 15;
+    SandboxScene.add( %composite );   
+}

+ 10 - 0
modules/Experiments/WaveCompositeToy/1/module.taml

@@ -0,0 +1,10 @@
+<ModuleDefinition
+	ModuleId="WaveCompositeToy"
+	VersionId="1"
+	Description="A composite-sprite based experiment."
+	Dependencies="ToyAssets=1"
+	Type="toy"
+	ToyCategoryIndex="7"
+	ScriptFile="main.cs"
+	CreateFunction="create"
+	DestroyFunction="destroy"/>

+ 12 - 1
modules/PointForceControllerToy/1/main.cs

@@ -90,6 +90,8 @@ function PointForceControllerToy::reset( %this )
     // Start a timer throwing asteroids.
     if ( PointForceControllerToy.autoSpawnAsteroids )
         %this.startTimer( "createAsteroid", 1000 );
+    else
+        %this.stopTimer();        
 }
 
 //-----------------------------------------------------------------------------
@@ -110,6 +112,9 @@ function PointForceControllerToy::createBackground( %this )
 
 function PointForceControllerToy::createPlanetoid( %this )
 {
+    // Choose a position for the planetoid.
+    %position = 0;
+    
     if ( PointForceControllerToy.showPlanetoid )
     {
         // Create the planetoid.
@@ -117,7 +122,7 @@ function PointForceControllerToy::createPlanetoid( %this )
         {
             class = "Planetoid";
         };
-        //%object.BodyType = static;
+        %object.Position = %position;
         %object.Size = PointForceControllerToy.planetoidSize;
         %object.Image = "ToyAssets:Planetoid";
         %object.AngularVelocity = -5;
@@ -130,6 +135,7 @@ function PointForceControllerToy::createPlanetoid( %this )
     // Create planetoid bubble.
     %player = new ParticlePlayer();
     %player.BodyType = static;
+    %player.Position = %position;
     %player.Particle = "ToyAssets:ForceBubble";
     %player.SceneLayer = 0;
     SandboxScene.add( %player );
@@ -143,6 +149,11 @@ function PointForceControllerToy::createPlanetoid( %this )
     %controller.LinearDrag = PointForceControllerToy.controllerLinearDrag;
     %controller.AngularDrag = PointForceControllerToy.controllerAngularDrag;
     SandboxScene.Controllers.add( %controller );
+
+    if ( isObject(%object) )
+        %controller.setTrackedObject( %object );
+    else
+        %controller.Position = %position;
     
     // This is so we can reference it in the toy, no other reason.
     PointForceControllerToy.Controller = %controller;

+ 2 - 1
modules/Sandbox/1/scripts/toolbox.cs

@@ -65,7 +65,8 @@ function ToyCategorySelectList::initialize(%this)
      %this.toyCategories[$toyAllCategoryIndex+3] = "Stress Testing";
      %this.toyCategories[$toyAllCategoryIndex+4] = "Fun and Games";
      %this.toyCategories[$toyAllCategoryIndex+5] = "Custom";
-     %this.maxToyCategories = $toyAllCategoryIndex + 6;
+     %this.toyCategories[$toyAllCategoryIndex+6] = "Experiments";
+     %this.maxToyCategories = $toyAllCategoryIndex + 7;
 
      // Set the "All" category as the default.
      // NOTE:    This is important to use so that the user-configurable default toy

+ 0 - 0
modules/ToyAssets/1/assets/images/skyBackground.aasset.taml → modules/ToyAssets/1/assets/images/skyBackground.asset.taml