Browse Source

Merge pull request #1 from GarageGames/development

Update to latest dev branch version
lilligreen 12 years ago
parent
commit
0a365fb
92 changed files with 2887 additions and 2379 deletions
  1. 7 4
      engine/compilers/VisualStudio 2010/Torque 2D.vcxproj
  2. 27 12
      engine/compilers/VisualStudio 2010/Torque 2D.vcxproj.filters
  3. 7 4
      engine/compilers/VisualStudio 2012/Torque 2D.vcxproj
  4. 27 12
      engine/compilers/VisualStudio 2012/Torque 2D.vcxproj.filters
  5. 36 12
      engine/compilers/Xcode/Torque2D.xcodeproj/project.pbxproj
  6. 36 12
      engine/compilers/Xcode_iOS/Torque2D.xcodeproj/project.pbxproj
  7. 1 1
      engine/source/2d/assets/AnimationAsset.h
  8. 0 336
      engine/source/2d/assets/AnimationController.cc
  9. 0 94
      engine/source/2d/assets/AnimationController.h
  10. 4 0
      engine/source/2d/assets/ImageAsset.cc
  11. 4 0
      engine/source/2d/assets/ImageAsset.h
  12. 1 1
      engine/source/2d/assets/ParticleAssetEmitter.cc
  13. 11 15
      engine/source/2d/assets/ParticleAssetEmitter.h
  14. 41 41
      engine/source/2d/controllers/BuoyancyController.cc
  15. 14 14
      engine/source/2d/controllers/BuoyancyController.h
  16. 29 8
      engine/source/2d/controllers/PointForceController.cc
  17. 17 4
      engine/source/2d/controllers/PointForceController.h
  18. 23 0
      engine/source/2d/controllers/PointForceController_ScriptBinding.h
  19. 51 0
      engine/source/2d/core/ImageFrameProvider.cc
  20. 47 0
      engine/source/2d/core/ImageFrameProvider.h
  21. 586 0
      engine/source/2d/core/ImageFrameProviderCore.cc
  22. 153 0
      engine/source/2d/core/ImageFrameProviderCore.h
  23. 6 5
      engine/source/2d/core/ParticleSystem.h
  24. 2 6
      engine/source/2d/core/RenderProxy.cc
  25. 11 19
      engine/source/2d/core/RenderProxy.h
  26. 28 32
      engine/source/2d/core/RenderProxy_ScriptBinding.h
  27. 7 11
      engine/source/2d/core/SpriteBase.cc
  28. 11 19
      engine/source/2d/core/SpriteBase.h
  29. 31 35
      engine/source/2d/core/SpriteBase_ScriptBinding.h
  30. 47 6
      engine/source/2d/core/SpriteBatch.cc
  31. 7 2
      engine/source/2d/core/SpriteBatch.h
  32. 7 8
      engine/source/2d/core/SpriteBatchItem.cc
  33. 10 12
      engine/source/2d/core/SpriteBatchItem.h
  34. 0 413
      engine/source/2d/core/SpriteProxyBase.cc
  35. 0 117
      engine/source/2d/core/SpriteProxyBase.h
  36. 271 0
      engine/source/2d/experimental/composites/WaveComposite.cc
  37. 93 0
      engine/source/2d/experimental/composites/WaveComposite.h
  38. 22 0
      engine/source/2d/experimental/composites/WaveComposite_ScriptBinding.h
  39. 8 8
      engine/source/2d/gui/guiSpriteCtrl.cc
  40. 8 12
      engine/source/2d/gui/guiSpriteCtrl.h
  41. 7 7
      engine/source/2d/gui/guiSpriteCtrl_ScriptBindings.h
  42. 11 6
      engine/source/2d/scene/ContactFilter.cc
  43. 553 467
      engine/source/2d/scene/Scene.cc
  44. 23 21
      engine/source/2d/scene/Scene.h
  45. 90 78
      engine/source/2d/scene/Scene_ScriptBinding.h
  46. 23 0
      engine/source/2d/sceneobject/CompositeSprite.cc
  47. 3 0
      engine/source/2d/sceneobject/CompositeSprite.h
  48. 2 6
      engine/source/2d/sceneobject/CompositeSprite_ScriptBinding.h
  49. 28 49
      engine/source/2d/sceneobject/ParticlePlayer.cc
  50. 3 12
      engine/source/2d/sceneobject/ParticlePlayer.h
  51. 4 10
      engine/source/2d/sceneobject/SceneObject.cc
  52. 52 10
      engine/source/2d/sceneobject/SceneObject_ScriptBinding.h
  53. 4 27
      engine/source/2d/sceneobject/Scroller.cc
  54. 1 1
      engine/source/2d/sceneobject/Sprite.cc
  55. 4 4
      engine/source/assets/assetBase.cc
  56. 2 2
      engine/source/assets/assetPtr.h
  57. 0 2
      engine/source/collection/undo.cc
  58. 0 10
      engine/source/collection/undo.h
  59. 166 189
      engine/source/component/behaviors/behaviorComponent.cpp
  60. 0 2
      engine/source/component/simComponent.cpp
  61. 20 18
      engine/source/console/compiledEval.cc
  62. 3 3
      engine/source/console/consoleObject.cc
  63. 0 20
      engine/source/graphics/PNGImage.cpp
  64. 0 6
      engine/source/graphics/PNGImage.h
  65. 4 0
      engine/source/graphics/TextureHandle.cc
  66. 4 0
      engine/source/graphics/TextureHandle.h
  67. 0 10
      engine/source/gui/guiControl.cc
  68. 9 8
      engine/source/gui/guiTypes.cc
  69. 0 21
      engine/source/messaging/message.cc
  70. 0 2
      engine/source/messaging/message.h
  71. 0 21
      engine/source/messaging/scriptMsgListener.cc
  72. 0 5
      engine/source/messaging/scriptMsgListener.h
  73. 1 1
      engine/source/module/moduleManager.cc
  74. 0 5
      engine/source/platform/menus/popupMenu.cc
  75. 8 2
      engine/source/platformOSX/osxString.mm
  76. 1 11
      engine/source/platformWin32/winStrings.cc
  77. 9 2
      engine/source/platformiOS/iOSStrings.mm
  78. 0 21
      engine/source/sim/scriptGroup.cc
  79. 0 2
      engine/source/sim/scriptGroup.h
  80. 0 23
      engine/source/sim/scriptObject.cc
  81. 0 2
      engine/source/sim/scriptObject.h
  82. 11 0
      engine/source/sim/simObject.cc
  83. 1 1
      engine/source/sim/simObject.h
  84. 1 2
      modules/AquariumToy/1/main.cs
  85. 93 0
      modules/Experiments/WaveCompositeToy/1/main.cs
  86. 10 0
      modules/Experiments/WaveCompositeToy/1/module.taml
  87. 10 1
      modules/PointForceControllerToy/1/main.cs
  88. 1 1
      modules/RestitutionToy/1/main.cs
  89. 2 1
      modules/Sandbox/1/scripts/toolbox.cs
  90. 0 0
      modules/ToyAssets/1/assets/images/skyBackground.asset.taml
  91. 13 12
      modules/TruckToy/1/main.cs
  92. 19 0
      tools/Zwoptex/ReadMe.txt

+ 7 - 4
engine/compilers/VisualStudio 2010/Torque 2D.vcxproj

@@ -233,7 +233,6 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\2d\assets\AnimationAsset.cc" />
-    <ClCompile Include="..\..\source\2d\assets\AnimationController.cc" />
     <ClCompile Include="..\..\source\2d\assets\ImageAsset.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAsset.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetEmitter.cc" />
@@ -246,15 +245,17 @@
     <ClCompile Include="..\..\source\2d\controllers\PointForceController.cc" />
     <ClCompile Include="..\..\source\2d\core\BatchRender.cc" />
     <ClCompile Include="..\..\source\2d\core\CoreMath.cc" />
+    <ClCompile Include="..\..\source\2d\core\ImageFrameProvider.cc" />
+    <ClCompile Include="..\..\source\2d\core\ImageFrameProviderCore.cc" />
     <ClCompile Include="..\..\source\2d\core\ParticleSystem.cc" />
     <ClCompile Include="..\..\source\2d\core\RenderProxy.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBase.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatch.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatchQuery.cc" />
-    <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" />
@@ -611,7 +612,6 @@
   <ItemGroup>
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset.h" />
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset_ScriptBinding.h" />
-    <ClInclude Include="..\..\source\2d\assets\AnimationController.h" />
     <ClInclude Include="..\..\source\2d\assets\ImageAsset.h" />
     <ClInclude Include="..\..\source\2d\assets\ImageAsset_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAsset.h" />
@@ -633,6 +633,8 @@
     <ClInclude Include="..\..\source\2d\controllers\PointForceController_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\core\BatchRender.h" />
     <ClInclude Include="..\..\source\2d\core\CoreMath.h" />
+    <ClInclude Include="..\..\source\2d\core\ImageFrameProvider.h" />
+    <ClInclude Include="..\..\source\2d\core\ImageFrameProviderCore.h" />
     <ClInclude Include="..\..\source\2d\core\ParticleSystem.h" />
     <ClInclude Include="..\..\source\2d\core\RenderProxy.h" />
     <ClInclude Include="..\..\source\2d\core\RenderProxy_ScriptBinding.h" />
@@ -642,10 +644,11 @@
     <ClInclude Include="..\..\source\2d\core\SpriteBatchItem.h" />
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQuery.h" />
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQueryResult.h" />
-    <ClInclude Include="..\..\source\2d\core\SpriteProxyBase.h" />
     <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" />

+ 27 - 12
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">
@@ -1122,9 +1128,6 @@
     <ClCompile Include="..\..\source\2d\assets\AnimationAsset.cc">
       <Filter>2d\assets</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\2d\assets\AnimationController.cc">
-      <Filter>2d\assets</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\2d\assets\ImageAsset.cc">
       <Filter>2d\assets</Filter>
     </ClCompile>
@@ -1161,9 +1164,6 @@
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc">
       <Filter>2d\core</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\2d\core\SpriteProxyBase.cc">
-      <Filter>2d\core</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\2d\core\Utility.cc">
       <Filter>2d\core</Filter>
     </ClCompile>
@@ -1299,6 +1299,15 @@
     <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>
+    <ClCompile Include="..\..\source\2d\core\ImageFrameProvider.cc">
+      <Filter>2d\core</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\2d\core\ImageFrameProviderCore.cc">
+      <Filter>2d\core</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -2351,9 +2360,6 @@
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset_ScriptBinding.h">
       <Filter>2d\assets</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\assets\AnimationController.h">
-      <Filter>2d\assets</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\2d\assets\ImageAsset.h">
       <Filter>2d\assets</Filter>
     </ClInclude>
@@ -2426,9 +2432,6 @@
     <ClInclude Include="..\..\source\2d\core\SpriteBatchItem.h">
       <Filter>2d\core</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\core\SpriteProxyBase.h">
-      <Filter>2d\core</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\2d\core\Utility.h">
       <Filter>2d\core</Filter>
     </ClInclude>
@@ -2667,6 +2670,18 @@
     <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>
+    <ClInclude Include="..\..\source\2d\core\ImageFrameProvider.h">
+      <Filter>2d\core</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\core\ImageFrameProviderCore.h">
+      <Filter>2d\core</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">

+ 7 - 4
engine/compilers/VisualStudio 2012/Torque 2D.vcxproj

@@ -240,7 +240,6 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\2d\assets\AnimationAsset.cc" />
-    <ClCompile Include="..\..\source\2d\assets\AnimationController.cc" />
     <ClCompile Include="..\..\source\2d\assets\ImageAsset.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAsset.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetEmitter.cc" />
@@ -253,15 +252,17 @@
     <ClCompile Include="..\..\source\2d\controllers\BuoyancyController.cc" />
     <ClCompile Include="..\..\source\2d\core\BatchRender.cc" />
     <ClCompile Include="..\..\source\2d\core\CoreMath.cc" />
+    <ClCompile Include="..\..\source\2d\core\ImageFrameProvider.cc" />
+    <ClCompile Include="..\..\source\2d\core\ImageFrameProviderCore.cc" />
     <ClCompile Include="..\..\source\2d\core\ParticleSystem.cc" />
     <ClCompile Include="..\..\source\2d\core\RenderProxy.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBase.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatch.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatchQuery.cc" />
-    <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" />
@@ -618,7 +619,6 @@
   <ItemGroup>
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset.h" />
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset_ScriptBinding.h" />
-    <ClInclude Include="..\..\source\2d\assets\AnimationController.h" />
     <ClInclude Include="..\..\source\2d\assets\ImageAsset.h" />
     <ClInclude Include="..\..\source\2d\assets\ImageAsset_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAsset.h" />
@@ -640,6 +640,8 @@
     <ClInclude Include="..\..\source\2d\controllers\BuoyancyController_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\core\BatchRender.h" />
     <ClInclude Include="..\..\source\2d\core\CoreMath.h" />
+    <ClInclude Include="..\..\source\2d\core\ImageFrameProvider.h" />
+    <ClInclude Include="..\..\source\2d\core\ImageFrameProviderCore.h" />
     <ClInclude Include="..\..\source\2d\core\ParticleSystem.h" />
     <ClInclude Include="..\..\source\2d\core\RenderProxy.h" />
     <ClInclude Include="..\..\source\2d\core\RenderProxy_ScriptBinding.h" />
@@ -649,10 +651,11 @@
     <ClInclude Include="..\..\source\2d\core\SpriteBatchItem.h" />
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQuery.h" />
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQueryResult.h" />
-    <ClInclude Include="..\..\source\2d\core\SpriteProxyBase.h" />
     <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" />

+ 27 - 12
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">
@@ -1122,9 +1128,6 @@
     <ClCompile Include="..\..\source\2d\assets\AnimationAsset.cc">
       <Filter>2d\assets</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\2d\assets\AnimationController.cc">
-      <Filter>2d\assets</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\2d\assets\ImageAsset.cc">
       <Filter>2d\assets</Filter>
     </ClCompile>
@@ -1161,9 +1164,6 @@
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc">
       <Filter>2d\core</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\2d\core\SpriteProxyBase.cc">
-      <Filter>2d\core</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\2d\core\Utility.cc">
       <Filter>2d\core</Filter>
     </ClCompile>
@@ -1299,6 +1299,15 @@
     <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>
+    <ClCompile Include="..\..\source\2d\core\ImageFrameProvider.cc">
+      <Filter>2d\core</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\2d\core\ImageFrameProviderCore.cc">
+      <Filter>2d\core</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -2351,9 +2360,6 @@
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset_ScriptBinding.h">
       <Filter>2d\assets</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\assets\AnimationController.h">
-      <Filter>2d\assets</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\2d\assets\ImageAsset.h">
       <Filter>2d\assets</Filter>
     </ClInclude>
@@ -2423,9 +2429,6 @@
     <ClInclude Include="..\..\source\2d\core\SpriteBatchItem.h">
       <Filter>2d\core</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\core\SpriteProxyBase.h">
-      <Filter>2d\core</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\2d\core\Utility.h">
       <Filter>2d\core</Filter>
     </ClInclude>
@@ -2664,6 +2667,18 @@
     <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>
+    <ClInclude Include="..\..\source\2d\core\ImageFrameProvider.h">
+      <Filter>2d\core</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\core\ImageFrameProviderCore.h">
+      <Filter>2d\core</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">

+ 36 - 12
engine/compilers/Xcode/Torque2D.xcodeproj/project.pbxproj

@@ -11,6 +11,8 @@
 		2A033011165D1D4100E9CD70 /* platformFileIoTests.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2A033010165D1D4100E9CD70 /* platformFileIoTests.cc */; };
 		2A25739016A48DAC00363C6F /* ParticlePlayer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2A25738E16A48DAC00363C6F /* ParticlePlayer.cc */; };
 		2A6F78CE16A4528C005C76D9 /* ParticleAssetEmitter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2A6F78CC16A4528C005C76D9 /* ParticleAssetEmitter.cc */; };
+		2AA3655916F3552200E7A900 /* ImageFrameProvider.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA3655516F3552200E7A900 /* ImageFrameProvider.cc */; };
+		2AA3655A16F3552200E7A900 /* ImageFrameProviderCore.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA3655716F3552200E7A900 /* ImageFrameProviderCore.cc */; };
 		2AA6865F16D69943003CEF0A /* SceneObjectList.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA6865A16D69943003CEF0A /* SceneObjectList.cc */; };
 		2AA6866016D69943003CEF0A /* SceneObjectSet.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA6865D16D69943003CEF0A /* SceneObjectSet.cc */; };
 		2AB14A0516D7CDC300EABBF2 /* PointForceController.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AB14A0316D7CDC200EABBF2 /* PointForceController.cc */; };
@@ -25,6 +27,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 */; };
@@ -174,7 +177,6 @@
 		86C281CD16A4307E00F030F4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 86C281CB16A4307E00F030F4 /* MainMenu.xib */; };
 		86D76F78165683240046D71F /* osxOutlineGL.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86D76F76165683240046D71F /* osxOutlineGL.cc */; };
 		86D76F791656868D0046D71F /* AnimationAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E7716518D4600D96ADF /* AnimationAsset.cc */; };
-		86D76F7A1656868D0046D71F /* AnimationController.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E7A16518D4600D96ADF /* AnimationController.cc */; };
 		86D76F7B1656868D0046D71F /* ImageAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E7C16518D4600D96ADF /* ImageAsset.cc */; };
 		86D76F7C1656868D0046D71F /* BatchRender.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8116518D4600D96ADF /* BatchRender.cc */; };
 		86D76F7D1656868D0046D71F /* CoreMath.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8316518D4600D96ADF /* CoreMath.cc */; };
@@ -182,7 +184,6 @@
 		86D76F7F1656868D0046D71F /* SpriteBase.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8816518D4600D96ADF /* SpriteBase.cc */; };
 		86D76F801656868D0046D71F /* SpriteBatch.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8B16518D4600D96ADF /* SpriteBatch.cc */; };
 		86D76F811656868D0046D71F /* SpriteBatchItem.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8D16518D4600D96ADF /* SpriteBatchItem.cc */; };
-		86D76F821656868D0046D71F /* SpriteProxyBase.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8F16518D4600D96ADF /* SpriteProxyBase.cc */; };
 		86D76F831656868D0046D71F /* Utility.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E9116518D4600D96ADF /* Utility.cc */; };
 		86D76F841656868D0046D71F /* Vector2.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E9316518D4600D96ADF /* Vector2.cc */; };
 		86D76F851656868D0046D71F /* guiImageButtonCtrl.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E9716518D4600D96ADF /* guiImageButtonCtrl.cc */; };
@@ -459,6 +460,10 @@
 		2A25738F16A48DAC00363C6F /* ParticlePlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParticlePlayer.h; sourceTree = "<group>"; };
 		2A6F78CC16A4528C005C76D9 /* ParticleAssetEmitter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParticleAssetEmitter.cc; sourceTree = "<group>"; };
 		2A6F78CD16A4528C005C76D9 /* ParticleAssetEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParticleAssetEmitter.h; sourceTree = "<group>"; };
+		2AA3655516F3552200E7A900 /* ImageFrameProvider.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageFrameProvider.cc; sourceTree = "<group>"; };
+		2AA3655616F3552200E7A900 /* ImageFrameProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageFrameProvider.h; sourceTree = "<group>"; };
+		2AA3655716F3552200E7A900 /* ImageFrameProviderCore.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageFrameProviderCore.cc; sourceTree = "<group>"; };
+		2AA3655816F3552200E7A900 /* ImageFrameProviderCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageFrameProviderCore.h; sourceTree = "<group>"; };
 		2AA6865A16D69943003CEF0A /* SceneObjectList.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneObjectList.cc; sourceTree = "<group>"; };
 		2AA6865B16D69943003CEF0A /* SceneObjectList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneObjectList.h; sourceTree = "<group>"; };
 		2AA6865C16D69943003CEF0A /* SceneObjectSet_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneObjectSet_ScriptBinding.h; sourceTree = "<group>"; };
@@ -496,6 +501,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>"; };
@@ -714,8 +722,6 @@
 		86BC7E7716518D4600D96ADF /* AnimationAsset.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimationAsset.cc; sourceTree = "<group>"; };
 		86BC7E7816518D4600D96ADF /* AnimationAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationAsset.h; sourceTree = "<group>"; };
 		86BC7E7916518D4600D96ADF /* AnimationAsset_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationAsset_ScriptBinding.h; sourceTree = "<group>"; };
-		86BC7E7A16518D4600D96ADF /* AnimationController.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimationController.cc; sourceTree = "<group>"; };
-		86BC7E7B16518D4600D96ADF /* AnimationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationController.h; sourceTree = "<group>"; };
 		86BC7E7C16518D4600D96ADF /* ImageAsset.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageAsset.cc; sourceTree = "<group>"; };
 		86BC7E7D16518D4600D96ADF /* ImageAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageAsset.h; sourceTree = "<group>"; };
 		86BC7E7E16518D4600D96ADF /* ImageAsset_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageAsset_ScriptBinding.h; sourceTree = "<group>"; };
@@ -733,8 +739,6 @@
 		86BC7E8C16518D4600D96ADF /* SpriteBatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteBatch.h; sourceTree = "<group>"; };
 		86BC7E8D16518D4600D96ADF /* SpriteBatchItem.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpriteBatchItem.cc; sourceTree = "<group>"; };
 		86BC7E8E16518D4600D96ADF /* SpriteBatchItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteBatchItem.h; sourceTree = "<group>"; };
-		86BC7E8F16518D4600D96ADF /* SpriteProxyBase.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpriteProxyBase.cc; sourceTree = "<group>"; };
-		86BC7E9016518D4600D96ADF /* SpriteProxyBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteProxyBase.h; sourceTree = "<group>"; };
 		86BC7E9116518D4600D96ADF /* Utility.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Utility.cc; sourceTree = "<group>"; };
 		86BC7E9216518D4600D96ADF /* Utility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utility.h; sourceTree = "<group>"; };
 		86BC7E9316518D4600D96ADF /* Vector2.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Vector2.cc; 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 */,
@@ -1831,8 +1854,6 @@
 				86BC7E7716518D4600D96ADF /* AnimationAsset.cc */,
 				86BC7E7816518D4600D96ADF /* AnimationAsset.h */,
 				86BC7E7916518D4600D96ADF /* AnimationAsset_ScriptBinding.h */,
-				86BC7E7A16518D4600D96ADF /* AnimationController.cc */,
-				86BC7E7B16518D4600D96ADF /* AnimationController.h */,
 				86BC7E7C16518D4600D96ADF /* ImageAsset.cc */,
 				86BC7E7D16518D4600D96ADF /* ImageAsset.h */,
 				86BC7E7E16518D4600D96ADF /* ImageAsset_ScriptBinding.h */,
@@ -1843,6 +1864,10 @@
 		86BC7E8016518D4600D96ADF /* core */ = {
 			isa = PBXGroup;
 			children = (
+				2AA3655516F3552200E7A900 /* ImageFrameProvider.cc */,
+				2AA3655616F3552200E7A900 /* ImageFrameProvider.h */,
+				2AA3655716F3552200E7A900 /* ImageFrameProviderCore.cc */,
+				2AA3655816F3552200E7A900 /* ImageFrameProviderCore.h */,
 				2ACF5A2516E52D4B00F838D9 /* SpriteBatchQuery.cc */,
 				2ACF5A2616E52D4B00F838D9 /* SpriteBatchQuery.h */,
 				2ACF5A2716E52D4B00F838D9 /* SpriteBatchQueryResult.h */,
@@ -1862,8 +1887,6 @@
 				86BC7E8C16518D4600D96ADF /* SpriteBatch.h */,
 				86BC7E8D16518D4600D96ADF /* SpriteBatchItem.cc */,
 				86BC7E8E16518D4600D96ADF /* SpriteBatchItem.h */,
-				86BC7E8F16518D4600D96ADF /* SpriteProxyBase.cc */,
-				86BC7E9016518D4600D96ADF /* SpriteProxyBase.h */,
 				86BC7E9116518D4600D96ADF /* Utility.cc */,
 				86BC7E9216518D4600D96ADF /* Utility.h */,
 				86BC7E9316518D4600D96ADF /* Vector2.cc */,
@@ -3101,7 +3124,6 @@
 				86D76F98165686B00046D71F /* Sprite.cc in Sources */,
 				86D76F99165686B00046D71F /* Trigger.cc in Sources */,
 				86D76F791656868D0046D71F /* AnimationAsset.cc in Sources */,
-				86D76F7A1656868D0046D71F /* AnimationController.cc in Sources */,
 				86D76F7B1656868D0046D71F /* ImageAsset.cc in Sources */,
 				86D76F7C1656868D0046D71F /* BatchRender.cc in Sources */,
 				86D76F7D1656868D0046D71F /* CoreMath.cc in Sources */,
@@ -3109,7 +3131,6 @@
 				86D76F7F1656868D0046D71F /* SpriteBase.cc in Sources */,
 				86D76F801656868D0046D71F /* SpriteBatch.cc in Sources */,
 				86D76F811656868D0046D71F /* SpriteBatchItem.cc in Sources */,
-				86D76F821656868D0046D71F /* SpriteProxyBase.cc in Sources */,
 				86D76F831656868D0046D71F /* Utility.cc in Sources */,
 				86D76F841656868D0046D71F /* Vector2.cc in Sources */,
 				86D76F851656868D0046D71F /* guiImageButtonCtrl.cc in Sources */,
@@ -3278,6 +3299,9 @@
 				2AB4C19F16DE9F0600B02479 /* PickingSceneController.cc in Sources */,
 				2AB4C1A316DE9F1100B02479 /* AmbientForceController.cc in Sources */,
 				2ACF5A2816E52D4B00F838D9 /* SpriteBatchQuery.cc in Sources */,
+				2AE2938516EF4C220015E200 /* WaveComposite.cc in Sources */,
+				2AA3655916F3552200E7A900 /* ImageFrameProvider.cc in Sources */,
+				2AA3655A16F3552200E7A900 /* ImageFrameProviderCore.cc in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 36 - 12
engine/compilers/Xcode_iOS/Torque2D.xcodeproj/project.pbxproj

@@ -7,6 +7,8 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		2AA3655F16F3553E00E7A900 /* ImageFrameProvider.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA3655B16F3553E00E7A900 /* ImageFrameProvider.cc */; };
+		2AA3656016F3553E00E7A900 /* ImageFrameProviderCore.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA3655D16F3553E00E7A900 /* ImageFrameProviderCore.cc */; };
 		2AA6866A16D69968003CEF0A /* SceneObjectList.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA6866516D69968003CEF0A /* SceneObjectList.cc */; };
 		2AA6866B16D69968003CEF0A /* SceneObjectSet.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA6866816D69968003CEF0A /* SceneObjectSet.cc */; };
 		2AB14A0916D7CDCE00EABBF2 /* PointForceController.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AB14A0716D7CDCE00EABBF2 /* PointForceController.cc */; };
@@ -16,6 +18,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 */; };
@@ -66,7 +69,6 @@
 		867BACF516AEC8BB0033868F /* popupMenu.mm in Sources */ = {isa = PBXBuildFile; fileRef = 867BACCC16AEC8BB0033868F /* popupMenu.mm */; };
 		867BACF616AEC8BB0033868F /* SoundEngine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 867BACD016AEC8BB0033868F /* SoundEngine.mm */; };
 		867BAFDF16AEC9050033868F /* AnimationAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BACFA16AEC9050033868F /* AnimationAsset.cc */; };
-		867BAFE016AEC9050033868F /* AnimationController.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BACFD16AEC9050033868F /* AnimationController.cc */; };
 		867BAFE116AEC9050033868F /* ImageAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BACFF16AEC9050033868F /* ImageAsset.cc */; };
 		867BAFE216AEC9050033868F /* ParticleAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD0216AEC9050033868F /* ParticleAsset.cc */; };
 		867BAFE316AEC9050033868F /* ParticleAssetEmitter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD0516AEC9050033868F /* ParticleAssetEmitter.cc */; };
@@ -79,7 +81,6 @@
 		867BAFEA16AEC9050033868F /* SpriteBase.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD1616AEC9050033868F /* SpriteBase.cc */; };
 		867BAFEB16AEC9050033868F /* SpriteBatch.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD1916AEC9050033868F /* SpriteBatch.cc */; };
 		867BAFEC16AEC9050033868F /* SpriteBatchItem.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD1B16AEC9050033868F /* SpriteBatchItem.cc */; };
-		867BAFED16AEC9050033868F /* SpriteProxyBase.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD1D16AEC9050033868F /* SpriteProxyBase.cc */; };
 		867BAFEE16AEC9050033868F /* Utility.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD1F16AEC9050033868F /* Utility.cc */; };
 		867BAFEF16AEC9050033868F /* Vector2.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD2116AEC9050033868F /* Vector2.cc */; };
 		867BAFF016AEC9050033868F /* guiImageButtonCtrl.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD2516AEC9050033868F /* guiImageButtonCtrl.cc */; };
@@ -481,6 +482,10 @@
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
+		2AA3655B16F3553E00E7A900 /* ImageFrameProvider.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageFrameProvider.cc; sourceTree = "<group>"; };
+		2AA3655C16F3553E00E7A900 /* ImageFrameProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageFrameProvider.h; sourceTree = "<group>"; };
+		2AA3655D16F3553E00E7A900 /* ImageFrameProviderCore.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageFrameProviderCore.cc; sourceTree = "<group>"; };
+		2AA3655E16F3553E00E7A900 /* ImageFrameProviderCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageFrameProviderCore.h; sourceTree = "<group>"; };
 		2AA6866516D69968003CEF0A /* SceneObjectList.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneObjectList.cc; sourceTree = "<group>"; };
 		2AA6866616D69968003CEF0A /* SceneObjectList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneObjectList.h; sourceTree = "<group>"; };
 		2AA6866716D69968003CEF0A /* SceneObjectSet_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneObjectSet_ScriptBinding.h; sourceTree = "<group>"; };
@@ -508,6 +513,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>"; };
@@ -587,8 +595,6 @@
 		867BACFA16AEC9050033868F /* AnimationAsset.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimationAsset.cc; sourceTree = "<group>"; };
 		867BACFB16AEC9050033868F /* AnimationAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationAsset.h; sourceTree = "<group>"; };
 		867BACFC16AEC9050033868F /* AnimationAsset_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationAsset_ScriptBinding.h; sourceTree = "<group>"; };
-		867BACFD16AEC9050033868F /* AnimationController.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimationController.cc; sourceTree = "<group>"; };
-		867BACFE16AEC9050033868F /* AnimationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationController.h; sourceTree = "<group>"; };
 		867BACFF16AEC9050033868F /* ImageAsset.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageAsset.cc; sourceTree = "<group>"; };
 		867BAD0016AEC9050033868F /* ImageAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageAsset.h; sourceTree = "<group>"; };
 		867BAD0116AEC9050033868F /* ImageAsset_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageAsset_ScriptBinding.h; sourceTree = "<group>"; };
@@ -618,8 +624,6 @@
 		867BAD1A16AEC9050033868F /* SpriteBatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteBatch.h; sourceTree = "<group>"; };
 		867BAD1B16AEC9050033868F /* SpriteBatchItem.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpriteBatchItem.cc; sourceTree = "<group>"; };
 		867BAD1C16AEC9050033868F /* SpriteBatchItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteBatchItem.h; sourceTree = "<group>"; };
-		867BAD1D16AEC9050033868F /* SpriteProxyBase.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpriteProxyBase.cc; sourceTree = "<group>"; };
-		867BAD1E16AEC9050033868F /* SpriteProxyBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteProxyBase.h; sourceTree = "<group>"; };
 		867BAD1F16AEC9050033868F /* Utility.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Utility.cc; sourceTree = "<group>"; };
 		867BAD2016AEC9050033868F /* Utility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utility.h; sourceTree = "<group>"; };
 		867BAD2116AEC9050033868F /* Vector2.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Vector2.cc; 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 */,
@@ -1573,8 +1596,6 @@
 				867BACFA16AEC9050033868F /* AnimationAsset.cc */,
 				867BACFB16AEC9050033868F /* AnimationAsset.h */,
 				867BACFC16AEC9050033868F /* AnimationAsset_ScriptBinding.h */,
-				867BACFD16AEC9050033868F /* AnimationController.cc */,
-				867BACFE16AEC9050033868F /* AnimationController.h */,
 				867BACFF16AEC9050033868F /* ImageAsset.cc */,
 				867BAD0016AEC9050033868F /* ImageAsset.h */,
 				867BAD0116AEC9050033868F /* ImageAsset_ScriptBinding.h */,
@@ -1595,6 +1616,10 @@
 		867BAD0C16AEC9050033868F /* core */ = {
 			isa = PBXGroup;
 			children = (
+				2AA3655B16F3553E00E7A900 /* ImageFrameProvider.cc */,
+				2AA3655C16F3553E00E7A900 /* ImageFrameProvider.h */,
+				2AA3655D16F3553E00E7A900 /* ImageFrameProviderCore.cc */,
+				2AA3655E16F3553E00E7A900 /* ImageFrameProviderCore.h */,
 				2ACF5A2916E52D6A00F838D9 /* SpriteBatchQuery.cc */,
 				2ACF5A2A16E52D6A00F838D9 /* SpriteBatchQuery.h */,
 				2ACF5A2B16E52D6A00F838D9 /* SpriteBatchQueryResult.h */,
@@ -1614,8 +1639,6 @@
 				867BAD1A16AEC9050033868F /* SpriteBatch.h */,
 				867BAD1B16AEC9050033868F /* SpriteBatchItem.cc */,
 				867BAD1C16AEC9050033868F /* SpriteBatchItem.h */,
-				867BAD1D16AEC9050033868F /* SpriteProxyBase.cc */,
-				867BAD1E16AEC9050033868F /* SpriteProxyBase.h */,
 				867BAD1F16AEC9050033868F /* Utility.cc */,
 				867BAD2016AEC9050033868F /* Utility.h */,
 				867BAD2116AEC9050033868F /* Vector2.cc */,
@@ -3011,7 +3034,6 @@
 				867BACF516AEC8BB0033868F /* popupMenu.mm in Sources */,
 				867BACF616AEC8BB0033868F /* SoundEngine.mm in Sources */,
 				867BAFDF16AEC9050033868F /* AnimationAsset.cc in Sources */,
-				867BAFE016AEC9050033868F /* AnimationController.cc in Sources */,
 				867BAFE116AEC9050033868F /* ImageAsset.cc in Sources */,
 				867BAFE216AEC9050033868F /* ParticleAsset.cc in Sources */,
 				867BAFE316AEC9050033868F /* ParticleAssetEmitter.cc in Sources */,
@@ -3024,7 +3046,6 @@
 				867BAFEA16AEC9050033868F /* SpriteBase.cc in Sources */,
 				867BAFEB16AEC9050033868F /* SpriteBatch.cc in Sources */,
 				867BAFEC16AEC9050033868F /* SpriteBatchItem.cc in Sources */,
-				867BAFED16AEC9050033868F /* SpriteProxyBase.cc in Sources */,
 				867BAFEE16AEC9050033868F /* Utility.cc in Sources */,
 				867BAFEF16AEC9050033868F /* Vector2.cc in Sources */,
 				867BAFF016AEC9050033868F /* guiImageButtonCtrl.cc in Sources */,
@@ -3414,6 +3435,9 @@
 				2AB4C1B016DE9F6700B02479 /* GroupedSceneController.cc in Sources */,
 				2AB4C1B116DE9F6700B02479 /* PickingSceneController.cc in Sources */,
 				2ACF5A2C16E52D6A00F838D9 /* SpriteBatchQuery.cc in Sources */,
+				2AE2938B16EF4C480015E200 /* WaveComposite.cc in Sources */,
+				2AA3655F16F3553E00E7A900 /* ImageFrameProvider.cc in Sources */,
+				2AA3656016F3553E00E7A900 /* ImageFrameProviderCore.cc in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

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

@@ -61,7 +61,7 @@ public:
     virtual void copyTo(SimObject* object);
 
     void            setImage( const char* pAssetId );
-    const AssetPtr<ImageAsset>& getImage( void ) const     { return mImageAsset; }
+    inline const AssetPtr<ImageAsset>& getImage( void ) const           { return mImageAsset; }
 
     void            setAnimationFrames( const char* pAnimationFrames );
     inline const Vector<S32>& getSpecifiedAnimationFrames( void ) const { return mAnimationFrames; }

+ 0 - 336
engine/source/2d/assets/AnimationController.cc

@@ -1,336 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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.
-//-----------------------------------------------------------------------------
-
-#include "graphics/gBitmap.h"
-#include "console/consoleTypes.h"
-#include "io/bitStream.h"
-#include "2d/sceneobject/SceneObject.h"
-#include "2d/assets/AnimationAsset.h"
-#include "AnimationController.h"
-
-// Debug Profiling.
-#include "debug/profiler.h"
-
-//-----------------------------------------------------------------------------
-
-AnimationController::AnimationController()
-{
-    // Register for animation asset refresh notifications.
-    mAnimationAsset.registerRefreshNotify( this );
-
-    // Reset the state.
-    resetState();
-}
-
-//-----------------------------------------------------------------------------
-
-AnimationController::~AnimationController()
-{
-}
-
-//-----------------------------------------------------------------------------
-
-void AnimationController::resetState( void )
-{
-    mCurrentFrameIndex = 0;
-    mLastFrameIndex = 0;
-    mMaxFrameIndex = 0;
-    mCurrentTime = 0.0f;
-    mPausedTime = 0.0f;
-    mAnimationTimeScale = 1.0f;
-    mTotalIntegrationTime = 0.0f;
-    mFrameIntegrationTime = 0.0f;
-    mAutoRestoreAnimation = false;
-    mAnimationFinished = true;
-
-    mAnimationAsset.clear();
-    mLastAnimationAsset.clear();
-}
-
-//-----------------------------------------------------------------------------
-
-void AnimationController::onAssetRefreshed( AssetPtrBase* pAssetPtrBase )
-{
-    // Don't perform any action if the animation is not already playing.
-    if ( mAnimationFinished )
-        return;
-
-    // Attempt to restart the animation.
-    playAnimation( mAnimationAsset, false );
-}
-
-//-----------------------------------------------------------------------------
-
-const ImageAsset::FrameArea& AnimationController::getCurrentImageFrameArea( void ) const
-{
-    // Fetch current frame.
-    const U32 currentFrame = getCurrentFrame();
-
-    // Sanity!
-    AssertFatal( mAnimationAsset.notNull(), "Animation controller requested image frame but no animation asset assigned." );
-
-    // Fetch image asset.
-    const AssetPtr<ImageAsset>& imageAsset = mAnimationAsset->getImage();
-
-    // Sanity!
-    AssertFatal( imageAsset.notNull(), "Animation controller requested image frame but no image asset assigned." );
-
-    // Sanity!
-    AssertFatal( currentFrame < imageAsset->getFrameCount(), "Animation controller requested image frame that is out of bounds." );
-
-    return imageAsset->getImageFrameArea(currentFrame);
-};
-
-//-----------------------------------------------------------------------------
-
-const U32 AnimationController::getCurrentFrame( void ) const
-{
-    // Sanity!
-    AssertFatal( mAnimationAsset.notNull(), "Animation controller requested current image frame but no animation asset assigned." );
-
-    // Fetch validated frames.
-    const Vector<S32>& validatedFrames = mAnimationAsset->getValidatedAnimationFrames();
-
-    // Sanity!
-    AssertFatal( mCurrentFrameIndex < validatedFrames.size(), "Animation controller requested the current frame but it is out of bounds of the validated frames." );
-
-    return validatedFrames[mCurrentFrameIndex];
-};
-
-//-----------------------------------------------------------------------------
-
-bool AnimationController::isAnimationValid( void ) const
-{
-    // Not valid if no animation asset.
-    if ( mAnimationAsset.isNull() )
-        return false;
-
-    // Fetch validated frames.
-    const Vector<S32>& validatedFrames = mAnimationAsset->getValidatedAnimationFrames();
-
-    // Not valid if current frame index is out of bounds of the validated frames.
-    if ( mCurrentFrameIndex >= validatedFrames.size() )
-        return false;
-
-    // Fetch image asset.
-    const AssetPtr<ImageAsset>& imageAsset = mAnimationAsset->getImage();
-
-    // Not valid if no image asset.
-    if ( imageAsset.isNull() )
-        return false;
-
-    // Fetch current frame.
-    const U32 currentFrame = getCurrentFrame();
-
-    // Not valid if current frame is out of bounds of the image asset.
-    if ( currentFrame >= imageAsset->getFrameCount() )
-        return false;
-
-    // Valid.
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-
-bool AnimationController::playAnimation( const AssetPtr<AnimationAsset>& animationAsset, const bool autoRestore )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(AnimationController_PlayAnimation);
-
-    // Stop animation.
-    stopAnimation();
-
-    // Finish if no animation asset.
-    if ( animationAsset.isNull() )
-        return true;
-
-    // Fetch validated frames.
-    const Vector<S32>& validatedFrames = animationAsset->getValidatedAnimationFrames();
-
-    // Check we've got some frames.
-    if ( validatedFrames.size() == 0 )
-    {
-        Con::warnf( "AnimationController::playAnimation() - Cannot play AnimationAsset '%s' - Animation has no validated frames!", mAnimationAsset.getAssetId() );
-        return false;
-    }
-
-    // Set last animation asset.
-    if ( autoRestore )
-        mLastAnimationAsset = mAnimationAsset;
-    else
-        mLastAnimationAsset.clear();
-
-    // Set animation asset.
-    mAnimationAsset = animationAsset;
-
-    // Set Maximum Frame Index.
-    mMaxFrameIndex = validatedFrames.size()-1;
-
-    // Calculate Total Integration Time.
-    mTotalIntegrationTime = mAnimationAsset->getAnimationTime();
-
-    // Calculate Frame Integration Time.
-    mFrameIntegrationTime = mTotalIntegrationTime / validatedFrames.size();
-
-    // No, so random Start?
-    if ( mAnimationAsset->getRandomStart() )
-    {
-        // Yes, so calculate start time.
-        mCurrentTime = CoreMath::mGetRandomF(0.0f, mTotalIntegrationTime*0.999f);
-    }
-    else
-    {
-        // No, so set first frame.
-        mCurrentTime = 0.0f;
-    }
-
-    // Set Auto Restore Animation Flag.
-    mAutoRestoreAnimation = autoRestore;
-
-    // Reset animation finished flag.
-    mAnimationFinished = false;
-
-    // Do an initial animation update.
-    updateAnimation(0.0f);
-
-    // Return Okay.
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-
-void AnimationController::stopAnimation( void )
-{
-    // Flag as animation finished.
-    mAnimationFinished = true;
-}
-
-//-----------------------------------------------------------------------------
-
-bool AnimationController::updateAnimation( const F32 elapsedTime )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(AnimationController_UpdateAnimation);
-
-    // Finish if animation asset is not valid.
-    if ( mAnimationAsset.isNull() || mAnimationAsset->getImage().isNull() )
-        return false;
-
-    // Finish if animation has finished.
-    if ( mAnimationFinished )
-        return false;
-
-    // Fetch validated frames.
-    const Vector<S32>& validatedFrames = mAnimationAsset->getValidatedAnimationFrames();
-
-    // Finish if there are no validated frames.
-    if ( validatedFrames.size() == 0 )
-        return false;
-
-    // Calculate scaled time.
-    const F32 scaledTime = elapsedTime * mAnimationTimeScale;
-
-    // Update Current Time.
-    mCurrentTime += scaledTime;
-
-    // Check if the animation has finished.
-    if ( !mAnimationAsset->getAnimationCycle() && mGreaterThanOrEqual(mCurrentTime, mTotalIntegrationTime) )
-    {
-        // Animation has finished.
-        mAnimationFinished = true;
-
-        // Are we restoring the animation?
-        if ( mAutoRestoreAnimation )
-        {
-            // Yes, so play last animation.
-            playAnimation( mLastAnimationAsset, false );
-        }
-        else
-        {
-            // No, so fix Animation at end of frames.
-            mCurrentTime = mTotalIntegrationTime - (mFrameIntegrationTime * 0.5f);
-        }
-    }
-
-    // Update Current Mod Time.
-    mCurrentModTime = mFmod( mCurrentTime, mTotalIntegrationTime );
-
-    // Calculate Current Frame.
-    mCurrentFrameIndex = (S32)(mCurrentModTime / mFrameIntegrationTime);
-
-    // Fetch frame.
-    S32 frame = validatedFrames[mCurrentFrameIndex];
-
-    // Fetch image frame count.
-    const S32 imageFrameCount = mAnimationAsset->getImage()->getFrameCount();
-
-    // Clamp frames.
-    if ( frame < 0 )
-        frame = 0;
-    else if (frame >= imageFrameCount )
-        frame = imageFrameCount-1;
-
-    // Calculate if frame has changed.
-    bool frameChanged = (mCurrentFrameIndex != mLastFrameIndex);
-
-    // Reset Last Frame.
-    mLastFrameIndex = mCurrentFrameIndex;
-
-    // Return Frame-Changed Flag.
-    return frameChanged;
-}
-
-//-----------------------------------------------------------------------------
-
-void AnimationController::resetTime( void )
-{
-    // Rest Time.
-    mCurrentTime = 0.0f;
-}
-
-//-----------------------------------------------------------------------------
-
-void AnimationController::setAnimationFrame( const U32 frameIndex )
-{
-    // Do we have a valid animation asset?
-    if ( mAnimationAsset.isNull() )
-    {
-        // No, so warn.
-        Con::warnf("AnimationController::setAnimationFrame() - Cannot set frame; animation is finished or is invalid!");
-        return;
-    }
-
-    // Validate Frame Index?
-    if ( (S32)frameIndex < 0 || frameIndex > mMaxFrameIndex )
-    {
-        // No, so warn.
-        Con::warnf("AnimationController::setAnimationFrame() - Animation Frame-Index Invalid (frame#%d of %d in %s)", frameIndex, mMaxFrameIndex, mAnimationAsset.getAssetId() );
-        // Finish here.
-        return;
-    }
-
-    // Calculate current time.
-    mCurrentTime = frameIndex*mFrameIntegrationTime;
-
-    // Do an immediate animation update.
-    updateAnimation(0.0f);
-}

+ 0 - 94
engine/source/2d/assets/AnimationController.h

@@ -1,94 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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 _ANIMATION_CONTROLLER_H_
-#define _ANIMATION_CONTROLLER_H_
-
-#ifndef _IMAGE_ASSET_H_
-#include "2d/assets/ImageAsset.h"
-#endif
-
-#ifndef _ANIMATION_ASSET_H_
-#include "2d/assets/AnimationAsset.h"
-#endif
-
-#ifndef _ASSET_PTR_H_
-#include "assets/assetPtr.h"
-#endif
-
-#ifndef _FACTORY_CACHE_H_
-#include "memory/factoryCache.h"
-#endif
-
-///-----------------------------------------------------------------------------
-
-class AnimationController : public IFactoryObjectReset, private AssetPtrCallback
-{
-private:
-    AssetPtr<AnimationAsset>                mAnimationAsset;
-    AssetPtr<AnimationAsset>                mLastAnimationAsset;
-    S32                                     mLastFrameIndex;
-    S32                                     mCurrentFrameIndex;
-    U32                                     mMaxFrameIndex;
-    F32                                     mCurrentTime;
-    F32                                     mPausedTime;
-    F32                                     mCurrentModTime;
-    F32                                     mAnimationTimeScale;
-    F32                                     mTotalIntegrationTime;
-    F32                                     mFrameIntegrationTime;
-    bool                                    mAutoRestoreAnimation;
-    bool                                    mAnimationFinished;
-
-private:
-    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
-
-public:
-    AnimationController();
-    virtual ~AnimationController();
-
-    TextureHandle&                                  getImageTexture( void )                 { return mAnimationAsset->getImage()->getImageTexture(); };
-    const ImageAsset::FrameArea&                    getCurrentImageFrameArea( void ) const;
-    const AnimationAsset*                           getCurrentAnimation( void ) const       { return mAnimationAsset.notNull() ? mAnimationAsset : NULL; };
-    const StringTableEntry                          getCurrentAnimationAssetId( void ) const { return mAnimationAsset.getAssetId(); };
-    const U32                                       getCurrentFrame( void ) const;
-    const F32                                       getCurrentTime( void ) const            { return mCurrentTime; };
-    bool                                            isAnimationValid( void ) const;
-    bool                                            isAnimationFinished( void ) const       { return mAnimationFinished; };
-
-    const AssetPtr<AnimationAsset>&                 getAnimationAsset( void ) const         { return mAnimationAsset; };
-
-    void                                            setAnimationFrame( const U32 frameIndex );
-    void                                            setAnimationTimeScale( const F32 scale ) { mAnimationTimeScale = scale; }
-    inline F32                                      getAnimationTimeScale( void ) const     { return mAnimationTimeScale; }
-
-    void                                            clearAssets( void )                     { mAnimationAsset.clear(); mLastAnimationAsset.clear(); }
-
-    bool playAnimation( const AssetPtr<AnimationAsset>& animationAsset, const bool autoRestore );
-    bool updateAnimation( const F32 elapsedTime );
-    void stopAnimation( void );
-    void resetTime( void );
-
-    virtual void resetState( void );
-};
-
-
-#endif // _ANIMATION_CONTROLLER_H_

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

@@ -60,6 +60,10 @@
 
 //------------------------------------------------------------------------------
 
+ImageAsset::FrameArea BadFrameArea(0, 0, 0, 0, 0.0f, 0.0f);
+
+//------------------------------------------------------------------------------
+
 ConsoleType( imageAssetPtr, TypeImageAssetPtr, sizeof(AssetPtr<ImageAsset>), ASSET_ID_FIELD_PREFIX )
 
 //-----------------------------------------------------------------------------

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

@@ -291,4 +291,8 @@ protected:
     static bool writeCellHeight( void* obj, StringTableEntry pFieldName )   { ImageAsset* pImageAsset = static_cast<ImageAsset*>(obj); return !pImageAsset->getExplicitMode() && pImageAsset->getCellHeight() != 0; }
 };
 
+//-----------------------------------------------------------------------------
+
+extern ImageAsset::FrameArea BadFrameArea;
+
 #endif // _IMAGE_ASSET_H_

+ 1 - 1
engine/source/2d/assets/ParticleAssetEmitter.cc

@@ -295,7 +295,7 @@ void ParticleAssetEmitter::copyTo(SimObject* object)
    pParticleAssetEmitter->setAlphaTest( getAlphaTest() );
 
    pParticleAssetEmitter->setRandomImageFrame( getRandomImageFrame() );
-   if ( pParticleAssetEmitter->isStaticMode() )
+   if ( pParticleAssetEmitter->isStaticFrameProvider() )
    {
        pParticleAssetEmitter->setImage( getImage() );
        pParticleAssetEmitter->setImageFrame( getImageFrame() );

+ 11 - 15
engine/source/2d/assets/ParticleAssetEmitter.h

@@ -27,16 +27,12 @@
 #include "2d/assets/particleAssetFieldCollection.h"
 #endif
 
-#ifndef _PARTICLE_ASSET_FIELD_H_
-#include "2d/assets/particleAssetField.h"
-#endif
-
 #ifndef _IMAGE_ASSET_H_
 #include "2d/assets/ImageAsset.h"
 #endif
 
-#ifndef _ANIMATION_CONTROLLER_H_
-#include "2d/assets/AnimationController.h"
+#ifndef _ANIMATION_ASSET_H_
+#include "2d/assets/AnimationAsset.h"
 #endif
 
 #ifndef _SCENE_OBJECT_H_
@@ -49,7 +45,7 @@ class ParticleAsset;
 
 //-----------------------------------------------------------------------------
 
-class ParticleAssetEmitter : public SimObject, public AssetPtrCallback
+class ParticleAssetEmitter : public SimObject, protected AssetPtrCallback
 {
     friend ParticleAsset;
 
@@ -185,7 +181,7 @@ public:
     inline void setOldestInFront( const bool oldestInFront ) { mOldestInFront = oldestInFront; refreshAsset();  }
     inline bool getOldestInFront( void ) const { return mOldestInFront; }
    
-    inline bool isStaticMode( void ) const { return mStaticMode; }
+    inline bool isStaticFrameProvider( void ) const { return mStaticMode; }
     bool setImage( const char* pAssetId, const U32 frame = 0 );
     inline StringTableEntry getImage( void ) const { return mImageAsset.getAssetId(); }
     bool setImageFrame( const U32 frame );
@@ -194,8 +190,8 @@ public:
     inline bool getRandomImageFrame( void ) const { return mRandomImageFrame; }
     bool setAnimation( const char* animationName );
     inline StringTableEntry getAnimation( void ) const { return mAnimationAsset.getAssetId(); }
-    inline const AssetPtr<ImageAsset>& getImageAsset( void ) const { return mImageAsset; }
-    inline const AssetPtr<AnimationAsset>& getAnimationAsset( void ) const { return mAnimationAsset; }
+    inline AssetPtr<ImageAsset>& getImageAsset( void ) { return mImageAsset; }
+    inline AssetPtr<AnimationAsset>& getAnimationAsset( void ) { return mAnimationAsset; }
 
     inline void setBlendMode( bool blendMode ) { mBlendMode = blendMode; refreshAsset(); }
     inline bool getBlendMode( void ) const { return mBlendMode; };
@@ -257,9 +253,9 @@ public:
 private:
     void setOwner( ParticleAsset* pParticleAsset );
     inline void refreshAsset( void );
-    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
 
 protected:
+    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
     void onTamlCustomWrite( TamlCustomNodes& customNodes );
     void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
@@ -305,14 +301,14 @@ protected:
 
     static bool     setImage(void* obj, const char* data)                               { static_cast<ParticleAssetEmitter*>(obj)->setImage(data); return false; };
     static const char* getImage(void* obj, const char* data)                            { return static_cast<ParticleAssetEmitter*>(obj)->getImage(); }
-    static bool     writeImage( void* obj, StringTableEntry pFieldName )                { ParticleAssetEmitter* pCastObject = static_cast<ParticleAssetEmitter*>(obj); if ( !pCastObject->isStaticMode() ) return false; return pCastObject->mImageAsset.notNull(); }
+    static bool     writeImage( void* obj, StringTableEntry pFieldName )                { ParticleAssetEmitter* pCastObject = static_cast<ParticleAssetEmitter*>(obj); if ( !pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mImageAsset.notNull(); }
     static bool     setImageFrame(void* obj, const char* data)                          { static_cast<ParticleAssetEmitter*>(obj)->setImageFrame(dAtoi(data)); return false; };
-    static bool     writeImageFrame( void* obj, StringTableEntry pFieldName )           { ParticleAssetEmitter* pCastObject = static_cast<ParticleAssetEmitter*>(obj); if ( !pCastObject->isStaticMode() ) return false; return pCastObject->mImageAsset.notNull() && !pCastObject->getRandomImageFrame(); }
+    static bool     writeImageFrame( void* obj, StringTableEntry pFieldName )           { ParticleAssetEmitter* pCastObject = static_cast<ParticleAssetEmitter*>(obj); if ( !pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mImageAsset.notNull() && !pCastObject->getRandomImageFrame(); }
     static bool     setRandomImageFrame(void* obj, const char* data)                    { static_cast<ParticleAssetEmitter*>(obj)->setRandomImageFrame(dAtob(data)); return false; };
-    static bool     writeRandomImageFrame( void* obj, StringTableEntry pFieldName )     { ParticleAssetEmitter* pCastObject = static_cast<ParticleAssetEmitter*>(obj); if ( !pCastObject->isStaticMode() ) return false; return pCastObject->getRandomImageFrame(); }
+    static bool     writeRandomImageFrame( void* obj, StringTableEntry pFieldName )     { ParticleAssetEmitter* pCastObject = static_cast<ParticleAssetEmitter*>(obj); if ( !pCastObject->isStaticFrameProvider() ) return false; return pCastObject->getRandomImageFrame(); }
     static bool     setAnimation(void* obj, const char* data)                           { static_cast<ParticleAssetEmitter*>(obj)->setAnimation(data); return false; };
     static const char* getAnimation(void* obj, const char* data)                        { return static_cast<ParticleAssetEmitter*>(obj)->getAnimation(); }
-    static bool     writeAnimation( void* obj, StringTableEntry pFieldName )            { ParticleAssetEmitter* pCastObject = static_cast<ParticleAssetEmitter*>(obj); if ( pCastObject->isStaticMode() ) return false; return pCastObject->mAnimationAsset.notNull(); }
+    static bool     writeAnimation( void* obj, StringTableEntry pFieldName )            { ParticleAssetEmitter* pCastObject = static_cast<ParticleAssetEmitter*>(obj); if ( pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mAnimationAsset.notNull(); }
 
     static bool     setBlendMode(void* obj, const char* data)                           { static_cast<ParticleAssetEmitter*>(obj)->setBlendMode(dAtob(data)); return false; }
     static bool     writeBlendMode( void* obj, StringTableEntry pFieldName )            { return static_cast<ParticleAssetEmitter*>(obj)->getBlendMode() == false; }

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

+ 14 - 14
engine/source/2d/controllers/BuoyancyController.h

@@ -41,26 +41,26 @@ private:
     /// The fluid area.
     b2AABB mFluidArea;
 
-	/// The fluid density.
-	F32 mFluidDensity;
+    /// The fluid density.
+    F32 mFluidDensity;
 
-	/// Fluid flow velocity for drag calculations.
-	Vector2 mFlowVelocity;
+    /// Fluid flow velocity for drag calculations.
+    Vector2 mFlowVelocity;
 
-	/// Linear drag co-efficient.
-	F32 mLinearDrag;
+    /// Linear drag co-efficient.
+    F32 mLinearDrag;
 
-	/// Linear drag co-efficient.
-	F32 mAngularDrag;
+    /// Linear drag co-efficient.
+    F32 mAngularDrag;
 
-	/// Gravity to use inside the fluid.
-	Vector2 mFluidGravity;
+    /// Gravity to use inside the fluid.
+    Vector2 mFluidGravity;
 
-	/// Whether to use the collision shape densities or assume a uniform density.
-	bool mUseShapeDensity;
+    /// Whether to use the collision shape densities or assume a uniform density.
+    bool mUseShapeDensity;
 
-	/// The outer fluid surface normal.
-	Vector2 mSurfaceNormal;
+    /// The outer fluid surface normal.
+    Vector2 mSurfaceNormal;
 
 protected:
     F32 ComputeCircleSubmergedArea( const b2Transform& bodyTransform, const b2CircleShape* pShape, Vector2& center );

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

+ 17 - 4
engine/source/2d/controllers/PointForceController.h

@@ -50,11 +50,14 @@ private:
     /// 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 mLinearDrag;
 
-	/// Linear drag co-efficient.
-	F32 mAngularDrag;
+    /// Linear drag co-efficient.
+    F32 mAngularDrag;
+
+    /// Tracked object.
+    SimObjectPtr<SceneObject> mTrackedObject;
 
 public:
     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();
+} 
+

+ 51 - 0
engine/source/2d/core/ImageFrameProvider.cc

@@ -0,0 +1,51 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#include "2d/core/imageFrameProvider.h"
+
+//-----------------------------------------------------------------------------
+
+ImageFrameProvider::ImageFrameProvider()
+{
+    // Register for animation asset refresh notifications.
+    mAnimationAsset.registerRefreshNotify( this );
+
+    // Allocate assets.
+    ImageFrameProviderCore::allocateAssets( &mImageAsset, &mAnimationAsset );
+}
+
+//-----------------------------------------------------------------------------
+
+ImageFrameProvider::~ImageFrameProvider()
+{
+    // Deallocate assets.
+    ImageFrameProviderCore::deallocateAssets();
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProvider::onAssetRefreshed( AssetPtrBase* pAssetPtrBase )
+{
+    // Call parent.
+    ImageFrameProviderCore::onAssetRefreshed( pAssetPtrBase );
+}
+

+ 47 - 0
engine/source/2d/core/ImageFrameProvider.h

@@ -0,0 +1,47 @@
+//-----------------------------------------------------------------------------
+// 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 _IMAGE_FRAME_PROVIDER_H
+#define _IMAGE_FRAME_PROVIDER_H
+
+#ifndef _IMAGE_FRAME_PROVIDER_CORE_H
+#include "2d/core/imageFrameProviderCore.h"
+#endif
+
+///-----------------------------------------------------------------------------
+
+class ImageFrameProvider : public ImageFrameProviderCore
+{
+protected:
+    AssetPtr<ImageAsset>                    mImageAsset;
+    AssetPtr<AnimationAsset>                mAnimationAsset;
+
+public:
+    ImageFrameProvider();
+    virtual ~ImageFrameProvider();
+
+protected:
+    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
+};
+
+
+#endif // _IMAGE_FRAME_PROVIDER_H

+ 586 - 0
engine/source/2d/core/ImageFrameProviderCore.cc

@@ -0,0 +1,586 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#include "2d/core/imageFrameProviderCore.h"
+
+#ifndef _SCENE_OBJECT_H_
+#include "2d/sceneobject/SceneObject.h"
+#endif
+
+#ifndef _DGL_H_
+#include "graphics/dgl.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+#ifndef _STRINGBUFFER_H_
+#include "string/stringBuffer.h"
+#endif
+
+#ifndef _RENDER_PROXY_H_
+#include "2d/core/renderProxy.h"
+#endif
+
+// Debug Profiling.
+#include "debug/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+ImageFrameProviderCore::ImageFrameProviderCore() : mpImageAsset(NULL), mpAnimationAsset(NULL)
+{
+}
+
+//-----------------------------------------------------------------------------
+
+ImageFrameProviderCore::~ImageFrameProviderCore()
+{
+    // Reset the state.
+    resetState();
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::allocateAssets( AssetPtr<ImageAsset>* pImageAssetPtr, AssetPtr<AnimationAsset>* pAnimationAssetPtr )
+{
+    // Sanity!
+    AssertFatal( mpImageAsset == NULL && mpAnimationAsset == NULL, "ImageFrameProviderCore: Assets already allocated." );
+    AssertFatal( pImageAssetPtr != NULL, "ImageFrameProviderCore: Image-Asset pointer cannot be NULL." );
+    AssertFatal( pAnimationAssetPtr != NULL, "ImageFrameProviderCore: Animation-Asset pointer cannot be NULL." );
+
+    // Reset the state.
+    resetState();
+
+    // Set asset pointers.
+    mpImageAsset = pImageAssetPtr;
+    mpAnimationAsset = pAnimationAssetPtr;
+
+    // Set static/animation frame provider.
+    mStaticProvider = mpImageAsset->notNull();
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::resetState( void )
+{
+    mSelfTick = false;
+
+    mCurrentFrameIndex = 0;
+    mLastFrameIndex = 0;
+    mMaxFrameIndex = 0;
+    mCurrentTime = 0.0f;
+    mPausedTime = 0.0f;
+    mAnimationTimeScale = 1.0f;
+    mTotalIntegrationTime = 0.0f;
+    mFrameIntegrationTime = 0.0f;
+    mAnimationPaused = false;
+    mAnimationFinished = true;
+
+    clearAssets();
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::copyTo( ImageFrameProviderCore* pImageFrameProviderCore ) const
+{
+    // Sanity!
+    AssertFatal(pImageFrameProviderCore != NULL, "ImageFrameProviderCore::copyTo - Copy object cannot be NULL.");
+
+    // Set self ticking.
+    pImageFrameProviderCore->mSelfTick = mSelfTick;
+
+    // Static provider?
+    if ( isStaticFrameProvider() )
+    {
+        // Yes, so use the image/frame if we have an asset.
+        if ( mpImageAsset->notNull() )
+            pImageFrameProviderCore->setImage( getImage(), getImageFrame() );
+    }
+    else if ( mpAnimationAsset->notNull() )
+    {
+        // No, so use current animation if we have an asset.
+        if ( mpAnimationAsset->notNull() )
+            pImageFrameProviderCore->setAnimation(getAnimation() );
+    }
+}
+
+//------------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::update( const F32 elapsedTime )
+{
+    // Static provider?
+    if ( isStaticFrameProvider() )
+    {
+        // Yes, so turn-off tick processing.
+        setProcessTicks( false );
+
+        return false;
+    }
+
+    // Finish if the animation has finished.
+    if ( isAnimationFinished() )
+        return false;
+
+    // Finish if animation is paused.
+    if ( isAnimationPaused() )
+        return true;
+
+    // Update the animation.
+    updateAnimation( Tickable::smTickSec );
+
+    // Finish if the animation has NOT finished.
+    if ( !isAnimationFinished() )
+        return false;
+
+    // Turn-off tick processing.
+    setProcessTicks( false );
+
+    // Perform callback.
+    onAnimationEnd();
+
+    // Flag animation as just finished.
+    return true;
+}
+
+//------------------------------------------------------------------------------
+
+void ImageFrameProviderCore::processTick( void )
+{
+    // Update using tick period.
+    update( Tickable::smTickSec );
+}
+
+//------------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::validRender( void ) const
+{
+    // Are we in static mode?
+    if ( isStaticFrameProvider() )
+    {
+        // Yes, so we must have an image asset and the frame must be in bounds.
+        return mpImageAsset->notNull() && ( getImageFrame() < (*mpImageAsset)->getFrameCount() );
+    }
+
+    // No, so if the animation must be valid.
+    return isAnimationValid();
+}
+
+//------------------------------------------------------------------------------
+
+void ImageFrameProviderCore::render(
+    const bool flipX,
+    const bool flipY,
+    const Vector2& vertexPos0,
+    const Vector2& vertexPos1,
+    const Vector2& vertexPos2,
+    const Vector2& vertexPos3,
+    BatchRender* pBatchRenderer ) const
+{
+    // Finish if we can't render.
+    if ( !validRender() )
+        return;
+
+    // Fetch texel area.
+    ImageAsset::FrameArea::TexelArea texelArea = getProviderImageFrameArea().mTexelArea;
+
+    // Flip texture coordinates appropriately.
+    texelArea.setFlip( flipX, flipY );
+
+    // Fetch lower/upper texture coordinates.
+    const Vector2& texLower = texelArea.mTexelLower;
+    const Vector2& texUpper = texelArea.mTexelUpper;
+    
+    // Submit batched quad.
+    pBatchRenderer->SubmitQuad(
+        vertexPos0,
+        vertexPos1,
+        vertexPos2,
+        vertexPos3,
+        Vector2( texLower.x, texUpper.y ),
+        Vector2( texUpper.x, texUpper.y ),
+        Vector2( texUpper.x, texLower.y ),
+        Vector2( texLower.x, texLower.y ),
+        getProviderTexture() );
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const
+{
+    // Validate frame provider.
+    if ( ( isStaticFrameProvider() && (mpImageAsset->isNull() || mImageFrame >= (*mpImageAsset)->getFrameCount()) ) ||
+        ( !isStaticFrameProvider() && (mpAnimationAsset->isNull() ) ) )
+    {
+        // Invalid so fetch the 'cannot render' proxy.
+        RenderProxy* pNoImageRenderProxy = Sim::findObject<RenderProxy>( CANNOT_RENDER_PROXY_NAME );
+
+        // Check that the render proxy can render.
+        if ( pNoImageRenderProxy != NULL && pNoImageRenderProxy->validRender() )
+        {
+            // Render using render-proxy.
+            pNoImageRenderProxy->renderGui( owner, offset, updateRect );
+        }
+
+        // Update control.
+        owner.setUpdate();
+    }
+    else
+    {
+        // Valid, so calculate source region.
+        const ImageAsset::FrameArea& frameArea = getProviderImageFrameArea();
+        RectI sourceRegion( frameArea.mPixelArea.mPixelOffset, Point2I(frameArea.mPixelArea.mPixelWidth, frameArea.mPixelArea.mPixelHeight) );
+
+        // Calculate destination region.
+        RectI destinationRegion(offset, owner.mBounds.extent);
+
+        // Render image.
+		dglSetBitmapModulation( owner.mProfile->mFillColor );
+        dglDrawBitmapStretchSR( getProviderTexture(), destinationRegion, sourceRegion );
+        dglClearBitmapModulation();
+    }
+
+    // Render child controls.
+    owner.renderChildControls(offset, updateRect);
+}
+
+//------------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::setImage( const char* pImageAssetId, const U32 frame )
+{
+    // Finish if invalid image asset.
+    if ( pImageAssetId == NULL )
+        return false;
+
+    // Set asset.
+    mpImageAsset->setAssetId( pImageAssetId );
+
+    // Set the image frame if the image asset was set.
+    if ( mpImageAsset->notNull() )
+        setImageFrame( frame );
+
+    // Set Frame.
+    mImageFrame = frame;
+
+    // Set as static provider.
+    mStaticProvider = true;
+
+    // Turn-off tick processing.
+    setProcessTicks( false );
+
+    // Return Okay.
+    return true;
+}
+
+//------------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::setImageFrame( const U32 frame )
+{
+    // Check Existing Image.
+    if ( mpImageAsset->isNull() )
+    {
+        // Warn.
+        Con::warnf("ImageFrameProviderCore::setImageFrame() - Cannot set Frame without existing asset Id.");
+
+        // Return Here.
+        return false;
+    }
+
+    // Check Frame Validity.
+    if ( frame >= (*mpImageAsset)->getFrameCount() )
+    {
+        // Warn.
+        Con::warnf( "ImageFrameProviderCore::setImageFrame() - Invalid Frame #%d for asset Id '%s'.", frame, mpImageAsset->getAssetId() );
+        // Return Here.
+        return false;
+    }
+
+    // Set Frame.
+    mImageFrame = frame;
+
+    // Return Okay.
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+const U32 ImageFrameProviderCore::getCurrentAnimationFrame( void ) const
+{
+    // Sanity!
+    AssertFatal( mpAnimationAsset->notNull(), "Animation controller requested current image frame but no animation asset assigned." );
+
+    // Fetch validated frames.
+    const Vector<S32>& validatedFrames = (*mpAnimationAsset)->getValidatedAnimationFrames();
+
+    // Sanity!
+    AssertFatal( mCurrentFrameIndex < validatedFrames.size(), "Animation controller requested the current frame but it is out of bounds of the validated frames." );
+
+    return validatedFrames[mCurrentFrameIndex];
+};
+
+//-----------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::isAnimationValid( void ) const
+{
+    // Not valid if no animation asset.
+    if ( mpAnimationAsset->isNull() )
+        return false;
+
+    // Fetch validated frames.
+    const Vector<S32>& validatedFrames = (*mpAnimationAsset)->getValidatedAnimationFrames();
+
+    // Not valid if current frame index is out of bounds of the validated frames.
+    if ( mCurrentFrameIndex >= validatedFrames.size() )
+        return false;
+
+    // Fetch image asset.
+    const AssetPtr<ImageAsset>& imageAsset = (*mpAnimationAsset)->getImage();
+
+    // Not valid if no image asset.
+    if ( imageAsset.isNull() )
+        return false;
+
+    // Fetch current frame.
+    const U32 currentFrame = getCurrentAnimationFrame();
+
+    // Not valid if current frame is out of bounds of the image asset.
+    if ( currentFrame >= imageAsset->getFrameCount() )
+        return false;
+
+    // Valid.
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::setAnimation( const char* pAnimationAssetId )
+{
+    // Set as dynamic provider.
+    mStaticProvider = false;
+
+    // Ensure animation is un-paused.
+    mAnimationPaused = false;
+
+    // Reset static asset.
+    mpImageAsset->clear();
+
+    // Fetch animation asset.
+    mpAnimationAsset->setAssetId( pAnimationAssetId );
+
+    // Finish if we didn't get an animation.
+    if ( mpAnimationAsset->isNull() )
+        return false;
+
+    // Play Animation.
+    if ( !playAnimation( *mpAnimationAsset ) )
+        return false;
+
+    // Turn-on tick processing.
+    setProcessTicks( true );
+
+    // Return Okay.
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::playAnimation( const AssetPtr<AnimationAsset>& animationAsset )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AnimationController_PlayAnimation);
+
+    // Stop animation.
+    stopAnimation();
+
+    // Finish if no animation asset.
+    if ( animationAsset.isNull() )
+        return true;
+
+    // Set as dynamic provider.
+    mStaticProvider = false;
+
+    // Fetch validated frames.
+    const Vector<S32>& validatedFrames = animationAsset->getValidatedAnimationFrames();
+
+    // Check we've got some frames.
+    if ( validatedFrames.size() == 0 )
+    {
+        Con::warnf( "ImageFrameProviderCore::playAnimation() - Cannot play AnimationAsset '%s' - Animation has no validated frames!", mpAnimationAsset->getAssetId() );
+        return false;
+    }
+
+    // Set animation asset.
+    mpAnimationAsset->setAssetId( animationAsset.getAssetId() );
+
+    // Set Maximum Frame Index.
+    mMaxFrameIndex = validatedFrames.size()-1;
+
+    // Calculate Total Integration Time.
+    mTotalIntegrationTime = (*mpAnimationAsset)->getAnimationTime();
+
+    // Calculate Frame Integration Time.
+    mFrameIntegrationTime = mTotalIntegrationTime / validatedFrames.size();
+
+    // No, so random Start?
+    if ( (*mpAnimationAsset)->getRandomStart() )
+    {
+        // Yes, so calculate start time.
+        mCurrentTime = CoreMath::mGetRandomF(0.0f, mTotalIntegrationTime*0.999f);
+    }
+    else
+    {
+        // No, so set first frame.
+        mCurrentTime = 0.0f;
+    }
+
+    // Reset animation finished flag.
+    mAnimationFinished = false;
+
+    // Do an initial animation update.
+    updateAnimation(0.0f);
+
+    // Return Okay.
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::updateAnimation( const F32 elapsedTime )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AnimationController_UpdateAnimation);
+
+    // Finish if animation asset is not valid.
+    if ( mpAnimationAsset->isNull() || (*mpAnimationAsset)->getImage().isNull() )
+        return false;
+
+    // Finish if animation has finished.
+    if ( mAnimationFinished )
+        return false;
+
+    // Fetch validated frames.
+    const Vector<S32>& validatedFrames = (*mpAnimationAsset)->getValidatedAnimationFrames();
+
+    // Finish if there are no validated frames.
+    if ( validatedFrames.size() == 0 )
+        return false;
+
+    // Calculate scaled time.
+    const F32 scaledTime = elapsedTime * mAnimationTimeScale;
+
+    // Update Current Time.
+    mCurrentTime += scaledTime;
+
+    // Check if the animation has finished.
+    if ( !(*mpAnimationAsset)->getAnimationCycle() && mGreaterThanOrEqual(mCurrentTime, mTotalIntegrationTime) )
+    {
+        // Animation has finished.
+        mAnimationFinished = true;
+
+        // Fix Animation at end of frames.
+        mCurrentTime = mTotalIntegrationTime - (mFrameIntegrationTime * 0.5f);
+    }
+
+    // Update Current Mod Time.
+    mCurrentModTime = mFmod( mCurrentTime, mTotalIntegrationTime );
+
+    // Calculate Current Frame.
+    mCurrentFrameIndex = (S32)(mCurrentModTime / mFrameIntegrationTime);
+
+    // Fetch frame.
+    S32 frame = validatedFrames[mCurrentFrameIndex];
+
+    // Fetch image frame count.
+    const S32 imageFrameCount = (*mpAnimationAsset)->getImage()->getFrameCount();
+
+    // Clamp frames.
+    if ( frame < 0 )
+        frame = 0;
+    else if (frame >= imageFrameCount )
+        frame = imageFrameCount-1;
+
+    // Calculate if frame has changed.
+    bool frameChanged = (mCurrentFrameIndex != mLastFrameIndex);
+
+    // Reset Last Frame.
+    mLastFrameIndex = mCurrentFrameIndex;
+
+    // Return Frame-Changed Flag.
+    return frameChanged;
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::setAnimationFrame( const U32 frameIndex )
+{
+    // Do we have a valid animation asset?
+    if ( mpAnimationAsset->isNull() )
+    {
+        // No, so warn.
+        Con::warnf("ImageFrameProviderCore::setAnimationFrame() - Cannot set frame; animation is finished or is invalid!");
+        return;
+    }
+
+    // Validate Frame Index?
+    if ( (S32)frameIndex < 0 || frameIndex > mMaxFrameIndex )
+    {
+        // No, so warn.
+        Con::warnf("ImageFrameProviderCore::setAnimationFrame() - Animation Frame-Index Invalid (frame#%d of %d in %s)", frameIndex, mMaxFrameIndex, mpAnimationAsset->getAssetId() );
+        // Finish here.
+        return;
+    }
+
+    // Calculate current time.
+    mCurrentTime = frameIndex*mFrameIntegrationTime;
+
+    // Do an immediate animation update.
+    updateAnimation(0.0f);
+}
+
+//------------------------------------------------------------------------------
+
+void ImageFrameProviderCore::clearAssets( void )
+{
+    // Clear assets.
+    if ( mpAnimationAsset != NULL )
+        mpAnimationAsset->clear();
+
+    if ( mpImageAsset != NULL )
+        mpImageAsset->clear();
+
+    // Reset remaining state.
+    mImageFrame = 0;
+    mStaticProvider = true;
+    setProcessTicks( false );
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::onAssetRefreshed( AssetPtrBase* pAssetPtrBase )
+{
+    // Don't perform any action if the animation is not already playing.
+    if ( mAnimationFinished )
+        return;
+
+    // Attempt to restart the animation.
+    playAnimation( *mpAnimationAsset );
+}

+ 153 - 0
engine/source/2d/core/ImageFrameProviderCore.h

@@ -0,0 +1,153 @@
+//-----------------------------------------------------------------------------
+// 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 _IMAGE_FRAME_PROVIDER_CORE_H
+#define _IMAGE_FRAME_PROVIDER_CORE_H
+
+#ifndef _IMAGE_ASSET_H_
+#include "2d/assets/ImageAsset.h"
+#endif
+
+#ifndef _ANIMATION_ASSET_H_
+#include "2d/assets/AnimationAsset.h"
+#endif
+
+#ifndef _TICKABLE_H_
+#include "platform/Tickable.h"
+#endif
+
+#ifndef _ASSET_PTR_H_
+#include "assets/assetPtr.h"
+#endif
+
+#ifndef _BATCH_RENDER_H_
+#include "BatchRender.h"
+#endif
+
+#ifndef _FACTORY_CACHE_H_
+#include "memory/factoryCache.h"
+#endif
+
+#ifndef _GUICONTROL_H_
+#include "gui/guiControl.h"
+#endif
+
+///-----------------------------------------------------------------------------
+
+class ImageFrameProviderCore :
+    public virtual Tickable,
+    public IFactoryObjectReset,
+    protected AssetPtrCallback
+{
+protected:
+    bool                                    mSelfTick;
+
+    bool                                    mStaticProvider;
+
+    U32                                     mImageFrame;
+    AssetPtr<ImageAsset>*                   mpImageAsset;
+    AssetPtr<AnimationAsset>*               mpAnimationAsset;
+
+    S32                                     mLastFrameIndex;
+    S32                                     mCurrentFrameIndex;
+    U32                                     mMaxFrameIndex;
+    F32                                     mCurrentTime;
+    F32                                     mPausedTime;
+    F32                                     mCurrentModTime;
+    F32                                     mAnimationTimeScale;
+    F32                                     mTotalIntegrationTime;
+    F32                                     mFrameIntegrationTime;
+    bool                                    mAnimationPaused;
+    bool                                    mAnimationFinished;
+
+public:
+    ImageFrameProviderCore();
+    virtual ~ImageFrameProviderCore();
+
+    void allocateAssets( AssetPtr<ImageAsset>* pImageAssetPtr, AssetPtr<AnimationAsset>* pAnimationAssetPtr );
+    inline void deallocateAssets( void ) { mpImageAsset = NULL; mpAnimationAsset = NULL; }
+
+    virtual void copyTo( ImageFrameProviderCore* pImageFrameProviderCore ) const;
+
+    /// Integration.
+    virtual bool update( const F32 elapsedTime );
+    virtual void processTick();
+    virtual void interpolateTick( F32 delta ) {};
+    virtual void advanceTime( F32 timeDelta ) {};
+    virtual void setProcessTicks( bool tick  ) { Tickable::setProcessTicks( mSelfTick ? tick : false ); }
+    bool updateAnimation( const F32 elapsedTime );
+
+    virtual bool validRender( void ) const;
+
+    virtual void render(
+        const bool flipX,
+        const bool flipY,
+        const Vector2& vertexPos0,
+        const Vector2& vertexPos1,
+        const Vector2& vertexPos2,
+        const Vector2& vertexPos3,
+        BatchRender* pBatchRenderer ) const;
+
+    void renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const;
+
+    /// Static-Image Frame.
+    inline bool setImage( const char* pImageAssetId ) { return setImage( pImageAssetId, mImageFrame ); }
+    virtual bool setImage( const char* pImageAssetId, const U32 frame );
+    inline StringTableEntry getImage( void ) const{ return mpImageAsset->getAssetId(); }
+    virtual bool setImageFrame( const U32 frame );
+    inline U32 getImageFrame( void ) const { return mImageFrame; }
+
+    /// Animated-Image Frame.
+    virtual bool setAnimation( const char* pAnimationAssetId );
+    inline StringTableEntry getAnimation( void ) const { return mpAnimationAsset->getAssetId(); }
+    void setAnimationFrame( const U32 frameIndex );
+    void setAnimationTimeScale( const F32 scale ) { mAnimationTimeScale = scale; }
+    inline F32 getAnimationTimeScale( void ) const { return mAnimationTimeScale; }
+    bool playAnimation( const AssetPtr<AnimationAsset>& animationAsset);
+    inline void pauseAnimation( const bool animationPaused ) { mAnimationPaused = animationPaused; }
+    inline void stopAnimation( void ) { mAnimationFinished = true; mAnimationPaused = false; }
+    inline void resetAnimationTime( void ) { mCurrentTime = 0.0f; }
+    inline bool isAnimationPaused( void ) const { return mAnimationPaused; }
+    inline bool isAnimationFinished( void ) const { return mAnimationFinished; };
+    bool isAnimationValid( void ) const;
+
+    /// Frame provision.
+    inline bool isStaticFrameProvider( void ) const { return mStaticProvider; }
+    inline TextureHandle& getProviderTexture( void ) const { return !validRender() ? BadTextureHandle : isStaticFrameProvider() ? (*mpImageAsset)->getImageTexture() : (*mpAnimationAsset)->getImage()->getImageTexture(); };
+    inline const ImageAsset::FrameArea& getProviderImageFrameArea( void ) const  { return !validRender() ? BadFrameArea : isStaticFrameProvider() ? (*mpImageAsset)->getImageFrameArea(mImageFrame) : (*mpAnimationAsset)->getImage()->getImageFrameArea(getCurrentAnimationFrame()); };
+
+    inline const AnimationAsset* getCurrentAnimation( void ) const { return mpAnimationAsset->notNull() ? *mpAnimationAsset : NULL; };
+    inline const StringTableEntry getCurrentAnimationAssetId( void ) const { return mpAnimationAsset->getAssetId(); };
+    const U32 getCurrentAnimationFrame( void ) const;
+    inline const F32 getCurrentAnimationTime( void ) const { return mCurrentTime; };
+
+    void clearAssets( void );
+
+    virtual void resetState( void );
+
+protected:
+    virtual void onAnimationEnd( void ) {}
+    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
+};
+
+
+#endif // _IMAGE_FRAME_PROVIDER_CORE_H

+ 6 - 5
engine/source/2d/core/ParticleSystem.h

@@ -23,8 +23,8 @@
 #ifndef _PARTICLE_SYSTEM_H_
 #define _PARTICLE_SYSTEM_H_
 
-#ifndef _ANIMATION_CONTROLLER_H_
-#include "2d/assets/AnimationController.h"
+#ifndef _IMAGE_FRAME_PROVIDER_H
+#include "2d/core/imageFrameProvider.h"
 #endif
 
 //-----------------------------------------------------------------------------
@@ -49,9 +49,8 @@ public:
         Vector2                 mVelocity;
         F32                     mOrientationAngle;
         Vector2                 mRenderOOBB[4];
-        U32                     mImageFrame;
         b2Transform             mTransform;
-        AnimationController     mAnimationController;
+        ImageFrameProviderCore  mFrameProvider;
 
         /// Render Properties.
         Vector2                 mRenderSize;
@@ -73,9 +72,11 @@ public:
         Vector2                 mPostTickPosition;
         Vector2                 mRenderTickPosition;
 
+        ParticleNode() { constructInPlace<ImageFrameProviderCore>(&mFrameProvider); resetState(); }
+
         virtual void resetState( void )
         {
-            mAnimationController.resetState();
+            mFrameProvider.resetState();
         }
     };
 

+ 2 - 6
engine/source/2d/core/RenderProxy.cc

@@ -32,10 +32,6 @@
 #include "graphics/dgl.h"
 #endif
 
-#ifndef _STRINGBUFFER_H_
-#include "string/stringBuffer.h"
-#endif
-
 // Script bindings.
 #include "RenderProxy_ScriptBinding.h"
 
@@ -81,6 +77,6 @@ void RenderProxy::copyTo(SimObject* object)
     // Sanity!
     AssertFatal(pRenderProxy != NULL, "RenderProxy::copyTo() - Object is not the correct type.");
 
-    // Call render proxy base.
-    SpriteProxyBase::copyTo( pRenderProxy );
+    // Call image frame provider.
+    ImageFrameProvider::copyTo( pRenderProxy );
 }

+ 11 - 19
engine/source/2d/core/RenderProxy.h

@@ -23,21 +23,13 @@
 #ifndef _RENDER_PROXY_H_
 #define _RENDER_PROXY_H_
 
-#ifndef _BATCH_RENDER_H_
-#include "BatchRender.h"
-#endif
-
-#ifndef _SPRITE_PROXY_BASE_H_
-#include "2d/core/SpriteProxyBase.h"
-#endif
-
-#ifndef _IMAGE_ASSET_H_
-#include "2d/assets/ImageAsset.h"
+#ifndef _IMAGE_FRAME_PROVIDER_H
+#include "2d/core/imageFrameProvider.h"
 #endif
 
 //------------------------------------------------------------------------------
 
-class RenderProxy : public SimObject, public SpriteProxyBase
+class RenderProxy : public SimObject, public ImageFrameProvider
 {
     typedef SimObject               Parent;
 
@@ -53,14 +45,14 @@ public:
     DECLARE_CONOBJECT( RenderProxy );
 
 protected:
-    static bool setImage(void* obj, const char* data) { DYNAMIC_VOID_CAST_TO(RenderProxy, SpriteProxyBase, obj)->setImage( data ); return false; };
-    static const char* getImage(void* obj, const char* data) { return DYNAMIC_VOID_CAST_TO(RenderProxy, SpriteProxyBase, obj)->getImage(); }
-    static bool writeImage( void* obj, StringTableEntry pFieldName ) { RenderProxy* pCastObject = static_cast<RenderProxy*>(obj); if ( !pCastObject->isStaticMode() ) return false; return pCastObject->mImageAsset.notNull(); }
-    static bool setImageFrame(void* obj, const char* data) { DYNAMIC_VOID_CAST_TO(RenderProxy, SpriteProxyBase, obj)->setImageFrame(dAtoi(data)); return false; };
-    static bool writeImageFrame( void* obj, StringTableEntry pFieldName ) { RenderProxy* pCastObject = static_cast<RenderProxy*>(obj); if ( !pCastObject->isStaticMode() ) return false; return pCastObject->mImageAsset.notNull(); }
-    static bool setAnimation(void* obj, const char* data) { DYNAMIC_VOID_CAST_TO(RenderProxy, SpriteProxyBase, obj)->setAnimation(data, false); return false; };
-    static const char* getAnimation(void* obj, const char* data) { return DYNAMIC_VOID_CAST_TO(RenderProxy, SpriteProxyBase, obj)->getAnimation(); }
-    static bool writeAnimation( void* obj, StringTableEntry pFieldName ) { RenderProxy* pCastObject = static_cast<RenderProxy*>(obj); if ( pCastObject->isStaticMode() ) return false; return pCastObject->mAnimationAsset.notNull(); }
+    static bool setImage(void* obj, const char* data) { DYNAMIC_VOID_CAST_TO(RenderProxy, ImageFrameProvider, obj)->setImage( data ); return false; };
+    static const char* getImage(void* obj, const char* data) { return DYNAMIC_VOID_CAST_TO(RenderProxy, ImageFrameProvider, obj)->getImage(); }
+    static bool writeImage( void* obj, StringTableEntry pFieldName ) { RenderProxy* pCastObject = static_cast<RenderProxy*>(obj); if ( !pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mImageAsset.notNull(); }
+    static bool setImageFrame(void* obj, const char* data) { DYNAMIC_VOID_CAST_TO(RenderProxy, ImageFrameProvider, obj)->setImageFrame(dAtoi(data)); return false; };
+    static bool writeImageFrame( void* obj, StringTableEntry pFieldName ) { RenderProxy* pCastObject = static_cast<RenderProxy*>(obj); if ( !pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mImageAsset.notNull(); }
+    static bool setAnimation(void* obj, const char* data) { DYNAMIC_VOID_CAST_TO(RenderProxy, ImageFrameProvider, obj)->setAnimation(data); return false; };
+    static const char* getAnimation(void* obj, const char* data) { return DYNAMIC_VOID_CAST_TO(RenderProxy, ImageFrameProvider, obj)->getAnimation(); }
+    static bool writeAnimation( void* obj, StringTableEntry pFieldName ) { RenderProxy* pCastObject = static_cast<RenderProxy*>(obj); if ( pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mAnimationAsset.notNull(); }
 };
 
 #endif // _RENDER_PROXY_H_

+ 28 - 32
engine/source/2d/core/RenderProxy_ScriptBinding.h

@@ -20,10 +20,10 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(RenderProxy, isStaticMode, bool, 2, 2,    "() - Gets whether the render-proxy is in static or dynamic (animated)mode.\n"
+ConsoleMethod(RenderProxy, isStaticFrameProvider, bool, 2, 2,    "() - Gets whether the render-proxy is in static or dynamic (animated)mode.\n"
                                                         "@return Returns whether the render-proxy is in static or dynamic (animated)mode.")
 {
-    return object->isStaticMode();
+    return object->isStaticFrameProvider();
 }
 
 //------------------------------------------------------------------------------
@@ -40,7 +40,7 @@ ConsoleMethod(RenderProxy, setImage, bool, 3, 4,    "(string imageAssetId, [int
     const U32 frame = argc >= 4 ? dAtoi(argv[3]) : 0;
 
     // Set Image.
-    return static_cast<SpriteProxyBase*>(object)->setImage(pImageAssetId, frame );
+    return static_cast<ImageFrameProvider*>(object)->setImage(pImageAssetId, frame );
 }   
 
 //------------------------------------------------------------------------------
@@ -49,7 +49,7 @@ ConsoleMethod(RenderProxy, getImage, const char*, 2, 2, "() - Gets current image
                                                         "@return (string imageAssetId) The image being displayed")
 {
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf( "RenderProxy::getImage() - Method invalid, not in static mode." );
@@ -57,7 +57,7 @@ ConsoleMethod(RenderProxy, getImage, const char*, 2, 2, "() - Gets current image
     }
 
     // Get Image.
-    return static_cast<SpriteProxyBase*>(object)->getImage();
+    return static_cast<ImageFrameProvider*>(object)->getImage();
 }   
 
 //------------------------------------------------------------------------------
@@ -67,7 +67,7 @@ ConsoleMethod(RenderProxy, setImageFrame, bool, 3, 3,   "(int frame) - Sets imag
                                                         "@return Returns true on success.")
 {
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf( "RenderProxy::setImageFrame() - Method invalid, not in static mode." );
@@ -75,7 +75,7 @@ ConsoleMethod(RenderProxy, setImageFrame, bool, 3, 3,   "(int frame) - Sets imag
     }
 
     // Set Image Frame.
-    return static_cast<SpriteProxyBase*>(object)->setImageFrame( dAtoi(argv[2]) );
+    return static_cast<ImageFrameProvider*>(object)->setImageFrame( dAtoi(argv[2]) );
 }
 
 //------------------------------------------------------------------------------
@@ -84,7 +84,7 @@ ConsoleMethod(RenderProxy, getImageFrame, S32, 2, 2,    "() - Gets current image
                                                         "@return (int frame) The frame currently being displayed")
 {
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf( "RenderProxy::getImageFrame() - Method invalid, not in static mode." );
@@ -97,16 +97,12 @@ ConsoleMethod(RenderProxy, getImageFrame, S32, 2, 2,    "() - Gets current image
 
 //------------------------------------------------------------------------------
 
-ConsoleMethod(RenderProxy, playAnimation, bool, 3, 4,   "(string animationAssetId, [bool autoRestore]) - Plays an animation.\n"
+ConsoleMethod(RenderProxy, playAnimation, bool, 3, 3,   "(string animationAssetId) - Plays an animation.\n"
                                                         "@param animationAssetId The animation asset Id to play\n"
-                                                        "@param autoRestore If true, the previous animation will be played when this new animation finishes.\n"
                                                         "@return Returns true on success.")
 {    
-    // Fetch Auto-Restore Flag.
-    const bool autoRestore = (argc >= 4) ? dAtob(argv[3]) : false;
-
     // Play Animation.
-    return static_cast<SpriteProxyBase*>(object)->setAnimation( argv[2], autoRestore );
+    return static_cast<ImageFrameProvider*>(object)->setAnimation( argv[2] );
 }   
 
 //-----------------------------------------------------------------------------
@@ -115,14 +111,14 @@ ConsoleMethod(RenderProxy, pauseAnimation, void, 3, 3,  "(bool enable) - Pause t
                                                         "@param enable If true, pause the animation. If false, continue animating\n")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "RenderProxy::pauseAnimation() - Method invalid, not in dynamic (animated) mode." );
         return;
     }
 
-    static_cast<SpriteProxyBase*>(object)->pauseAnimation(dAtob(argv[2]));
+    static_cast<ImageFrameProvider*>(object)->pauseAnimation(dAtob(argv[2]));
 }
 
 //-----------------------------------------------------------------------------
@@ -131,14 +127,14 @@ ConsoleMethod(RenderProxy, stopAnimation, void, 2, 2,   "() - Stop the current a
                                                         "@return No return value.")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "RenderProxy::stopAnimation() - Method invalid, not in dynamic (animated) mode." );
         return;
     }
 
-    object->getAnimationController()->stopAnimation();
+    object->stopAnimation();
 }
 
 //-----------------------------------------------------------------------------
@@ -148,7 +144,7 @@ ConsoleMethod(RenderProxy, setAnimationFrame, void, 3, 3, "(int frame) - Sets th
                                                                 "@return No return value.")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "RenderProxy::setAnimationFrame() - Method invalid, not in dynamic (animated) mode." );
@@ -156,7 +152,7 @@ ConsoleMethod(RenderProxy, setAnimationFrame, void, 3, 3, "(int frame) - Sets th
     }
 
     // Set Animation Frame
-    object->getAnimationController()->setAnimationFrame( dAtoi(argv[2]) );
+    object->setAnimationFrame( dAtoi(argv[2]) );
 }
 
 //-----------------------------------------------------------------------------
@@ -165,7 +161,7 @@ ConsoleMethod(RenderProxy, getAnimationFrame, S32, 2, 2,    "() - Gets current a
                                                             "@return (int frame) The current animation frame")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "RenderProxy::getAnimationFrame() - Method invalid, not in dynamic (animated) mode." );
@@ -173,7 +169,7 @@ ConsoleMethod(RenderProxy, getAnimationFrame, S32, 2, 2,    "() - Gets current a
     }
 
     // Get Animation Frame.
-    return object->getAnimationController()->getCurrentFrame();
+    return object->getCurrentAnimationFrame();
 }
 
 //-----------------------------------------------------------------------------
@@ -182,7 +178,7 @@ ConsoleMethod(RenderProxy, getAnimation, const char*, 2, 2, "() - Gets current a
                                                             "@return (string AnimationAssetId) The current animation asset Id.")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "RenderProxy::getAnimation() - Method invalid, not in dynamic (animated) mode." );
@@ -191,7 +187,7 @@ ConsoleMethod(RenderProxy, getAnimation, const char*, 2, 2, "() - Gets current a
 
 
     // Get Current Animation.
-    return object->getAnimationController()->getCurrentAnimationAssetId();
+    return object->getCurrentAnimationAssetId();
 }
 
 //-----------------------------------------------------------------------------
@@ -200,7 +196,7 @@ ConsoleMethod(RenderProxy, getAnimationTime, F32, 2, 2, "() - Gets current anima
                                                         "@return (float time) The current animation time")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "RenderProxy::getAnimationTime() - Method invalid, not in dynamic (animated) mode." );
@@ -209,7 +205,7 @@ ConsoleMethod(RenderProxy, getAnimationTime, F32, 2, 2, "() - Gets current anima
 
 
     // Get Animation Time.
-    return object->getAnimationController()->getCurrentTime();
+    return object->getCurrentAnimationTime();
 }
 
 //-----------------------------------------------------------------------------
@@ -218,7 +214,7 @@ ConsoleMethod(RenderProxy, getIsAnimationFinished, bool, 2, 2,  "() - Checks ani
                                                                 "@return (bool finished) Whether or not the animation is finished")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "RenderProxy::getIsAnimationFinished() - Method invalid, not in dynamic (animated) mode." );
@@ -226,7 +222,7 @@ ConsoleMethod(RenderProxy, getIsAnimationFinished, bool, 2, 2,  "() - Checks ani
     }
 
     // Return Animation Finished Status.
-    return object->getAnimationController()->isAnimationFinished();
+    return object->isAnimationFinished();
 }
 
 //-----------------------------------------------------------------------------
@@ -235,14 +231,14 @@ ConsoleMethod(RenderProxy, setAnimationTimeScale, void, 3, 3,   "(float timeScal
                                                                 "@param timeScale Value which will scale the frame animation speed. 1 by default.\n")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "RenderProxy::setAnimationTimeScale() - Method invalid, not in dynamic (animated) mode." );
         return;
     }
 
-    object->getAnimationController()->setAnimationTimeScale(dAtof(argv[2]));
+    object->setAnimationTimeScale(dAtof(argv[2]));
 }
 
 //-----------------------------------------------------------------------------
@@ -251,13 +247,13 @@ ConsoleMethod(RenderProxy, getAnimationTimeScale, F32, 2, 2,    "() - Get the an
                                                                 "@return (float) Returns the animation time scale for this render-proxy.\n")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "RenderProxy::getSpeedFactor() - Method invalid, not in dynamic (animated) mode." );
         return 1.0f;
     }
 
-    return object->getAnimationController()->getAnimationTimeScale();
+    return object->getAnimationTimeScale();
 }
 

+ 7 - 11
engine/source/2d/core/SpriteBase.cc

@@ -21,19 +21,15 @@
 //-----------------------------------------------------------------------------
 
 #ifndef _SPRITE_BASE_H_
-#include "SpriteBase.h"
+#include "2d/core/SpriteBase.h"
 #endif
 
 #ifndef _DGL_H_
 #include "graphics/dgl.h"
 #endif
 
-#ifndef _STRINGBUFFER_H_
-#include "string/stringBuffer.h"
-#endif
-
 // Script bindings.
-#include "SpriteBase_ScriptBinding.h"
+#include "2d/core/SpriteBase_ScriptBinding.h"
 
 //------------------------------------------------------------------------------
 
@@ -70,15 +66,15 @@ void SpriteBase::integrateObject( const F32 totalTime, const F32 elapsedTime, De
     // Call Parent.
     Parent::integrateObject( totalTime, elapsedTime, pDebugStats );
 
-    // Update render proxy base.
-    SpriteProxyBase::update( elapsedTime );
+    // Update image frame provider.
+    ImageFrameProvider::update( elapsedTime );
 }
 
 //------------------------------------------------------------------------------
 
 bool SpriteBase::validRender( void ) const
 {
-    return SpriteProxyBase::validRender();
+    return ImageFrameProvider::validRender();
 }
 
 //------------------------------------------------------------------------------
@@ -94,8 +90,8 @@ void SpriteBase::copyTo(SimObject* object)
     // Sanity!
     AssertFatal(pSpriteBase != NULL, "SpriteBase::copyTo() - Object is not the correct type.");
 
-    // Call render proxy base.
-    SpriteProxyBase::copyTo( pSpriteBase );
+    // Call image frame provider.
+    ImageFrameProvider::copyTo( pSpriteBase );
 }
 
 //------------------------------------------------------------------------------

+ 11 - 19
engine/source/2d/core/SpriteBase.h

@@ -27,21 +27,13 @@
 #include "2d/sceneobject/SceneObject.h"
 #endif
 
-#ifndef _SPRITE_PROXY_BASE_H_
-#include "2d/core/SpriteProxyBase.h"
-#endif
-
-#ifndef _IMAGE_ASSET_H_
-#include "2d/assets/ImageAsset.h"
-#endif
-
-#ifndef _ASSET_PTR_H_
-#include "assets/assetPtr.h"
+#ifndef _IMAGE_FRAME_PROVIDER_H
+#include "2d/core/imageFrameProvider.h"
 #endif
 
 //------------------------------------------------------------------------------
 
-class SpriteBase : public SceneObject, public SpriteProxyBase
+class SpriteBase : public SceneObject, public ImageFrameProvider
 {
     typedef SceneObject Parent;
 
@@ -65,14 +57,14 @@ protected:
     virtual void onAnimationEnd( void );
 
 protected:
-    static bool setImage(void* obj, const char* data)                       { DYNAMIC_VOID_CAST_TO(SpriteBase, SpriteProxyBase, obj)->setImage(data); return false; };
-    static const char* getImage(void* obj, const char* data)                { return DYNAMIC_VOID_CAST_TO(SpriteBase, SpriteProxyBase, obj)->getImage(); }
-    static bool writeImage( void* obj, StringTableEntry pFieldName )        { SpriteBase* pCastObject = static_cast<SpriteBase*>(obj); if ( !pCastObject->isStaticMode() ) return false; return pCastObject->mImageAsset.notNull(); }
-    static bool setImageFrame(void* obj, const char* data)                  { DYNAMIC_VOID_CAST_TO(SpriteBase, SpriteProxyBase, obj)->setImageFrame(dAtoi(data)); return false; };
-    static bool writeImageFrame( void* obj, StringTableEntry pFieldName )   { SpriteBase* pCastObject = static_cast<SpriteBase*>(obj); if ( !pCastObject->isStaticMode() ) return false; return pCastObject->mImageAsset.notNull(); }
-    static bool setAnimation(void* obj, const char* data)                   { DYNAMIC_VOID_CAST_TO(SpriteBase, SpriteProxyBase, obj)->setAnimation(data, false); return false; };
-    static const char* getAnimation(void* obj, const char* data)            { return DYNAMIC_VOID_CAST_TO(SpriteBase, SpriteProxyBase, obj)->getAnimation(); }
-    static bool writeAnimation( void* obj, StringTableEntry pFieldName )    { SpriteBase* pCastObject = static_cast<SpriteBase*>(obj); if ( pCastObject->isStaticMode() ) return false; return pCastObject->mAnimationAsset.notNull(); }
+    static bool setImage(void* obj, const char* data)                       { DYNAMIC_VOID_CAST_TO(SpriteBase, ImageFrameProvider, obj)->setImage(data); return false; };
+    static const char* getImage(void* obj, const char* data)                { return DYNAMIC_VOID_CAST_TO(SpriteBase, ImageFrameProvider, obj)->getImage(); }
+    static bool writeImage( void* obj, StringTableEntry pFieldName )        { SpriteBase* pCastObject = static_cast<SpriteBase*>(obj); if ( !pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mImageAsset.notNull(); }
+    static bool setImageFrame(void* obj, const char* data)                  { DYNAMIC_VOID_CAST_TO(SpriteBase, ImageFrameProvider, obj)->setImageFrame(dAtoi(data)); return false; };
+    static bool writeImageFrame( void* obj, StringTableEntry pFieldName )   { SpriteBase* pCastObject = static_cast<SpriteBase*>(obj); if ( !pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mImageAsset.notNull(); }
+    static bool setAnimation(void* obj, const char* data)                   { DYNAMIC_VOID_CAST_TO(SpriteBase, ImageFrameProvider, obj)->setAnimation(data); return false; };
+    static const char* getAnimation(void* obj, const char* data)            { return DYNAMIC_VOID_CAST_TO(SpriteBase, ImageFrameProvider, obj)->getAnimation(); }
+    static bool writeAnimation( void* obj, StringTableEntry pFieldName )    { SpriteBase* pCastObject = static_cast<SpriteBase*>(obj); if ( pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mAnimationAsset.notNull(); }
 };
 
 #endif // _SPRITE_BASE_H_

+ 31 - 35
engine/source/2d/core/SpriteBase_ScriptBinding.h

@@ -20,10 +20,10 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(SpriteBase, isStaticMode, bool, 2, 2,     "() - Gets whether the sprite is in static or dynamic (animated)mode.\n"
+ConsoleMethod(SpriteBase, isStaticFrameProvider, bool, 2, 2,     "() - Gets whether the sprite is in static or dynamic (animated)mode.\n"
                                                     "@return Returns whether the sprite is in static or dynamic (animated)mode.")
 {
-    return object->isStaticMode();
+    return object->isStaticFrameProvider();
 }
 
 //------------------------------------------------------------------------------
@@ -37,7 +37,7 @@ ConsoleMethod(SpriteBase, setImage, bool, 3, 4, "(string imageAssetId, [int fram
     U32 frame = argc >= 4 ? dAtoi(argv[3]) : 0;
 
     // Set image.
-    return static_cast<SpriteProxyBase*>(object)->setImage( argv[2], frame );
+    return static_cast<ImageFrameProvider*>(object)->setImage( argv[2], frame );
 }
 
 //------------------------------------------------------------------------------
@@ -46,7 +46,7 @@ ConsoleMethod(SpriteBase, getImage, const char*, 2, 2,  "() - Gets current image
                                                         "@return (string imageAssetId) The image being displayed")
 {
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf( "SpriteBase::getImage() - Method invalid, not in static mode." );
@@ -54,7 +54,7 @@ ConsoleMethod(SpriteBase, getImage, const char*, 2, 2,  "() - Gets current image
     }
 
     // Get image.
-    return static_cast<SpriteProxyBase*>(object)->getImage();
+    return static_cast<ImageFrameProvider*>(object)->getImage();
 }   
 
 //------------------------------------------------------------------------------
@@ -64,7 +64,7 @@ ConsoleMethod(SpriteBase, setImageFrame, bool, 3, 3,    "(frame) - Sets the imag
                                                         "@return Returns true on success.")
 {
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf( "SpriteBase::setImageFrame() - Method invalid, not in static mode." );
@@ -72,7 +72,7 @@ ConsoleMethod(SpriteBase, setImageFrame, bool, 3, 3,    "(frame) - Sets the imag
     }
 
     // Set image Frame.
-    return static_cast<SpriteProxyBase*>(object)->setImageFrame( dAtoi(argv[2]) );
+    return static_cast<ImageFrameProvider*>(object)->setImageFrame( dAtoi(argv[2]) );
 }
 
 //------------------------------------------------------------------------------
@@ -81,7 +81,7 @@ ConsoleMethod(SpriteBase, getImageFrame, S32, 2, 2, "() - Gets the current image
                                                     "@return The current image frame.")
 {
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf( "SpriteBase::getImageFrame() - Method invalid, not in static mode." );
@@ -89,21 +89,17 @@ ConsoleMethod(SpriteBase, getImageFrame, S32, 2, 2, "() - Gets the current image
     }
 
     // Get image Frame.
-    return static_cast<SpriteProxyBase*>(object)->getImageFrame();
+    return static_cast<ImageFrameProvider*>(object)->getImageFrame();
 }
 
 //------------------------------------------------------------------------------
 
-ConsoleMethod(SpriteBase, playAnimation, bool, 3, 4,    "(string animationAssetId, [bool autoRestore]) - Plays an animation.\n"
-                                                    "@param animationAssetId The animation asset Id to play.\n"
-                                                    "@param autoRestore If true, the previous animation will be played when this new animation finishes.\n"
-                                                    "@return Returns true on success.")
+ConsoleMethod(SpriteBase, playAnimation, bool, 3, 3,    "(string animationAssetId) - Plays an animation.\n"
+                                                        "@param animationAssetId The animation asset Id to play.\n"
+                                                        "@return Returns true on success.")
 {    
-    // Fetch Auto-Restore Flag.
-    const bool autoRestore = (argc >= 4) ? dAtob(argv[3]) : false;
-
     // Play Animation.
-    return static_cast<SpriteProxyBase*>(object)->setAnimation( argv[2], autoRestore );
+    return static_cast<ImageFrameProvider*>(object)->setAnimation( argv[2] );
 }   
 
 //-----------------------------------------------------------------------------
@@ -112,14 +108,14 @@ ConsoleMethod(SpriteBase, pauseAnimation, void, 3, 3, "(bool enable) - Pause the
                                                              "@param enable If true, pause the animation. If false, continue animating\n")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "SpriteBase::pauseAnimation() - Method invalid, not in dynamic (animated) mode." );
         return;
     }
 
-    return static_cast<SpriteProxyBase*>(object)->pauseAnimation(dAtob(argv[2]));
+    return static_cast<ImageFrameProvider*>(object)->pauseAnimation(dAtob(argv[2]));
 }
 
 
@@ -129,14 +125,14 @@ ConsoleMethod(SpriteBase, stopAnimation, void, 2, 2,   "() - Stop the current an
                                                         "@return No return value.")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "SpriteBase::stopAnimation() - Method invalid, not in dynamic (animated) mode." );
         return;
     }
 
-    object->getAnimationController()->stopAnimation();
+    object->stopAnimation();
 }
 
 //-----------------------------------------------------------------------------
@@ -146,7 +142,7 @@ ConsoleMethod(SpriteBase, setAnimationFrame, void, 3, 3, "(int frame) - Sets the
                                                                 "@return No return value.")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "SpriteBase::setAnimationFrame() - Method invalid, not in dynamic (animated) mode." );
@@ -154,7 +150,7 @@ ConsoleMethod(SpriteBase, setAnimationFrame, void, 3, 3, "(int frame) - Sets the
     }
 
     // Set Animation Frame
-    object->getAnimationController()->setAnimationFrame( dAtoi(argv[2]) );
+    object->setAnimationFrame( dAtoi(argv[2]) );
 }
 
 //-----------------------------------------------------------------------------
@@ -163,7 +159,7 @@ ConsoleMethod(SpriteBase, getAnimationFrame, S32, 2, 2, "() - Gets current anima
                                                                "@return (int frame) The current animation frame")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "SpriteBase::getAnimationFrame() - Method invalid, not in dynamic (animated) mode." );
@@ -171,7 +167,7 @@ ConsoleMethod(SpriteBase, getAnimationFrame, S32, 2, 2, "() - Gets current anima
     }
 
     // Get Animation Frame.
-    return object->getAnimationController()->getCurrentFrame();
+    return object->getCurrentAnimationFrame();
 }
 
 //-----------------------------------------------------------------------------
@@ -180,7 +176,7 @@ ConsoleMethod(SpriteBase, getAnimation, const char*, 2, 2,  "() - Gets current a
                                                         "@return (string AnimationAssetId) The current animation asset Id.")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "SpriteBase::getAnimation() - Method invalid, not in dynamic (animated) mode." );
@@ -189,7 +185,7 @@ ConsoleMethod(SpriteBase, getAnimation, const char*, 2, 2,  "() - Gets current a
 
 
     // Get Current Animation.
-    return object->getAnimationController()->getCurrentAnimationAssetId();
+    return object->getCurrentAnimationAssetId();
 }
 
 //-----------------------------------------------------------------------------
@@ -198,7 +194,7 @@ ConsoleMethod(SpriteBase, getAnimationTime, F32, 2, 2,  "() - Gets current anima
                                                     "@return (float time) The current animation time")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "SpriteBase::getAnimationTime() - Method invalid, not in dynamic (animated) mode." );
@@ -207,7 +203,7 @@ ConsoleMethod(SpriteBase, getAnimationTime, F32, 2, 2,  "() - Gets current anima
 
 
     // Get Animation Time.
-    return object->getAnimationController()->getCurrentTime();
+    return object->getCurrentAnimationTime();
 }
 
 //-----------------------------------------------------------------------------
@@ -216,7 +212,7 @@ ConsoleMethod(SpriteBase, getIsAnimationFinished, bool, 2, 2,   "() - Checks ani
                                                             "@return (bool finished) Whether or not the animation is finished")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "SpriteBase::getIsAnimationFinished() - Method invalid, not in dynamic (animated) mode." );
@@ -224,7 +220,7 @@ ConsoleMethod(SpriteBase, getIsAnimationFinished, bool, 2, 2,   "() - Checks ani
     }
 
     // Return Animation Finished Status.
-    return object->getAnimationController()->isAnimationFinished();
+    return object->isAnimationFinished();
 }
 
 //-----------------------------------------------------------------------------
@@ -233,14 +229,14 @@ ConsoleMethod(SpriteBase, setAnimationTimeScale, void, 3, 3,   "(float timeScale
                                                             "@param timeScale Value which will scale the frame animation speed. 1 by default.\n")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "SpriteBase::setAnimationTimeScale() - Method invalid, not in dynamic (animated) mode." );
         return;
     }
 
-    object->getAnimationController()->setAnimationTimeScale(dAtof(argv[2]));
+    object->setAnimationTimeScale(dAtof(argv[2]));
 }
 
 //-----------------------------------------------------------------------------
@@ -249,12 +245,12 @@ ConsoleMethod(SpriteBase, getAnimationTimeScale, F32, 2, 2,     "() - Get the an
                                                             "@return (float) Returns the animation time scale for this sprite.\n")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "SpriteBase::getSpeedFactor() - Method invalid, not in dynamic (animated) mode." );
         return 1.0f;
     }
 
-    return object->getAnimationController()->getAnimationTimeScale();
+    return object->getAnimationTimeScale();
 }

+ 47 - 6
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();
@@ -490,7 +507,7 @@ U32 SpriteBatch::getSpriteImageFrame( void ) const
 
 //------------------------------------------------------------------------------
 
-void SpriteBatch::setSpriteAnimation( const char* pAssetId, const bool autoRestore )
+void SpriteBatch::setSpriteAnimation( const char* pAssetId )
 {
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_SetSpriteAnimation);
@@ -503,7 +520,7 @@ void SpriteBatch::setSpriteAnimation( const char* pAssetId, const bool autoResto
         return;
 
     // Set animation.
-    mSelectedSprite->setAnimation( pAssetId, autoRestore );
+    mSelectedSprite->setAnimation( pAssetId );
 }
 
 //------------------------------------------------------------------------------
@@ -527,7 +544,7 @@ void SpriteBatch::clearSpriteAsset( void )
         return;
 
     // Clear the asset.
-    mSelectedSprite->clearAsset();
+    mSelectedSprite->clearAssets();
 }
 
 //------------------------------------------------------------------------------
@@ -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.

+ 7 - 2
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(); }
@@ -123,7 +125,7 @@ public:
     StringTableEntry getSpriteImage( void ) const;
     void setSpriteImageFrame( const U32 imageFrame );
     U32 getSpriteImageFrame( void ) const;
-    void setSpriteAnimation( const char* pAssetId, const bool autoRestore = false );
+    void setSpriteAnimation( const char* pAssetId );
     StringTableEntry getSpriteAnimation( void ) const;
     void clearSpriteAsset( void );
 
@@ -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;
 

+ 7 - 8
engine/source/2d/core/SpriteBatchItem.cc

@@ -28,10 +28,6 @@
 #include "2d/core/SpriteBatch.h"
 #endif
 
-#ifndef _SCENE_RENDER_REQUEST_H_
-#include "2d/scene/SceneRenderRequest.h"
-#endif
-
 #ifndef _SCENE_OBJECT_H_
 #include "2d/sceneobject/SceneObject.h"
 #endif
@@ -159,6 +155,8 @@ void SpriteBatchItem::resetState( void )
 
     mSpriteBatchQueryKey = 0;
 
+    mUserData = NULL;
+
     // Require self ticking.
     mSelfTick = true;
 }
@@ -310,10 +308,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.
@@ -340,8 +339,8 @@ void SpriteBatchItem::onTamlCustomWrite( TamlCustomNode* pSpriteNode )
     if ( getName() != StringTable->EmptyString )
         pSpriteNode->addField( spriteNameName, getName() );
 
-    // Write asset.
-    if ( isStaticMode() )
+    // Static frame provider?
+    if ( isStaticFrameProvider() )
     {
         // Fetch image asset Id.
         StringTableEntry assetId = getImage();

+ 10 - 12
engine/source/2d/core/SpriteBatchItem.h

@@ -23,16 +23,8 @@
 #ifndef _SPRITE_BATCH_ITEM_H_
 #define _SPRITE_BATCH_ITEM_H_
 
-#ifndef _SPRITE_PROXY_BASE_H_
-#include "2d/core/SpriteProxyBase.h"
-#endif
-
-#ifndef _SIM_OBJECT_PTR_H_
-#include "sim/simObjectPtr.h"
-#endif
-
-#ifndef _FACTORY_CACHE_H_
-#include "memory/factoryCache.h"
+#ifndef _IMAGE_FRAME_PROVIDER_H
+#include "2d/core/imageFrameProvider.h"
 #endif
 
 //------------------------------------------------------------------------------  
@@ -42,11 +34,11 @@ class SceneRenderRequest;
 
 //------------------------------------------------------------------------------  
 
-class SpriteBatchItem : public SpriteProxyBase
+class SpriteBatchItem : public ImageFrameProvider
 {
     friend class SpriteBatch;
 
-    typedef SpriteProxyBase Parent;
+    typedef ImageFrameProvider Parent;
 
 public:
     // Represents a logical position.
@@ -225,6 +217,8 @@ protected:
 
     U32                 mSpriteBatchQueryKey;
 
+    void*               mUserData;
+
 public:
     SpriteBatchItem();
     virtual ~SpriteBatchItem();
@@ -284,6 +278,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; }
 

+ 0 - 413
engine/source/2d/core/SpriteProxyBase.cc

@@ -1,413 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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 _SPRITE_PROXY_BASE_H_
-#include "2d/core/SpriteProxyBase.h"
-#endif
-
-#ifndef _DGL_H_
-#include "graphics/dgl.h"
-#endif
-
-#ifndef _RENDER_PROXY_H_
-#include "2d/core/RenderProxy.h"
-#endif
-
-#ifndef _STRINGBUFFER_H_
-#include "string/stringBuffer.h"
-#endif
-
-//------------------------------------------------------------------------------
-
-SpriteProxyBase::SpriteProxyBase() :
-    mpAnimationController(NULL)
-{
-    resetState();
-}
-
-//------------------------------------------------------------------------------
-
-SpriteProxyBase::~SpriteProxyBase()
-{
-    resetState();
-}
-
-//------------------------------------------------------------------------------
-
-void SpriteProxyBase::resetState( void )
-{
-    clearAsset();
-    mSelfTick = false;
-    mAnimationPaused = false;
-}
-
-//------------------------------------------------------------------------------
-
-bool SpriteProxyBase::update( const F32 elapsedTime )
-{
-    // Are we in static mode?
-    if ( isStaticMode() )
-    {
-        // Yes, so turn-off tick processing.
-        setProcessTicks( false );
-
-        return false;
-    }
-
-    // Finish if no animation controller.
-    if ( mpAnimationController == NULL )
-        return false;
-
-    // Finish if the animation has finished.
-    if ( mpAnimationController->isAnimationFinished() )
-        return false;
-
-    // Finish if animation is paused.
-    if ( mAnimationPaused )
-        return true;
-
-    // Update the animation.
-    mpAnimationController->updateAnimation( Tickable::smTickSec );
-
-    // Finish if the animation has NOT finished.
-    if ( !mpAnimationController->isAnimationFinished() )
-        return false;
-
-    // Turn-off tick processing.
-    setProcessTicks( false );
-
-    // Perform callback.
-    onAnimationEnd();
-
-    // Flag animation as just finished.
-    return true;
-}
-
-//------------------------------------------------------------------------------
-
-void SpriteProxyBase::processTick( void )
-{
-    // Update using tick period.
-    update( Tickable::smTickSec );
-}
-
-//------------------------------------------------------------------------------
-
-bool SpriteProxyBase::validRender( void ) const
-{
-    // Are we in static mode?
-    if ( isStaticMode() )
-    {
-        // Yes, so we must have an image asset and the frame must be in bounds.
-        return mImageAsset.notNull() && ( getImageFrame() < mImageAsset->getFrameCount() );
-    }
-
-    // No, so we must have an animation controller and the animation must be valid.
-    return mpAnimationController != NULL && mpAnimationController->isAnimationValid();
-}
-
-//------------------------------------------------------------------------------
-
-void SpriteProxyBase::render(
-    const bool flipX,
-    const bool flipY,
-    const Vector2& vertexPos0,
-    const Vector2& vertexPos1,
-    const Vector2& vertexPos2,
-    const Vector2& vertexPos3,
-    BatchRender* pBatchRenderer ) const
-{
-    // Finish if we can't render.
-    if ( !validRender() )
-        return;
-
-    // Static mode?
-    if ( isStaticMode() )
-    {
-        // Fetch current frame area.
-        ImageAsset::FrameArea::TexelArea texelArea = mImageAsset->getImageFrameArea( mImageFrame ).mTexelArea;
-
-        // Flip texture coordinates appropriately.
-        texelArea.setFlip( flipX, flipY );
-   
-        // Fetch lower/upper texture coordinates.
-        const Vector2& texLower = texelArea.mTexelLower;
-        const Vector2& texUpper = texelArea.mTexelUpper;
-    
-        // Submit batched quad.
-        pBatchRenderer->SubmitQuad(
-            vertexPos0,
-            vertexPos1,
-            vertexPos2,
-            vertexPos3,
-            Vector2( texLower.x, texUpper.y ),
-            Vector2( texUpper.x, texUpper.y ),
-            Vector2( texUpper.x, texLower.y ),
-            Vector2( texLower.x, texLower.y ),
-            mImageAsset->getImageTexture() );
-
-        return;
-    }
-    
-    // Fetch current frame area.
-    ImageAsset::FrameArea::TexelArea texelArea = mpAnimationController->getCurrentImageFrameArea().mTexelArea;
-
-    // Flip texture coordinates appropriately.
-    texelArea.setFlip( flipX, flipY );
-   
-    // Fetch lower/upper texture coordinates.
-    const Vector2& texLower = texelArea.mTexelLower;
-    const Vector2& texUpper = texelArea.mTexelUpper;
-    
-    // Submit batched quad.
-    pBatchRenderer->SubmitQuad(
-        vertexPos0,
-        vertexPos1,
-        vertexPos2,
-        vertexPos3,
-        Vector2( texLower.x, texUpper.y ),
-        Vector2( texUpper.x, texUpper.y ),
-        Vector2( texUpper.x, texLower.y ),
-        Vector2( texLower.x, texLower.y ),
-        mpAnimationController->getImageTexture() );
-}
-
-//-----------------------------------------------------------------------------
-
-void SpriteProxyBase::renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const
-{
-    // Are we in static mode?
-    if ( isStaticMode() )
-    {
-        // Do we have a valid image to render?
-        if ( mImageAsset.notNull() && mImageFrame < mImageAsset->getFrameCount() )
-        {
-            // Yes, so calculate source region.
-            const ImageAsset::FrameArea& frameArea = mImageAsset->getImageFrameArea( mImageFrame );
-            RectI sourceRegion( frameArea.mPixelArea.mPixelOffset, Point2I(frameArea.mPixelArea.mPixelWidth, frameArea.mPixelArea.mPixelHeight) );
-
-            // Calculate destination region.
-            RectI destinationRegion(offset, owner.mBounds.extent);
-
-            // Render image.
-			dglSetBitmapModulation( owner.mProfile->mFillColor );
-            dglDrawBitmapStretchSR( mImageAsset->getImageTexture(), destinationRegion, sourceRegion );
-            dglClearBitmapModulation();
-        }
-        else
-        {
-            // No, so render no-image render-proxy.
-            renderNoImage( owner, offset, updateRect );
-        }
-    }
-    else
-    {
-        // Do we have a valid animation to render?
-        if ( mpAnimationController != NULL && mpAnimationController->getAnimationAsset().notNull() )
-        {
-            // Yes, so calculate source region.
-            const ImageAsset::FrameArea& frameArea = mpAnimationController->getCurrentImageFrameArea();
-            RectI sourceRegion( frameArea.mPixelArea.mPixelOffset, Point2I(frameArea.mPixelArea.mPixelWidth, frameArea.mPixelArea.mPixelHeight) );
-
-            // Calculate destination region.
-            RectI destinationRegion(offset, owner.mBounds.extent);
-
-            // Render animation image.
-			dglSetBitmapModulation( owner.mProfile->mFillColor );
-            dglDrawBitmapStretchSR( mpAnimationController->getImageTexture(), destinationRegion, sourceRegion );
-            dglClearBitmapModulation();
-
-            // Update control.
-            owner.setUpdate();
-        }
-        else
-        {
-            // No, so render no-image render-proxy.
-            renderNoImage( owner, offset, updateRect );
-        }
-    }
-
-    // Render child controls.
-    owner.renderChildControls(offset, updateRect);
-}
-
-
-//------------------------------------------------------------------------------
-
-void SpriteProxyBase::renderNoImage( GuiControl& owner, Point2I &offset, const RectI& updateRect ) const
-{
-    // Fetch the 'cannot render' proxy.
-    RenderProxy* pNoImageRenderProxy = Sim::findObject<RenderProxy>( CANNOT_RENDER_PROXY_NAME );
-
-    // Finish if no render proxy available or it can't render.
-    if ( pNoImageRenderProxy == NULL || !pNoImageRenderProxy->validRender() )
-        return;
-
-    // Render using render-proxy.
-    pNoImageRenderProxy->renderGui( owner, offset, updateRect );
-
-    // Update control.
-    owner.setUpdate();
-}
-
-//------------------------------------------------------------------------------
-
-void SpriteProxyBase::copyTo(SpriteProxyBase* pSpriteProxyBase) const
-{
-    // Sanity!
-    AssertFatal(pSpriteProxyBase != NULL, "SpriteProxyBase::copyTo - Copy object cannot be NULL.");
-
-    // Set self ticking.
-    pSpriteProxyBase->mSelfTick = mSelfTick;
-
-    // Are we in static mode?
-    if ( mStaticMode )
-    {
-        // Yes, so use the image/frame if we have an asset.
-        if ( mImageAsset.notNull() )
-            pSpriteProxyBase->setImage( getImage(), getImageFrame() );
-    }
-    else if ( mAnimationAsset.notNull() )
-    {
-        // No, so use current animation if we have an asset.
-        if ( mAnimationAsset.notNull() )
-            pSpriteProxyBase->setAnimation(getAnimation(), false );
-    }
-}
-
-//------------------------------------------------------------------------------
-
-void SpriteProxyBase::clearAsset( void )
-{
-    // Destroy animation controller if required.
-    if ( mpAnimationController != NULL )
-    {
-        delete mpAnimationController;
-        mpAnimationController = NULL;
-    }
-
-    mAnimationAsset = NULL;
-    mImageAsset = NULL;
-    mImageFrame = 0;
-    mStaticMode = true;
-    setProcessTicks( false );
-}
-
-//------------------------------------------------------------------------------
-
-bool SpriteProxyBase::setImage( const char* pImageAssetId, const U32 frame )
-{
-    // Finish if invalid image asset.
-    if ( pImageAssetId == NULL )
-        return false;
-
-    // Set asset.
-    mImageAsset = pImageAssetId;
-
-    // Set the image frame if the image asset was set.
-    if ( mImageAsset.notNull() )
-        setImageFrame( frame );
-
-    // Destroy animation controller if required.
-    if ( mpAnimationController != NULL )
-    {
-        delete mpAnimationController;
-        mpAnimationController = NULL;
-    }
-
-    // Set Frame.
-    mImageFrame = frame;
-
-    // Set as static render.
-    mStaticMode = true;
-
-    // Turn-off tick processing.
-    setProcessTicks( false );
-
-    // Return Okay.
-    return true;
-}
-
-//------------------------------------------------------------------------------
-
-bool SpriteProxyBase::setImageFrame( const U32 frame )
-{
-    // Check Existing Image.
-    if ( mImageAsset.isNull() )
-    {
-        // Warn.
-        Con::warnf("SpriteProxyBase::setImageFrame() - Cannot set Frame without existing asset Id.");
-
-        // Return Here.
-        return false;
-    }
-
-    // Check Frame Validity.
-    if ( frame >= mImageAsset->getFrameCount() )
-    {
-        // Warn.
-        Con::warnf( "SpriteProxyBase::setImageFrame() - Invalid Frame #%d for asset Id '%s'.", frame, mImageAsset.getAssetId() );
-        // Return Here.
-        return false;
-    }
-
-    // Set Frame.
-    mImageFrame = frame;
-
-    // Return Okay.
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-
-bool SpriteProxyBase::setAnimation( const char* pAnimationAssetId, const bool autoRestore )
-{
-    // Set as dynamic render.
-    mStaticMode = false;
-
-    // Ensure animation is un-paused.
-    mAnimationPaused = false;
-
-    // Create animation controller if required.
-    if ( mpAnimationController == NULL )
-        mpAnimationController = new AnimationController();
-
-    // Reset static asset.
-    mImageAsset.clear();
-
-    // Fetch animation asset.
-    mAnimationAsset = StringTable->insert( pAnimationAssetId );
-
-    // Finish if we didn't get an animation.
-    if ( mAnimationAsset.isNull() )
-        return false;
-
-    // Play Animation.
-    if ( !mpAnimationController->playAnimation( mAnimationAsset, autoRestore ) )
-        return false;
-
-    // Turn-on tick processing.
-    setProcessTicks( true );
-
-    // Return Okay.
-    return true;
-}

+ 0 - 117
engine/source/2d/core/SpriteProxyBase.h

@@ -1,117 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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 _SPRITE_PROXY_BASE_H_
-#define _SPRITE_PROXY_BASE_H_
-
-#ifndef _BATCH_RENDER_H_
-#include "BatchRender.h"
-#endif
-
-#ifndef _IMAGE_ASSET_H_
-#include "2d/assets/ImageAsset.h"
-#endif
-
-#ifndef _ANIMATION_ASSET_H_
-#include "2d/assets/AnimationAsset.h"
-#endif
-
-#ifndef _ANIMATION_CONTROLLER_H_
-#include "2d/assets/AnimationController.h"
-#endif
-
-#ifndef _GUICONTROL_H_
-#include "gui/guiControl.h"
-#endif
-
-#ifndef _TICKABLE_H_
-#include "platform/Tickable.h"
-#endif
-
-//------------------------------------------------------------------------------
-
-class SpriteProxyBase : public virtual Tickable, public IFactoryObjectReset
-{
-protected:
-    AssetPtr<ImageAsset>        mImageAsset;
-    AssetPtr<AnimationAsset>    mAnimationAsset;
-
-    bool                        mStaticMode;
-    U32                         mImageFrame;
-    bool                        mAnimationPaused;
-    AnimationController*        mpAnimationController;
-
-    bool                        mSelfTick;
-
-public:
-    SpriteProxyBase();
-    virtual ~SpriteProxyBase();
-
-    virtual void resetState( void );
-
-    /// Integration.
-    virtual bool update( const F32 elapsedTime );
-    virtual void processTick();
-    virtual void interpolateTick( F32 delta ) {};
-    virtual void advanceTime( F32 timeDelta ) {};
-
-    virtual bool validRender( void ) const;
-
-    virtual void render(
-        const bool flipX,
-        const bool flipY,
-        const Vector2& vertexPos0,
-        const Vector2& vertexPos1,
-        const Vector2& vertexPos2,
-        const Vector2& vertexPos3,
-        BatchRender* pBatchRenderer ) const;
-
-    void renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const;
-
-	void renderNoImage( GuiControl& owner, Point2I &offset, const RectI& updateRect ) const;
-
-    virtual void copyTo(SpriteProxyBase* pSpriteProxyBase) const;
-
-    void clearAsset( void );
-
-    // Image.
-    inline bool setImage( const char* pImageAssetId ) { return setImage( pImageAssetId, mImageFrame ); }
-    virtual bool setImage( const char* pImageAssetId, const U32 frame );
-    inline StringTableEntry getImage( void ) const { return mImageAsset.getAssetId(); }
-    virtual bool setImageFrame( const U32 frame );
-    inline U32 getImageFrame( void ) const { return mImageFrame; }
-    inline StringTableEntry getAnimation( void ) const { return mAnimationAsset.getAssetId(); }
-
-    /// Animation.
-    virtual bool setAnimation( const char* pAnimationAssetId, const bool autoRestore = false );
-    inline AnimationController* getAnimationController( void ) const { return mpAnimationController; }
-    inline bool isStaticMode( void ) const { return mStaticMode; }
-    inline void pauseAnimation( const bool animationPaused ) { mAnimationPaused = animationPaused; }
-
-    /// Self ticking control.
-    virtual void setProcessTicks( bool tick  ) { Tickable::setProcessTicks( mSelfTick ? tick : false ); }
-
-protected:
-    virtual void onAnimationEnd( void ) {}
-};
-
-#endif // _SPRITE_PROXY_BASE_H_

+ 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, ImageFrameProvider, 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.
+//-----------------------------------------------------------------------------
+

+ 8 - 8
engine/source/2d/gui/guiSpriteCtrl.cc

@@ -82,12 +82,12 @@ bool GuiSpriteCtrl::onWake()
     if ( mImageAssetId != StringTable->EmptyString )
     {
         // Set image asset.
-		SpriteProxyBase::setImage( mImageAssetId );
+		ImageFrameProvider::setImage( mImageAssetId );
     }
     else if ( mAnimationAssetId != StringTable->EmptyString )
     {
         // Play animation asset.
-		SpriteProxyBase::setAnimation( mAnimationAssetId, false );
+		ImageFrameProvider::setAnimation( mAnimationAssetId );
     }
 
     return true;
@@ -98,7 +98,7 @@ bool GuiSpriteCtrl::onWake()
 void GuiSpriteCtrl::onSleep()
 {
     // Clear assets.
-	SpriteProxyBase::clearAsset();
+	ImageFrameProvider::clearAssets();
 
     // Call parent.
     Parent::onSleep();
@@ -125,7 +125,7 @@ bool GuiSpriteCtrl::setImage( const char* pImageAssetId )
 		return true;
 
 	// Call parent.
-	if ( !SpriteProxyBase::setImage( pImageAssetId, 0 ) )
+	if ( !ImageFrameProvider::setImage( pImageAssetId, 0 ) )
 		return false;
 
     // Update control.
@@ -139,7 +139,7 @@ bool GuiSpriteCtrl::setImage( const char* pImageAssetId )
 bool GuiSpriteCtrl::setImageFrame( const U32 frame )
 {
 	// Call parent.
-	if ( !SpriteProxyBase::setImageFrame( frame ) )
+	if ( !ImageFrameProvider::setImageFrame( frame ) )
 		return false;
 
     // Update control.
@@ -167,7 +167,7 @@ bool GuiSpriteCtrl::setAnimation( const char* pAnimationAssetId )
 
     // Play animation asset if it's valid.
     if ( mAnimationAssetId != StringTable->EmptyString )
-		SpriteProxyBase::setAnimation( mAnimationAssetId, false );
+		ImageFrameProvider::setAnimation( mAnimationAssetId );
 
 	return true;
 }
@@ -177,7 +177,7 @@ bool GuiSpriteCtrl::setAnimation( const char* pAnimationAssetId )
 void GuiSpriteCtrl::onRender( Point2I offset, const RectI &updateRect)
 {
 	// Call parent.
-	SpriteProxyBase::renderGui( *this, offset, updateRect );
+	ImageFrameProvider::renderGui( *this, offset, updateRect );
 }
 
 //------------------------------------------------------------------------------
@@ -185,5 +185,5 @@ void GuiSpriteCtrl::onRender( Point2I offset, const RectI &updateRect)
 void GuiSpriteCtrl::onAnimationEnd( void )
 {
     // Clear assets.
-	SpriteProxyBase::clearAsset();
+	ImageFrameProvider::clearAssets();
 }

+ 8 - 12
engine/source/2d/gui/guiSpriteCtrl.h

@@ -23,17 +23,13 @@
 #ifndef _GUISPRITECTRL_H_
 #define _GUISPRITECTRL_H_
 
-#ifndef _GUICONTROL_H_
-#include "gui/guiControl.h"
-#endif
-
-#ifndef _SPRITE_PROXY_BASE_H_
-#include "2d/core/SpriteProxyBase.h"
+#ifndef _IMAGE_FRAME_PROVIDER_H
+#include "2d/core/imageFrameProvider.h"
 #endif
 
 //-----------------------------------------------------------------------------
 
-class GuiSpriteCtrl : public GuiControl, public SpriteProxyBase
+class GuiSpriteCtrl : public GuiControl, public ImageFrameProvider
 {
 private:
     typedef GuiControl Parent;
@@ -63,13 +59,13 @@ protected:
 
 protected:
     static bool setImage(void* obj, const char* data) { static_cast<GuiSpriteCtrl*>(obj)->setImage( data ); return false; }
-    static const char* getImage(void* obj, const char* data) { return DYNAMIC_VOID_CAST_TO(GuiSpriteCtrl, SpriteProxyBase, obj)->getImage(); }
-    static bool writeImage( void* obj, StringTableEntry pFieldName ) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if ( !pCastObject->isStaticMode() ) return false; return pCastObject->mImageAssetId != StringTable->EmptyString; }
+    static const char* getImage(void* obj, const char* data) { return DYNAMIC_VOID_CAST_TO(GuiSpriteCtrl, ImageFrameProvider, obj)->getImage(); }
+    static bool writeImage( void* obj, StringTableEntry pFieldName ) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if ( !pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mImageAssetId != StringTable->EmptyString; }
     static bool setImageFrame(void* obj, const char* data) { static_cast<GuiSpriteCtrl*>(obj)->setImageFrame( dAtoi(data) ); return false; }
-    static bool writeImageFrame( void* obj, StringTableEntry pFieldName ) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); return pCastObject->isStaticMode() && pCastObject->getImageFrame() > 0; }
+    static bool writeImageFrame( void* obj, StringTableEntry pFieldName ) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); return pCastObject->isStaticFrameProvider() && pCastObject->getImageFrame() > 0; }
     static bool setAnimation(void* obj, const char* data) { static_cast<GuiSpriteCtrl*>(obj)->setAnimation(data); return false; };
-    static const char* getAnimation(void* obj, const char* data) { return DYNAMIC_VOID_CAST_TO(GuiSpriteCtrl, SpriteProxyBase, obj)->getAnimation(); }
-    static bool writeAnimation( void* obj, StringTableEntry pFieldName ) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if ( pCastObject->isStaticMode() ) return false; return pCastObject->mAnimationAssetId != StringTable->EmptyString; }
+    static const char* getAnimation(void* obj, const char* data) { return DYNAMIC_VOID_CAST_TO(GuiSpriteCtrl, ImageFrameProvider, obj)->getAnimation(); }
+    static bool writeAnimation( void* obj, StringTableEntry pFieldName ) { GuiSpriteCtrl* pCastObject = static_cast<GuiSpriteCtrl*>(obj); if ( pCastObject->isStaticFrameProvider() ) return false; return pCastObject->mAnimationAssetId != StringTable->EmptyString; }
 };
 
 #endif //_GUISPRITECTRL_H_

+ 7 - 7
engine/source/2d/gui/guiSpriteCtrl_ScriptBindings.h

@@ -20,10 +20,10 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
-ConsoleMethod( GuiSpriteCtrl, isStaticMode, bool, 2, 2, "() - Gets whether the control is in static or dynamic (animated)mode.\n"
+ConsoleMethod( GuiSpriteCtrl, isStaticFrameProvider, bool, 2, 2, "() - Gets whether the control is in static or dynamic (animated)mode.\n"
                                                         "@return Returns whether the control is in static or dynamic (animated)mode.")
 {
-    return object->isStaticMode();
+    return object->isStaticFrameProvider();
 }
 
 //-----------------------------------------------------------------------------
@@ -41,7 +41,7 @@ ConsoleMethod( GuiSpriteCtrl, getImage, const char*, 2, 2,  "() - Gets current i
                                                             "@return (string imageAssetId) The image being displayed.")
 {
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf( "GuiSpriteCtrl::getImage() - Method invalid, not in static mode." );
@@ -49,7 +49,7 @@ ConsoleMethod( GuiSpriteCtrl, getImage, const char*, 2, 2,  "() - Gets current i
     }
 
     // Get image.
-    return DYNAMIC_VOID_CAST_TO(GuiSpriteCtrl, SpriteProxyBase, object)->getImage();
+    return DYNAMIC_VOID_CAST_TO(GuiSpriteCtrl, ImageFrameProvider, object)->getImage();
 }
 
 //-----------------------------------------------------------------------------
@@ -67,7 +67,7 @@ ConsoleMethod( GuiSpriteCtrl, getImageFrame, S32, 2, 2, "() - Gets current image
                                                         "@return (int frame) The frame currently being displayed.")
 {
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
         // No, so warn.
         Con::warnf( "GuiSpriteCtrl::getFrame() - Method invalid, not in static mode." );
@@ -94,7 +94,7 @@ ConsoleMethod( GuiSpriteCtrl, getAnimation, const char*, 2, 2,  "() - Gets the c
                                                                 "@return (string ianimationAssetId) The animation being displayed.")
 {
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
         // Yes, so warn.
         Con::warnf( "GuiSpriteCtrl::getAnimation() - Method invalid, in static mode." );
@@ -102,5 +102,5 @@ ConsoleMethod( GuiSpriteCtrl, getAnimation, const char*, 2, 2,  "() - Gets the c
     }
 
     // Get animation.
-    return DYNAMIC_VOID_CAST_TO(GuiSpriteCtrl, SpriteProxyBase, object)->getAnimation();
+    return DYNAMIC_VOID_CAST_TO(GuiSpriteCtrl, ImageFrameProvider, object)->getAnimation();
 }

+ 11 - 6
engine/source/2d/scene/ContactFilter.cc

@@ -48,10 +48,15 @@ bool ContactFilter::ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB)
     if ( pSceneObjectA->mCollisionSuppress || pSceneObjectB->mCollisionSuppress )
         return false;
 
-    // Check group/layer masks.
-    return
-        (pSceneObjectA->mCollisionGroupMask & pSceneObjectB->mSceneGroupMask) != 0 &&
-        (pSceneObjectB->mCollisionGroupMask & pSceneObjectA->mSceneGroupMask) != 0 &&
-        (pSceneObjectA->mCollisionLayerMask & pSceneObjectB->mSceneLayerMask) != 0 &&
-        (pSceneObjectB->mCollisionLayerMask & pSceneObjectA->mSceneLayerMask) != 0;
+    // Check collision rule A -> B.
+    if ( (pSceneObjectA->mCollisionGroupMask & pSceneObjectB->mSceneGroupMask) != 0 &&
+         (pSceneObjectA->mCollisionLayerMask & pSceneObjectB->mSceneLayerMask) != 0 )
+         return true;
+
+    // Check collision rule B -> A.
+    if ( (pSceneObjectB->mCollisionGroupMask & pSceneObjectA->mSceneGroupMask) != 0 &&
+         (pSceneObjectB->mCollisionLayerMask & pSceneObjectA->mSceneLayerMask) != 0 )
+         return true;
+
+    return false;
 }

+ 553 - 467
engine/source/2d/scene/Scene.cc

@@ -237,7 +237,7 @@ Scene::Scene() :
         jointMotorMaxTorqueName           = jointRevoluteMotorMaxTorqueName;
         jointMotorCorrectionFactorName    = StringTable->insert( "CorrectionFactor" );
 
-		controllerCustomNodeName	  = StringTable->insert( "Controllers" );
+        controllerCustomNodeName	      = StringTable->insert( "Controllers" );
 
         // Flag as initialized.
         tamlPropertiesInitialized = true;
@@ -256,22 +256,20 @@ Scene::Scene() :
     // Set debug stats for batch renderer.
     mBatchRenderer.setDebugStats( &mDebugStats );
 
-	// Register the scene controllers set.
+    // Register the scene controllers set.
     mControllers = new SimSet();
     mControllers->registerObject();
 
     // Assign scene index.    
     mSceneIndex = ++sSceneMasterIndex;
     sSceneCount++;
-
-    mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 
 //-----------------------------------------------------------------------------
 
 Scene::~Scene()
 {
-	// Unregister the scene controllers set.
+    // Unregister the scene controllers set.
     mControllers->deleteObject();
 
     // Decrease scene count.
@@ -286,9 +284,6 @@ bool Scene::onAdd()
     if(!Parent::onAdd())
         return false;
 
-    // Synchronize Namespace's
-    linkNamespaces();
-
     // Create physics world.
     mpWorld = new b2World( mWorldGravity );
 
@@ -313,9 +308,6 @@ bool Scene::onAdd()
     // Set loading scene.
     Scene::LoadingScene = this;
 
-    // Tell the scripts
-    Con::executef(this, 1, "onAdd");
-
     // Turn-on tick processing.
     setProcessTicks( true );
 
@@ -330,9 +322,6 @@ void Scene::onRemove()
     // Turn-off tick processing.
     setProcessTicks( false );
 
-    // tell the scripts
-    Con::executef(this, 1, "onRemove");
-
     // Clear Scene.
     clearScene();
 
@@ -355,9 +344,6 @@ void Scene::onRemove()
     // Call Parent. Clear scene handles all the object removal, so we can skip
     // that part and just do the sim-object stuff.
     SimObject::onRemove();
-
-    // Restore NameSpace's
-    unlinkNamespaces();
 }
 
 //-----------------------------------------------------------------------------
@@ -557,12 +543,8 @@ void Scene::dispatchBeginContactCallbacks( void )
         if ( pSceneObjectA->isBeingDeleted() || pSceneObjectB->isBeingDeleted() )
             continue;
 
-        // Fetch collision callback status.
-        const bool sceneObjectACallback = pSceneObjectA->getCollisionCallback();
-        const bool sceneObjectBCallback = pSceneObjectB->getCollisionCallback();
-
         // Skip if both objects don't have collision callback active.
-        if ( !sceneObjectACallback && !sceneObjectBCallback )
+        if ( !pSceneObjectA->getCollisionCallback() && !pSceneObjectB->getCollisionCallback() )
             continue;
 
         // Fetch normal and contact points.
@@ -614,36 +596,33 @@ void Scene::dispatchBeginContactCallbacks( void )
                 normalImpulse1,
                 tangentImpulse1 );
         }
-		else
-		{
+        else
+        {
             dSprintf(pMiscInfoBuffer, 64,
                 "%d %d",
                 shapeIndexA, shapeIndexB );
-		}
+        }
 
-        // Do both objects have collision callback active?
-        if ( sceneObjectACallback && sceneObjectBCallback )
+        // Does the scene handle the collision callback?
+        Namespace* pNamespace = getNamespace();
+        if ( pNamespace != NULL && pNamespace->lookup( StringTable->insert( "onSceneCollision" ) ) != NULL )
         {
-            // Yes, so does the scene handle the collision callback?
-            Namespace* pNamespace = getNamespace();
-            if ( pNamespace != NULL && pNamespace->lookup( StringTable->insert( "onSceneCollision" ) ) != NULL )
-            {
-                // Yes, so perform script callback on the Scene.
-                Con::executef( this, 4, "onSceneCollision",
-                    pSceneObjectABuffer,
-                    pSceneObjectBBuffer,
-                    pMiscInfoBuffer );
-            }
-            else
-            {
-                // No, so call it on its behaviors.
-                const char* args[5] = { "onSceneCollision", this->getIdString(), pSceneObjectABuffer, pSceneObjectBBuffer, pMiscInfoBuffer };
-                callOnBehaviors( 5, args );
-            }
+            // Yes, so perform script callback on the Scene.
+            Con::executef( this, 4, "onSceneCollision",
+                pSceneObjectABuffer,
+                pSceneObjectBBuffer,
+                pMiscInfoBuffer );
+        }
+        else
+        {
+            // No, so call it on its behaviors.
+            const char* args[5] = { "onSceneCollision", getIdString(), pSceneObjectABuffer, pSceneObjectBBuffer, pMiscInfoBuffer };
+            callOnBehaviors( 5, args );
         }
 
-        // Does object A have collision callback active?
-        if ( sceneObjectACallback )
+        // Is object A allowed to collide with object B?
+        if (    (pSceneObjectA->mCollisionGroupMask & pSceneObjectB->mSceneGroupMask) != 0 &&
+                (pSceneObjectA->mCollisionLayerMask & pSceneObjectB->mSceneLayerMask) != 0 )
         {
             // Yes, so does it handle the collision callback?
             if ( pSceneObjectA->isMethod("onCollision") )            
@@ -661,8 +640,9 @@ void Scene::dispatchBeginContactCallbacks( void )
             }
         }
 
-        // Does object B have collision callback active?
-        if ( sceneObjectBCallback )
+        // Is object B allowed to collide with object A?
+        if (    (pSceneObjectB->mCollisionGroupMask & pSceneObjectA->mSceneGroupMask) != 0 &&
+                (pSceneObjectB->mCollisionLayerMask & pSceneObjectA->mSceneLayerMask) != 0 )
         {
             // Yes, so does it handle the collision callback?
             if ( pSceneObjectB->isMethod("onCollision") )            
@@ -713,12 +693,8 @@ void Scene::dispatchEndContactCallbacks( void )
         if ( pSceneObjectA->isBeingDeleted() || pSceneObjectB->isBeingDeleted() )
             continue;
 
-        // Fetch collision callback status.
-        const bool sceneObjectACallback = pSceneObjectA->getCollisionCallback();
-        const bool sceneObjectBCallback = pSceneObjectB->getCollisionCallback();
-
         // Skip if both objects don't have collision callback active.
-        if ( !sceneObjectACallback && !sceneObjectBCallback )
+        if ( !pSceneObjectA->getCollisionCallback() && !pSceneObjectB->getCollisionCallback() )
             continue;
 
         // Fetch shape index.
@@ -739,29 +715,26 @@ void Scene::dispatchEndContactCallbacks( void )
         char* pMiscInfoBuffer = Con::getArgBuffer(32);
         dSprintf(pMiscInfoBuffer, 32, "%d %d", shapeIndexA, shapeIndexB );
 
-        // Do both objects have collision callback active?
-        if ( sceneObjectACallback && sceneObjectBCallback )
+        // Does the scene handle the collision callback?
+        Namespace* pNamespace = getNamespace();
+        if ( pNamespace != NULL && pNamespace->lookup( StringTable->insert( "onSceneEndCollision" ) ) != NULL )
         {
             // Yes, so does the scene handle the collision callback?
-            Namespace* pNamespace = getNamespace();
-            if ( pNamespace != NULL && pNamespace->lookup( StringTable->insert( "onSceneEndCollision" ) ) != NULL )
-            {
-                // Yes, so does the scene handle the collision callback?
-                Con::executef( this, 4, "onSceneEndCollision",
-                    pSceneObjectABuffer,
-                    pSceneObjectBBuffer,
-                    pMiscInfoBuffer );
-            }
-            else
-            {
-                // No, so call it on its behaviors.
-                const char* args[5] = { "onSceneEndCollision", this->getIdString(), pSceneObjectABuffer, pSceneObjectBBuffer, pMiscInfoBuffer };
-                callOnBehaviors( 5, args );
-            }
+            Con::executef( this, 4, "onSceneEndCollision",
+                pSceneObjectABuffer,
+                pSceneObjectBBuffer,
+                pMiscInfoBuffer );
+        }
+        else
+        {
+            // No, so call it on its behaviors.
+            const char* args[5] = { "onSceneEndCollision", getIdString(), pSceneObjectABuffer, pSceneObjectBBuffer, pMiscInfoBuffer };
+            callOnBehaviors( 5, args );
         }
 
-        // Does object A have collision callback active?
-        if ( sceneObjectACallback )
+        // Is object A allowed to collide with object B?
+        if (    (pSceneObjectA->mCollisionGroupMask & pSceneObjectB->mSceneGroupMask) != 0 &&
+                (pSceneObjectA->mCollisionLayerMask & pSceneObjectB->mSceneLayerMask) != 0 )
         {
             // Yes, so does it handle the collision callback?
             if ( pSceneObjectA->isMethod("onEndCollision") )            
@@ -774,13 +747,14 @@ void Scene::dispatchEndContactCallbacks( void )
             else
             {
                 // No, so call it on its behaviors.
-                const char* args[3] = { "onEndCollision", pSceneObjectBBuffer, pMiscInfoBuffer };
-                pSceneObjectA->callOnBehaviors( 3, args );
+                const char* args[4] = { "onEndCollision", pSceneObjectABuffer, pSceneObjectBBuffer, pMiscInfoBuffer };
+                pSceneObjectA->callOnBehaviors( 4, args );
             }
         }
 
-        // Does object B have collision callback active?
-        if ( sceneObjectBCallback )
+        // Is object B allowed to collide with object A?
+        if (    (pSceneObjectB->mCollisionGroupMask & pSceneObjectA->mSceneGroupMask) != 0 &&
+                (pSceneObjectB->mCollisionLayerMask & pSceneObjectA->mSceneLayerMask) != 0 )
         {
             // Yes, so does it handle the collision callback?
             if ( pSceneObjectB->isMethod("onEndCollision") )            
@@ -793,8 +767,8 @@ void Scene::dispatchEndContactCallbacks( void )
             else
             {
                 // No, so call it on its behaviors.
-                const char* args[3] = { "onEndCollision", pSceneObjectABuffer, pMiscInfoBuffer };
-                pSceneObjectB->callOnBehaviors( 3, args );
+                const char* args[4] = { "onEndCollision", pSceneObjectBBuffer, pSceneObjectABuffer, pMiscInfoBuffer };
+                pSceneObjectB->callOnBehaviors( 4, args );
             }
         }
     }
@@ -881,10 +855,10 @@ void Scene::processTick( void )
         // Debug Status Reference.
         DebugStats* pDebugStats = &mDebugStats;
 
-		// Fetch ticked scene object count.
-		const S32 tickedSceneObjectCount = mTickedSceneObjects.size();
+        // Fetch ticked scene object count.
+        const S32 tickedSceneObjectCount = mTickedSceneObjects.size();
 
-		// ****************************************************
+        // ****************************************************
         // Pre-integrate objects.
         // ****************************************************
 
@@ -899,7 +873,7 @@ void Scene::processTick( void )
         }
 
         // ****************************************************
-		// Integrate controllers.
+        // Integrate controllers.
         // ****************************************************
 
         // Fetch the controller set.
@@ -911,22 +885,22 @@ void Scene::processTick( void )
             // Debug Profiling.
             PROFILE_SCOPE(Scene_IntegrateSceneControllers);
 
-		    // Yes, so fetch scene controller count.
-		    const S32 sceneControllerCount = (S32)pControllerSet->size();
+            // Yes, so fetch scene controller count.
+            const S32 sceneControllerCount = (S32)pControllerSet->size();
 
-		    // Iterate scene controllers.
-		    for( S32 i = 0; i < sceneControllerCount; i++ )
-		    {
-			    // Fetch the scene controller.
-			    SceneController* pController = dynamic_cast<SceneController*>((*pControllerSet)[i]);
+            // Iterate scene controllers.
+            for( S32 i = 0; i < sceneControllerCount; i++ )
+            {
+                // Fetch the scene controller.
+                SceneController* pController = dynamic_cast<SceneController*>((*pControllerSet)[i]);
 
-			    // Skip if not a controller.
-			    if ( pController == NULL )
-				    continue;
+                // Skip if not a controller.
+                if ( pController == NULL )
+                    continue;
 
-			    // Integrate.
-			    pController->integrate( this, mSceneTime, Tickable::smTickSec, pDebugStats );
-		    }
+                // Integrate.
+                pController->integrate( this, mSceneTime, Tickable::smTickSec, pDebugStats );
+            }
         }
 
         // Debug Profiling.
@@ -1013,11 +987,11 @@ void Scene::interpolateTick( F32 timeDelta )
     PROFILE_SCOPE(Scene_InterpolateTick);
 
     // ****************************************************
-	// Interpolate scene objects.
+    // Interpolate scene objects.
     // ****************************************************
 
-	// Fetch the scene object count.
-	const S32 sceneObjectCount = mSceneObjects.size();
+    // Fetch the scene object count.
+    const S32 sceneObjectCount = mSceneObjects.size();
 
     // Iterate scene objects.
     for( S32 n = 0; n < sceneObjectCount; ++n )
@@ -1321,22 +1295,22 @@ void Scene::sceneRender( const SceneRenderState* pSceneRenderState )
             // Debug Profiling.
             PROFILE_SCOPE(Scene_RenderControllers);
 
-		    // Yes, so fetch scene controller count.
-		    const S32 sceneControllerCount = (S32)pControllerSet->size();
+            // Yes, so fetch scene controller count.
+            const S32 sceneControllerCount = (S32)pControllerSet->size();
 
-		    // Iterate scene controllers.
-		    for( S32 i = 0; i < sceneControllerCount; i++ )
-		    {
-			    // Fetch the scene controller.
-			    SceneController* pController = dynamic_cast<SceneController*>((*pControllerSet)[i]);
+            // Iterate scene controllers.
+            for( S32 i = 0; i < sceneControllerCount; i++ )
+            {
+                // Fetch the scene controller.
+                SceneController* pController = dynamic_cast<SceneController*>((*pControllerSet)[i]);
 
-			    // Skip if not a controller.
-			    if ( pController == NULL )
-				    continue;
+                // Skip if not a controller.
+                if ( pController == NULL )
+                    continue;
 
-			    // Render the overlay.
+                // Render the overlay.
                 pController->renderOverlay( this, pSceneRenderState, &mBatchRenderer );
-		    }
+            }
 
             // Flush isolated batch.
             mBatchRenderer.flush( pDebugStats->batchIsolatedFlush );
@@ -1568,7 +1542,7 @@ void Scene::mergeScene( const Scene* pScene )
 
 //-----------------------------------------------------------------------------
 
-b2Joint* Scene::findJoint( const U32 jointId )
+b2Joint* Scene::findJoint( const S32 jointId )
 {
     // Find joint.
     typeJointHash::iterator itr = mJoints.find( jointId );
@@ -1578,7 +1552,7 @@ b2Joint* Scene::findJoint( const U32 jointId )
 
 //-----------------------------------------------------------------------------
 
-b2JointType Scene::getJointType( const U32 jointId )
+b2JointType Scene::getJointType( const S32 jointId )
 {
     // Sanity!
     if ( jointId >= mJointMasterId )
@@ -1592,7 +1566,7 @@ b2JointType Scene::getJointType( const U32 jointId )
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::findJointId( b2Joint* pJoint )
+S32 Scene::findJointId( b2Joint* pJoint )
 {
     // Sanity!
     AssertFatal( pJoint != NULL, "Joint cannot be NULL." );
@@ -1611,7 +1585,7 @@ U32 Scene::findJointId( b2Joint* pJoint )
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createJoint( b2JointDef* pJointDef )
+S32 Scene::createJoint( b2JointDef* pJointDef )
 {
     // Sanity!
     AssertFatal( pJointDef != NULL, "Joint definition cannot be NULL." );
@@ -1620,7 +1594,7 @@ U32 Scene::createJoint( b2JointDef* pJointDef )
     b2Joint* pJoint = mpWorld->CreateJoint( pJointDef );
 
     // Allocate joint Id.
-    const U32 jointId = mJointMasterId++;
+    const S32 jointId = mJointMasterId++;
 
     // Insert joint.
     typeJointHash::iterator itr = mJoints.insert( jointId, pJoint );
@@ -1676,7 +1650,7 @@ bool Scene::hasJoints( SceneObject* pSceneObject )
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createDistanceJoint(
+S32 Scene::createDistanceJoint(
     const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
     const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
     const F32 length,
@@ -1693,6 +1667,13 @@ U32 Scene::createDistanceJoint(
         return -1;
     }
 
+    // Check for two invalid objects.
+    if ( pSceneObjectA == NULL && pSceneObjectB == NULL )
+    {
+        Con::warnf("Scene::createDistanceJoint() - Cannot create joint without at least a single scene object." );
+        return -1;
+    }
+
     // Fetch bodies.
     b2Body* pBodyA = pSceneObjectA != NULL ? pSceneObjectA->getBody() : getGroundBody();
     b2Body* pBodyB = pSceneObjectB != NULL ? pSceneObjectB->getBody() : getGroundBody();
@@ -1883,7 +1864,7 @@ F32 Scene::getDistanceJointDampingRatio( const U32 jointId )
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createRopeJoint(
+S32 Scene::createRopeJoint(
         const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
         const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
         const F32 maxLength,
@@ -1898,6 +1879,13 @@ U32 Scene::createRopeJoint(
         return -1;
     }
 
+    // Check for two invalid objects.
+    if ( pSceneObjectA == NULL && pSceneObjectB == NULL )
+    {
+        Con::warnf("Scene::createRopeJoint() - Cannot create joint without at least a single scene object." );
+        return -1;
+    }
+
     // Fetch bodies.
     b2Body* pBodyA = pSceneObjectA != NULL ? pSceneObjectA->getBody() : getGroundBody();
     b2Body* pBodyB = pSceneObjectB != NULL ? pSceneObjectB->getBody() : getGroundBody();
@@ -1974,7 +1962,7 @@ F32 Scene::getRopeJointMaxLength( const U32 jointId )
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createRevoluteJoint(
+S32 Scene::createRevoluteJoint(
         const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
         const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
         const bool collideConnected )
@@ -1988,6 +1976,13 @@ U32 Scene::createRevoluteJoint(
         return -1;
     }
 
+    // Check for two invalid objects.
+    if ( pSceneObjectA == NULL && pSceneObjectB == NULL )
+    {
+        Con::warnf("Scene::createRevoluteJoint() - Cannot create joint without at least a single scene object." );
+        return -1;
+    }
+
     // Fetch bodies.
     b2Body* pBodyA = pSceneObjectA != NULL ? pSceneObjectA->getBody() : getGroundBody();
     b2Body* pBodyB = pSceneObjectB != NULL ? pSceneObjectB->getBody() : getGroundBody();
@@ -2141,7 +2136,7 @@ bool Scene::getRevoluteJointMotor(
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createWeldJoint(
+S32 Scene::createWeldJoint(
         const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
         const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
         const F32 frequency,
@@ -2157,6 +2152,13 @@ U32 Scene::createWeldJoint(
         return -1;
     }
 
+    // Check for two invalid objects.
+    if ( pSceneObjectA == NULL && pSceneObjectB == NULL )
+    {
+        Con::warnf("Scene::createWeldJoint() - Cannot create joint without at least a single scene object." );
+        return -1;
+    }
+
     // Fetch bodies.
     b2Body* pBodyA = pSceneObjectA != NULL ? pSceneObjectA->getBody() : getGroundBody();
     b2Body* pBodyB = pSceneObjectB != NULL ? pSceneObjectB->getBody() : getGroundBody();
@@ -2292,7 +2294,7 @@ F32 Scene::getWeldJointDampingRatio( const U32 jointId )
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createWheelJoint(
+S32 Scene::createWheelJoint(
         const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
         const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
         const b2Vec2& worldAxis,
@@ -2307,6 +2309,13 @@ U32 Scene::createWheelJoint(
         return -1;
     }
 
+    // Check for two invalid objects.
+    if ( pSceneObjectA == NULL && pSceneObjectB == NULL )
+    {
+        Con::warnf("Scene::createWheelJoint() - Cannot create joint without at least a single scene object." );
+        return -1;
+    }
+
     // Fetch bodies.
     b2Body* pBodyA = pSceneObjectA != NULL ? pSceneObjectA->getBody() : getGroundBody();
     b2Body* pBodyB = pSceneObjectB != NULL ? pSceneObjectB->getBody() : getGroundBody();
@@ -2507,7 +2516,7 @@ F32 Scene::getWheelJointDampingRatio( const U32 jointId )
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createFrictionJoint(
+S32 Scene::createFrictionJoint(
         const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
         const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
         const F32 maxForce,
@@ -2523,6 +2532,13 @@ U32 Scene::createFrictionJoint(
         return -1;
     }
 
+    // Check for two invalid objects.
+    if ( pSceneObjectA == NULL && pSceneObjectB == NULL )
+    {
+        Con::warnf("Scene::createFrictionJoint() - Cannot create joint without at least a single scene object." );
+        return -1;
+    }
+
     // Fetch bodies.
     b2Body* pBodyA = pSceneObjectA != NULL ? pSceneObjectA->getBody() : getGroundBody();
     b2Body* pBodyB = pSceneObjectB != NULL ? pSceneObjectB->getBody() : getGroundBody();
@@ -2657,7 +2673,7 @@ F32 Scene::getFrictionJointMaxTorque( const U32 jointId )
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createPrismaticJoint(
+S32 Scene::createPrismaticJoint(
         const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
         const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
         const b2Vec2& worldAxis,
@@ -2672,6 +2688,13 @@ U32 Scene::createPrismaticJoint(
         return -1;
     }
 
+    // Check for two invalid objects.
+    if ( pSceneObjectA == NULL && pSceneObjectB == NULL )
+    {
+        Con::warnf("Scene::createPrismaticJoint() - Cannot create joint without at least a single scene object." );
+        return -1;
+    }
+
     // Fetch bodies.
     b2Body* pBodyA = pSceneObjectA != NULL ? pSceneObjectA->getBody() : getGroundBody();
     b2Body* pBodyB = pSceneObjectB != NULL ? pSceneObjectB->getBody() : getGroundBody();
@@ -2826,7 +2849,7 @@ bool Scene::getPrismaticJointMotor(
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createPulleyJoint(
+S32 Scene::createPulleyJoint(
         const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
         const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
         const b2Vec2& worldGroundAnchorA, const b2Vec2& worldGroundAnchorB,
@@ -2843,6 +2866,13 @@ U32 Scene::createPulleyJoint(
         return -1;
     }
 
+    // Check for two invalid objects.
+    if ( pSceneObjectA == NULL && pSceneObjectB == NULL )
+    {
+        Con::warnf("Scene::createPulleyJoint() - Cannot create joint without at least a single scene object." );
+        return -1;
+    }
+
     // Fetch bodies.
     b2Body* pBodyA = pSceneObjectA != NULL ? pSceneObjectA->getBody() : getGroundBody();
     b2Body* pBodyB = pSceneObjectB != NULL ? pSceneObjectB->getBody() : getGroundBody();
@@ -2867,7 +2897,7 @@ U32 Scene::createPulleyJoint(
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createTargetJoint(
+S32 Scene::createTargetJoint(
         const SceneObject* pSceneObject,
         const b2Vec2& worldTarget,
         const F32 maxForce,
@@ -2884,8 +2914,12 @@ U32 Scene::createTargetJoint(
         return -1;
     }
 
-    // Sanity!
-    AssertFatal( pSceneObject != NULL, "Invalid scene object." );
+    // Check for invalid object.
+    if ( pSceneObject == NULL )
+    {
+        Con::warnf("Scene::createPulleyJoint() - Cannot create joint without a scene object." );
+        return -1;
+    }
 
     // Fetch bodies.
     b2Body* pBody = pSceneObject->getBody();
@@ -3144,7 +3178,7 @@ F32 Scene::getTargetJointDampingRatio( const U32 jointId )
 
 //-----------------------------------------------------------------------------
 
-U32 Scene::createMotorJoint(
+S32 Scene::createMotorJoint(
             const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
             const b2Vec2 linearOffset,
             const F32 angularOffset,
@@ -3162,6 +3196,13 @@ U32 Scene::createMotorJoint(
         return -1;
     }
 
+    // Check for two invalid objects.
+    if ( pSceneObjectA == NULL && pSceneObjectB == NULL )
+    {
+        Con::warnf("Scene::createMotorJoint() - Cannot create joint without at least a single scene object." );
+        return -1;
+    }
+
     // Fetch bodies.
     b2Body* pBodyA = pSceneObjectA != NULL ? pSceneObjectA->getBody() : getGroundBody();
     b2Body* pBodyB = pSceneObjectB != NULL ? pSceneObjectB->getBody() : getGroundBody();
@@ -3665,10 +3706,55 @@ void Scene::SayGoodbye( b2Joint* pJoint )
 
 //-----------------------------------------------------------------------------
 
-void Scene::SayGoodbye( b2Fixture* pFixture )
+SceneObject* Scene::create( const char* pType )
 {
-    // The scene is not currently interested in tracking fixtures
-    // so we do nothing here for now.
+    // Sanity!
+    AssertFatal( pType != NULL, "Scene::create() - Cannot create a NULL type." );
+
+    // Find the class rep.
+    AbstractClassRep* pClassRep = AbstractClassRep::findClassRep( pType ); 
+
+    // Did we find the type?
+    if ( pClassRep == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Scene::create() - Could not find type '%s' to create.", pType );
+        return NULL;
+    }
+
+    // Find the scene object rep.
+    AbstractClassRep* pSceneObjectRep = AbstractClassRep::findClassRep( "SceneObject" ); 
+
+    // Sanity!
+    AssertFatal( pSceneObjectRep != NULL,  "Scene::create() - Could not find SceneObject class rep." );
+
+    // Is the type derived from scene object?
+    if ( !pClassRep->isClass( pSceneObjectRep ) )
+    {
+        // No, so warn.
+        Con::warnf( "Scene::create() - Type '%s' is not derived from SceneObject.", pType );
+        return NULL;
+    }
+    
+    // Create the type.
+    SceneObject* pSceneObject = dynamic_cast<SceneObject*>( pClassRep->create() );
+
+    // Sanity!
+    AssertFatal( pSceneObject != NULL, "Scene::create() - Failed to create type via class rep." );
+
+    // Attempt to register the object.
+    if ( !pSceneObject->registerObject() )
+    {
+        // No, so warn.
+        Con::warnf( "Scene::create() - Failed to register type '%s'.", pType );
+        delete pSceneObject;
+        return NULL;
+    }
+
+    // Add to the scene.
+    addToScene( pSceneObject );
+
+    return pSceneObject;
 }
 
 //-----------------------------------------------------------------------------
@@ -4460,8 +4546,8 @@ void Scene::onTamlPostRead( const TamlCustomNodes& customNodes )
     // Do we have any controllers?
     if ( pControllerNode != NULL )
     {
-		// Yes, so fetch the scene controllers.
-		SimSet* pControllerSet = getControllers();
+        // Yes, so fetch the scene controllers.
+        SimSet* pControllerSet = getControllers();
 
         // Fetch children controller nodes.
         const TamlCustomNodeVector& controllerChildren = pControllerNode->getChildren();
@@ -4511,442 +4597,442 @@ void Scene::onTamlCustomWrite( TamlCustomNodes& customNodes )
 
     // Do we have any joints?
     if ( jointCount > 0 )
-	{
-		// Yes, so add joint custom node.
-		TamlCustomNode* pJointCustomNode = customNodes.addNode( jointCustomNodeName );
-
-		// Iterate joints.
-		for( typeJointHash::iterator jointItr = mJoints.begin(); jointItr != mJoints.end(); ++jointItr )
-		{
-			// Fetch base joint.
-			b2Joint* pBaseJoint = jointItr->value;
-
-			// Add joint node.
-			// NOTE:    The name of the node will get updated shortly.
-			TamlCustomNode* pJointNode = pJointCustomNode->addNode( StringTable->EmptyString );
-
-			// Fetch common details.
-			b2Body* pBodyA = pBaseJoint->GetBodyA();
-			b2Body* pBodyB = pBaseJoint->GetBodyB();
-
-			// Fetch physics proxies.
-			PhysicsProxy* pPhysicsProxyA = static_cast<PhysicsProxy*>(pBodyA->GetUserData());
-			PhysicsProxy* pPhysicsProxyB = static_cast<PhysicsProxy*>(pBodyB->GetUserData());
-
-			// Fetch physics proxy type.
-			PhysicsProxy::ePhysicsProxyType proxyTypeA = static_cast<PhysicsProxy*>(pBodyA->GetUserData())->getPhysicsProxyType();
-			PhysicsProxy::ePhysicsProxyType proxyTypeB = static_cast<PhysicsProxy*>(pBodyB->GetUserData())->getPhysicsProxyType();
-
-			// Fetch scene objects.
-			SceneObject* pSceneObjectA = proxyTypeA == PhysicsProxy::PHYSIC_PROXY_SCENEOBJECT ? static_cast<SceneObject*>(pPhysicsProxyA) : NULL;
-			SceneObject* pSceneObjectB = proxyTypeB == PhysicsProxy::PHYSIC_PROXY_SCENEOBJECT ? static_cast<SceneObject*>(pPhysicsProxyB) : NULL;
-
-			// Populate joint appropriately.
-			switch( pBaseJoint->GetType() )
-			{
-				case e_distanceJoint:
-					{
-						// Set joint name.
+    {
+        // Yes, so add joint custom node.
+        TamlCustomNode* pJointCustomNode = customNodes.addNode( jointCustomNodeName );
+
+        // Iterate joints.
+        for( typeJointHash::iterator jointItr = mJoints.begin(); jointItr != mJoints.end(); ++jointItr )
+        {
+            // Fetch base joint.
+            b2Joint* pBaseJoint = jointItr->value;
+
+            // Add joint node.
+            // NOTE:    The name of the node will get updated shortly.
+            TamlCustomNode* pJointNode = pJointCustomNode->addNode( StringTable->EmptyString );
+
+            // Fetch common details.
+            b2Body* pBodyA = pBaseJoint->GetBodyA();
+            b2Body* pBodyB = pBaseJoint->GetBodyB();
+
+            // Fetch physics proxies.
+            PhysicsProxy* pPhysicsProxyA = static_cast<PhysicsProxy*>(pBodyA->GetUserData());
+            PhysicsProxy* pPhysicsProxyB = static_cast<PhysicsProxy*>(pBodyB->GetUserData());
+
+            // Fetch physics proxy type.
+            PhysicsProxy::ePhysicsProxyType proxyTypeA = static_cast<PhysicsProxy*>(pBodyA->GetUserData())->getPhysicsProxyType();
+            PhysicsProxy::ePhysicsProxyType proxyTypeB = static_cast<PhysicsProxy*>(pBodyB->GetUserData())->getPhysicsProxyType();
+
+            // Fetch scene objects.
+            SceneObject* pSceneObjectA = proxyTypeA == PhysicsProxy::PHYSIC_PROXY_SCENEOBJECT ? static_cast<SceneObject*>(pPhysicsProxyA) : NULL;
+            SceneObject* pSceneObjectB = proxyTypeB == PhysicsProxy::PHYSIC_PROXY_SCENEOBJECT ? static_cast<SceneObject*>(pPhysicsProxyB) : NULL;
+
+            // Populate joint appropriately.
+            switch( pBaseJoint->GetType() )
+            {
+                case e_distanceJoint:
+                    {
+                        // Set joint name.
                         pJointNode->setNodeName( jointDistanceNodeName );
 
-						// Fetch joint.
-						const b2DistanceJoint* pJoint = dynamic_cast<const b2DistanceJoint*>( pBaseJoint );
+                        // Fetch joint.
+                        const b2DistanceJoint* pJoint = dynamic_cast<const b2DistanceJoint*>( pBaseJoint );
 
-						// Sanity!
-						AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid distance joint type returned." );
+                        // Sanity!
+                        AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid distance joint type returned." );
 
-						// Add length.
-						pJointNode->addField( jointDistanceLengthName, pJoint->GetLength() );
+                        // Add length.
+                        pJointNode->addField( jointDistanceLengthName, pJoint->GetLength() );
 
-						// Add frequency.
-						if ( mNotZero( pJoint->GetFrequency() ) )
-							pJointNode->addField( jointDistanceFrequencyName, pJoint->GetFrequency() );
+                        // Add frequency.
+                        if ( mNotZero( pJoint->GetFrequency() ) )
+                            pJointNode->addField( jointDistanceFrequencyName, pJoint->GetFrequency() );
 
-						// Add damping ratio.
-						if ( mNotZero( pJoint->GetDampingRatio() ) )
-							pJointNode->addField( jointDistanceDampingRatioName, pJoint->GetDampingRatio() );
+                        // Add damping ratio.
+                        if ( mNotZero( pJoint->GetDampingRatio() ) )
+                            pJointNode->addField( jointDistanceDampingRatioName, pJoint->GetDampingRatio() );
 
-						// Add local anchors.
-						if ( mNotZero( pJoint->GetLocalAnchorA().LengthSquared() ) )
-							pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
-						if ( mNotZero( pJoint->GetLocalAnchorB().LengthSquared() ) )
-							pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
+                        // Add local anchors.
+                        if ( mNotZero( pJoint->GetLocalAnchorA().LengthSquared() ) )
+                            pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
+                        if ( mNotZero( pJoint->GetLocalAnchorB().LengthSquared() ) )
+                            pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
 
-						// Add scene object bodies.
-						if ( pSceneObjectA != NULL )
+                        // Add scene object bodies.
+                        if ( pSceneObjectA != NULL )
                             pJointNode->addNode( pSceneObjectA );
 
-						if ( pSceneObjectB != NULL )
+                        if ( pSceneObjectB != NULL )
                             pJointNode->addNode( pSceneObjectB );
-					}
-					break;
+                    }
+                    break;
 
-				case e_ropeJoint:
-					{
-						// Set joint name.
-						pJointNode->setNodeName( jointRopeNodeName );
+                case e_ropeJoint:
+                    {
+                        // Set joint name.
+                        pJointNode->setNodeName( jointRopeNodeName );
 
-						// Fetch joint.
-						const b2RopeJoint* pJoint = dynamic_cast<const b2RopeJoint*>( pBaseJoint );
+                        // Fetch joint.
+                        const b2RopeJoint* pJoint = dynamic_cast<const b2RopeJoint*>( pBaseJoint );
 
-						// Sanity!
-						AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid rope joint type returned." );
+                        // Sanity!
+                        AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid rope joint type returned." );
 
-						// Add max length.
-						if ( mNotZero( pJoint->GetMaxLength() ) )
-							pJointNode->addField( jointRopeMaxLengthName, pJoint->GetMaxLength() );
+                        // Add max length.
+                        if ( mNotZero( pJoint->GetMaxLength() ) )
+                            pJointNode->addField( jointRopeMaxLengthName, pJoint->GetMaxLength() );
 
-						// Add local anchors.
-						if ( mNotZero( pJoint->GetLocalAnchorA().LengthSquared() ) )
-							pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
-						if ( mNotZero( pJoint->GetLocalAnchorB().LengthSquared() ) )
-							pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
+                        // Add local anchors.
+                        if ( mNotZero( pJoint->GetLocalAnchorA().LengthSquared() ) )
+                            pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
+                        if ( mNotZero( pJoint->GetLocalAnchorB().LengthSquared() ) )
+                            pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
 
-						// Add scene object bodies.
-						if ( pSceneObjectA != NULL )
+                        // Add scene object bodies.
+                        if ( pSceneObjectA != NULL )
                             pJointNode->addNode( pSceneObjectA );
 
-						if ( pSceneObjectB != NULL )
+                        if ( pSceneObjectB != NULL )
                             pJointNode->addNode( pSceneObjectB );
-					}
-					break;
-
-				case e_revoluteJoint:
-					{
-						// Set join name.
-						pJointNode->setNodeName( jointRevoluteNodeName );
-
-						// Fetch joint.
-						const b2RevoluteJoint* pJoint = dynamic_cast<const b2RevoluteJoint*>( pBaseJoint );
-
-						// Sanity!
-						AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid revolute joint type returned." );
-
-						// Add limit.
-						if ( pJoint->IsLimitEnabled() )
-						{
-							// Add limits.
-							pJointNode->addField( jointRevoluteLimitLowerAngleName, mRadToDeg(pJoint->GetLowerLimit()) );
-							pJointNode->addField( jointRevoluteLimitUpperAngleName, mRadToDeg(pJoint->GetUpperLimit()) );
-						}
-
-						// Add motor.
-						if ( pJoint->IsMotorEnabled() )
-						{
-							// Add motor.
-							pJointNode->addField( jointRevoluteMotorSpeedName, mRadToDeg(pJoint->GetMotorSpeed()) );
-							pJointNode->addField( jointRevoluteMotorMaxTorqueName, pJoint->GetMaxMotorTorque() );
-						}
-
-						// Add local anchors.
-						if ( mNotZero( pJoint->GetLocalAnchorA().LengthSquared() ) )
-							pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
-						if ( mNotZero( pJoint->GetLocalAnchorB().LengthSquared() ) )
-							pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
-
-						// Add scene object bodies.
-						if ( pSceneObjectA != NULL )
+                    }
+                    break;
+
+                case e_revoluteJoint:
+                    {
+                        // Set join name.
+                        pJointNode->setNodeName( jointRevoluteNodeName );
+
+                        // Fetch joint.
+                        const b2RevoluteJoint* pJoint = dynamic_cast<const b2RevoluteJoint*>( pBaseJoint );
+
+                        // Sanity!
+                        AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid revolute joint type returned." );
+
+                        // Add limit.
+                        if ( pJoint->IsLimitEnabled() )
+                        {
+                            // Add limits.
+                            pJointNode->addField( jointRevoluteLimitLowerAngleName, mRadToDeg(pJoint->GetLowerLimit()) );
+                            pJointNode->addField( jointRevoluteLimitUpperAngleName, mRadToDeg(pJoint->GetUpperLimit()) );
+                        }
+
+                        // Add motor.
+                        if ( pJoint->IsMotorEnabled() )
+                        {
+                            // Add motor.
+                            pJointNode->addField( jointRevoluteMotorSpeedName, mRadToDeg(pJoint->GetMotorSpeed()) );
+                            pJointNode->addField( jointRevoluteMotorMaxTorqueName, pJoint->GetMaxMotorTorque() );
+                        }
+
+                        // Add local anchors.
+                        if ( mNotZero( pJoint->GetLocalAnchorA().LengthSquared() ) )
+                            pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
+                        if ( mNotZero( pJoint->GetLocalAnchorB().LengthSquared() ) )
+                            pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
+
+                        // Add scene object bodies.
+                        if ( pSceneObjectA != NULL )
                             pJointNode->addNode( pSceneObjectA );
 
-						if ( pSceneObjectB != NULL )
+                        if ( pSceneObjectB != NULL )
                             pJointNode->addNode( pSceneObjectB );
-					}
-					break;
+                    }
+                    break;
 
-				case e_weldJoint:
-					{
-						// Set joint name.
-						pJointNode->setNodeName( jointWeldNodeName );
+                case e_weldJoint:
+                    {
+                        // Set joint name.
+                        pJointNode->setNodeName( jointWeldNodeName );
 
-						// Fetch joint.
-						const b2WeldJoint* pJoint = dynamic_cast<const b2WeldJoint*>( pBaseJoint );
+                        // Fetch joint.
+                        const b2WeldJoint* pJoint = dynamic_cast<const b2WeldJoint*>( pBaseJoint );
 
-						// Sanity!
-						AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid weld joint type returned." );
+                        // Sanity!
+                        AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid weld joint type returned." );
 
-						// Add frequency.
-						if ( mNotZero( pJoint->GetFrequency() ) )
-							pJointNode->addField( jointWeldFrequencyName, pJoint->GetFrequency() );
+                        // Add frequency.
+                        if ( mNotZero( pJoint->GetFrequency() ) )
+                            pJointNode->addField( jointWeldFrequencyName, pJoint->GetFrequency() );
 
-						// Add damping ratio.
-						if ( mNotZero( pJoint->GetDampingRatio() ) )
-							pJointNode->addField( jointWeldDampingRatioName, pJoint->GetDampingRatio() );
+                        // Add damping ratio.
+                        if ( mNotZero( pJoint->GetDampingRatio() ) )
+                            pJointNode->addField( jointWeldDampingRatioName, pJoint->GetDampingRatio() );
 
-						// Add local anchors.
-						if ( mNotZero( pJoint->GetLocalAnchorA().LengthSquared() ) )
-							pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
-						if ( mNotZero( pJoint->GetLocalAnchorB().LengthSquared() ) )
-							pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
+                        // Add local anchors.
+                        if ( mNotZero( pJoint->GetLocalAnchorA().LengthSquared() ) )
+                            pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
+                        if ( mNotZero( pJoint->GetLocalAnchorB().LengthSquared() ) )
+                            pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
 
-						// Add scene object bodies.
-						if ( pSceneObjectA != NULL )
+                        // Add scene object bodies.
+                        if ( pSceneObjectA != NULL )
                             pJointNode->addNode( pSceneObjectA );
 
-						if ( pSceneObjectB != NULL )
+                        if ( pSceneObjectB != NULL )
                             pJointNode->addNode( pSceneObjectB );
-					}
-					break;
+                    }
+                    break;
 
-				case e_wheelJoint:
-					{
-						// Set joint name.
-						pJointNode->setNodeName( jointWheelNodeName );
+                case e_wheelJoint:
+                    {
+                        // Set joint name.
+                        pJointNode->setNodeName( jointWheelNodeName );
 
-						// Fetch joint.
-						b2WheelJoint* pJoint = dynamic_cast<b2WheelJoint*>( pBaseJoint );
+                        // Fetch joint.
+                        b2WheelJoint* pJoint = dynamic_cast<b2WheelJoint*>( pBaseJoint );
 
-						// Sanity!
-						AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid wheel joint type returned." );
+                        // Sanity!
+                        AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid wheel joint type returned." );
 
-						// Add motor.
-						if ( pJoint->IsMotorEnabled() )
-						{
-							// Add motor.
-							pJointNode->addField( jointWheelMotorSpeedName, mRadToDeg(pJoint->GetMotorSpeed()) );
-							pJointNode->addField( jointWheelMotorMaxTorqueName, pJoint->GetMaxMotorTorque() );
-						}
+                        // Add motor.
+                        if ( pJoint->IsMotorEnabled() )
+                        {
+                            // Add motor.
+                            pJointNode->addField( jointWheelMotorSpeedName, mRadToDeg(pJoint->GetMotorSpeed()) );
+                            pJointNode->addField( jointWheelMotorMaxTorqueName, pJoint->GetMaxMotorTorque() );
+                        }
 
-						// Add frequency.
-						if ( mNotZero( pJoint->GetSpringFrequencyHz() ) )
-							pJointNode->addField( jointWheelFrequencyName, pJoint->GetSpringFrequencyHz() );
+                        // Add frequency.
+                        if ( mNotZero( pJoint->GetSpringFrequencyHz() ) )
+                            pJointNode->addField( jointWheelFrequencyName, pJoint->GetSpringFrequencyHz() );
 
-						// Add damping ratio.
-						if ( mNotZero( pJoint->GetSpringDampingRatio() ) )
-							pJointNode->addField( jointWheelDampingRatioName, pJoint->GetSpringDampingRatio() );
+                        // Add damping ratio.
+                        if ( mNotZero( pJoint->GetSpringDampingRatio() ) )
+                            pJointNode->addField( jointWheelDampingRatioName, pJoint->GetSpringDampingRatio() );
 
-						// Add world axis.
-						pJointNode->addField( jointWheelWorldAxisName, pJoint->GetBodyA()->GetWorldVector( pJoint->GetLocalAxisA() ) );
+                        // Add world axis.
+                        pJointNode->addField( jointWheelWorldAxisName, pJoint->GetBodyA()->GetWorldVector( pJoint->GetLocalAxisA() ) );
 
-						// Add local anchors.
-						pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
-						pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
+                        // Add local anchors.
+                        pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
+                        pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
 
-						// Add scene object bodies.
-						if ( pSceneObjectA != NULL )
+                        // Add scene object bodies.
+                        if ( pSceneObjectA != NULL )
                             pJointNode->addNode( pSceneObjectA );
 
-						if ( pSceneObjectB != NULL )
+                        if ( pSceneObjectB != NULL )
                             pJointNode->addNode( pSceneObjectB );
-					}
-					break;
+                    }
+                    break;
 
-				case e_frictionJoint:
-					{
-						// Set joint name.
-						pJointNode->setNodeName( jointFrictionNodeName );
+                case e_frictionJoint:
+                    {
+                        // Set joint name.
+                        pJointNode->setNodeName( jointFrictionNodeName );
 
-						// Fetch joint.
-						const b2FrictionJoint* pJoint = dynamic_cast<const b2FrictionJoint*>( pBaseJoint );
+                        // Fetch joint.
+                        const b2FrictionJoint* pJoint = dynamic_cast<const b2FrictionJoint*>( pBaseJoint );
 
-						// Add max force.
-						if ( mNotZero( pJoint->GetMaxForce() ) )
-							pJointNode->addField( jointFrictionMaxForceName, pJoint->GetMaxForce() );
+                        // Add max force.
+                        if ( mNotZero( pJoint->GetMaxForce() ) )
+                            pJointNode->addField( jointFrictionMaxForceName, pJoint->GetMaxForce() );
 
-						// Add max torque.
-						if ( mNotZero( pJoint->GetMaxTorque() ) )
-							pJointNode->addField( jointFrictionMaxTorqueName, pJoint->GetMaxTorque() );
+                        // Add max torque.
+                        if ( mNotZero( pJoint->GetMaxTorque() ) )
+                            pJointNode->addField( jointFrictionMaxTorqueName, pJoint->GetMaxTorque() );
 
-						// Sanity!
-						AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid friction joint type returned." );
+                        // Sanity!
+                        AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid friction joint type returned." );
 
-						// Add local anchors.
-						if ( mNotZero( pJoint->GetLocalAnchorA().LengthSquared() ) )
-							pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
-						if ( mNotZero( pJoint->GetLocalAnchorB().LengthSquared() ) )
-							pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
+                        // Add local anchors.
+                        if ( mNotZero( pJoint->GetLocalAnchorA().LengthSquared() ) )
+                            pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
+                        if ( mNotZero( pJoint->GetLocalAnchorB().LengthSquared() ) )
+                            pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
 
-						// Add scene object bodies.
-						if ( pSceneObjectA != NULL )
+                        // Add scene object bodies.
+                        if ( pSceneObjectA != NULL )
                             pJointNode->addNode( pSceneObjectA );
 
-						if ( pSceneObjectB != NULL )
+                        if ( pSceneObjectB != NULL )
                             pJointNode->addNode( pSceneObjectB );
-					}
-					break;
-
-				case e_prismaticJoint:
-					{
-						// Set joint name.
-						pJointNode->setNodeName( jointPrismaticNodeName );
-
-						// Fetch joint.
-						b2PrismaticJoint* pJoint = dynamic_cast<b2PrismaticJoint*>( pBaseJoint );
-
-						// Sanity!
-						AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid prismatic joint type returned." );
-
-						// Add limit.
-						if ( pJoint->IsLimitEnabled() )
-						{
-							// Add limits.
-							pJointNode->addField( jointPrismaticLimitLowerTransName, pJoint->GetLowerLimit() );
-							pJointNode->addField( jointPrismaticLimitUpperTransName, pJoint->GetUpperLimit() );
-						}
-
-						// Add motor.
-						if ( pJoint->IsMotorEnabled() )
-						{
-							// Add motor.
-							pJointNode->addField( jointPrismaticMotorSpeedName, mRadToDeg(pJoint->GetMotorSpeed()) );
-							pJointNode->addField( jointPrismaticMotorMaxForceName, pJoint->GetMaxMotorForce() );
-						}
-
-						// Add world axis.
-						pJointNode->addField( jointPrismaticWorldAxisName, pJoint->GetBodyA()->GetWorldVector( pJoint->GetLocalAxisA() ) );
-
-						// Add local anchors.
-						pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
-						pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
-
-						// Add scene object bodies.
-						if ( pSceneObjectA != NULL )
+                    }
+                    break;
+
+                case e_prismaticJoint:
+                    {
+                        // Set joint name.
+                        pJointNode->setNodeName( jointPrismaticNodeName );
+
+                        // Fetch joint.
+                        b2PrismaticJoint* pJoint = dynamic_cast<b2PrismaticJoint*>( pBaseJoint );
+
+                        // Sanity!
+                        AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid prismatic joint type returned." );
+
+                        // Add limit.
+                        if ( pJoint->IsLimitEnabled() )
+                        {
+                            // Add limits.
+                            pJointNode->addField( jointPrismaticLimitLowerTransName, pJoint->GetLowerLimit() );
+                            pJointNode->addField( jointPrismaticLimitUpperTransName, pJoint->GetUpperLimit() );
+                        }
+
+                        // Add motor.
+                        if ( pJoint->IsMotorEnabled() )
+                        {
+                            // Add motor.
+                            pJointNode->addField( jointPrismaticMotorSpeedName, mRadToDeg(pJoint->GetMotorSpeed()) );
+                            pJointNode->addField( jointPrismaticMotorMaxForceName, pJoint->GetMaxMotorForce() );
+                        }
+
+                        // Add world axis.
+                        pJointNode->addField( jointPrismaticWorldAxisName, pJoint->GetBodyA()->GetWorldVector( pJoint->GetLocalAxisA() ) );
+
+                        // Add local anchors.
+                        pJointNode->addField( jointLocalAnchorAName, pJoint->GetLocalAnchorA() );
+                        pJointNode->addField( jointLocalAnchorBName, pJoint->GetLocalAnchorB() );
+
+                        // Add scene object bodies.
+                        if ( pSceneObjectA != NULL )
                             pJointNode->addNode( pSceneObjectA );
 
-						if ( pSceneObjectB != NULL )
+                        if ( pSceneObjectB != NULL )
                             pJointNode->addNode( pSceneObjectB );
-					}
-					break;
+                    }
+                    break;
 
-				case e_pulleyJoint:
-					{
-						// Set joint name.
-						pJointNode->setNodeName( jointPulleyNodeName );
+                case e_pulleyJoint:
+                    {
+                        // Set joint name.
+                        pJointNode->setNodeName( jointPulleyNodeName );
 
-						// Fetch joint.
-						b2PulleyJoint* pJoint = dynamic_cast<b2PulleyJoint*>( pBaseJoint );
+                        // Fetch joint.
+                        b2PulleyJoint* pJoint = dynamic_cast<b2PulleyJoint*>( pBaseJoint );
 
-						// Sanity!
-						AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid pulley joint type returned." );
+                        // Sanity!
+                        AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid pulley joint type returned." );
 
-						// Add lengths.
-						pJointNode->addField( jointPulleyLengthAName, pJoint->GetLengthA() );
-						pJointNode->addField( jointPulleyLengthBName, pJoint->GetLengthB() );
+                        // Add lengths.
+                        pJointNode->addField( jointPulleyLengthAName, pJoint->GetLengthA() );
+                        pJointNode->addField( jointPulleyLengthBName, pJoint->GetLengthB() );
 
-						// Add ratio,
-						pJointNode->addField( jointPulleyRatioName, pJoint->GetRatio() );
+                        // Add ratio,
+                        pJointNode->addField( jointPulleyRatioName, pJoint->GetRatio() );
 
-						// Add ground anchors.
-						pJointNode->addField( jointPulleyGroundAnchorAName, pJoint->GetGroundAnchorA() );
-						pJointNode->addField( jointPulleyGroundAnchorBName, pJoint->GetGroundAnchorB() );
+                        // Add ground anchors.
+                        pJointNode->addField( jointPulleyGroundAnchorAName, pJoint->GetGroundAnchorA() );
+                        pJointNode->addField( jointPulleyGroundAnchorBName, pJoint->GetGroundAnchorB() );
 
-						// Add local anchors.
-						pJointNode->addField( jointLocalAnchorAName, pJoint->GetBodyA()->GetLocalPoint( pJoint->GetAnchorA() ) );
-						pJointNode->addField( jointLocalAnchorBName, pJoint->GetBodyB()->GetLocalPoint( pJoint->GetAnchorB() ) );
+                        // Add local anchors.
+                        pJointNode->addField( jointLocalAnchorAName, pJoint->GetBodyA()->GetLocalPoint( pJoint->GetAnchorA() ) );
+                        pJointNode->addField( jointLocalAnchorBName, pJoint->GetBodyB()->GetLocalPoint( pJoint->GetAnchorB() ) );
 
-						// Add scene object bodies.
-						if ( pSceneObjectA != NULL )
+                        // Add scene object bodies.
+                        if ( pSceneObjectA != NULL )
                             pJointNode->addNode( pSceneObjectA );
 
-						if ( pSceneObjectB != NULL )
+                        if ( pSceneObjectB != NULL )
                             pJointNode->addNode( pSceneObjectB );
-					}
-					break;
+                    }
+                    break;
 
-				case e_mouseJoint:
-					{
-						// Set joint name.
-						pJointNode->setNodeName( jointTargetNodeName );
+                case e_mouseJoint:
+                    {
+                        // Set joint name.
+                        pJointNode->setNodeName( jointTargetNodeName );
 
-						// Fetch joint.
-						const b2MouseJoint* pJoint = dynamic_cast<const b2MouseJoint*>( pBaseJoint );
+                        // Fetch joint.
+                        const b2MouseJoint* pJoint = dynamic_cast<const b2MouseJoint*>( pBaseJoint );
 
-						// Sanity!
-						AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid target joint type returned." );
+                        // Sanity!
+                        AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid target joint type returned." );
 
-						// Add target.
-						pJointNode->addField( jointTargetWorldTargetName, pJoint->GetTarget() );
+                        // Add target.
+                        pJointNode->addField( jointTargetWorldTargetName, pJoint->GetTarget() );
 
-						// Add max force.
-						pJointNode->addField( jointTargetMaxForceName, pJoint->GetMaxForce() );
+                        // Add max force.
+                        pJointNode->addField( jointTargetMaxForceName, pJoint->GetMaxForce() );
 
-						// Add frequency
-						pJointNode->addField( jointTargetFrequencyName, pJoint->GetFrequency() );
+                        // Add frequency
+                        pJointNode->addField( jointTargetFrequencyName, pJoint->GetFrequency() );
 
-						// Add damping ratio.
-						pJointNode->addField( jointTargetDampingRatioName, pJoint->GetDampingRatio() );
+                        // Add damping ratio.
+                        pJointNode->addField( jointTargetDampingRatioName, pJoint->GetDampingRatio() );
 
-						// Add body.
-						// NOTE: This joint uses BODYB as the object, BODYA is the ground-body however for easy of use
-						// we'll refer to this as OBJECTA in the persisted format.
-						if ( pSceneObjectB != NULL )
+                        // Add body.
+                        // NOTE: This joint uses BODYB as the object, BODYA is the ground-body however for easy of use
+                        // we'll refer to this as OBJECTA in the persisted format.
+                        if ( pSceneObjectB != NULL )
                             pJointNode->addNode( pSceneObjectB );
-					}
-					break;
+                    }
+                    break;
 
-				case e_motorJoint:
-					{
-						// Set joint name.
-						pJointNode->setNodeName( jointMotorNodeName );
+                case e_motorJoint:
+                    {
+                        // Set joint name.
+                        pJointNode->setNodeName( jointMotorNodeName );
 
-						// Fetch joint.
-						const b2MotorJoint* pJoint = dynamic_cast<const b2MotorJoint*>( pBaseJoint );
+                        // Fetch joint.
+                        const b2MotorJoint* pJoint = dynamic_cast<const b2MotorJoint*>( pBaseJoint );
 
-						// Sanity!
-						AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid motor joint type returned." );
+                        // Sanity!
+                        AssertFatal( pJoint != NULL, "Scene::onTamlCustomWrite() - Invalid motor joint type returned." );
 
-						// Add linear offset.
-						if ( mNotZero( pJoint->GetLinearOffset().LengthSquared() ) )
-							pJointNode->addField( jointMotorLinearOffsetName, pJoint->GetLinearOffset() );
+                        // Add linear offset.
+                        if ( mNotZero( pJoint->GetLinearOffset().LengthSquared() ) )
+                            pJointNode->addField( jointMotorLinearOffsetName, pJoint->GetLinearOffset() );
 
-						// Add angular offset.
-						if ( mNotZero( pJoint->GetAngularOffset() ) )
-							pJointNode->addField( jointMotorAngularOffsetName, mRadToDeg( pJoint->GetAngularOffset() ) );
+                        // Add angular offset.
+                        if ( mNotZero( pJoint->GetAngularOffset() ) )
+                            pJointNode->addField( jointMotorAngularOffsetName, mRadToDeg( pJoint->GetAngularOffset() ) );
 
-						// Add max force.
-						pJointNode->addField( jointMotorMaxForceName, pJoint->GetMaxForce() );
+                        // Add max force.
+                        pJointNode->addField( jointMotorMaxForceName, pJoint->GetMaxForce() );
 
-						// Add max torque.
-						pJointNode->addField( jointMotorMaxTorqueName, pJoint->GetMaxTorque() );
+                        // Add max torque.
+                        pJointNode->addField( jointMotorMaxTorqueName, pJoint->GetMaxTorque() );
 
-						// Add correction factor.
-						pJointNode->addField( jointMotorCorrectionFactorName, pJoint->GetCorrectionFactor() );
+                        // Add correction factor.
+                        pJointNode->addField( jointMotorCorrectionFactorName, pJoint->GetCorrectionFactor() );
 
-						// Add scene object bodies.
-						if ( pSceneObjectA != NULL )
+                        // Add scene object bodies.
+                        if ( pSceneObjectA != NULL )
                             pJointNode->addNode( pSceneObjectA );
 
-						if ( pSceneObjectB != NULL )
+                        if ( pSceneObjectB != NULL )
                             pJointNode->addNode( pSceneObjectB );
-					}
-					break;
-
-			default:
-				// Sanity!
-				AssertFatal( false, "Scene::onTamlCustomWrite() - Unknown joint type detected." );
-			}
-
-			// Add collide connected flag.
-			if ( pBaseJoint->GetCollideConnected() )
-				pJointNode->addField( jointCollideConnectedName, pBaseJoint->GetCollideConnected() );
-		}
-	}
-
-	// Fetch controller count.
-	const S32 sceneControllerCount = getControllers() ? getControllers()->size() : 0;
-	
-	// Do we have any scene controllers?
-	if ( sceneControllerCount > 0 )
-	{
-		// Yes, so add controller node.
+                    }
+                    break;
+
+            default:
+                // Sanity!
+                AssertFatal( false, "Scene::onTamlCustomWrite() - Unknown joint type detected." );
+            }
+
+            // Add collide connected flag.
+            if ( pBaseJoint->GetCollideConnected() )
+                pJointNode->addField( jointCollideConnectedName, pBaseJoint->GetCollideConnected() );
+        }
+    }
+
+    // Fetch controller count.
+    const S32 sceneControllerCount = getControllers() ? getControllers()->size() : 0;
+    
+    // Do we have any scene controllers?
+    if ( sceneControllerCount > 0 )
+    {
+        // Yes, so add controller node.
         TamlCustomNode* pControllerCustomNode = customNodes.addNode( controllerCustomNodeName );
 
-		// Fetch the scene controllers.
-		SimSet* pControllerSet = getControllers();
+        // Fetch the scene controllers.
+        SimSet* pControllerSet = getControllers();
 
-		// Iterate scene controllers.
-		for( S32 i = 0; i < sceneControllerCount; i++ )
-		{
+        // Iterate scene controllers.
+        for( S32 i = 0; i < sceneControllerCount; i++ )
+        {
             // Fetch the set object.
             SimObject* pSetObject = pControllerSet->at(i);
 
-			// Skip if not a controller.
+            // Skip if not a controller.
             if ( !pSetObject->isType<SceneController*>() )
-				continue;
+                continue;
 
             // Add controller node.
             pControllerCustomNode->addNode( pSetObject );
-		}
-	}
+        }
+    }
 }
 
 //-----------------------------------------------------------------------------

+ 23 - 21
engine/source/2d/scene/Scene.h

@@ -162,8 +162,8 @@ class Scene :
     public virtual Tickable
 {
 public:
-    typedef HashMap<U32, b2Joint*>              typeJointHash;
-    typedef HashMap<U32, U32>                   typeReverseJointHash;
+    typedef HashMap<S32, b2Joint*>              typeJointHash;
+    typedef HashMap<U32, S32>                   typeReverseJointHash;
     typedef Vector<tDeleteRequest>              typeDeleteVector;
     typedef Vector<TickContact>                 typeContactVector;
     typedef HashMap<b2Contact*, TickContact>    typeContactHash;
@@ -219,10 +219,10 @@ private:
     /// Joint access.
     typeJointHash               mJoints;
     typeReverseJointHash        mReverseJoints;
-    U32                         mJointMasterId;
+    S32                         mJointMasterId;
 
-	/// Scene controllers.
-	SimObjectPtr<SimSet>	    mControllers;
+    /// Scene controllers.
+    SimObjectPtr<SimSet>	    mControllers;
 
     /// Scene time.
     F32                         mSceneTime;
@@ -343,7 +343,7 @@ public:
 
     void                    mergeScene( const Scene* pScene );
 
-	inline SimSet*			getControllers( void )						{ return mControllers; }
+    inline SimSet*			getControllers( void )						{ return mControllers; }
 
     /// Scene time.
     inline F32              getSceneTime( void ) const                  { return mSceneTime; };
@@ -352,15 +352,15 @@ public:
 
     /// Joint access.
     inline U32              getJointCount( void ) const                 { return mJoints.size(); }
-    b2JointType             getJointType( const U32 jointId );
-    b2Joint*                findJoint( const U32 jointId );
-    U32                     findJointId( b2Joint* pJoint );
-    U32                     createJoint( b2JointDef* pJointDef );
+    b2JointType             getJointType( const S32 jointId );
+    b2Joint*                findJoint( const S32 jointId );
+    S32                     findJointId( b2Joint* pJoint );
+    S32                     createJoint( b2JointDef* pJointDef );
     bool                    deleteJoint( const U32 jointId );
     bool                    hasJoints( SceneObject* pSceneObject );
 
     /// Distance joint.
-    U32                     createDistanceJoint(
+    S32                     createDistanceJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const F32 length = -1.0f,
@@ -387,7 +387,7 @@ public:
     F32                     getDistanceJointDampingRatio( const U32 jointId );
 
     /// Rope joint.
-    U32                     createRopeJoint(
+    S32                     createRopeJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const F32 maxLength = -1.0f,
@@ -400,7 +400,7 @@ public:
     F32                     getRopeJointMaxLength( const U32 jointId );
 
     /// Revolute joint.
-    U32                     createRevoluteJoint(
+    S32                     createRevoluteJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const bool collideConnected = false );
@@ -427,7 +427,7 @@ public:
                                 F32& motorSpeed,
                                 F32& maxMotorTorque );
     /// Weld joint.
-    U32                     createWeldJoint(
+    S32                     createWeldJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const F32 frequency = 0.0f,
@@ -447,7 +447,7 @@ public:
     F32                     getWeldJointDampingRatio( const U32 jointId );
 
     /// Wheel joint.
-    U32                     createWheelJoint(
+    S32                     createWheelJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
                                 const b2Vec2& worldAxis,
@@ -478,7 +478,7 @@ public:
     F32                     getWheelJointDampingRatio( const U32 jointId );
 
     /// Friction joint.
-    U32                     createFrictionJoint(
+    S32                     createFrictionJoint(
                                 const SceneObject* pSceneObjectA,const  SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const F32 maxForce = 0.0f,
@@ -498,7 +498,7 @@ public:
     F32                     getFrictionJointMaxTorque( const U32 jointId );
 
     /// Prismatic joint.
-    U32                     createPrismaticJoint(
+    S32                     createPrismaticJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
                                 const b2Vec2& worldAxis,
@@ -527,7 +527,7 @@ public:
                                 F32& maxMotorTorque );
 
     /// Pulley joint.
-    U32                     createPulleyJoint(
+    S32                     createPulleyJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
                                 const b2Vec2& worldGroundAnchorA, const b2Vec2& worldGroundAnchorB,
@@ -536,7 +536,7 @@ public:
                                 const bool collideConnected = false );
 
     /// Target (a.k.a Mouse) joint.
-    U32                     createTargetJoint(
+    S32                     createTargetJoint(
                                 const SceneObject* pSceneObject,
                                 const b2Vec2& worldTarget,
                                 const F32 maxForce,
@@ -570,7 +570,7 @@ public:
     F32                     getTargetJointDampingRatio( const U32 jointId );
 
     /// Motor Joint.
-    U32                     createMotorJoint(
+    S32                     createMotorJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2 linearOffset = b2Vec2_zero,
                                 const F32 angularOffset = 0.0f,
@@ -629,7 +629,9 @@ public:
 
     /// Destruction listeners.
     virtual                 void SayGoodbye( b2Joint* pJoint );
-    virtual                 void SayGoodbye( b2Fixture* pFixture );
+    virtual                 void SayGoodbye( b2Fixture* pFixture )      {}
+
+    virtual SceneObject*    create( const char* pType );
 
     /// Miscellaneous.
     inline void             setBatchingEnabled( const bool enabled )    { mBatchRenderer.setBatchEnabled( enabled ); }

+ 90 - 78
engine/source/2d/scene/Scene_ScriptBinding.h

@@ -269,7 +269,7 @@ ConsoleMethod(Scene, mergeScene, void, 3, 3,    "(scene) Merges the specified sc
 //-----------------------------------------------------------------------------
 
 ConsoleMethod(Scene, getControllers, const char*, 2, 2,	"() Gets the Scene Controllers.\n"
-														"@return Gets the scene controllers.")
+                                                        "@return Gets the scene controllers.")
 {
     // Fetch the scene controllers.
     SimSet* pControllerSet = object->getControllers();
@@ -319,7 +319,7 @@ ConsoleMethod(Scene, isJoint, bool, 3, 3,   "(int jointId) Gets whether the join
                                             "@return whether the joint Id is valid or not." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi( argv[2] );
+    const S32 jointId = dAtoi( argv[2] );
 
     return object->findJoint( jointId ) != NULL;
 }                                                                  
@@ -332,7 +332,7 @@ ConsoleMethod(Scene, getJointType, const char*, 3, 3,   "(int jointId) Gets the
                                                                 "@return The type of joint of the specified joint Id." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi( argv[2] );
+    const S32 jointId = dAtoi( argv[2] );
 
     // Fetch joint type.
     const b2JointType jointType = object->getJointType( jointId );
@@ -351,7 +351,7 @@ ConsoleMethod(Scene, deleteJoint, bool, 3, 3,           "(int jointId) Deletes t
                                                                 "@return Whether the joint was successfully deleted or not." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi( argv[2] );
+    const S32 jointId = dAtoi( argv[2] );
 
     return object->deleteJoint( jointId );
 }
@@ -369,9 +369,9 @@ ConsoleMethod(Scene, createDistanceJoint, S32, 4, 12,   "(sceneObjectA, sceneObj
                                                                 "@param collideConnected Whether the scene objects can collide with each other while connected with this joint.\n"
                                                                 "@return The joint Id (-1 if error).")
 {
-	// Fetch scene object references.
-	const char* sceneObjectA = argv[2];
-	const char* sceneObjectB = argv[3];
+    // Fetch scene object references.
+    const char* sceneObjectA = argv[2];
+    const char* sceneObjectB = argv[3];
 
     SceneObject* pSceneObjectA = NULL;
     SceneObject* pSceneObjectB = NULL;
@@ -490,7 +490,7 @@ ConsoleMethod(Scene, setDistanceJointLength, void, 4, 4,    "(jointId, length) S
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 length = dAtof(argv[3]);
@@ -506,7 +506,7 @@ ConsoleMethod(Scene, getDistanceJointLength, F32, 3, 3,     "(jointId) Gets the
                                                                     "@return Returns the distance the joint should maintain between scene objects (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getDistanceJointLength( jointId );
@@ -520,7 +520,7 @@ ConsoleMethod(Scene, setDistanceJointFrequency, void, 4, 4, "(jointId, frequency
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 frequency = dAtof(argv[3]);
@@ -536,7 +536,7 @@ ConsoleMethod(Scene, getDistanceJointFrequency, F32, 3, 3,  "(jointId) Gets the
                                                                     "@return Returns the mass-spring-damper frequency in Hertz (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getDistanceJointFrequency( jointId );
@@ -550,7 +550,7 @@ ConsoleMethod(Scene, setDistanceJointDampingRatio, void, 4, 4,  "(jointId, dampi
                                                                         "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 dampingRatio = dAtof(argv[3]);
@@ -566,7 +566,7 @@ ConsoleMethod(Scene, getDistanceJointDampingRatio, F32, 3, 3,   "(jointId) Gets
                                                                         "@return Returns the damping ratio (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getDistanceJointDampingRatio( jointId );
@@ -583,9 +583,9 @@ ConsoleMethod(Scene, createRopeJoint, S32, 4, 10,       "(sceneObjectA, sceneObj
                                                                 "@param collideConnected Whether the scene objects can collide with each other while connected with this joint.\n"
                                                                 "@return The joint Id (-1 if error).")
 {
-	// Fetch scene object references.
-	const char* sceneObjectA = argv[2];
-	const char* sceneObjectB = argv[3];
+    // Fetch scene object references.
+    const char* sceneObjectA = argv[2];
+    const char* sceneObjectB = argv[3];
 
     SceneObject* pSceneObjectA = NULL;
     SceneObject* pSceneObjectB = NULL;
@@ -688,7 +688,7 @@ ConsoleMethod(Scene, setRopeJointMaxLength, void, 4, 4,     "(jointId, maxLength
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 maxLength = dAtof(argv[3]);
@@ -704,7 +704,7 @@ ConsoleMethod(Scene, getRopeJointMaxLength, F32, 3, 3,     "(jointId) Gets the m
                                                                     "@return Returns the maximum rigid length of the rope (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getRopeJointMaxLength( jointId );
@@ -720,9 +720,9 @@ ConsoleMethod(Scene, createRevoluteJoint, S32, 4, 9,    "(sceneObjectA, sceneObj
                                                                 "@param collideConnected Whether the scene objects can collide with each other while connected with this joint.\n"
                                                                 "@return The joint Id (-1 if error).")
 {
-	// Fetch scene object references.
-	const char* sceneObjectA = argv[2];
-	const char* sceneObjectB = argv[3];
+    // Fetch scene object references.
+    const char* sceneObjectA = argv[2];
+    const char* sceneObjectB = argv[3];
 
     SceneObject* pSceneObjectA = NULL;
     SceneObject* pSceneObjectB = NULL;
@@ -819,7 +819,7 @@ ConsoleMethod(Scene, setRevoluteJointLimit, void, 4, 6,     "(jointId, enableLim
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const bool enableLimit = dAtob(argv[3]);
@@ -837,7 +837,7 @@ ConsoleMethod(Scene, getRevoluteJointLimit, const char*, 3, 3,  "(jointId) Gets
                                                                         "@return Returns whether the joint has angular limits or not and the limits themselves (empty string indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Args.
     bool enableLimit;
@@ -866,7 +866,7 @@ ConsoleMethod(Scene, setRevoluteJointMotor, void, 4, 6,     "(jointId, enableMot
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const bool enableMotor = dAtob(argv[3]);
@@ -884,7 +884,7 @@ ConsoleMethod(Scene, getRevoluteJointMotor, const char*, 3, 3,  "(jointId) Gets
                                                                         "@return Returns whether the joint has a motor or not and the motor settings (empty string indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Args.
     bool enableMotor;
@@ -915,9 +915,9 @@ ConsoleMethod(Scene, createWeldJoint, S32, 4, 11,       "(sceneObjectA, sceneObj
                                                                 "@param collideConnected Whether the scene objects can collide with each other while connected with this joint.\n"
                                                                 "@return The joint Id (-1 if error).")
 {
-	// Fetch scene object references.
-	const char* sceneObjectA = argv[2];
-	const char* sceneObjectB = argv[3];
+    // Fetch scene object references.
+    const char* sceneObjectA = argv[2];
+    const char* sceneObjectB = argv[3];
 
     SceneObject* pSceneObjectA = NULL;
     SceneObject* pSceneObjectB = NULL;
@@ -1028,7 +1028,7 @@ ConsoleMethod(Scene, setWeldJointFrequency, void, 4, 4,     "(jointId, frequency
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 frequency = dAtof(argv[3]);
@@ -1044,7 +1044,7 @@ ConsoleMethod(Scene, getWeldJointFrequency, F32, 3, 3,     "(jointId) Gets the m
                                                                     "@return Returns the mass-spring-damper frequency in Hertz (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getWeldJointFrequency( jointId );
@@ -1058,7 +1058,7 @@ ConsoleMethod(Scene, setWeldJointDampingRatio, void, 4, 4,      "(jointId, dampi
                                                                         "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 dampingRatio = dAtof(argv[3]);
@@ -1074,7 +1074,7 @@ ConsoleMethod(Scene, getWeldJointDampingRatio, F32, 3, 3,       "(jointId) Gets
                                                                         "@return Returns the damping ratio (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getWeldJointDampingRatio( jointId );
@@ -1091,9 +1091,9 @@ ConsoleMethod(Scene, createWheelJoint, S32, 7, 11,      "(sceneObjectA, sceneObj
                                                                 "@param collideConnected Whether the scene objects can collide with each other while connected with this joint.\n"
                                                                 "@return The joint Id (-1 if error).")
 {
-	// Fetch scene object references.
-	const char* sceneObjectA = argv[2];
-	const char* sceneObjectB = argv[3];
+    // Fetch scene object references.
+    const char* sceneObjectA = argv[2];
+    const char* sceneObjectB = argv[3];
 
     SceneObject* pSceneObjectA = NULL;
     SceneObject* pSceneObjectB = NULL;
@@ -1201,7 +1201,7 @@ ConsoleMethod(Scene, setWheelJointMotor, void, 4, 6,        "(jointId, enableMot
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const bool enableMotor = dAtob(argv[3]);
@@ -1219,7 +1219,7 @@ ConsoleMethod(Scene, getWheelJointMotor, const char*, 3, 3, "(jointId) Gets whet
                                                                     "@return Returns whether the joint has a motor or not and the motor settings (empty string indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Args.
     bool enableMotor;
@@ -1246,7 +1246,7 @@ ConsoleMethod(Scene, setWheelJointFrequency, void, 4, 4,    "(jointId, frequency
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 frequency = dAtof(argv[3]);
@@ -1262,7 +1262,7 @@ ConsoleMethod(Scene, getWheelJointFrequency, F32, 3, 3,     "(jointId) Gets the
                                                                     "@return Returns the mass-spring-damper frequency in Hertz (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getWheelJointFrequency( jointId );
@@ -1276,7 +1276,7 @@ ConsoleMethod(Scene, setWheelJointDampingRatio, void, 4, 4,     "(jointId, dampi
                                                                         "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 dampingRatio = dAtof(argv[3]);
@@ -1292,7 +1292,7 @@ ConsoleMethod(Scene, getWheelJointDampingRatio, F32, 3, 3,      "(jointId) Gets
                                                                         "@return Returns the damping ratio (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getWheelJointDampingRatio( jointId );
@@ -1310,9 +1310,9 @@ ConsoleMethod(Scene, createFrictionJoint, S32, 4, 11,   "(sceneObjectA, sceneObj
                                                                 "@param collideConnected Whether the scene objects can collide with each other while connected with this joint.\n"
                                                                 "@return The joint Id (-1 if error).")
 {
-	// Fetch scene object references.
-	const char* sceneObjectA = argv[2];
-	const char* sceneObjectB = argv[3];
+    // Fetch scene object references.
+    const char* sceneObjectA = argv[2];
+    const char* sceneObjectB = argv[3];
 
     SceneObject* pSceneObjectA = NULL;
     SceneObject* pSceneObjectB = NULL;
@@ -1418,7 +1418,7 @@ ConsoleMethod(Scene, setFrictionJointMaxForce, void, 4, 4,  "(jointId, maxForce)
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 maxForce = dAtof(argv[3]);
@@ -1434,7 +1434,7 @@ ConsoleMethod(Scene, getFrictionJointMaxForce, F32, 3, 3,   "(jointId) Sets the
                                                                     "@return Returns the maximum friction force (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getFrictionJointMaxForce( jointId );
@@ -1448,7 +1448,7 @@ ConsoleMethod(Scene, setFrictionJointMaxTorque, void, 4, 4, "(jointId, maxTorque
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 maxTorque = dAtof(argv[3]);
@@ -1464,7 +1464,7 @@ ConsoleMethod(Scene, getFrictionJointMaxTorque, F32, 3, 3,  "(jointId) Gets the
                                                                     "@return Returns the maximum torque force (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getFrictionJointMaxTorque( jointId );
@@ -1481,9 +1481,9 @@ ConsoleMethod(Scene, createPrismaticJoint, S32, 7, 11,  "(sceneObjectA, sceneObj
                                                                 "@param collideConnected Whether the scene objects can collide with each other while connected with this joint.\n"
                                                                 "@return The joint Id (-1 if error).")
 {
-	// Fetch scene object references.
-	const char* sceneObjectA = argv[2];
-	const char* sceneObjectB = argv[3];
+    // Fetch scene object references.
+    const char* sceneObjectA = argv[2];
+    const char* sceneObjectB = argv[3];
 
     SceneObject* pSceneObjectA = NULL;
     SceneObject* pSceneObjectB = NULL;
@@ -1591,7 +1591,7 @@ ConsoleMethod(Scene, setPrismaticJointLimit, void, 4, 6,    "(jointId, enableLim
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const bool enableLimit = dAtob(argv[3]);
@@ -1608,7 +1608,7 @@ ConsoleMethod(Scene, getPrismaticJointLimit, const char*, 3, 3, "(jointId) Gets
                                                                         "@return Returns whether the joint has translational limits or not and the limits themselves (empty string indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Args.
     bool enableLimit;
@@ -1637,7 +1637,7 @@ ConsoleMethod(Scene, setPrismaticJointMotor, void, 4, 6,    "(jointId, enableMot
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const bool enableMotor = dAtob(argv[3]);
@@ -1654,7 +1654,7 @@ ConsoleMethod(Scene, getPrismaticJointMotor, const char*, 3, 3,    "(jointId) Ge
                                                                             "@return Returns whether the joint has a motor or not and the motor settings (empty string indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Args.
     bool enableMotor;
@@ -1688,9 +1688,9 @@ ConsoleMethod(Scene, createPulleyJoint, S32, 9, 16,     "(sceneObjectA, sceneObj
                                                                 "@param collideConnected Whether the scene objects can collide with each other while connected with this joint.\n"
                                                                 "@return The joint Id (-1 if error).")
 {
-	// Fetch scene object references.
-	const char* sceneObjectA = argv[2];
-	const char* sceneObjectB = argv[3];
+    // Fetch scene object references.
+    const char* sceneObjectA = argv[2];
+    const char* sceneObjectB = argv[3];
 
     SceneObject* pSceneObjectA = NULL;
     SceneObject* pSceneObjectB = NULL;
@@ -1824,7 +1824,7 @@ ConsoleMethod(Scene, createTargetJoint, S32, 5, 10,     "(sceneObject, worldTarg
                                                         "@param collideConnected Whether the scene objects can collide with each other while connected with this joint.\n"
                                                         "@return The joint Id (-1 if error).")
 {
-	// Fetch scene object.
+    // Fetch scene object.
     SceneObject* pSceneObject = Sim::findObject<SceneObject>(argv[2]);
 
     // Check scene object.
@@ -1902,7 +1902,7 @@ ConsoleMethod(Scene, setTargetJointTarget, void, 4, 5,      "(jointId, worldTarg
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // World target.
     const U32 worldTargetElementCount = Utility::mGetStringElementCount(argv[3]);
@@ -1934,7 +1934,7 @@ ConsoleMethod(Scene, getTargetJointTarget, const char*, 3, 3,   "(jointId) Gets
                                                                         "@return Returns the target world point for the scene object (always 0,0 if error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     const Vector2 worldTarget = object->getTargetJointTarget( jointId );
@@ -1950,7 +1950,7 @@ ConsoleMethod(Scene, setTargetJointFrequency, void, 4, 4,   "(jointId, frequency
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 frequency = dAtof(argv[3]);
@@ -1966,7 +1966,7 @@ ConsoleMethod(Scene, getTargetJointFrequency, F32, 3, 3,   "(jointId) Gets the m
                                                                     "@return Returns the mass-spring-damper frequency in Hertz (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getTargetJointFrequency( jointId );
@@ -1980,7 +1980,7 @@ ConsoleMethod(Scene, setTargetJointDampingRatio, void, 4, 4,    "(jointId, dampi
                                                                         "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 dampingRatio = dAtof(argv[3]);
@@ -1996,7 +1996,7 @@ ConsoleMethod(Scene, getTargetJointDampingRatio, F32, 3, 3,    "(jointId) Sets t
                                                                         "@return Returns the damping ratio (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getTargetJointDampingRatio( jointId );
@@ -2015,9 +2015,9 @@ ConsoleMethod(Scene, createMotorJoint, S32, 4, 11,      "(sceneObjectA, sceneObj
                                                                 "@param collideConnected Whether the scene objects can collide with each other while connected with this joint.\n"
                                                                 "@return The joint Id (-1 if error).")
 {
-	// Fetch scene object references.
-	const char* sceneObjectA = argv[2];
-	const char* sceneObjectB = argv[3];
+    // Fetch scene object references.
+    const char* sceneObjectA = argv[2];
+    const char* sceneObjectB = argv[3];
 
     SceneObject* pSceneObjectA = NULL;
     SceneObject* pSceneObjectB = NULL;
@@ -2110,7 +2110,7 @@ ConsoleMethod(Scene, setMotorJointLinearOffset, void, 4, 5,     "(jointId, linea
                                                                         "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Linear offset.
     const U32 linearOffsetElementCount = Utility::mGetStringElementCount(argv[3]);
@@ -2142,7 +2142,7 @@ ConsoleMethod(Scene, getMotorJointLinearOffset, const char*, 3, 3,  "(jointId) G
                                                                             "@return Returns the linear offset in sceneObjectA space (always 0,0 if error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     const Vector2 linearOffset = object->getMotorJointLinearOffset( jointId );
@@ -2158,7 +2158,7 @@ ConsoleMethod(Scene, setMotorJointAngularOffset, void, 4, 4,    "(jointId, angul
                                                                         "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 angularOffset = mDegToRad(dAtof(argv[3]));
@@ -2174,7 +2174,7 @@ ConsoleMethod(Scene, getMotorJointAngularOffset, F32, 3, 3,     "(jointId) Gets
                                                                         "@return Returns the angularOffset between the bodies (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return mRadToDeg( object->getMotorJointAngularOffset( jointId ) );
@@ -2188,7 +2188,7 @@ ConsoleMethod(Scene, setMotorJointMaxForce, void, 4, 4,     "(jointId, maxForce)
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 maxForce = dAtof(argv[3]);
@@ -2204,7 +2204,7 @@ ConsoleMethod(Scene, getMotorJointMaxForce, F32, 3, 3,   "(jointId) Sets the max
                                                                     "@return Returns the maximum motor force (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getMotorJointMaxForce( jointId );
@@ -2218,7 +2218,7 @@ ConsoleMethod(Scene, setMotorJointMaxTorque, void, 4, 4, "(jointId, maxTorque) S
                                                                     "@return Returns no value." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Fetch args.
     const F32 maxTorque = dAtof(argv[3]);
@@ -2234,7 +2234,7 @@ ConsoleMethod(Scene, getMotorJointMaxTorque, F32, 3, 3,  "(jointId) Gets the max
                                                                     "@return Returns the maximum motor torque force (-1 indicates error)." )
 {
     // Fetch joint Id.
-    const U32 jointId = dAtoi(argv[2]);
+    const S32 jointId = dAtoi(argv[2]);
 
     // Access joint.
     return object->getMotorJointMaxTorque( jointId );
@@ -3069,8 +3069,20 @@ ConsoleMethod(Scene, getBatchingEnabled, bool, 2, 2,    "() Gets whether render
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(Scene, setIsEditorScene, void, 3, 3, "() Sets whether this is an editor scene\n"
+ConsoleMethod(Scene, setIsEditorScene, void, 3, 3, "() Sets whether this is an editor scene.\n"
                                                             "@return No return value.")
 {
    object->setIsEditorScene(dAtob(argv[2]));
-}
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(Scene, create, const char*, 3, 3, "(type) Creates the specified scene-object derived type and adds it to the scene.\n"
+                                                "@return The scene-object or NULL if not created.")
+{
+    // Create the scene object.
+    SceneObject* pSceneObject = object->create( argv[2] );
+
+    return pSceneObject == NULL ? NULL : pSceneObject->getIdString();
+}
+

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

+ 2 - 6
engine/source/2d/sceneobject/CompositeSprite_ScriptBinding.h

@@ -355,15 +355,11 @@ ConsoleMethod(CompositeSprite, getSpriteImageFrame, S32, 2, 2,  "() - Gets the s
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(CompositeSprite, setSpriteAnimation, void, 3, 4,  "(animationAssetId, [bool autoRestore]) - Sets the sprite animation.\n"
+ConsoleMethod(CompositeSprite, setSpriteAnimation, void, 3, 4,  "(animationAssetId) - Sets the sprite animation.\n"
                                                                 "@param imageAssetId The animation to set the sprite to.\n"
-                                                                "@param autoRestore Whether to restore any previously playing animation or not.\n"
                                                                 "@return No return value." )
 {
-    // Fetch Auto-Restore Flag.
-    const bool autoRestore = (argc >= 4) ? dAtob(argv[3]) : false;
-
-    object->setSpriteAnimation( argv[2], autoRestore );
+    object->setSpriteAnimation( argv[2] );
 }
 
 //-----------------------------------------------------------------------------

+ 28 - 49
engine/source/2d/sceneobject/ParticlePlayer.cc

@@ -55,6 +55,9 @@ void ParticlePlayer::EmitterNode::freeParticle( ParticleSystem::ParticleNode* pP
     // Sanity!
     AssertFatal( mOwner != NULL, "ParticlePlayer::EmitterNode::freeParticle() - Cannot free a particle with a NULL owner." );
 
+    // Deallocate the assets.
+    pParticleNode->mFrameProvider.deallocateAssets();
+
     // Remove the node from the emitter chain.
     pParticleNode->mPreviousNode->mNextNode = pParticleNode->mNextNode;
     pParticleNode->mNextNode->mPreviousNode = pParticleNode->mPreviousNode;
@@ -551,10 +554,10 @@ void ParticlePlayer::sceneRender( const SceneRenderState* pSceneRenderState, con
         const AssetPtr<AnimationAsset>& animationAsset = pParticleAssetEmitter->getAnimationAsset();
 
         // Fetch static mode.
-        const bool isStaticMode = pParticleAssetEmitter->isStaticMode();
+        const bool isStaticFrameProvider = pParticleAssetEmitter->isStaticFrameProvider();
 
         // Are we in static mode?
-        if ( isStaticMode )
+        if ( isStaticFrameProvider )
         {
             // Yes, so skip if no image available.
             if ( imageAsset.isNull() )
@@ -613,26 +616,6 @@ void ParticlePlayer::sceneRender( const SceneRenderState* pSceneRenderState, con
             }
         }
 
-        // Frame texture.
-        TextureHandle frameTexture;
-
-        // Frame area.
-        ImageAsset::FrameArea::TexelArea texelFrameArea;
-
-        // Are we in static mode?
-        if ( isStaticMode )
-        {
-            // Yes, so fetch the frame texture.
-            frameTexture = imageAsset->getImageTexture();
-
-            // Are we using a random image frame?
-            if ( !pParticleAssetEmitter->getRandomImageFrame() )
-            {
-                // No, so fetch frame area.
-                texelFrameArea = imageAsset->getImageFrameArea( pParticleAssetEmitter->getImageFrame() ).mTexelArea;
-            }
-        }
-
         // Fetch the oldest-in-front flag.
         const bool oldestInFront = pParticleAssetEmitter->getOldestInFront();
 
@@ -642,23 +625,17 @@ void ParticlePlayer::sceneRender( const SceneRenderState* pSceneRenderState, con
         // Fetch the particle node head.
         ParticleSystem::ParticleNode* pParticleNodeHead = pEmitterNode->getParticleNodeHead();
 
-        // Process All particle nodes.
+        // Process all particle nodes.
         while ( pParticleNode != pParticleNodeHead )
         {
-            // Are we in static mode are using a random image frame?
-            if ( isStaticMode && pParticleAssetEmitter->getRandomImageFrame() )
-            {
-                // Yes, so fetch frame area.
-                texelFrameArea = imageAsset->getImageFrameArea( pParticleNode->mImageFrame ).mTexelArea;
-            }
+            // Fetch the frame provider.
+            const ImageFrameProviderCore& frameProvider = pParticleNode->mFrameProvider;
 
-            // Are we using an animation?
-            if ( !isStaticMode )
-            {
-                // Yes, so fetch current frame area.
-                texelFrameArea = pParticleNode->mAnimationController.getCurrentImageFrameArea().mTexelArea;
-                frameTexture = pParticleNode->mAnimationController.getImageTexture();
-            }
+            // Fetch the frame area.
+            const ImageAsset::FrameArea::TexelArea& texelFrameArea = frameProvider.getProviderImageFrameArea().mTexelArea;
+
+            // Frame texture.
+            TextureHandle& frameTexture = frameProvider.getProviderTexture();
 
             // Fetch the particle render OOBB.
             Vector2* renderOOBB = pParticleNode->mRenderOOBB;
@@ -1274,8 +1251,14 @@ void ParticlePlayer::configureParticle( EmitterNode* pEmitterNode, ParticleSyste
     // Image, Frame and Animation Controller.
     // **********************************************************************************************************************
 
+    // Fetch the image frame provider.
+    ImageFrameProviderCore& frameProvider = pParticleNode->mFrameProvider;
+
+    // Allocate assets to the particle.
+    frameProvider.allocateAssets( &(pParticleAssetEmitter->getImageAsset()), &(pParticleAssetEmitter->getAnimationAsset()) );
+
     // Is the emitter in static mode?
-    if ( pParticleAssetEmitter->isStaticMode() )
+    if ( pParticleAssetEmitter->isStaticFrameProvider() )
     {
         // Yes, so is random image frame active?
         if ( pParticleAssetEmitter->getRandomImageFrame() )
@@ -1284,12 +1267,12 @@ void ParticlePlayer::configureParticle( EmitterNode* pEmitterNode, ParticleSyste
             const U32 frameCount = pParticleAssetEmitter->getImageAsset()->getFrameCount();
 
             // Choose a random frame.
-            pParticleNode->mImageFrame = (U32)CoreMath::mGetRandomI( 0, frameCount-1 );
+            frameProvider.setImageFrame( (U32)CoreMath::mGetRandomI( 0, frameCount-1 ) );
         }
         else
         {
             // No, so set the emitter image frame.
-            pParticleNode->mImageFrame = pParticleAssetEmitter->getImageFrame();
+            frameProvider.setImageFrame( pParticleAssetEmitter->getImageFrame() );
         }
     }
     else
@@ -1297,12 +1280,8 @@ void ParticlePlayer::configureParticle( EmitterNode* pEmitterNode, ParticleSyste
         // No, so fetch the animation asset.
         const AssetPtr<AnimationAsset>& animationAsset = pParticleAssetEmitter->getAnimationAsset();
 
-        // Is an animation available?
-        if ( animationAsset.notNull() )
-        {
-            // Yes, so play it.
-            pParticleNode->mAnimationController.playAnimation( animationAsset, false );
-        }
+        // Play it.
+        frameProvider.playAnimation( animationAsset );
     }
 
 
@@ -1407,10 +1386,10 @@ void ParticlePlayer::integrateParticle( EmitterNode* pEmitterNode, ParticleSyste
 
 
     // Is the emitter in static mode?
-    if ( !pParticleAssetEmitter->isStaticMode() )
+    if ( !pParticleAssetEmitter->isStaticFrameProvider() )
     {
         // No, so update animation.
-        pParticleNode->mAnimationController.updateAnimation( elapsedTime );
+        pParticleNode->mFrameProvider.updateAnimation( elapsedTime );
     }
 
 
@@ -1554,8 +1533,8 @@ void ParticlePlayer::initializeParticleAsset( void )
         const AssetPtr<AnimationAsset>& animationAsset = pParticleAssetEmitter->getAnimationAsset();
 
         // Skip if the emitter does not have a valid assigned asset to render.
-        if (( pParticleAssetEmitter->isStaticMode() && (imageAsset.isNull() || imageAsset->getFrameCount() == 0 ) ) ||
-            ( !pParticleAssetEmitter->isStaticMode() && (animationAsset.isNull() || animationAsset->getValidatedAnimationFrames().size() == 0 ) ) )
+        if (( pParticleAssetEmitter->isStaticFrameProvider() && (imageAsset.isNull() || imageAsset->getFrameCount() == 0 ) ) ||
+            ( !pParticleAssetEmitter->isStaticFrameProvider() && (animationAsset.isNull() || animationAsset->getValidatedAnimationFrames().size() == 0 ) ) )
             continue;
 
         // Create a new emitter node.

+ 3 - 12
engine/source/2d/sceneobject/ParticlePlayer.h

@@ -31,14 +31,6 @@
 #include "2d/core/particleSystem.h"
 #endif
 
-#ifndef _SCENE_OBJECT_H_
-#include "2d/sceneObject/sceneObject.h"
-#endif
-
-#ifndef _ANIMATION_CONTROLLER_H_
-#include "2d/assets/AnimationController.h"
-#endif
-
 //-----------------------------------------------------------------------------
 
 #define PARTICLE_PLAYER_EMISSION_RATE_SCALE     "$pref::T2D::ParticlePlayerEmissionRateScale"
@@ -48,12 +40,11 @@
 
 //-----------------------------------------------------------------------------
 
-class ParticlePlayer : public SceneObject, public AssetPtrCallback
+class ParticlePlayer : public SceneObject, protected AssetPtrCallback
 {
 private:
     typedef SceneObject Parent;
 
-
     /// Emitter node.
     class EmitterNode
     {
@@ -198,6 +189,8 @@ protected:
     virtual void OnRegisterScene( Scene* pScene );
     virtual void OnUnregisterScene( Scene* pScene );
 
+    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
+
     /// Particle Creation/Integration.
     void configureParticle( EmitterNode* pEmitterNode, ParticleSystem::ParticleNode* pParticleNode );
     void integrateParticle( EmitterNode* pEmitterNode, ParticleSystem::ParticleNode* pParticleNode, const F32 particleAge, const F32 elapsedTime );
@@ -214,8 +207,6 @@ protected:
     static bool     writeTimeScale( void* obj, StringTableEntry pFieldName )                { return !mIsOne( static_cast<ParticlePlayer*>( obj )->getTimeScale() ); }
 
 private:
-    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
-
     void initializeParticleAsset( void );
     void destroyParticleAsset( void );
 };

+ 4 - 10
engine/source/2d/sceneobject/SceneObject.cc

@@ -373,9 +373,6 @@ bool SceneObject::onAdd()
 
         mpTargetScene = NULL;
     }
-
-    // Perform the callback.
-    Con::executef(this, 1, "onAdd");
    
     // Return Okay.
     return true;
@@ -385,9 +382,6 @@ bool SceneObject::onAdd()
 
 void SceneObject::onRemove()
 {
-    // Perform the callback.
-    Con::executef(this, 1, "onRemove");
-
     // Detach Any GUI Control.
     detachGui();
 
@@ -1442,14 +1436,14 @@ void SceneObject::setCollisionAgainst( const SceneObject* pSceneObject, const bo
     if ( clearMasks )
     {
         // Yes, so just set the masks to the referenced-objects' masks.
-        setCollisionGroupMask( pSceneObject->getCollisionGroupMask() );
-        setCollisionLayerMask( pSceneObject->getCollisionLayerMask() ); 
+        setCollisionGroupMask( pSceneObject->getSceneGroupMask() );
+        setCollisionLayerMask( pSceneObject->getSceneLayerMask() ); 
     }
     else
     {
         // No, so merge with existing masks.
-        setCollisionGroupMask( getCollisionGroupMask() | pSceneObject->getCollisionGroupMask() );
-        setCollisionLayerMask( getCollisionLayerMask() | pSceneObject->getCollisionLayerMask() ); 
+        setCollisionGroupMask( getCollisionGroupMask() | pSceneObject->getSceneGroupMask() );
+        setCollisionLayerMask( getCollisionLayerMask() | pSceneObject->getSceneLayerMask() ); 
     }
 }
 

+ 52 - 10
engine/source/2d/sceneobject/SceneObject_ScriptBinding.h

@@ -1107,12 +1107,16 @@ ConsoleMethod(SceneObject, setCollisionAgainst, void, 3, 4, "(SceneObject object
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(SceneObject, setCollisionLayers, void, 3, 2 + MASK_BITCOUNT, "(layers$) - Sets the collision layers(s).\n"
-                                                                                  "@param layers A list of layers to collide with.\n"
-                                                      "@return No return value.")
+ConsoleMethod(SceneObject, setCollisionLayers, void, 2, 2 + MASK_BITCOUNT,  "(layers) - Sets the collision layers(s).\n"
+                                                                            "@param layers A list of layers to collide with.\n"
+                                                                            "@return No return value.")
 {
-    // The mask.
-    U32 mask = 0;
+    // Set to all if no arguments.
+    if ( argc == 2 )
+    {
+        object->setCollisionLayerMask(MASK_ALL);
+        return;
+    }
 
     // Grab the element count of the first parameter.
     const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
@@ -1123,6 +1127,24 @@ ConsoleMethod(SceneObject, setCollisionLayers, void, 3, 2 + MASK_BITCOUNT, "(lay
         object->setCollisionLayerMask(MASK_ALL);
         return;
     }
+    else if ( elementCount == 1 )
+    {
+        if ( dStricmp( argv[2], "all" ) == 0 )
+        {
+            object->setCollisionLayerMask(MASK_ALL);
+            return;
+        }
+        else if ( dStricmp( argv[2], "none" ) == 0 || dStricmp( argv[2], "off" ) == 0 )
+        {
+            object->setCollisionLayerMask(0);
+            return;
+        }
+
+        return;
+    }
+
+    // The mask.
+    U32 mask = 0;
 
     // Space separated list.
     if (argc == 3)
@@ -1167,12 +1189,16 @@ ConsoleMethod(SceneObject, setCollisionLayers, void, 3, 2 + MASK_BITCOUNT, "(lay
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(SceneObject, setCollisionGroups, void, 3, 2 + MASK_BITCOUNT, "(groups$) - Sets the collision group(s).\n"
-                                                                                  "@param groups A list of collision groups to collide with.\n"
-                                                                                "@return No return value.")
+ConsoleMethod(SceneObject, setCollisionGroups, void, 2, 2 + MASK_BITCOUNT,  "(groups) - Sets the collision group(s).\n"
+                                                                            "@param groups A list of collision groups to collide with.\n"
+                                                                            "@return No return value.")
 {
-    // The mask.
-    U32 mask = 0;
+    // Set to all if no arguments.
+    if ( argc == 2 )
+    {
+        object->setCollisionGroupMask(MASK_ALL);
+        return;
+    }
 
     // Grab the element count of the first parameter.
     const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
@@ -1183,6 +1209,22 @@ ConsoleMethod(SceneObject, setCollisionGroups, void, 3, 2 + MASK_BITCOUNT, "(gro
         object->setCollisionGroupMask(MASK_ALL);
         return;
     }
+    else if ( elementCount == 1 )
+    {
+        if ( dStricmp( argv[2], "all" ) == 0 )
+        {
+            object->setCollisionGroupMask(MASK_ALL);
+            return;
+        }
+        else if ( dStricmp( argv[2], "none" ) == 0 || dStricmp( argv[2], "off" ) == 0 )
+        {
+            object->setCollisionGroupMask(0);
+            return;
+        }
+    }
+
+    // The mask.
+    U32 mask = 0;
 
     // Space separated list.
     if (argc == 3)

+ 4 - 27
engine/source/2d/sceneobject/Scroller.cc

@@ -249,35 +249,12 @@ void Scroller::updateTickScrollPosition( void )
 void Scroller::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
 {
     // Finish if we can't render.
-    if ( !SpriteProxyBase::validRender() )
+    if ( !ImageFrameProvider::validRender() )
         return;
 
-    ImageAsset::FrameArea::TexelArea frameTexelArea;
-    TextureHandle texture;
-
-    // Static mode?
-    if ( isStaticMode() )
-    {
-        // Fetch frame texel area.
-        frameTexelArea = mImageAsset->getImageFrameArea( mImageFrame ).mTexelArea;
-
-        // Fetch asset texture.
-        texture = mImageAsset->getImageTexture();
-    }
-    else
-    {
-        // Fetch animation controller.
-        AnimationController* pAnimationController = getAnimationController();
-
-        // Sanity!
-        AssertFatal( pAnimationController != NULL, "Animation controller cannot be NULL." );
-      
-        // Fetch frame texel area.
-        frameTexelArea = pAnimationController->getCurrentImageFrameArea().mTexelArea;
-
-        // Fetch asset texture.
-        texture = pAnimationController->getImageTexture();
-    }
+    // Fetch texture and texture area.
+    const ImageAsset::FrameArea::TexelArea& frameTexelArea = getProviderImageFrameArea().mTexelArea;
+    TextureHandle& texture = getProviderTexture();
 
     // Calculate render offset.
     F32 renderOffsetX = mFmod( mRenderTickTextureOffset.x, 1.0f );

+ 1 - 1
engine/source/2d/sceneobject/Sprite.cc

@@ -87,7 +87,7 @@ void Sprite::initPersistFields()
 void Sprite::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
 {
     // Let the parent render.
-    SpriteProxyBase::render(
+    ImageFrameProvider::render(
         getFlipX(), getFlipY(),
         mRenderOOBB[0],
         mRenderOOBB[1],

+ 4 - 4
engine/source/assets/assetBase.cc

@@ -188,7 +188,7 @@ StringTableEntry AssetBase::expandAssetFilePath( const char* pAssetFilePath ) co
 
     // Fetch the asset base-path hint.
     StringTableEntry assetBasePathHint;
-    if ( getOwned() )
+    if ( getOwned() && !getAssetPrivate() )
     {
         assetBasePathHint = mpOwningAssetManager->getAssetPath( getAssetId() );
     }
@@ -225,10 +225,10 @@ StringTableEntry AssetBase::collapseAssetFilePath( const char* pAssetFilePath )
 
     char assetFilePathBuffer[1024];
 
-    // Is the asset owned
-    if ( !mpOwningAssetManager )
+    // Is the asset not owned or private?
+    if ( !getOwned() || getAssetPrivate() )
     {
-        // No, so we can only collapse the path using the platform layer.
+        // Yes, so we can only collapse the path using the platform layer.
         Con::collapsePath( assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath );
         return StringTable->insert( assetFilePathBuffer );
     }

+ 2 - 2
engine/source/assets/assetPtr.h

@@ -33,7 +33,7 @@ class AssetPtrCallback
 {
     friend class AssetManager;
 
-private:
+protected:
     virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase ) = 0;    
 };
 
@@ -61,7 +61,7 @@ public:
     virtual bool notNull( void ) const = 0;
 
     /// Notification.
-    void registerRefreshNotify( AssetPtrCallback* pCallback )
+    inline void registerRefreshNotify( AssetPtrCallback* pCallback )
     {
         // Sanity!
         AssertFatal( AssetDatabase.isProperlyAdded(), "AssetPtrBase::registerRefreshNotify() - Cannot register an asset pointer with the asset system." );

+ 0 - 2
engine/source/collection/undo.cc

@@ -35,8 +35,6 @@ UndoAction::UndoAction( const UTF8* actionName)
 {
    mActionName = StringTable->insert(actionName);
    mUndoManager = NULL;
-
-   mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 
 // Modified to clean up quiet sub actions [KNM | 08/10/11 | ITGB-152]

+ 0 - 10
engine/source/collection/undo.h

@@ -147,7 +147,6 @@ public:
 
    UndoScriptAction() : UndoAction()
    {
-      mNSLinkMask = LinkSuperClassName | LinkClassName;
    };
 
    virtual void undo() { Con::executef(this, 1, "undo"); };
@@ -159,11 +158,6 @@ public:
       if(!Parent::onAdd())
          return false;
 
-
-      // Notify Script.
-      if(isMethod("onAdd"))
-         Con::executef(this, 1, "onAdd");
-
       // Return Success.
       return true;
    };
@@ -173,10 +167,6 @@ public:
       if (mUndoManager)
          mUndoManager->removeAction((UndoAction*)this);
 
-      // notify script
-      if(isMethod("onRemove"))
-         Con::executef(this, 1, "onRemove");
-
       Parent::onRemove();
    }
 

+ 166 - 189
engine/source/component/behaviors/behaviorComponent.cpp

@@ -41,7 +41,6 @@
 //-----------------------------------------------------------------------------
 
 #define BEHAVIOR_FIELDNAME              "Behavior"
-#define BEHAVIOR_CONNECTION_FIELDNAME   "BehaviorConnection"
 
 //-----------------------------------------------------------------------------
 
@@ -952,10 +951,7 @@ void BehaviorComponent::onTamlCustomWrite( TamlCustomNodes& customNodes )
     // Finish if no behavior connections.
     if ( behaviorConnectionCount == 0 )
         return;
-
-    // Add custom behavior connection property.
-    TamlCustomNode* pCustomConnection = customNodes.addNode( BEHAVIOR_CONNECTION_NODE_NAME );
-    
+   
     // Iterate instance connections.
     for( typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.begin(); instanceItr != mBehaviorConnections.end(); ++instanceItr )
     {
@@ -975,7 +971,7 @@ void BehaviorComponent::onTamlCustomWrite( TamlCustomNodes& customNodes )
                 BehaviorPortConnection* pConnection = connectionItr;
 
                 // Add connectionnode.
-                TamlCustomNode* pConnectionNode = pCustomConnection->addNode( BEHAVIOR_CONNECTION_TYPE_NAME );
+                TamlCustomNode* pConnectionNode = pCustomBehaviorNode->addNode( BEHAVIOR_CONNECTION_TYPE_NAME );
 
                 // Add behavior field.
                 pConnectionNode->addField( pConnection->mOutputName, pConnection->mOutputInstance->getBehaviorId() );
@@ -1016,232 +1012,213 @@ void BehaviorComponent::onTamlCustomRead( const TamlCustomNodes& customNodes )
             // Fetch behavior node.
             TamlCustomNode* pBehaviorNode = *behaviorNodeItr;
 
-            // Fetch template.
-            BehaviorTemplate* pTemplate = dynamic_cast<BehaviorTemplate *>( Sim::findObject( pBehaviorNode->getNodeName() ) );
-
-            // Find template?
-            if( pTemplate == NULL )
+            if ( pBehaviorNode->getNodeName() == BEHAVIOR_CONNECTION_TYPE_NAME )
             {
-                // No, so warn appropriately.
-                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Missing Behavior '%s'", pBehaviorNode->getNodeName() );
-
-                if( isMethod( "onBehaviorMissing" ) )
-                    Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
+                // Fetch field nodes.
+                const TamlCustomFieldVector& connectionFieldNodes = pBehaviorNode->getFields();
 
-                // Skip it.
-                continue;
-            }
-
-            // Create an instance of the template.
-            BehaviorInstance* pBehaviorInstance = pTemplate->createInstance();
-
-            // Did we create a behavior instance?
-            if ( pBehaviorInstance == NULL )
-            {
-                // No, so warn appropriately.
-                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Found behavior could not create an instance '%s'", pBehaviorNode->getNodeName() );
-
-                if( isMethod( "onBehaviorMissing" ) )
-                    Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
+                // Are there two properties?
+                if ( connectionFieldNodes.size() != 2 )
+                {
+                    // No, so warn.
+                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Encountered a behavior connection with more than two connection fields." );
+                    continue;
+                }
 
-                // Skip it.
-                continue;
-            }
+                // Fetch property field #1.
+                TamlCustomField* pPropertyField1 = *connectionFieldNodes.begin();
+                TamlCustomField* pPropertyField2 = *(connectionFieldNodes.begin()+1);
+           
+                // Fetch behavior instances #1.
+                BehaviorInstance* pBehaviorInstance1 = getBehaviorByInstanceId( dAtoi( pPropertyField1->getFieldValue() ) );
 
-            S32 behaviorId = 0;
+                // Did we find the behavior?
+                if ( pBehaviorInstance1 == NULL )
+                {
+                    // No, so warn.
+                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior instance Id '%s=%s'.",
+                        pPropertyField1->getFieldName(), pPropertyField1->getFieldValue() );
+                    continue;
+                }
 
-            // Fetch field nodes.
-            const TamlCustomFieldVector& fields = pBehaviorNode->getFields();
+                // Fetch behavior instances #2.
+                BehaviorInstance* pBehaviorInstance2 = getBehaviorByInstanceId( dAtoi( pPropertyField2->getFieldValue() ) );
 
-            // Iterate fields.
-            for ( TamlCustomFieldVector::const_iterator nodeFieldItr = fields.begin(); nodeFieldItr != fields.end(); ++nodeFieldItr )
-            {
-                // Fetch field.
-                TamlCustomField* pField = *nodeFieldItr;
+                // Did we find the behavior?
+                if ( pBehaviorInstance2 == NULL )
+                {
+                    // No, so warn.
+                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior instance Id '%s=%s'.",
+                        pPropertyField2->getFieldName(), pPropertyField2->getFieldValue() );
+                    continue;
+                }
 
-                // Fetch field name.
-                const char* pFieldName = pField->getFieldName();
+                // Fetch behavior fields.
+                StringTableEntry behaviorFieldName1 = pPropertyField1->getFieldName();
+                StringTableEntry behaviorFieldName2 = pPropertyField2->getFieldName();
 
-                // Fetch field value.
-                const char* pFieldValue = pField->getFieldValue();
+                BehaviorInstance* pOutputInstance;
+                BehaviorInstance* pInputInstance;
+                StringTableEntry outputName;
+                StringTableEntry inputName;
 
-                // Is this the behavior field Id name?
-                if ( pFieldName == behaviorFieldIdName )
+                // Is the output on behavior instance #1?
+                if ( pBehaviorInstance1->getTemplate()->hasBehaviorOutput( behaviorFieldName1 ) )
                 {
-                    // Yes, so assign it.
-                    behaviorId = dAtoi( pFieldValue );
-
-                    // Is the behavior Id valid?
-                    if ( behaviorId < 1 )
+                    // Yes, so has behavior instance #2 got the input?
+                    if ( !pBehaviorInstance2->getTemplate()->hasBehaviorInput( behaviorFieldName2 ) )
                     {
                         // No, so warn.
-                        Con::warnf( "BehaviorComponent::onTamlCustomRead() - Encountered an invalid behavior Id of '%d' on behavior '%s'.",
-                            behaviorId,
-                            pBehaviorNode->getNodeName() );
+                        Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior input '%s' on behavior '%s'.",
+                            behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
+                        continue;
                     }
 
-                    // Update maximum behavior Id found.
-                    if ( behaviorId > maximumBehaviorId )
-                        maximumBehaviorId = behaviorId;
+                    // Assign output/input appropriately.
+                    pOutputInstance = pBehaviorInstance1;
+                    pInputInstance = pBehaviorInstance2;
+                    outputName = behaviorFieldName1;
+                    inputName = behaviorFieldName2;
+                }
+                // Is the output on behavior instance #2?
+                else if ( pBehaviorInstance2->getTemplate()->hasBehaviorOutput( behaviorFieldName2 ) )
+                {
+                    // Yes, so has behavior instance #1 got the input?
+                    if ( !pBehaviorInstance1->getTemplate()->hasBehaviorInput( behaviorFieldName1 ) )
+                    {
+                        // No, so warn.
+                        Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior input '%s' on behavior '%s'.",
+                            behaviorFieldName1, pBehaviorInstance1->getTemplateName() );
+                        continue;
+                    }
 
-                    /// Skip it.
+                    // Assign output/input appropriately.
+                    pOutputInstance = pBehaviorInstance2;
+                    pInputInstance = pBehaviorInstance1;
+                    outputName = behaviorFieldName2;
+                    inputName = behaviorFieldName1;
+                }
+                else
+                {
+                    // Warn.
+                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Invalid output/input on behavior connection '%s=%s' & '%s=%s''.",
+                        behaviorFieldName1, pBehaviorInstance1->getTemplateName(),
+                        behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
                     continue;
                 }
 
-                // Fetch behavior field.
-                BehaviorTemplate::BehaviorField* pBehaviorField = pTemplate->getBehaviorField( pFieldName );
-
-                // Set default field type.
-                S32 fieldType = -1;
-
-                // Is this an asset field type?
-                if ( pBehaviorField != NULL && pBehaviorField->mType == behaviorTemplateAssetFieldType )
+                // Can we connect?
+                if ( !connect( pOutputInstance, pInputInstance, outputName, inputName ) )
                 {
-                    // Yes, so update field type.
-                    fieldType = TypeAssetId;
+                    // No, so warn.
+                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Failed to connect behaviors '%s=%s' & '%s=%s''.",
+                        behaviorFieldName1, pBehaviorInstance1->getTemplateName(),
+                        behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
+                    continue;
                 }
-
-                // Set field.
-                pBehaviorInstance->setPrefixedDynamicDataField( pField->getFieldName(), NULL, pField->getFieldValue(), fieldType );
             }
+            else
+            {
+                // Fetch template.
+                BehaviorTemplate* pTemplate = dynamic_cast<BehaviorTemplate *>( Sim::findObject( pBehaviorNode->getNodeName() ) );
 
-            // Add behavior.
-            addBehavior( pBehaviorInstance );
-
-            // Override the automatically allocated behavior Id when adding the behavior.
-            // NOTE: This must be done after adding the behavior.
-            pBehaviorInstance->setBehaviorId( behaviorId );
-        }
+                // Find template?
+                if( pTemplate == NULL )
+                {
+                    // No, so warn appropriately.
+                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Missing Behavior '%s'", pBehaviorNode->getNodeName() );
 
-        // Set master as next behavior id.
-        mMasterBehaviorId = (U32)maximumBehaviorId+1;
-    }
+                    if( isMethod( "onBehaviorMissing" ) )
+                        Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
 
-    // Find behavior connections custom node.
-    const TamlCustomNode* pCustomConnectionNode = customNodes.findNode( BEHAVIOR_CONNECTION_NODE_NAME );
+                    // Skip it.
+                    continue;
+                }
 
-    // Do we have the custom connection node?
-    if ( pCustomConnectionNode != NULL )
-    {
-        // Yes, so fetch the connection node name..
-        StringTableEntry connectionNodeName = StringTable->insert( BEHAVIOR_CONNECTION_TYPE_NAME );
+                // Create an instance of the template.
+                BehaviorInstance* pBehaviorInstance = pTemplate->createInstance();
 
-        // Fetch children connection nodes.
-        const TamlCustomNodeVector& connectionNodes = pCustomConnectionNode->getChildren();
+                // Did we create a behavior instance?
+                if ( pBehaviorInstance == NULL )
+                {
+                    // No, so warn appropriately.
+                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Found behavior could not create an instance '%s'", pBehaviorNode->getNodeName() );
 
-        // Iterate property alias.
-        for( TamlCustomNodeVector::const_iterator connectionNodeItr = connectionNodes.begin(); connectionNodeItr != connectionNodes.end(); ++connectionNodeItr )
-        {
-            // Fetch connection node.
-            TamlCustomNode* pConnectionNode = *connectionNodeItr;
+                    if( isMethod( "onBehaviorMissing" ) )
+                        Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
 
-            // Skip if the alias isn't a connection.
-            if ( pConnectionNode->getNodeName() != connectionNodeName )
-                continue;
+                    // Skip it.
+                    continue;
+                }
 
-            // Fetch field nodes.
-            const TamlCustomFieldVector& connectionFieldNodes = pConnectionNode->getFields();
+                S32 behaviorId = 0;
 
-            // Are there two properties?
-            if ( connectionFieldNodes.size() != 2 )
-            {
-                // No, so warn.
-                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Encountered a behavior connection with more than two connection fields." );
-                continue;
-            }
+                // Fetch field nodes.
+                const TamlCustomFieldVector& fields = pBehaviorNode->getFields();
 
-            // Fetch property field #1.
-            TamlCustomField* pPropertyField1 = *connectionFieldNodes.begin();
-            TamlCustomField* pPropertyField2 = *(connectionFieldNodes.begin()+1);
-           
-            // Fetch behavior instances #1.
-            BehaviorInstance* pBehaviorInstance1 = getBehaviorByInstanceId( dAtoi( pPropertyField1->getFieldValue() ) );
+                // Iterate fields.
+                for ( TamlCustomFieldVector::const_iterator nodeFieldItr = fields.begin(); nodeFieldItr != fields.end(); ++nodeFieldItr )
+                {
+                    // Fetch field.
+                    TamlCustomField* pField = *nodeFieldItr;
 
-            // Did we find the behavior?
-            if ( pBehaviorInstance1 == NULL )
-            {
-                // No, so warn.
-                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior instance Id '%s=%s'.",
-                    pPropertyField1->getFieldName(), pPropertyField1->getFieldValue() );
-                continue;
-            }
+                    // Fetch field name.
+                    const char* pFieldName = pField->getFieldName();
 
-            // Fetch behavior instances #2.
-            BehaviorInstance* pBehaviorInstance2 = getBehaviorByInstanceId( dAtoi( pPropertyField2->getFieldValue() ) );
+                    // Fetch field value.
+                    const char* pFieldValue = pField->getFieldValue();
 
-            // Did we find the behavior?
-            if ( pBehaviorInstance2 == NULL )
-            {
-                // No, so warn.
-                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior instance Id '%s=%s'.",
-                    pPropertyField2->getFieldName(), pPropertyField2->getFieldValue() );
-                continue;
-            }
+                    // Is this the behavior field Id name?
+                    if ( pFieldName == behaviorFieldIdName )
+                    {
+                        // Yes, so assign it.
+                        behaviorId = dAtoi( pFieldValue );
+
+                        // Is the behavior Id valid?
+                        if ( behaviorId < 1 )
+                        {
+                            // No, so warn.
+                            Con::warnf( "BehaviorComponent::onTamlCustomRead() - Encountered an invalid behavior Id of '%d' on behavior '%s'.",
+                                behaviorId,
+                                pBehaviorNode->getNodeName() );
+                        }
+
+                        // Update maximum behavior Id found.
+                        if ( behaviorId > maximumBehaviorId )
+                            maximumBehaviorId = behaviorId;
+
+                        /// Skip it.
+                        continue;
+                    }
 
-            // Fetch behavior fields.
-            StringTableEntry behaviorFieldName1 = pPropertyField1->getFieldName();
-            StringTableEntry behaviorFieldName2 = pPropertyField2->getFieldName();
+                    // Fetch behavior field.
+                    BehaviorTemplate::BehaviorField* pBehaviorField = pTemplate->getBehaviorField( pFieldName );
 
-            BehaviorInstance* pOutputInstance;
-            BehaviorInstance* pInputInstance;
-            StringTableEntry outputName;
-            StringTableEntry inputName;
+                    // Set default field type.
+                    S32 fieldType = -1;
 
-            // Is the output on behavior instance #1?
-            if ( pBehaviorInstance1->getTemplate()->hasBehaviorOutput( behaviorFieldName1 ) )
-            {
-                // Yes, so has behavior instance #2 got the input?
-                if ( !pBehaviorInstance2->getTemplate()->hasBehaviorInput( behaviorFieldName2 ) )
-                {
-                    // No, so warn.
-                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior input '%s' on behavior '%s'.",
-                        behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
-                    continue;
-                }
+                    // Is this an asset field type?
+                    if ( pBehaviorField != NULL && pBehaviorField->mType == behaviorTemplateAssetFieldType )
+                    {
+                        // Yes, so update field type.
+                        fieldType = TypeAssetId;
+                    }
 
-                // Assign output/input appropriately.
-                pOutputInstance = pBehaviorInstance1;
-                pInputInstance = pBehaviorInstance2;
-                outputName = behaviorFieldName1;
-                inputName = behaviorFieldName2;
-            }
-            // Is the output on behavior instance #2?
-            else if ( pBehaviorInstance2->getTemplate()->hasBehaviorOutput( behaviorFieldName2 ) )
-            {
-                // Yes, so has behavior instance #1 got the input?
-                if ( !pBehaviorInstance1->getTemplate()->hasBehaviorInput( behaviorFieldName1 ) )
-                {
-                    // No, so warn.
-                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior input '%s' on behavior '%s'.",
-                        behaviorFieldName1, pBehaviorInstance1->getTemplateName() );
-                    continue;
+                    // Set field.
+                    pBehaviorInstance->setPrefixedDynamicDataField( pField->getFieldName(), NULL, pField->getFieldValue(), fieldType );
                 }
 
-                // Assign output/input appropriately.
-                pOutputInstance = pBehaviorInstance2;
-                pInputInstance = pBehaviorInstance1;
-                outputName = behaviorFieldName2;
-                inputName = behaviorFieldName1;
-            }
-            else
-            {
-                // Warn.
-                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Invalid output/input on behavior connection '%s=%s' & '%s=%s''.",
-                    behaviorFieldName1, pBehaviorInstance1->getTemplateName(),
-                    behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
-                continue;
-            }
+                // Add behavior.
+                addBehavior( pBehaviorInstance );
 
-            // Can we connect?
-            if ( !connect( pOutputInstance, pInputInstance, outputName, inputName ) )
-            {
-                // No, so warn.
-                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Failed to connect behaviors '%s=%s' & '%s=%s''.",
-                    behaviorFieldName1, pBehaviorInstance1->getTemplateName(),
-                    behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
-                continue;
+                // Override the automatically allocated behavior Id when adding the behavior.
+                // NOTE: This must be done after adding the behavior.
+                pBehaviorInstance->setBehaviorId( behaviorId );
             }
         }
+
+        // Set master as next behavior id.
+        mMasterBehaviorId = (U32)maximumBehaviorId+1;
     }
 }
 

+ 0 - 2
engine/source/component/simComponent.cpp

@@ -33,8 +33,6 @@ SimComponent::SimComponent() : mOwner( NULL )
    mMutex = Mutex::createMutex();
    
    mEnabled = true;
-
-   mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 
 SimComponent::~SimComponent()

+ 20 - 18
engine/source/console/compiledEval.cc

@@ -355,7 +355,7 @@ static const StringTableEntry _count = StringTable->insert( "count" );
 //-----------------------------------------------------------------------------
 
 // Gets a component of an object's field value or a variable and returns it in val.
-static void getFieldComponent( SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, FrameTemp<char>& val )
+static void getFieldComponent( SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, char* val, const U32 bufferSize )
 {
     const char* prevVal = NULL;
    
@@ -364,7 +364,7 @@ static void getFieldComponent( SimObject* object, StringTableEntry field, const
         prevVal = object->getDataField( field, array );
    
     // Otherwise, grab from the string stack. The value coming in will always
-    // be a string because that is how multicomponent variables are handled.
+    // be a string because that is how multi-component variables are handled.
     else
         prevVal = STR.getStringValue();
 
@@ -372,22 +372,22 @@ static void getFieldComponent( SimObject* object, StringTableEntry field, const
     if ( prevVal && *prevVal )
     {
         if ( subField == _count )
-            dSprintf( val, val.getObjectCount(), "%d", StringUnit::getUnitCount( prevVal, " \t\n" ) );
+            dSprintf( val, bufferSize, "%d", StringUnit::getUnitCount( prevVal, " \t\n" ) );
 
         else if ( subField == _xyzw[0] || subField == _rgba[0] || subField == _size[0] )
-            dStrcpy( val, StringUnit::getUnit( prevVal, 0, " \t\n") );
+            dStrncpy( val, StringUnit::getUnit( prevVal, 0, " \t\n"), bufferSize );
 
         else if ( subField == _xyzw[1] || subField == _rgba[1] || subField == _size[1] )
-            dStrcpy( val, StringUnit::getUnit( prevVal, 1, " \t\n") );
+            dStrncpy( val, StringUnit::getUnit( prevVal, 1, " \t\n"), bufferSize );
 
         else if ( subField == _xyzw[2] || subField == _rgba[2] )
-            dStrcpy( val, StringUnit::getUnit( prevVal, 2, " \t\n") );
+            dStrncpy( val, StringUnit::getUnit( prevVal, 2, " \t\n"), bufferSize );
 
         else if ( subField == _xyzw[3] || subField == _rgba[3] )
-            dStrcpy( val, StringUnit::getUnit( prevVal, 3, " \t\n") );
+            dStrncpy( val, StringUnit::getUnit( prevVal, 3, " \t\n"), bufferSize );
 
         else if ( *subField == '_' && isDigitsOnly(subField+1) )
-            dStrcpy( val, StringUnit::getUnit( prevVal, dAtoi(subField+1), " \t\n") );
+            dStrncpy( val, StringUnit::getUnit( prevVal, dAtoi(subField+1), " \t\n"), bufferSize );
 
         else
             val[0] = 0;
@@ -404,9 +404,10 @@ static void setFieldComponent( SimObject* object, StringTableEntry field, const
 {
     // Copy the current string value
     char strValue[1024];
-    dStrncpy( strValue, STR.getStringValue(), 1024 );
+    dStrncpy( strValue, STR.getStringValue(), sizeof(strValue) );
 
     char val[1024] = "";
+    const U32 bufferSize = sizeof(val);
     const char* prevVal = NULL;
 
     // Set the value on an object field.
@@ -419,22 +420,22 @@ static void setFieldComponent( SimObject* object, StringTableEntry field, const
 
     // Ensure that the variable has a value
     if (!prevVal)
-	    return;
+        return;
 
     if ( subField == _xyzw[0] || subField == _rgba[0] || subField == _size[0] )
-	    dStrcpy( val, StringUnit::setUnit( prevVal, 0, strValue, " \t\n") );
+        dStrncpy( val, StringUnit::setUnit( prevVal, 0, strValue, " \t\n"), bufferSize );
 
     else if ( subField == _xyzw[1] || subField == _rgba[1] || subField == _size[1] )
-        dStrcpy( val, StringUnit::setUnit( prevVal, 1, strValue, " \t\n") );
+        dStrncpy( val, StringUnit::setUnit( prevVal, 1, strValue, " \t\n"), bufferSize );
 
     else if ( subField == _xyzw[2] || subField == _rgba[2] )
-        dStrcpy( val, StringUnit::setUnit( prevVal, 2, strValue, " \t\n") );
+        dStrncpy( val, StringUnit::setUnit( prevVal, 2, strValue, " \t\n"), bufferSize );
 
     else if ( subField == _xyzw[3] || subField == _rgba[3] )
-        dStrcpy( val, StringUnit::setUnit( prevVal, 3, strValue, " \t\n") );
+        dStrncpy( val, StringUnit::setUnit( prevVal, 3, strValue, " \t\n"), bufferSize );
 
     else if ( *subField == '_' && isDigitsOnly(subField+1) )
-        dStrcpy( val, StringUnit::setUnit( prevVal, dAtoi(subField+1), strValue, " \t\n") );
+        dStrncpy( val, StringUnit::setUnit( prevVal, dAtoi(subField+1), strValue, " \t\n"), bufferSize );
 
     if ( val[0] != 0 )
     {
@@ -1236,7 +1237,8 @@ breakContinue:
             {
                // The field is not being retrieved from an object. Maybe it's
                // a special accessor?
-               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer );
+
+               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer, VAL_BUFFER_SIZE );
                intStack[UINT+1] = dAtoi( valBuffer );
             }
             UINT++;
@@ -1249,7 +1251,7 @@ breakContinue:
             {
                // The field is not being retrieved from an object. Maybe it's
                // a special accessor?
-               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer );
+               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer, VAL_BUFFER_SIZE );
                floatStack[FLT+1] = dAtof( valBuffer );
             }
             FLT++;
@@ -1265,7 +1267,7 @@ breakContinue:
             {
                // The field is not being retrieved from an object. Maybe it's
                // a special accessor?
-               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer );
+               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer, VAL_BUFFER_SIZE );
                STR.setStringValue( valBuffer );
             }
 

+ 3 - 3
engine/source/console/consoleObject.cc

@@ -55,7 +55,7 @@ AbstractClassRep* AbstractClassRep::findClassRep(const char* in_pClassName)
       "AbstractClassRep::findClassRep() - Tried to find an AbstractClassRep before AbstractClassRep::initialize().");
 
    for (AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass)
-      if (!dStrcmp(walk->getClassName(), in_pClassName))
+      if (dStricmp(walk->getClassName(), in_pClassName) == 0)
          return walk;
 
    return NULL;
@@ -69,7 +69,7 @@ void AbstractClassRep::registerClassRep(AbstractClassRep* in_pRep)
 #ifdef TORQUE_DEBUG  // assert if this class is already registered.
    for(AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass)
    {
-      AssertFatal(dStrcmp(in_pRep->mClassName, walk->mClassName),
+      AssertFatal(dStricmp(in_pRep->mClassName, walk->mClassName) != 0,
          "Duplicate class name registered in AbstractClassRep::registerClassRep()");
    }
 #endif
@@ -119,7 +119,7 @@ static S32 QSORT_CALLBACK ACRCompare(const void *aptr, const void *bptr)
 
    if(a->mClassType != b->mClassType)
       return a->mClassType - b->mClassType;
-   return dStrcmp(a->getClassName(), b->getClassName());
+   return dStricmp(a->getClassName(), b->getClassName());
 }
 
 void AbstractClassRep::initialize()

+ 0 - 20
engine/source/graphics/PNGImage.cpp

@@ -31,26 +31,6 @@ IMPLEMENT_CONOBJECT(PNGImage);
 
 #define PNGSIGSIZE 8
 
-bool PNGImage::onAdd()
-{
-   if (!Parent::onAdd())
-      return false;
-
-   // Call onAdd in script!
-   Con::executef(this, 2, "onAdd", Con::getIntArg(getId()));
-   return true;
-}
-
-void PNGImage::onRemove()
-{
-   // We call this on this objects namespace so we unlink them after. - jdd
-   //
-   // Call onRemove in script!
-   Con::executef(this, 2, "onRemove", Con::getIntArg(getId()));
-
-   Parent::onRemove();
-}
-
 PNGImage::PNGImage() : mPNGImageType(PNGTYPE_UNKNOWN)
 {
     mWidth = 0;

+ 0 - 6
engine/source/graphics/PNGImage.h

@@ -58,12 +58,6 @@ public:
     PNGImage();
     ~PNGImage();
 
-    /// Called when the object is instantiated and registered 
-    bool onAdd();
-
-    /// Called when the object is destroyed and removed from script memory
-    void onRemove();
-
     DECLARE_CONOBJECT(PNGImage);
 
     /// Construct the png information from the .png file path provided.

+ 4 - 0
engine/source/graphics/TextureHandle.cc

@@ -26,6 +26,10 @@
 
 //-----------------------------------------------------------------------------
 
+TextureHandle BadTextureHandle;
+
+//-----------------------------------------------------------------------------
+
 TextureHandle::TextureHandle( const char* pTextureKey, TextureHandleType type, bool clampToEdge, bool force16Bit )
 {
     // Sanity!

+ 4 - 0
engine/source/graphics/TextureHandle.h

@@ -187,4 +187,8 @@ private:
 
 };
 
+//-----------------------------------------------------------------------------
+
+extern TextureHandle BadTextureHandle;
+
 #endif // _TEXTURE_HANDLE_H_

+ 0 - 10
engine/source/gui/guiControl.cc

@@ -80,8 +80,6 @@ GuiControl::GuiControl()
    mTipHoverTime        = 1000;
    mTooltipWidth		= 250;
    mIsContainer         = false;
-
-   mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 
 GuiControl::~GuiControl()
@@ -109,10 +107,6 @@ bool GuiControl::onAdd()
    // Add to root group.
    Sim::getGuiGroup()->addObject(this);
 
-   // Notify Script.
-   if( isMethod("onAdd") )
-      Con::executef(this, 1, "onAdd");
-
    // Return Success.
    return true;
 }
@@ -1125,10 +1119,6 @@ ConsoleMethod( GuiControl, getMinExtent, const char*, 2, 2, "() Get the minimum
 
 void GuiControl::onRemove()
 {
-   // Only invoke script callbacks if they can be received
-   if( isMethod("onRemove") )
-      Con::executef(this, 1, "onRemove");
-
    clearFirstResponder();
 
    Parent::onRemove();

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

+ 0 - 21
engine/source/messaging/message.cc

@@ -53,32 +53,11 @@ extern SimIdDictionary *gIdDictionary;
 Message::Message()
 {
    mRefCount = 0;
-
-   mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 
 
 IMPLEMENT_CONOBJECT(Message);
 
-//////////////////////////////////////////////////////////////////////////
-
-bool Message::onAdd()
-{
-   if(! Parent::onAdd())
-      return false;
-
-   linkNamespaces();
-   Con::executef(this, 1, "onAdd");
-   return true;
-}
-
-void Message::onRemove()
-{
-   Con::executef(this, 1, "onRemove");
-   unlinkNamespaces();
-   
-   Parent::onRemove();
-}
 
 //////////////////////////////////////////////////////////////////////////
 // Public Methods

+ 0 - 2
engine/source/messaging/message.h

@@ -119,8 +119,6 @@ public:
    //////////////////////////////////////////////////////////////////////////
    static SimObjectId getNextMessageID();
 
-   virtual bool onAdd();
-   virtual void onRemove();
 
    //////////////////////////////////////////////////////////////////////////
    /// @brief Get the type of the message

+ 0 - 21
engine/source/messaging/scriptMsgListener.cc

@@ -43,31 +43,10 @@
 
 ScriptMsgListener::ScriptMsgListener()
 {
-   mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 
 IMPLEMENT_CONOBJECT(ScriptMsgListener);
 
-//////////////////////////////////////////////////////////////////////////
-
-bool ScriptMsgListener::onAdd()
-{
-   if(! Parent::onAdd())
-      return false;
-
-   linkNamespaces();
-   Con::executef(this, 1, "onAdd");
-   return true;
-}
-
-void ScriptMsgListener::onRemove()
-{
-   Con::executef(this, 1, "onRemove");
-   unlinkNamespaces();
-   
-   Parent::onRemove();
-}
-
 //////////////////////////////////////////////////////////////////////////
 // Public Methods
 //////////////////////////////////////////////////////////////////////////

+ 0 - 5
engine/source/messaging/scriptMsgListener.h

@@ -52,11 +52,6 @@ public:
 
    ///////////////////////////////////////////////////////////////////////
 
-   virtual bool onAdd();
-   virtual void onRemove();
-
-   ///////////////////////////////////////////////////////////////////////
-
    virtual bool onMessageReceived(StringTableEntry queue, const char* event, const char* data);
    virtual bool onMessageObjectReceived(StringTableEntry queue, Message *msg);
 

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

+ 0 - 5
engine/source/platform/menus/popupMenu.cc

@@ -37,8 +37,6 @@ PopupMenu::PopupMenu()
    mSubmenus->registerObject();
 
    mIsPopup = false;
-
-   mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 
 PopupMenu::~PopupMenu()
@@ -80,14 +78,11 @@ bool PopupMenu::onAdd()
 
    createPlatformMenu();
 
-   Con::executef(this, 1, "onAdd");
    return true;
 }
 
 void PopupMenu::onRemove()
 {
-   Con::executef(this, 1, "onRemove");
-
    Parent::onRemove();
 }
 

+ 8 - 2
engine/source/platformOSX/osxString.mm

@@ -413,20 +413,26 @@ int dVprintf(const char *format, void *arglist)
 
 //-----------------------------------------------------------------------------
 
-int dSprintf(char *buffer, dsize_t /*bufferSize*/, const char *format, ...)
+int dSprintf(char *buffer, dsize_t bufferSize, const char *format, ...)
 {
     va_list args;
     va_start(args, format);
     S32 len = vsprintf(buffer, format, args);
     
+    // Sanity!
+    AssertFatal(len <= bufferSize, "dSprintf - String format exceeded buffer size.  This will cause corruption.");
+    
     return (len);
 }
 
 //-----------------------------------------------------------------------------
 
-int dVsprintf(char *buffer, dsize_t /*bufferSize*/, const char *format, void *arglist)
+int dVsprintf(char *buffer, dsize_t bufferSize, const char *format, void *arglist)
 {
 	S32 len = vsprintf(buffer, format, (char*)arglist);
+
+    // Sanity!
+    AssertFatal(len <= bufferSize, "dSprintf - String format exceeded buffer size.  This will cause corruption.");
     
     return (len);
 }

+ 1 - 11
engine/source/platformWin32/winStrings.cc

@@ -317,12 +317,7 @@ S32 dSprintf(char *buffer, U32 bufferSize, const char *format, ...)
    va_list args;
    va_start(args, format);
 
-#if defined(TORQUE_COMPILER_CODEWARRIOR)
    S32 len = vsnprintf(buffer, bufferSize, format, args);
-#else
-   bufferSize;
-   S32 len = vsprintf(buffer, format, args);
-#endif
 
    AssertFatal( (U32)len < bufferSize, "dSprintf wrote to more memory than the specified buffer size - Stack Corruption Possible" ); //Added
 
@@ -332,15 +327,10 @@ S32 dSprintf(char *buffer, U32 bufferSize, const char *format, ...)
 
 S32 dVsprintf(char *buffer, U32 bufferSize, const char *format, void *arglist)
 {
-#if defined(TORQUE_COMPILER_CODEWARRIOR)
    S32 len = vsnprintf(buffer, bufferSize, format, (char*)arglist);
-#else
-   bufferSize;
-   S32 len = vsprintf(buffer, format, (char*)arglist);
-#endif
     
    AssertFatal( (U32)len < bufferSize, "dVsprintf wrote to more memory than the specified buffer size - Stack Corruption Possible" );
-//   S32 len = vsnprintf(buffer, bufferSize, format, (char*)arglist);
+
    return (len);
 }
 

+ 9 - 2
engine/source/platformiOS/iOSStrings.mm

@@ -329,19 +329,26 @@ int dVprintf(const char *format, void *arglist)
    return (len);
 }   
 
-int dSprintf(char *buffer, dsize_t /*bufferSize*/, const char *format, ...)
+int dSprintf(char *buffer, dsize_t bufferSize, const char *format, ...)
 {
    va_list args;
    va_start(args, format);
    S32 len = vsprintf(buffer, format, args);
 
+    // Sanity!
+    AssertFatal(len <= bufferSize, "dSprintf - String format exceeded buffer size.  This will cause corruption.");
+    
    return (len);
 }   
 
 
-int dVsprintf(char *buffer, dsize_t /*bufferSize*/, const char *format, void *arglist)
+int dVsprintf(char *buffer, dsize_t bufferSize, const char *format, void *arglist)
 {
 	S32 len = vsprintf(buffer, format, (char*)arglist);
+
+    // Sanity!
+    AssertFatal(len <= bufferSize, "dSprintf - String format exceeded buffer size.  This will cause corruption.");
+    
    return (len);
 }   
 

+ 0 - 21
engine/source/sim/scriptGroup.cc

@@ -34,28 +34,7 @@ IMPLEMENT_CONOBJECT(ScriptGroup);
 
 ScriptGroup::ScriptGroup()
 {
-   mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 
 //-----------------------------------------------------------------------------
 
-bool ScriptGroup::onAdd()
-{
-   if (!Parent::onAdd())
-      return false;
-
-   // Call onAdd in script!
-   Con::executef(this, 2, "onAdd", Con::getIntArg(getId()));
-   return true;
-}
-
-//-----------------------------------------------------------------------------
-
-void ScriptGroup::onRemove()
-{
-   // Call onRemove in script!
-   Con::executef(this, 2, "onRemove", Con::getIntArg(getId()));
-
-   // Call parent.
-   Parent::onRemove();
-}

+ 0 - 2
engine/source/sim/scriptGroup.h

@@ -35,8 +35,6 @@ class ScriptGroup : public SimGroup
    
 public:
    ScriptGroup();
-   bool onAdd();
-   void onRemove();
 
    DECLARE_CONOBJECT(ScriptGroup);
 };

+ 0 - 23
engine/source/sim/scriptObject.cc

@@ -34,28 +34,5 @@ IMPLEMENT_CONOBJECT(ScriptObject);
 
 ScriptObject::ScriptObject()
 {
-   mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 
-//-----------------------------------------------------------------------------
-
-bool ScriptObject::onAdd()
-{
-   if (!Parent::onAdd())
-      return false;
-
-   // Call onAdd in script!
-   Con::executef(this, 2, "onAdd", Con::getIntArg(getId()));
-   return true;
-}
-
-//-----------------------------------------------------------------------------
-
-void ScriptObject::onRemove()
-{
-   // Call onRemove in script!
-   Con::executef(this, 2, "onRemove", Con::getIntArg(getId()));
-
-   // Call parent.
-   Parent::onRemove();
-}

+ 0 - 2
engine/source/sim/scriptObject.h

@@ -35,8 +35,6 @@ class ScriptObject : public SimObject
 
 public:
    ScriptObject();
-   bool onAdd();
-   void onRemove();
 
    DECLARE_CONOBJECT(ScriptObject);
 };

+ 11 - 0
engine/source/sim/simObject.cc

@@ -97,6 +97,10 @@ bool SimObject::registerObject()
       unregisterObject();
 
    AssertFatal(!ret || isProperlyAdded(), "Object did not call SimObject::onAdd()");
+
+    if ( isMethod( "onAdd" ) )
+        Con::executef( this, 1, "onAdd" );
+
    return ret;
 }
 
@@ -107,6 +111,9 @@ void SimObject::unregisterObject()
     // Sanity!
     AssertISV( getScriptCallbackGuard() == 0, "SimObject::unregisterObject: Object is being unregistered whilst performing a script callback!" );
 
+    if ( isMethod( "onRemove" ) )
+        Con::executef( this, 1, "onRemove" );
+
    mFlags.set(Removed);
 
    // Notify object first
@@ -1473,6 +1480,8 @@ void SimObject::copyTo(SimObject* object)
    object->linkNamespaces();
 }
 
+//-----------------------------------------------------------------------------
+
 bool SimObject::setParentGroup(void* obj, const char* data)
 {
    SimGroup *parent = NULL;
@@ -1654,11 +1663,13 @@ void SimObject::unlinkNamespaces()
 void SimObject::setClassNamespace( const char *classNamespace )
 {
    mClassName = StringTable->insert( classNamespace );
+   linkNamespaces();
 }
 
 void SimObject::setSuperClassNamespace( const char *superClassNamespace )
 {  
    mSuperClassName = StringTable->insert( superClassNamespace );
+   linkNamespaces();
 }
 
 ConsoleMethod(SimObject, getClassNamespace, const char*, 2, 2, "")

+ 1 - 1
engine/source/sim/simObject.h

@@ -453,7 +453,7 @@ public:
     //from the console or C++.
     virtual void			dumpClassHierarchy();
     ///
-    SimObject( const U8 namespaceLinkMask = 0 );
+    SimObject( const U8 namespaceLinkMask = LinkSuperClassName | LinkClassName );
     virtual ~SimObject();
 
     virtual bool processArguments(S32 argc, const char **argv);  ///< Process constructor options. (ie, new SimObject(1,2,3))

+ 1 - 2
modules/AquariumToy/1/main.cs

@@ -95,10 +95,9 @@ function AquariumToy::spawnFish(%this)
         CollisionCallback = true;
     };
 
+    %fish.setCollisionGroups( none );
     %fish.createPolygonBoxCollisionShape( 15, 15);
-    %fish.setCollisionGroups( 15 );
     %fish.setDefaultDensity( 1 );
-    %fish.setDefaultFriction( 1.0 );
     SandboxScene.add( %fish );
 
     %this.currentFish++;

+ 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"/>

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

@@ -112,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.
@@ -119,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;
@@ -132,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 );
@@ -145,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;

+ 1 - 1
modules/RestitutionToy/1/main.cs

@@ -112,7 +112,7 @@ function RestitutionToy::createGround( %this )
     %ground.setSize(RestitutionToy.GroundWidth, 6);
     %ground.setRepeatX(RestitutionToy.GroundWidth / 60);   
     %ground.setSceneGroup( 1 );
-    %ground.setCollisionGroups( 2 );
+    %ground.setCollisionGroups( none );
     %ground.createEdgeCollisionShape(RestitutionToy.GroundWidth/-2, 3, RestitutionToy.GroundWidth/2, 3);
     SandboxScene.add(%ground);  
     

+ 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


+ 13 - 12
modules/TruckToy/1/main.cs

@@ -35,6 +35,7 @@ function TruckToy::create( %this )
     TruckToy.BackdropDomain = 31;
     TruckToy.BackgroundDomain = 25;
     TruckToy.TruckDomain = 20;
+    TruckToy.GroundDomain = 18;
     TruckToy.ObstacleDomain = 15;
     TruckToy.ProjectileDomain = 16;
     TruckToy.ForegroundDomain = 10;    
@@ -226,9 +227,9 @@ function TruckToy::createFloor(%this)
     %obj.setPosition( 0, TruckToy.FloorLevel - (%obj.getSizeY()/2) );
     %obj.setRepeatX( TruckToy.WorldWidth / 12 );   
     %obj.setSceneLayer( TruckToy.ObstacleDomain );
-    %obj.setSceneGroup( TruckToy.ObstacleDomain );
+    %obj.setSceneGroup( TruckToy.GroundDomain );
     %obj.setDefaultFriction( TruckToy.ObstacleFriction );
-    %obj.setCollisionGroups( TruckToy.ObstacleDomain SPC TruckToy.ProjectileDomain );
+    %obj.setCollisionGroups( none );
     %obj.createEdgeCollisionShape( TruckToy.WorldWidth/-2, 1.5, TruckToy.WorldWidth/2, 1.5 );
     %obj.createEdgeCollisionShape( TruckToy.WorldWidth/-2, 3, TruckToy.WorldWidth/-2, 50 );
     %obj.createEdgeCollisionShape( TruckToy.WorldWidth/2, 3, TruckToy.WorldWidth/2, 50 );
@@ -345,7 +346,7 @@ function TruckToy::createBridge( %this, %posX, %posY, %linkCount )
       }
       else
       {      
-         %obj.setCollisionGroups( TruckToy.ObstacleDomain );   
+         %obj.setCollisionGroups( none );
          %obj.setDefaultDensity( 1 );
          %obj.setDefaultFriction( TruckToy.ObstacleFriction );
          %obj.createPolygonBoxCollisionShape( %linkWidth, %linkHeight );
@@ -406,7 +407,7 @@ function TruckToy::createChain( %this, %posX, %posY, %linkCount )
         
         %obj.setSceneLayer( TruckToy.BackgroundDomain-1 );
         %obj.setSceneGroup( TruckToy.ObstacleDomain );
-        %obj.setCollisionGroups( TruckToy.ObstacleDomain );
+        %obj.setCollisionGroups( none );
         %obj.setDefaultDensity( 1 );
         %obj.setDefaultFriction( 0.2 );
         %obj.createPolygonBoxCollisionShape( %linkWidth, %linkHeight );
@@ -521,7 +522,7 @@ function TruckToy::createBrick( %this, %brickNumber, %posX, %posY, %static )
     %obj.setSize( 1, 0.5 );
     %obj.setSceneLayer( TruckToy.ObstacleDomain );
     %obj.setSceneGroup( TruckToy.ObstacleDomain );
-    %obj.setCollisionGroups( TruckToy.ObstacleDomain );
+    %obj.setCollisionGroups( TruckToy.GroundDomain, TruckToy.ObstacleDomain );
     %obj.setDefaultFriction( TruckToy.ObstacleFriction );
     %obj.createPolygonBoxCollisionShape( 1, 0.5 );
     %obj.setAwake( false );
@@ -568,7 +569,7 @@ function TruckToy::createPlank( %this, %plankNumber, %posX, %posY, %angle, %stat
     %obj.setSceneLayer( TruckToy.ObstacleDomain );
     %obj.setSceneGroup( TruckToy.ObstacleDomain );
     %obj.setDefaultFriction( TruckToy.ObstacleFriction );
-    %obj.setCollisionGroups( TruckToy.ObstacleDomain );
+    %obj.setCollisionGroups( TruckToy.GroundDomain, TruckToy.ObstacleDomain );
     %obj.setAwake( false );
     %obj.setDefaultFriction( 1.0 );
 
@@ -607,7 +608,7 @@ function TruckToy::createWreckedCar( %this, %carNumber, %posX, %posY, %angle, %s
     %obj.setSize( 4, 1.5 );   
     %obj.setSceneLayer( TruckToy.ObstacleDomain );
     %obj.setSceneGroup( TruckToy.ObstacleDomain );
-    %obj.setCollisionGroups( TruckToy.ObstacleDomain );
+    %obj.setCollisionGroups( TruckToy.GroundDomain, TruckToy.ObstacleDomain );
     %obj.setAwake( false );
     %obj.setDefaultFriction( TruckToy.ObstacleFriction );
 
@@ -660,7 +661,7 @@ function TruckToy::createProjectile(%this)
     %projectile.Size = getRandom(0.5, 2);
     %projectile.Lifetime = 2.5;
     %projectile.createCircleCollisionShape( 0.2 ); 
-    %projectile.setCollisionGroups( TruckToy.ObstacleDomain );
+    %projectile.setCollisionGroups( TruckToy.GroundDomain );
     %projectile.CollisionCallback = true;
     SandboxScene.add( %projectile ); 
 }
@@ -708,8 +709,8 @@ function TruckToy::createTruck( %this, %posX, %posY )
     TruckToy.TruckBody.setImage( "TruckToy:truckBody" );
     TruckToy.TruckBody.setSize( 5, 2.5 );
     TruckToy.TruckBody.setSceneLayer( TruckToy.TruckDomain );
-    TruckToy.TruckBody.setSceneGroup( TruckToy.ObstacleDomain );
-    TruckToy.TruckBody.setCollisionGroups( TruckToy.ObstacleDomain SPC TruckToy.ObstacleDomain-1 );
+    TruckToy.TruckBody.setSceneGroup( TruckToy.ObstacleDomain);
+    TruckToy.TruckBody.setCollisionGroups( TruckToy.ObstacleDomain, TruckToy.ObstacleDomain-1, TruckToy.GroundDomain );
     TruckToy.TruckBody.createPolygonCollisionShape( "-2 0.2 -2 -0.5 0 -.95 2 -0.5 2 0.0 0 0.7 -1.5 0.7" ); 
     //TruckToy.TruckBody.setDebugOn( 5 );
     SandboxScene.add( TruckToy.TruckBody );
@@ -732,7 +733,7 @@ function TruckToy::createTruck( %this, %posX, %posY )
     %tireRear.setSize( 1.7, 1.7 );
     %tireRear.setSceneLayer( TruckToy.TruckDomain-1 );
     %tireRear.setSceneGroup( TruckToy.ObstacleDomain );
-    %tireRear.setCollisionGroups( TruckToy.ObstacleDomain );
+    %tireRear.setCollisionGroups( TruckToy.ObstacleDomain, TruckToy.GroundDomain );
     %tireRear.setDefaultFriction( TruckToy.WheelFriction );
     %tireRear.setDefaultDensity( TruckToy.RearWheelDensity );
     %tireRear.createCircleCollisionShape( 0.8 ); 
@@ -746,7 +747,7 @@ function TruckToy::createTruck( %this, %posX, %posY )
     %tireFront.setSize( 1.7, 1.7 );
     %tireFront.setSceneLayer( TruckToy.TruckDomain-1 );
     %tireFront.setSceneGroup( TruckToy.ObstacleDomain );
-    %tireFront.setCollisionGroups( TruckToy.ObstacleDomain );
+    %tireFront.setCollisionGroups( TruckToy.ObstacleDomain, TruckToy.GroundDomain );
     %tireFront.setDefaultFriction( TruckToy.WheelFriction );
     %tireFront.setDefaultDensity( TruckToy.FrontWheelDensity );
     %tireFront.createCircleCollisionShape( 0.8 ); 

+ 19 - 0
tools/Zwoptex/ReadMe.txt

@@ -0,0 +1,19 @@
+This read me contains instructions for adding a new template to Zwoptex, allowing you to publish directly to a T2D ImageAsset format.
+
+1. Open Zwoptex
+2. Open preferences (cmd+,)
+3. Click on "Coordinates Formats"
+4. Click the plus symbol at the bottom
+5. Rename to T2D
+6. Change the extension to .asset.taml
+7. Copy the following to the source box:
+
+<ImageAsset
+    AssetName="{{ metadata.target.name }}"
+    ImageFile="@assetFile={{ metadata.target.textureFileName }}{{ metadata.target.textureFileExtension }}">
+	<ImageAsset.Cells>
+		{% for sprite in spritesAndAliases %}<Cell Offset="{{ sprite.textureRectX }} {{ sprite.textureRectY }}" Width="{{ sprite.textureRectWidth }}" Height="{{ sprite.textureRectHeight }}"/>
+		{% /for %}</ImageAsset.Cells>
+</ImageAsset>
+
+And that's it! You can now publish ImageAssets directly from Zoptex