Browse Source

Merge remote-tracking branch 'upstream/development' into development

Charlie Patterson 12 years ago
parent
commit
8f8aa85
100 changed files with 5007 additions and 4101 deletions
  1. 7 6
      engine/compilers/VisualStudio 2010/Torque 2D.vcxproj
  2. 27 18
      engine/compilers/VisualStudio 2010/Torque 2D.vcxproj.filters
  3. 7 6
      engine/compilers/VisualStudio 2012/Torque 2D.vcxproj
  4. 27 18
      engine/compilers/VisualStudio 2012/Torque 2D.vcxproj.filters
  5. 36 18
      engine/compilers/Xcode/Torque2D.xcodeproj/project.pbxproj
  6. 36 18
      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. 9 20
      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. 11 32
      engine/source/2d/assets/ParticleAssetField.cc
  15. 2 3
      engine/source/2d/assets/ParticleAssetFieldCollection.cc
  16. 41 41
      engine/source/2d/controllers/BuoyancyController.cc
  17. 14 14
      engine/source/2d/controllers/BuoyancyController.h
  18. 29 8
      engine/source/2d/controllers/PointForceController.cc
  19. 17 4
      engine/source/2d/controllers/PointForceController.h
  20. 23 0
      engine/source/2d/controllers/PointForceController_ScriptBinding.h
  21. 51 0
      engine/source/2d/core/ImageFrameProvider.cc
  22. 47 49
      engine/source/2d/core/ImageFrameProvider.h
  23. 586 0
      engine/source/2d/core/ImageFrameProviderCore.cc
  24. 153 0
      engine/source/2d/core/ImageFrameProviderCore.h
  25. 6 5
      engine/source/2d/core/ParticleSystem.h
  26. 2 6
      engine/source/2d/core/RenderProxy.cc
  27. 11 19
      engine/source/2d/core/RenderProxy.h
  28. 28 32
      engine/source/2d/core/RenderProxy_ScriptBinding.h
  29. 7 11
      engine/source/2d/core/SpriteBase.cc
  30. 11 19
      engine/source/2d/core/SpriteBase.h
  31. 31 35
      engine/source/2d/core/SpriteBase_ScriptBinding.h
  32. 47 6
      engine/source/2d/core/SpriteBatch.cc
  33. 7 2
      engine/source/2d/core/SpriteBatch.h
  34. 27 60
      engine/source/2d/core/SpriteBatchItem.cc
  35. 10 12
      engine/source/2d/core/SpriteBatchItem.h
  36. 0 413
      engine/source/2d/core/SpriteProxyBase.cc
  37. 0 117
      engine/source/2d/core/SpriteProxyBase.h
  38. 271 0
      engine/source/2d/experimental/composites/WaveComposite.cc
  39. 93 0
      engine/source/2d/experimental/composites/WaveComposite.h
  40. 22 29
      engine/source/2d/experimental/composites/WaveComposite_ScriptBinding.h
  41. 8 8
      engine/source/2d/gui/guiSpriteCtrl.cc
  42. 8 12
      engine/source/2d/gui/guiSpriteCtrl.h
  43. 7 7
      engine/source/2d/gui/guiSpriteCtrl_ScriptBindings.h
  44. 11 6
      engine/source/2d/scene/ContactFilter.cc
  45. 380 274
      engine/source/2d/scene/Scene.cc
  46. 38 21
      engine/source/2d/scene/Scene.h
  47. 177 84
      engine/source/2d/scene/Scene_ScriptBinding.h
  48. 23 0
      engine/source/2d/sceneobject/CompositeSprite.cc
  49. 3 0
      engine/source/2d/sceneobject/CompositeSprite.h
  50. 2 6
      engine/source/2d/sceneobject/CompositeSprite_ScriptBinding.h
  51. 28 49
      engine/source/2d/sceneobject/ParticlePlayer.cc
  52. 3 12
      engine/source/2d/sceneobject/ParticlePlayer.h
  53. 356 56
      engine/source/2d/sceneobject/SceneObject.cc
  54. 52 10
      engine/source/2d/sceneobject/SceneObject_ScriptBinding.h
  55. 4 27
      engine/source/2d/sceneobject/Scroller.cc
  56. 1 1
      engine/source/2d/sceneobject/Sprite.cc
  57. 4 4
      engine/source/assets/assetBase.cc
  58. 0 150
      engine/source/assets/assetManager.cc
  59. 0 8
      engine/source/assets/assetManager.h
  60. 0 50
      engine/source/assets/assetManager_ScriptBinding.h
  61. 2 2
      engine/source/assets/assetPtr.h
  62. 0 2
      engine/source/collection/undo.cc
  63. 0 10
      engine/source/collection/undo.h
  64. 166 189
      engine/source/component/behaviors/behaviorComponent.cpp
  65. 0 1
      engine/source/component/behaviors/behaviorInstance.cpp
  66. 0 2
      engine/source/component/simComponent.cpp
  67. 20 18
      engine/source/console/compiledEval.cc
  68. 49 3
      engine/source/console/consoleObject.cc
  69. 582 495
      engine/source/console/consoleObject.h
  70. 0 20
      engine/source/graphics/PNGImage.cpp
  71. 0 6
      engine/source/graphics/PNGImage.h
  72. 4 0
      engine/source/graphics/TextureHandle.cc
  73. 4 0
      engine/source/graphics/TextureHandle.h
  74. 383 384
      engine/source/gui/buttons/guiButtonBaseCtrl.cc
  75. 0 10
      engine/source/gui/editor/guiInspector.cc
  76. 0 3
      engine/source/gui/editor/guiInspector.h
  77. 1 11
      engine/source/gui/guiControl.cc
  78. 1 0
      engine/source/gui/guiControl.h
  79. 0 1
      engine/source/gui/guiTextEditCtrl.cc
  80. 9 8
      engine/source/gui/guiTypes.cc
  81. 0 21
      engine/source/messaging/message.cc
  82. 0 2
      engine/source/messaging/message.h
  83. 0 21
      engine/source/messaging/scriptMsgListener.cc
  84. 0 5
      engine/source/messaging/scriptMsgListener.h
  85. 1 1
      engine/source/module/moduleManager.cc
  86. 573 561
      engine/source/network/netConnection.h
  87. 299 0
      engine/source/persistence/taml/taml.cc
  88. 3 0
      engine/source/persistence/taml/taml.h
  89. 23 0
      engine/source/persistence/taml/tamlBinaryReader.cc
  90. 27 4
      engine/source/persistence/taml/tamlXmlReader.cc
  91. 13 0
      engine/source/persistence/taml/taml_ScriptBinding.h
  92. 0 5
      engine/source/platform/menus/popupMenu.cc
  93. 8 2
      engine/source/platformOSX/osxString.mm
  94. 1 11
      engine/source/platformWin32/winStrings.cc
  95. 9 2
      engine/source/platformiOS/iOSStrings.mm
  96. 0 21
      engine/source/sim/scriptGroup.cc
  97. 0 2
      engine/source/sim/scriptGroup.h
  98. 0 23
      engine/source/sim/scriptObject.cc
  99. 0 2
      engine/source/sim/scriptObject.h
  100. 11 0
      engine/source/sim/simObject.cc

+ 7 - 6
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" />
@@ -281,7 +282,6 @@
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
     <ClCompile Include="..\..\source\assets\assetManager.cc" />
     <ClCompile Include="..\..\source\assets\assetQuery.cc" />
-    <ClCompile Include="..\..\source\assets\assetSnapshot.cc" />
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc" />
     <ClCompile Include="..\..\source\assets\declaredAssets.cc" />
     <ClCompile Include="..\..\source\assets\referencedAssets.cc" />
@@ -611,7 +611,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 +632,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 +643,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" />
@@ -702,7 +704,6 @@
     <ClInclude Include="..\..\source\assets\assetPtr.h" />
     <ClInclude Include="..\..\source\assets\assetQuery.h" />
     <ClInclude Include="..\..\source\assets\assetQuery_ScriptBinding.h" />
-    <ClInclude Include="..\..\source\assets\assetSnapshot.h" />
     <ClInclude Include="..\..\source\assets\assetTagsManifest.h" />
     <ClInclude Include="..\..\source\assets\assetTagsManifest_ScriptBinding.h" />
     <ClInclude Include="..\..\source\assets\declaredAssets.h" />

+ 27 - 18
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">
@@ -711,9 +717,6 @@
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc">
       <Filter>assets</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\assets\assetSnapshot.cc">
-      <Filter>assets</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\assets\assetBase.cc">
       <Filter>assets</Filter>
     </ClCompile>
@@ -1122,9 +1125,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 +1161,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 +1296,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">
@@ -1910,9 +1916,6 @@
     <ClInclude Include="..\..\source\module\moduleCallbacks.h">
       <Filter>module</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\assets\assetSnapshot.h">
-      <Filter>assets</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\assets\assetBase.h">
       <Filter>assets</Filter>
     </ClInclude>
@@ -2351,9 +2354,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 +2426,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 +2664,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 - 6
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" />
@@ -288,7 +289,6 @@
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
     <ClCompile Include="..\..\source\assets\assetManager.cc" />
     <ClCompile Include="..\..\source\assets\assetQuery.cc" />
-    <ClCompile Include="..\..\source\assets\assetSnapshot.cc" />
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc" />
     <ClCompile Include="..\..\source\assets\declaredAssets.cc" />
     <ClCompile Include="..\..\source\assets\referencedAssets.cc" />
@@ -618,7 +618,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 +639,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 +650,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" />
@@ -708,7 +710,6 @@
     <ClInclude Include="..\..\source\assets\assetPtr.h" />
     <ClInclude Include="..\..\source\assets\assetQuery.h" />
     <ClInclude Include="..\..\source\assets\assetQuery_ScriptBinding.h" />
-    <ClInclude Include="..\..\source\assets\assetSnapshot.h" />
     <ClInclude Include="..\..\source\assets\assetTagsManifest.h" />
     <ClInclude Include="..\..\source\assets\assetTagsManifest_ScriptBinding.h" />
     <ClInclude Include="..\..\source\assets\declaredAssets.h" />

+ 27 - 18
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">
@@ -711,9 +717,6 @@
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc">
       <Filter>assets</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\assets\assetSnapshot.cc">
-      <Filter>assets</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\assets\assetBase.cc">
       <Filter>assets</Filter>
     </ClCompile>
@@ -1122,9 +1125,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 +1161,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 +1296,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">
@@ -1910,9 +1916,6 @@
     <ClInclude Include="..\..\source\module\moduleCallbacks.h">
       <Filter>module</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\assets\assetSnapshot.h">
-      <Filter>assets</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\assets\assetBase.h">
       <Filter>assets</Filter>
     </ClInclude>
@@ -2351,9 +2354,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 +2423,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 +2661,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 - 18
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 */; };
@@ -205,7 +206,6 @@
 		86D76F9C165686D80046D71F /* assetFieldTypes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7EEC16518D4600D96ADF /* assetFieldTypes.cc */; };
 		86D76F9D165686D80046D71F /* assetManager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7EEE16518D4600D96ADF /* assetManager.cc */; };
 		86D76F9F165686D80046D71F /* assetQuery.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7EF416518D4600D96ADF /* assetQuery.cc */; };
-		86D76FA0165686D80046D71F /* assetSnapshot.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7EF716518D4600D96ADF /* assetSnapshot.cc */; };
 		86D76FA1165686D80046D71F /* assetTagsManifest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7EF916518D4600D96ADF /* assetTagsManifest.cc */; };
 		86D76FA2165686D80046D71F /* audio.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7F0116518D4600D96ADF /* audio.cc */; };
 		86D76FA3165686D80046D71F /* AudioAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7F0316518D4600D96ADF /* AudioAsset.cc */; };
@@ -459,6 +459,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 +500,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 +721,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 +738,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>"; };
@@ -810,8 +813,6 @@
 		86BC7EF416518D4600D96ADF /* assetQuery.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assetQuery.cc; sourceTree = "<group>"; };
 		86BC7EF516518D4600D96ADF /* assetQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetQuery.h; sourceTree = "<group>"; };
 		86BC7EF616518D4600D96ADF /* assetQuery_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetQuery_ScriptBinding.h; sourceTree = "<group>"; };
-		86BC7EF716518D4600D96ADF /* assetSnapshot.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assetSnapshot.cc; sourceTree = "<group>"; };
-		86BC7EF816518D4600D96ADF /* assetSnapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetSnapshot.h; sourceTree = "<group>"; };
 		86BC7EF916518D4600D96ADF /* assetTagsManifest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assetTagsManifest.cc; sourceTree = "<group>"; };
 		86BC7EFA16518D4600D96ADF /* assetTagsManifest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetTagsManifest.h; sourceTree = "<group>"; };
 		86BC7EFB16518D4600D96ADF /* assetTagsManifest_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetTagsManifest_ScriptBinding.h; sourceTree = "<group>"; };
@@ -1407,6 +1408,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 +1823,7 @@
 		86BC7E7516518D4600D96ADF /* 2d */ = {
 			isa = PBXGroup;
 			children = (
+				2AE2938016EF4BFA0015E200 /* experimental */,
 				2AB4F1CF16D55B7300C9A27B /* controllers */,
 				86BC7E7616518D4600D96ADF /* assets */,
 				86BC7E8016518D4600D96ADF /* core */,
@@ -1831,8 +1851,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 +1861,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 +1884,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 */,
@@ -1990,8 +2010,6 @@
 				86BC7EF416518D4600D96ADF /* assetQuery.cc */,
 				86BC7EF516518D4600D96ADF /* assetQuery.h */,
 				86BC7EF616518D4600D96ADF /* assetQuery_ScriptBinding.h */,
-				86BC7EF716518D4600D96ADF /* assetSnapshot.cc */,
-				86BC7EF816518D4600D96ADF /* assetSnapshot.h */,
 				86BC7EF916518D4600D96ADF /* assetTagsManifest.cc */,
 				86BC7EFA16518D4600D96ADF /* assetTagsManifest.h */,
 				86BC7EFB16518D4600D96ADF /* assetTagsManifest_ScriptBinding.h */,
@@ -3078,7 +3096,6 @@
 				86D76F9C165686D80046D71F /* assetFieldTypes.cc in Sources */,
 				86D76F9D165686D80046D71F /* assetManager.cc in Sources */,
 				86D76F9F165686D80046D71F /* assetQuery.cc in Sources */,
-				86D76FA0165686D80046D71F /* assetSnapshot.cc in Sources */,
 				86D76FA1165686D80046D71F /* assetTagsManifest.cc in Sources */,
 				86D76FA2165686D80046D71F /* audio.cc in Sources */,
 				86D76FA3165686D80046D71F /* AudioAsset.cc in Sources */,
@@ -3101,7 +3118,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 +3125,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 +3293,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 - 18
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 */; };
@@ -105,7 +106,6 @@
 		867BB00816AEC9050033868F /* assetFieldTypes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD7516AEC9050033868F /* assetFieldTypes.cc */; };
 		867BB00916AEC9050033868F /* assetManager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD7716AEC9050033868F /* assetManager.cc */; };
 		867BB00B16AEC9050033868F /* assetQuery.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD7D16AEC9050033868F /* assetQuery.cc */; };
-		867BB00C16AEC9050033868F /* assetSnapshot.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD8016AEC9050033868F /* assetSnapshot.cc */; };
 		867BB00D16AEC9050033868F /* assetTagsManifest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD8216AEC9050033868F /* assetTagsManifest.cc */; };
 		867BB00E16AEC9050033868F /* audio.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD8A16AEC9050033868F /* audio.cc */; };
 		867BB00F16AEC9050033868F /* AudioAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD8C16AEC9050033868F /* AudioAsset.cc */; };
@@ -481,6 +481,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 +512,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 +594,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 +623,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>"; };
@@ -698,8 +701,6 @@
 		867BAD7D16AEC9050033868F /* assetQuery.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assetQuery.cc; sourceTree = "<group>"; };
 		867BAD7E16AEC9050033868F /* assetQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetQuery.h; sourceTree = "<group>"; };
 		867BAD7F16AEC9050033868F /* assetQuery_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetQuery_ScriptBinding.h; sourceTree = "<group>"; };
-		867BAD8016AEC9050033868F /* assetSnapshot.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assetSnapshot.cc; sourceTree = "<group>"; };
-		867BAD8116AEC9050033868F /* assetSnapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetSnapshot.h; sourceTree = "<group>"; };
 		867BAD8216AEC9050033868F /* assetTagsManifest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assetTagsManifest.cc; sourceTree = "<group>"; };
 		867BAD8316AEC9050033868F /* assetTagsManifest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetTagsManifest.h; sourceTree = "<group>"; };
 		867BAD8416AEC9050033868F /* assetTagsManifest_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetTagsManifest_ScriptBinding.h; sourceTree = "<group>"; };
@@ -1477,6 +1478,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 +1575,7 @@
 		867BACF816AEC9050033868F /* 2d */ = {
 			isa = PBXGroup;
 			children = (
+				2AE2938616EF4C310015E200 /* experimental */,
 				2AB4F1D416D55B9F00C9A27B /* controllers */,
 				867BACF916AEC9050033868F /* assets */,
 				867BAD0C16AEC9050033868F /* core */,
@@ -1573,8 +1593,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 +1613,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 +1636,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 */,
@@ -1742,8 +1762,6 @@
 				867BAD7D16AEC9050033868F /* assetQuery.cc */,
 				867BAD7E16AEC9050033868F /* assetQuery.h */,
 				867BAD7F16AEC9050033868F /* assetQuery_ScriptBinding.h */,
-				867BAD8016AEC9050033868F /* assetSnapshot.cc */,
-				867BAD8116AEC9050033868F /* assetSnapshot.h */,
 				867BAD8216AEC9050033868F /* assetTagsManifest.cc */,
 				867BAD8316AEC9050033868F /* assetTagsManifest.h */,
 				867BAD8416AEC9050033868F /* assetTagsManifest_ScriptBinding.h */,
@@ -3011,7 +3029,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 +3041,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 */,
@@ -3050,7 +3066,6 @@
 				867BB00816AEC9050033868F /* assetFieldTypes.cc in Sources */,
 				867BB00916AEC9050033868F /* assetManager.cc in Sources */,
 				867BB00B16AEC9050033868F /* assetQuery.cc in Sources */,
-				867BB00C16AEC9050033868F /* assetSnapshot.cc in Sources */,
 				867BB00D16AEC9050033868F /* assetTagsManifest.cc in Sources */,
 				867BB00E16AEC9050033868F /* audio.cc in Sources */,
 				867BB00F16AEC9050033868F /* AudioAsset.cc in Sources */,
@@ -3414,6 +3429,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_

+ 9 - 20
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 )
 
 //-----------------------------------------------------------------------------
@@ -107,13 +111,11 @@ IMPLEMENT_CONOBJECT(ImageAsset);
 
 //------------------------------------------------------------------------------
 
-static bool explicitCellPropertiesInitialized = false;
-
-static StringTableEntry cellCustomNodeName;
-static StringTableEntry cellNodeName;
-static StringTableEntry cellOffsetName;
-static StringTableEntry cellWidthName;
-static StringTableEntry cellHeightName;
+static StringTableEntry cellCustomNodeName          = StringTable->insert( "Cells" );
+static StringTableEntry cellNodeName                = StringTable->insert( "Cell" );
+static StringTableEntry cellOffsetName              = StringTable->insert( "Offset" );
+static StringTableEntry cellWidthName               = StringTable->insert( "Width" );
+static StringTableEntry cellHeightName              = StringTable->insert( "Height" );
 
 //------------------------------------------------------------------------------
 
@@ -177,19 +179,6 @@ ImageAsset::ImageAsset() :  mImageFile(StringTable->EmptyString),
     // Set Vector Associations.
     VECTOR_SET_ASSOCIATION( mFrames );
     VECTOR_SET_ASSOCIATION( mExplicitFrames );
-
-    // Initialize explicit cell field names.
-    if ( !explicitCellPropertiesInitialized )
-    {
-        cellCustomNodeName          = StringTable->insert( "Cells" );
-        cellNodeName                = StringTable->insert( "Cell" );
-        cellOffsetName              = StringTable->insert( "Offset" );
-        cellWidthName               = StringTable->insert( "Width" );
-        cellHeightName              = StringTable->insert( "Height" );
-
-        // Flag as initialized.
-        explicitCellPropertiesInitialized = true;
-    }
 }
 
 //------------------------------------------------------------------------------

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

+ 11 - 32
engine/source/2d/assets/ParticleAssetField.cc

@@ -40,19 +40,17 @@
 
 //-----------------------------------------------------------------------------
 
-static bool particleAssetFieldPropertiesInitialized = false;
-
-static StringTableEntry particleAssetFieldRepeatTimeName;
-static StringTableEntry particleAssetFieldMaxTimeName;
-static StringTableEntry particleAssetFieldMinValueName;
-static StringTableEntry particleAssetFieldMaxValueName;
-static StringTableEntry particleAssetFieldDefaultValueName;
-static StringTableEntry particleAssetFieldValueScaleName;
-static StringTableEntry particleAssetFieldDataKeysName;
-
-static StringTableEntry particleAssetFieldDataKeyName;
-static StringTableEntry particleAssetFieldDataKeyTimeName;
-static StringTableEntry particleAssetFieldDataKeyValueName;
+static StringTableEntry particleAssetFieldRepeatTimeName   = StringTable->insert( "RepeatTime" );
+static StringTableEntry particleAssetFieldMaxTimeName      = StringTable->insert( "MaxTime" );
+static StringTableEntry particleAssetFieldMinValueName     = StringTable->insert( "MinValue" );
+static StringTableEntry particleAssetFieldMaxValueName     = StringTable->insert( "MaxValue" );
+static StringTableEntry particleAssetFieldDefaultValueName = StringTable->insert( "DefaultValue" );
+static StringTableEntry particleAssetFieldValueScaleName   = StringTable->insert( "ValueScale" );
+static StringTableEntry particleAssetFieldDataKeysName     = StringTable->insert( "Keys" );
+
+static StringTableEntry particleAssetFieldDataKeyName      = StringTable->insert( "Key" );
+static StringTableEntry particleAssetFieldDataKeyTimeName  = StringTable->insert( "Time" );
+static StringTableEntry particleAssetFieldDataKeyValueName = StringTable->insert( "Value" );
 
 ParticleAssetField::DataKey ParticleAssetField::BadDataKey( -1.0f, 0.0f );
 
@@ -70,25 +68,6 @@ ParticleAssetField::ParticleAssetField() :
 {
     // Set Vector Associations.
     VECTOR_SET_ASSOCIATION( mDataKeys );
-
-    // Initialize names.
-    if ( !particleAssetFieldPropertiesInitialized )
-    {
-        particleAssetFieldRepeatTimeName   = StringTable->insert( "RepeatTime" );
-        particleAssetFieldMaxTimeName      = StringTable->insert( "MaxTime" );
-        particleAssetFieldMinValueName     = StringTable->insert( "MinValue" );
-        particleAssetFieldMaxValueName     = StringTable->insert( "MaxValue" );
-        particleAssetFieldDefaultValueName = StringTable->insert( "DefaultValue" );
-        particleAssetFieldValueScaleName   = StringTable->insert( "ValueScale" );
-        particleAssetFieldDataKeysName     = StringTable->insert( "Keys" );
-
-        particleAssetFieldDataKeyName      = StringTable->insert( "Key" );
-        particleAssetFieldDataKeyTimeName  = StringTable->insert( "Time" );
-        particleAssetFieldDataKeyValueName = StringTable->insert( "Value" );
-
-        // Flag as initialized.
-        particleAssetFieldPropertiesInitialized = true;
-    }
 }
 
 //-----------------------------------------------------------------------------

+ 2 - 3
engine/source/2d/assets/ParticleAssetFieldCollection.cc

@@ -24,15 +24,14 @@
 
 //-----------------------------------------------------------------------------
 
-static StringTableEntry particleAssetFieldNodeName;
+    // Set custom property name.
+static StringTableEntry particleAssetFieldNodeName = StringTable->insert("Fields");
 
 //-----------------------------------------------------------------------------
 
 ParticleAssetFieldCollection::ParticleAssetFieldCollection() :
                                     mpSelectedField( NULL )
 {
-    // Set custom property name.
-    particleAssetFieldNodeName = StringTable->insert("Fields");
 }
 
 //-----------------------------------------------------------------------------

+ 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 - 49
engine/source/assets/assetSnapshot.h → engine/source/2d/core/ImageFrameProvider.h

@@ -1,49 +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 _ASSET_SNAPSHOT_H_
-#define _ASSET_SNAPSHOT_H_
-
-#ifndef _SIMBASE_H_
-#include "sim/simBase.h"
-#endif
-
-//-----------------------------------------------------------------------------
-
-class AssetSnapshot : public SimObject
-{
-private:
-    typedef SimObject Parent;
-
-public:
-    AssetSnapshot() {}
-    virtual ~AssetSnapshot() {}
-
-    /// Reset asset snapshot.
-    inline void resetSnapshot() { clearDynamicFields(); }
-
-    /// Declare Console Object.
-    DECLARE_CONOBJECT( AssetSnapshot );
-};
-
-#endif // _ASSET_SNAPSHOT_H_
-
+//-----------------------------------------------------------------------------
+// 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;
 

+ 27 - 60
engine/source/2d/core/SpriteBatchItem.cc

@@ -28,73 +28,37 @@
 #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
 
 //-----------------------------------------------------------------------------
 
-static bool spriteBatchItemPropertiesInitialized = false;
-
-static StringTableEntry spriteLogicalPositionName;
-static StringTableEntry spriteVisibleName;
-static StringTableEntry spriteLocalPositionName;
-static StringTableEntry spriteLocalAngleName;
-static StringTableEntry spriteDepthName;
-static StringTableEntry spriteSizeName;
-static StringTableEntry spriteFlipXName;
-static StringTableEntry spriteFlipYName;
-static StringTableEntry spriteSortPointName;
-static StringTableEntry spriteRenderGroupName;
-static StringTableEntry spriteBlendModeName;
-static StringTableEntry spriteSrcBlendFactorName;
-static StringTableEntry spriteDstBlendFactorName;
-static StringTableEntry spriteBlendColorName;
-static StringTableEntry spriteAlphaTestName;
-static StringTableEntry spriteImageName;
-static StringTableEntry spriteImageFrameName;
-static StringTableEntry spriteAnimationName;
-static StringTableEntry spriteDataObjectName;
-static StringTableEntry spriteNameName;
+static StringTableEntry spriteNameName              = StringTable->insert("Name");
+static StringTableEntry spriteLogicalPositionName   = StringTable->insert("LogicalPosition");
+static StringTableEntry spriteVisibleName           = StringTable->insert("Visible");
+static StringTableEntry spriteLocalPositionName     = StringTable->insert("Position");
+static StringTableEntry spriteLocalAngleName        = StringTable->insert("Angle");
+static StringTableEntry spriteSizeName              = StringTable->insert("Size");
+static StringTableEntry spriteDepthName             = StringTable->insert("Depth");
+static StringTableEntry spriteFlipXName             = StringTable->insert("FlipX");
+static StringTableEntry spriteFlipYName             = StringTable->insert("FlipY");
+static StringTableEntry spriteSortPointName         = StringTable->insert("SortPoint");
+static StringTableEntry spriteRenderGroupName       = StringTable->insert("RenderGroup");
+static StringTableEntry spriteBlendModeName         = StringTable->insert("BlendMode");
+static StringTableEntry spriteSrcBlendFactorName    = StringTable->insert("SrcBlendFactor");
+static StringTableEntry spriteDstBlendFactorName    = StringTable->insert("DstBlendFactor");
+static StringTableEntry spriteBlendColorName        = StringTable->insert("BlendColor");
+static StringTableEntry spriteAlphaTestName         = StringTable->insert("AlphaTest");
+static StringTableEntry spriteImageName             = StringTable->insert("Image");
+static StringTableEntry spriteImageFrameName        = StringTable->insert("Frame");
+static StringTableEntry spriteAnimationName         = StringTable->insert("Animation");
+static StringTableEntry spriteDataObjectName        = StringTable->insert("DataObject");
 
 //------------------------------------------------------------------------------
 
 SpriteBatchItem::SpriteBatchItem() : mProxyId( SpriteBatch::INVALID_SPRITE_PROXY )
 {
-    // Are the sprite batch item properties initialized?
-    if ( !spriteBatchItemPropertiesInitialized )
-    {
-        // No, so initialize...
-
-        spriteNameName              = StringTable->insert("Name");
-        spriteLogicalPositionName   = StringTable->insert("LogicalPosition");
-        spriteVisibleName           = StringTable->insert("Visible");
-        spriteLocalPositionName     = StringTable->insert("Position");
-        spriteLocalAngleName        = StringTable->insert("Angle");
-        spriteSizeName              = StringTable->insert("Size");
-        spriteDepthName             = StringTable->insert("Depth");
-        spriteFlipXName             = StringTable->insert("FlipX");
-        spriteFlipYName             = StringTable->insert("FlipY");
-        spriteSortPointName         = StringTable->insert("SortPoint");
-        spriteRenderGroupName       = StringTable->insert("RenderGroup");
-        spriteBlendModeName         = StringTable->insert("BlendMode");
-        spriteSrcBlendFactorName    = StringTable->insert("SrcBlendFactor");
-        spriteDstBlendFactorName    = StringTable->insert("DstBlendFactor");
-        spriteBlendColorName        = StringTable->insert("BlendColor");
-        spriteAlphaTestName         = StringTable->insert("AlphaTest");
-        spriteImageName             = StringTable->insert("Image");
-        spriteImageFrameName        = StringTable->insert("Frame");
-        spriteAnimationName         = StringTable->insert("Animation");
-        spriteDataObjectName        = StringTable->insert("DataObject");
-
-        // Flag as initialized.
-        spriteBatchItemPropertiesInitialized = true;
-    }
-
     resetState();
 }
 
@@ -159,6 +123,8 @@ void SpriteBatchItem::resetState( void )
 
     mSpriteBatchQueryKey = 0;
 
+    mUserData = NULL;
+
     // Require self ticking.
     mSelfTick = true;
 }
@@ -310,10 +276,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 +307,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 - 29
engine/source/assets/assetSnapshot.cc → engine/source/2d/experimental/composites/WaveComposite_ScriptBinding.h

@@ -1,29 +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.
-//-----------------------------------------------------------------------------
-
-#ifndef _ASSET_SNAPSHOT_H_
-#include "assetSnapshot.h"
-#endif
-
-//-----------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT( AssetSnapshot );
+//-----------------------------------------------------------------------------
+// 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;
 }

File diff suppressed because it is too large
+ 380 - 274
engine/source/2d/scene/Scene.cc


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

@@ -71,6 +71,10 @@
 #include "component/behaviors/behaviorComponent.h"
 #endif
 
+#ifndef _ASSET_PTR_H_
+#include "assets/assetPtr.h"
+#endif
+
 //-----------------------------------------------------------------------------
 
 extern EnumTable jointTypeTable;
@@ -162,11 +166,12 @@ 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;
+    typedef Vector<AssetPtr<AssetBase>*>        typeAssetPtrVector;
 
     /// Scene Debug Options.
     enum DebugOption
@@ -202,6 +207,7 @@ public:
 
 private:
     typedef BehaviorComponent   Parent;
+    typedef SceneObject         Children;
 
     /// World.
     b2World*                    mpWorld;
@@ -219,10 +225,13 @@ private:
     /// Joint access.
     typeJointHash               mJoints;
     typeReverseJointHash        mReverseJoints;
-    U32                         mJointMasterId;
+    S32                         mJointMasterId;
+
+    /// Scene controllers.
+    SimObjectPtr<SimSet>	    mControllers;
 
-	/// Scene controllers.
-	SimObjectPtr<SimSet>	    mControllers;
+    /// Asset pre-loads.
+    typeAssetPtrVector          mAssetPreloads;
 
     /// Scene time.
     F32                         mSceneTime;
@@ -343,7 +352,13 @@ public:
 
     void                    mergeScene( const Scene* pScene );
 
-	inline SimSet*			getControllers( void )						{ return mControllers; }
+    inline SimSet*			getControllers( void )						{ return mControllers; }
+
+    inline S32              getAssetPreloadCount( void ) const          { return mAssetPreloads.size(); }
+    const AssetPtr<AssetBase>* getAssetPreload( const S32 index ) const;
+    void                    addAssetPreload( const char* pAssetId );
+    void                    removeAssetPreload( const char* pAssetId );
+    void                    clearAssetPreloads( void );
 
     /// Scene time.
     inline F32              getSceneTime( void ) const                  { return mSceneTime; };
@@ -352,15 +367,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 +402,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 +415,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 +442,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 +462,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 +493,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 +513,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 +542,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 +551,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 +585,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 +644,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 ); }

+ 177 - 84
engine/source/2d/scene/Scene_ScriptBinding.h

@@ -250,6 +250,66 @@ ConsoleMethod(Scene, getSceneObjectList, const char*, 2, 2, "() Gets the Scene O
 
 //-----------------------------------------------------------------------------
 
+ConsoleMethod(Scene, getAssetPreloadCount, S32, 2, 2,   "() Gets the number of assets set to preload for this scene.\n"
+                                                        "@return The number of assets set to preload for this scene.")
+{
+    return object->getAssetPreloadCount();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(Scene, getAssetPreload, const char*, 3, 3,    "(index) Gets the asset to be preloaded at the specified index.\n"
+                                                            "@param index The index of the preloaded asset.\n"
+                                                            "@return The asset to be preloaded at the specified index.")
+{
+    // Fetch preload index.
+    const S32 index = dAtoi(argv[2]);
+
+    // Fetch the asset pointer.
+    const AssetPtr<AssetBase>* pAssetPtr = object->getAssetPreload( index );
+
+    return pAssetPtr == NULL ? NULL : pAssetPtr->getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(Scene, addAssetPreload, void, 3, 3,   "(assetId) Adds the asset Id so that it is preloaded when the scene is loaded.\n"
+                                                    "The asset loaded immediately by this operation.  Duplicate assets are ignored.\n"
+                                                    "@param assetId The asset Id to be added.\n"
+                                                    "@return No return value.")
+{
+    // Fetch asset Id.
+    const char* pAssetId = argv[2];
+
+    // Add asset preload.
+    object->addAssetPreload( pAssetId );
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(Scene, removeAssetPreload, void, 3, 3,    "(assetId) Removes the asset Id from being preloaded when the scene is loaded.\n"
+                                                        "The asset may be unloaded immediately by this operation if it has no other references.\n"
+                                                        "@param assetId The asset Id to be removed.\n"
+                                                        "@return No return value.")
+{
+    // Fetch asset Id.
+    const char* pAssetId = argv[2];
+
+    // Remove asset preload.
+    object->removeAssetPreload( pAssetId );
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(Scene, clearAssetPreloads, void, 2, 2,    "() Clears all assets added as a preload.\n"
+                                                        "@return No return value.")
+{
+    // Clear asset preloads.
+    object->clearAssetPreloads();
+}
+
+//-----------------------------------------------------------------------------
+
 ConsoleMethod(Scene, mergeScene, void, 3, 3,    "(scene) Merges the specified scene into this scene by cloning the scenes contents.")
 {
     // Find the specified scene.
@@ -269,7 +329,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 +379,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 +392,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 +411,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 +429,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 +550,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 +566,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 +580,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 +596,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 +610,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 +626,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 +643,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 +748,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 +764,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 +780,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 +879,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 +897,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 +926,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 +944,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;
@@ -892,7 +952,7 @@ ConsoleMethod(Scene, getRevoluteJointMotor, const char*, 3, 3,  "(jointId) Gets
     F32 maxMotorTorque;
 
     // Access joint.
-    if ( !object->getRevoluteJointLimit( jointId, enableMotor, motorSpeed, maxMotorTorque ) )
+    if ( !object->getRevoluteJointMotor( jointId, enableMotor, motorSpeed, maxMotorTorque ) )
     {
         return NULL;
     }
@@ -915,9 +975,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 +1088,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 +1104,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 +1118,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 +1134,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 +1151,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 +1261,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 +1279,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 +1306,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 +1322,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 +1336,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 +1352,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 +1370,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 +1478,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 +1494,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 +1508,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 +1524,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 +1541,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 +1651,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 +1668,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 +1697,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 +1714,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 +1748,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 +1884,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 +1962,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 +1994,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 +2010,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 +2026,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 +2040,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 +2056,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 +2075,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 +2170,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 +2202,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 +2218,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 +2234,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 +2248,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 +2264,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 +2278,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 +2294,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 );
@@ -2931,12 +2991,33 @@ ConsoleMethod(Scene, setDebugOff, void, 3, 2 + DEBUG_MODE_COUNT,    "(debugOptio
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(Scene, getDebugOn, bool, 3, 3, "(debugMode) Gets the state of the debug mode.\n"
-              "@param The specific debug mode to check active state of.\n"
-              "@return Returns true if active, false if not.")
+ConsoleMethod(Scene, getDebugOn, const char*, 2, 2, "() Gets the state of the debug modes.\n"
+                                                    "@return Returns a space separated list of debug modes that are active.")
 {
-   const U32 mask = 1 << dAtoi(argv[2]);
-   return object->getDebugMask() & mask;
+    // Fetch debug mask,.
+    const U32 debugMask = object->getDebugMask();
+
+    // Fetch a return buffer.
+    S32 bufferSize = 1024;
+    char* pReturnBuffer = Con::getReturnBuffer(bufferSize);
+    *pReturnBuffer = 0;
+    char* pWriteCursor = pReturnBuffer;
+
+    // Iterate debug mask.
+    for( U32 bit = 0; bit < 32; ++bit )
+    {
+        // Calculate debug mask bit.
+        const S32 debugBit = 1 << bit;
+        if ( (debugMask & debugBit) == 0 )
+            continue;
+
+        // Format option.
+        const S32 size = dSprintf( pWriteCursor, bufferSize, "%s ", object->getDebugOptionDescription( (Scene::DebugOption)debugBit ) );
+        bufferSize -= size;
+        pWriteCursor += size;
+    }
+
+    return pReturnBuffer;
 }
 
 //-----------------------------------------------------------------------------
@@ -3069,8 +3150,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 );
 };

+ 356 - 56
engine/source/2d/sceneobject/SceneObject.cc

@@ -76,33 +76,26 @@
 
 //-----------------------------------------------------------------------------
 
-IMPLEMENT_CONOBJECT(SceneObject);
-
-//-----------------------------------------------------------------------------
-
 // Scene-Object counter.
 static U32 sGlobalSceneObjectCount = 0;
 static U32 sSceneObjectMasterSerialId = 0;
 
-// Collision shape property names.
-static bool collisionShapePropertiesInitialized = false;
-
-static StringTableEntry shapeCustomNodeName;
-
-static StringTableEntry shapeDensityName;
-static StringTableEntry shapeFrictionName;
-static StringTableEntry shapeRestitutionName;
-static StringTableEntry shapeSensorName;
-static StringTableEntry shapePointName;
-static StringTableEntry shapePrevPointName;
-static StringTableEntry shapeNextPointName;
-
-static StringTableEntry circleTypeName;
-static StringTableEntry circleRadiusName;
-static StringTableEntry circleOffsetName;
-static StringTableEntry polygonTypeName;
-static StringTableEntry chainTypeName;
-static StringTableEntry edgeTypeName;
+// Collision shapes custom node names.
+static StringTableEntry shapeCustomNodeName     = StringTable->insert( "CollisionShapes" );
+
+static StringTableEntry shapeDensityName        = StringTable->insert( "Density" );
+static StringTableEntry shapeFrictionName       = StringTable->insert( "Friction" );
+static StringTableEntry shapeRestitutionName    = StringTable->insert( "Restitution" );
+static StringTableEntry shapeSensorName         = StringTable->insert( "Sensor" );
+static StringTableEntry shapePointName          = StringTable->insert( "Point" );
+static StringTableEntry shapePrevPointName      = StringTable->insert( "PreviousPoint" );
+static StringTableEntry shapeNextPointName      = StringTable->insert( "NextPoint" );
+static StringTableEntry circleTypeName          = StringTable->insert( "Circle" );
+static StringTableEntry circleRadiusName        = StringTable->insert( "Radius" );
+static StringTableEntry circleOffsetName        = StringTable->insert( "Offset" );
+static StringTableEntry polygonTypeName         = StringTable->insert( "Polygon" );
+static StringTableEntry chainTypeName           = StringTable->insert( "Chain" );
+static StringTableEntry edgeTypeName            = StringTable->insert( "Edge" );
 
 //------------------------------------------------------------------------------
 
@@ -194,29 +187,6 @@ SceneObject::SceneObject() :
     mSerialId(0),
     mRenderGroup( StringTable->EmptyString )
 {
-    // Initialize collision shape field names.
-    if ( !collisionShapePropertiesInitialized )
-    {
-        shapeCustomNodeName     = StringTable->insert( "CollisionShapes" );
-
-        shapeDensityName        = StringTable->insert( "Density" );
-        shapeFrictionName       = StringTable->insert( "Friction" );
-        shapeRestitutionName    = StringTable->insert( "Restitution" );
-        shapeSensorName         = StringTable->insert( "Sensor" );
-        shapePointName          = StringTable->insert( "Point" );
-        shapePrevPointName      = StringTable->insert( "PreviousPoint" );
-        shapeNextPointName      = StringTable->insert( "NextPoint" );
-        circleTypeName          = StringTable->insert( "Circle" );
-        circleRadiusName        = StringTable->insert( "Radius" );
-        circleOffsetName        = StringTable->insert( "Offset" );
-        polygonTypeName         = StringTable->insert( "Polygon" );
-        chainTypeName           = StringTable->insert( "Chain" );
-        edgeTypeName            = StringTable->insert( "Edge" );
-
-        // Flag as initialized.
-        collisionShapePropertiesInitialized = true;
-    }
-
     // Set Vector Associations.
     VECTOR_SET_ASSOCIATION( mDestroyNotifyList );
     VECTOR_SET_ASSOCIATION( mCollisionFixtureDefs );
@@ -373,9 +343,6 @@ bool SceneObject::onAdd()
 
         mpTargetScene = NULL;
     }
-
-    // Perform the callback.
-    Con::executef(this, 1, "onAdd");
    
     // Return Okay.
     return true;
@@ -385,9 +352,6 @@ bool SceneObject::onAdd()
 
 void SceneObject::onRemove()
 {
-    // Perform the callback.
-    Con::executef(this, 1, "onRemove");
-
     // Detach Any GUI Control.
     detachGui();
 
@@ -1442,14 +1406,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() ); 
     }
 }
 
@@ -4132,3 +4096,339 @@ const char* SceneObject::getDstBlendFactorDescription(const GLenum factor)
 
     return StringTable->EmptyString;
 }
+
+//-----------------------------------------------------------------------------
+
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    char buffer[1024];
+
+    // Create shapes node element.
+    TiXmlElement* pShapesNodeElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), shapeCustomNodeName );
+    pShapesNodeElement->SetAttribute( "name", buffer );
+    pShapesNodeElement->SetAttribute( "minOccurs", 0 );
+    pShapesNodeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pShapesNodeElement );
+    
+    // Create complex type.
+    TiXmlElement* pShapesNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pShapesNodeElement->LinkEndChild( pShapesNodeComplexTypeElement );
+    
+    // Create choice element.
+    TiXmlElement* pShapesNodeChoiceElement = new TiXmlElement( "xs:choice" );
+    pShapesNodeChoiceElement->SetAttribute( "minOccurs", 0 );
+    pShapesNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pShapesNodeComplexTypeElement->LinkEndChild( pShapesNodeChoiceElement );
+
+    // ********************************************************************************
+    // Create Circle
+    // ********************************************************************************
+    TiXmlElement* pCircleElement = new TiXmlElement( "xs:element" );
+    pCircleElement->SetAttribute( "name", circleTypeName );
+    pCircleElement->SetAttribute( "minOccurs", 0 );
+    pCircleElement->SetAttribute( "maxOccurs", 1 );
+    pShapesNodeChoiceElement->LinkEndChild( pCircleElement );
+
+    // Create complex type Element.
+    TiXmlElement* pCircleComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pCircleElement->LinkEndChild( pCircleComplexTypeElement );
+
+    // Create "Radius" attribute.
+    TiXmlElement* pCircleElementA = new TiXmlElement( "xs:attribute" );
+    pCircleElementA->SetAttribute( "name", circleRadiusName );
+    pCircleComplexTypeElement->LinkEndChild( pCircleElementA );
+    TiXmlElement* pCircleElementB = new TiXmlElement( "xs:simpleType" );
+    pCircleElementA->LinkEndChild( pCircleElementB );
+    TiXmlElement* pCircleElementC = new TiXmlElement( "xs:restriction" );
+    pCircleElementC->SetAttribute( "base", "xs:float" );
+    pCircleElementB->LinkEndChild( pCircleElementC );
+    TiXmlElement* pCircleElementD = new TiXmlElement( "xs:minExclusive" );
+    pCircleElementD->SetAttribute( "value", "0" );
+    pCircleElementC->LinkEndChild( pCircleElementD );
+
+    // Create "Offset" attribute.
+    pCircleElementA = new TiXmlElement( "xs:attribute" );
+    pCircleElementA->SetAttribute( "name", circleOffsetName );
+    pCircleElementA->SetAttribute( "type", "Vector2_ConsoleType" );
+    pCircleComplexTypeElement->LinkEndChild( pCircleElementA );
+
+    // Create "IsSensor" attribute.
+    pCircleElementA = new TiXmlElement( "xs:attribute" );
+    pCircleElementA->SetAttribute( "name", shapeSensorName );
+    pCircleElementA->SetAttribute( "type", "xs:boolean" );
+    pCircleComplexTypeElement->LinkEndChild( pCircleElementA );
+
+    // Create "Density" attribute.
+    pCircleElementA = new TiXmlElement( "xs:attribute" );
+    pCircleElementA->SetAttribute( "name", shapeDensityName );
+    pCircleComplexTypeElement->LinkEndChild( pCircleElementA );
+    pCircleElementB = new TiXmlElement( "xs:simpleType" );
+    pCircleElementA->LinkEndChild( pCircleElementB );
+    pCircleElementC = new TiXmlElement( "xs:restriction" );
+    pCircleElementC->SetAttribute( "base", "xs:float" );
+    pCircleElementB->LinkEndChild( pCircleElementC );
+    pCircleElementD = new TiXmlElement( "xs:minInclusive" );
+    pCircleElementD->SetAttribute( "value", "0" );
+    pCircleElementC->LinkEndChild( pCircleElementD );
+
+    // Create "Friction" attribute.
+    pCircleElementA = new TiXmlElement( "xs:attribute" );
+    pCircleElementA->SetAttribute( "name", shapeFrictionName );
+    pCircleComplexTypeElement->LinkEndChild( pCircleElementA );
+    pCircleElementB = new TiXmlElement( "xs:simpleType" );
+    pCircleElementA->LinkEndChild( pCircleElementB );
+    pCircleElementC = new TiXmlElement( "xs:restriction" );
+    pCircleElementC->SetAttribute( "base", "xs:float" );
+    pCircleElementB->LinkEndChild( pCircleElementC );
+    pCircleElementD = new TiXmlElement( "xs:minInclusive" );
+    pCircleElementD->SetAttribute( "value", "0" );
+    pCircleElementC->LinkEndChild( pCircleElementD );
+
+    // Create "Restitution" attribute.
+    pCircleElementA = new TiXmlElement( "xs:attribute" );
+    pCircleElementA->SetAttribute( "name", shapeRestitutionName );
+    pCircleComplexTypeElement->LinkEndChild( pCircleElementA );
+    pCircleElementB = new TiXmlElement( "xs:simpleType" );
+    pCircleElementA->LinkEndChild( pCircleElementB );
+    pCircleElementC = new TiXmlElement( "xs:restriction" );
+    pCircleElementC->SetAttribute( "base", "xs:float" );
+    pCircleElementB->LinkEndChild( pCircleElementC );
+    pCircleElementD = new TiXmlElement( "xs:minInclusive" );
+    pCircleElementD->SetAttribute( "value", "0" );
+    pCircleElementC->LinkEndChild( pCircleElementD );
+
+    // ********************************************************************************
+    // Create Polygon
+    // ********************************************************************************
+    TiXmlElement* pPolygonElement = new TiXmlElement( "xs:element" );
+    pPolygonElement->SetAttribute( "name", polygonTypeName );
+    pPolygonElement->SetAttribute( "minOccurs", 0 );
+    pPolygonElement->SetAttribute( "maxOccurs", 1 );
+    pShapesNodeChoiceElement->LinkEndChild( pPolygonElement );
+
+    // Create complex type Element.
+    TiXmlElement* pPolygonComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pPolygonElement->LinkEndChild( pPolygonComplexTypeElement );
+
+    // Create "polygon" child.
+    TiXmlElement* pPolygonElementA = new TiXmlElement( "xs:choice" );
+    pPolygonElementA->SetAttribute( "minOccurs", 0 );
+    pPolygonElementA->SetAttribute( "maxOccurs", "unbounded" );
+    pPolygonComplexTypeElement->LinkEndChild( pPolygonElementA );
+    TiXmlElement* pPolygonElementB = new TiXmlElement( "xs:element" );
+    pPolygonElementB->SetAttribute( "name", shapePointName );
+    pPolygonElementB->SetAttribute( "type", "Vector2_ConsoleType" );
+    pPolygonElementA->LinkEndChild( pPolygonElementB );
+
+    // Create "IsSensor" attribute.
+    pPolygonElementA = new TiXmlElement( "xs:attribute" );
+    pPolygonElementA->SetAttribute( "name", shapeSensorName );
+    pPolygonElementA->SetAttribute( "type", "xs:boolean" );
+    pPolygonComplexTypeElement->LinkEndChild( pPolygonElementA );
+
+    // Create "Density" attribute.
+    pPolygonElementA = new TiXmlElement( "xs:attribute" );
+    pPolygonElementA->SetAttribute( "name", shapeDensityName );
+    pPolygonComplexTypeElement->LinkEndChild( pPolygonElementA );
+    pPolygonElementB = new TiXmlElement( "xs:simpleType" );
+    pPolygonElementA->LinkEndChild( pPolygonElementB );
+    TiXmlElement* pPolygonElementC = new TiXmlElement( "xs:restriction" );
+    pPolygonElementC->SetAttribute( "base", "xs:float" );
+    pPolygonElementB->LinkEndChild( pPolygonElementC );
+    TiXmlElement* pPolygonElementD = new TiXmlElement( "xs:minInclusive" );
+    pPolygonElementD->SetAttribute( "value", "0" );
+    pPolygonElementC->LinkEndChild( pPolygonElementD );
+
+    // Create "Friction" attribute.
+    pPolygonElementA = new TiXmlElement( "xs:attribute" );
+    pPolygonElementA->SetAttribute( "name", shapeFrictionName );
+    pPolygonComplexTypeElement->LinkEndChild( pPolygonElementA );
+    pPolygonElementB = new TiXmlElement( "xs:simpleType" );
+    pPolygonElementA->LinkEndChild( pPolygonElementB );
+    pPolygonElementC = new TiXmlElement( "xs:restriction" );
+    pPolygonElementC->SetAttribute( "base", "xs:float" );
+    pPolygonElementB->LinkEndChild( pPolygonElementC );
+    pPolygonElementD = new TiXmlElement( "xs:minInclusive" );
+    pPolygonElementD->SetAttribute( "value", "0" );
+    pPolygonElementC->LinkEndChild( pPolygonElementD );
+
+    // Create "Restitution" attribute.
+    pPolygonElementA = new TiXmlElement( "xs:attribute" );
+    pPolygonElementA->SetAttribute( "name", shapeRestitutionName );
+    pPolygonComplexTypeElement->LinkEndChild( pPolygonElementA );
+    pPolygonElementB = new TiXmlElement( "xs:simpleType" );
+    pPolygonElementA->LinkEndChild( pPolygonElementB );
+    pPolygonElementC = new TiXmlElement( "xs:restriction" );
+    pPolygonElementC->SetAttribute( "base", "xs:float" );
+    pPolygonElementB->LinkEndChild( pPolygonElementC );
+    pPolygonElementD = new TiXmlElement( "xs:minInclusive" );
+    pPolygonElementD->SetAttribute( "value", "0" );
+    pPolygonElementC->LinkEndChild( pPolygonElementD );
+
+    // ********************************************************************************
+    // Create Chain
+    // ********************************************************************************
+    TiXmlElement* pChainElement = new TiXmlElement( "xs:element" );
+    pChainElement->SetAttribute( "name", chainTypeName );
+    pChainElement->SetAttribute( "minOccurs", 0 );
+    pChainElement->SetAttribute( "maxOccurs", 1 );
+    pShapesNodeChoiceElement->LinkEndChild( pChainElement );
+
+    // Create complex type Element.
+    TiXmlElement* pChainComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pChainElement->LinkEndChild( pChainComplexTypeElement );
+
+    // Create "Chain" child.
+    TiXmlElement* pChainElementA = new TiXmlElement( "xs:sequence" );
+    pChainComplexTypeElement->LinkEndChild( pChainElementA );
+    TiXmlElement* pChainElementB = new TiXmlElement( "xs:choice" );
+    pChainElementB->SetAttribute( "minOccurs", 0 );
+    pChainElementB->SetAttribute( "maxOccurs", "unbounded" );
+    pChainElementA->LinkEndChild( pChainElementB );
+    TiXmlElement* pChainElementC = new TiXmlElement( "xs:element" );
+    pChainElementC->SetAttribute( "name", shapePointName );
+    pChainElementC->SetAttribute( "type", "Vector2_ConsoleType" );
+    pChainElementB->LinkEndChild( pChainElementC );
+    TiXmlElement* pChainElementD = new TiXmlElement( "xs:element" );
+    pChainElementD->SetAttribute( "name", shapePrevPointName );
+    pChainElementD->SetAttribute( "type", "Vector2_ConsoleType" );
+    pChainElementD->SetAttribute( "minOccurs", 0 );
+    pChainElementD->SetAttribute( "maxOccurs", 1 );
+    pChainElementA->LinkEndChild( pChainElementD );
+    TiXmlElement* pChainElementE = new TiXmlElement( "xs:element" );
+    pChainElementE->SetAttribute( "name", shapeNextPointName );
+    pChainElementE->SetAttribute( "type", "Vector2_ConsoleType" );
+    pChainElementE->SetAttribute( "minOccurs", 0 );
+    pChainElementE->SetAttribute( "maxOccurs", 1 );
+    pChainElementA->LinkEndChild( pChainElementE );
+
+    // Create "IsSensor" attribute.
+    pChainElementA = new TiXmlElement( "xs:attribute" );
+    pChainElementA->SetAttribute( "name", shapeSensorName );
+    pChainElementA->SetAttribute( "type", "xs:boolean" );
+    pChainComplexTypeElement->LinkEndChild( pChainElementA );
+
+    // Create "Density" attribute.
+    pChainElementA = new TiXmlElement( "xs:attribute" );
+    pChainElementA->SetAttribute( "name", shapeDensityName );
+    pChainComplexTypeElement->LinkEndChild( pChainElementA );
+    pChainElementB = new TiXmlElement( "xs:simpleType" );
+    pChainElementA->LinkEndChild( pChainElementB );
+    pChainElementC = new TiXmlElement( "xs:restriction" );
+    pChainElementC->SetAttribute( "base", "xs:float" );
+    pChainElementB->LinkEndChild( pChainElementC );
+    pChainElementD = new TiXmlElement( "xs:minInclusive" );
+    pChainElementD->SetAttribute( "value", "0" );
+    pChainElementC->LinkEndChild( pChainElementD );
+
+    // Create "Friction" attribute.
+    pChainElementA = new TiXmlElement( "xs:attribute" );
+    pChainElementA->SetAttribute( "name", shapeFrictionName );
+    pChainComplexTypeElement->LinkEndChild( pChainElementA );
+    pChainElementB = new TiXmlElement( "xs:simpleType" );
+    pChainElementA->LinkEndChild( pChainElementB );
+    pChainElementC = new TiXmlElement( "xs:restriction" );
+    pChainElementC->SetAttribute( "base", "xs:float" );
+    pChainElementB->LinkEndChild( pChainElementC );
+    pChainElementD = new TiXmlElement( "xs:minInclusive" );
+    pChainElementD->SetAttribute( "value", "0" );
+    pChainElementC->LinkEndChild( pChainElementD );
+
+    // Create "Restitution" attribute.
+    pChainElementA = new TiXmlElement( "xs:attribute" );
+    pChainElementA->SetAttribute( "name", shapeRestitutionName );
+    pChainComplexTypeElement->LinkEndChild( pChainElementA );
+    pChainElementB = new TiXmlElement( "xs:simpleType" );
+    pChainElementA->LinkEndChild( pChainElementB );
+    pChainElementC = new TiXmlElement( "xs:restriction" );
+    pChainElementC->SetAttribute( "base", "xs:float" );
+    pChainElementB->LinkEndChild( pChainElementC );
+    pChainElementD = new TiXmlElement( "xs:minInclusive" );
+    pChainElementD->SetAttribute( "value", "0" );
+    pChainElementC->LinkEndChild( pChainElementD );
+
+    // ********************************************************************************
+    // Create Edge
+    // ********************************************************************************
+    TiXmlElement* pEdgeElement = new TiXmlElement( "xs:element" );
+    pEdgeElement->SetAttribute( "name", edgeTypeName );
+    pEdgeElement->SetAttribute( "minOccurs", 0 );
+    pEdgeElement->SetAttribute( "maxOccurs", 1 );
+    pShapesNodeChoiceElement->LinkEndChild( pEdgeElement );
+
+    // Create complex type Element.
+    TiXmlElement* pEdgeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pEdgeElement->LinkEndChild( pEdgeComplexTypeElement );
+
+    // Create "Edge" child.
+    TiXmlElement* pEdgeElementA = new TiXmlElement( "xs:sequence" );
+    pEdgeComplexTypeElement->LinkEndChild( pEdgeElementA );
+    TiXmlElement* pEdgeElementB = new TiXmlElement( "xs:element" );
+    pEdgeElementB->SetAttribute( "name", shapePointName );
+    pEdgeElementB->SetAttribute( "type", "Vector2_ConsoleType" );
+    pEdgeElementB->SetAttribute( "minOccurs", 0 );
+    pEdgeElementB->SetAttribute( "maxOccurs", 2 );
+    pEdgeElementA->LinkEndChild( pEdgeElementB );
+    TiXmlElement* pEdgeElementC = new TiXmlElement( "xs:element" );
+    pEdgeElementC->SetAttribute( "name", shapePrevPointName );
+    pEdgeElementC->SetAttribute( "type", "Vector2_ConsoleType" );
+    pEdgeElementC->SetAttribute( "minOccurs", 0 );
+    pEdgeElementC->SetAttribute( "maxOccurs", 1 );
+    pEdgeElementA->LinkEndChild( pEdgeElementC );
+    TiXmlElement* pEdgeElementD = new TiXmlElement( "xs:element" );
+    pEdgeElementD->SetAttribute( "name", shapeNextPointName );
+    pEdgeElementD->SetAttribute( "type", "Vector2_ConsoleType" );
+    pEdgeElementD->SetAttribute( "minOccurs", 0 );
+    pEdgeElementD->SetAttribute( "maxOccurs", 1 );
+    pEdgeElementA->LinkEndChild( pEdgeElementD );
+
+    // Create "IsSensor" attribute.
+    pEdgeElementA = new TiXmlElement( "xs:attribute" );
+    pEdgeElementA->SetAttribute( "name", shapeSensorName );
+    pEdgeElementA->SetAttribute( "type", "xs:boolean" );
+    pEdgeComplexTypeElement->LinkEndChild( pEdgeElementA );
+
+    // Create "Density" attribute.
+    pEdgeElementA = new TiXmlElement( "xs:attribute" );
+    pEdgeElementA->SetAttribute( "name", shapeDensityName );
+    pEdgeComplexTypeElement->LinkEndChild( pEdgeElementA );
+    pEdgeElementB = new TiXmlElement( "xs:simpleType" );
+    pEdgeElementA->LinkEndChild( pEdgeElementB );
+    pEdgeElementC = new TiXmlElement( "xs:restriction" );
+    pEdgeElementC->SetAttribute( "base", "xs:float" );
+    pEdgeElementB->LinkEndChild( pEdgeElementC );
+    pEdgeElementD = new TiXmlElement( "xs:minInclusive" );
+    pEdgeElementD->SetAttribute( "value", "0" );
+    pEdgeElementC->LinkEndChild( pEdgeElementD );
+
+    // Create "Friction" attribute.
+    pEdgeElementA = new TiXmlElement( "xs:attribute" );
+    pEdgeElementA->SetAttribute( "name", shapeFrictionName );
+    pEdgeComplexTypeElement->LinkEndChild( pEdgeElementA );
+    pEdgeElementB = new TiXmlElement( "xs:simpleType" );
+    pEdgeElementA->LinkEndChild( pEdgeElementB );
+    pEdgeElementC = new TiXmlElement( "xs:restriction" );
+    pEdgeElementC->SetAttribute( "base", "xs:float" );
+    pEdgeElementB->LinkEndChild( pEdgeElementC );
+    pEdgeElementD = new TiXmlElement( "xs:minInclusive" );
+    pEdgeElementD->SetAttribute( "value", "0" );
+    pEdgeElementC->LinkEndChild( pEdgeElementD );
+
+    // Create "Restitution" attribute.
+    pEdgeElementA = new TiXmlElement( "xs:attribute" );
+    pEdgeElementA->SetAttribute( "name", shapeRestitutionName );
+    pEdgeComplexTypeElement->LinkEndChild( pEdgeElementA );
+    pEdgeElementB = new TiXmlElement( "xs:simpleType" );
+    pEdgeElementA->LinkEndChild( pEdgeElementB );
+    pEdgeElementC = new TiXmlElement( "xs:restriction" );
+    pEdgeElementC->SetAttribute( "base", "xs:float" );
+    pEdgeElementB->LinkEndChild( pEdgeElementC );
+    pEdgeElementD = new TiXmlElement( "xs:minInclusive" );
+    pEdgeElementD->SetAttribute( "value", "0" );
+    pEdgeElementC->LinkEndChild( pEdgeElementD );
+}
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT_SCHEMA(SceneObject, WriteCustomTamlSchema);

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

+ 0 - 150
engine/source/assets/assetManager.cc

@@ -1003,156 +1003,6 @@ void AssetManager::purgeAssets( void )
 
 //-----------------------------------------------------------------------------
 
-bool AssetManager::getAssetSnapshot( AssetSnapshot* pAssetSnapshot, const char* pAssetId )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(AssetManager_GetAssetSnapshot);
-
-    // Sanity!
-    AssertFatal( pAssetSnapshot != NULL, "cannot get asset snapshot using NULL asset snapshot." );
-    AssertFatal( pAssetId != NULL, "Cannot get asset snapshot NULL asset Id." );
-
-    // Find asset.
-    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
-
-    // Did we find the asset?
-    if ( pAssetDefinition == NULL )
-    {
-        // No, so warn.
-        Con::warnf( "Asset Manager: Failed to get asset snapshot of asset Id '%s' as it does not exist.", pAssetId );
-        return false;
-    }
-
-    // Acquire asset.
-    AssetBase* pAssetBase = acquireAsset<AssetBase>( pAssetId );
-
-    // Did we acquire the asset?
-    if ( pAssetBase == NULL )
-    {
-        // No, so warn.
-        Con::warnf( "Asset Manager: Failed to get asset snapshot of asset Id '%s' as it could not be acquired.", pAssetId );
-        return false;
-    }
-
-    // Reset asset snapshot.
-    pAssetSnapshot->resetSnapshot();
-
-    // Fetch asset parent abstract class rep.
-    // NOTE: I don't like referring to types in a string but we don't have much choice here.
-    AbstractClassRep* pAssetBaseParentClassRep = AbstractClassRep::findClassRep( "AssetBase" )->getParentClass();
-
-    // Fetch asset field list.
-    const AbstractClassRep::FieldList& assetFieldList = pAssetBase->getFieldList();
-
-    // Populate asset snapshot.
-    for( Vector<AbstractClassRep::Field>::const_iterator assetFieldItr = assetFieldList.begin(); assetFieldItr != assetFieldList.end(); ++assetFieldItr )
-    {
-        // Skip abstract class rep fields.
-        if (    assetFieldItr->type == AbstractClassRep::StartGroupFieldType ||
-                assetFieldItr->type == AbstractClassRep::EndGroupFieldType ||
-                assetFieldItr->type == AbstractClassRep::DepricatedFieldType )
-            continue;
-
-        // Fetch asset field name.
-        StringTableEntry assetFieldName = assetFieldItr->pFieldname;
-
-        // Skip asset parent field.
-        if ( pAssetBaseParentClassRep->findField( assetFieldName ) != NULL )
-            continue;
-
-        // Fetch asset field value.
-        const char* pFieldValue = pAssetBase->getDataField( assetFieldName, NULL );
-
-        // Set asset snapshot field.
-        pAssetSnapshot->setDataField( assetFieldName, NULL, pFieldValue );
-    }
-
-    // Release asset.
-    releaseAsset( pAssetId );
-
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-
-bool AssetManager::setAssetSnapshot( AssetSnapshot* pAssetSnapshot, const char* pAssetId )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(AssetManager_SetAssetSnapshot);
-
-    // Sanity!
-    AssertFatal( pAssetSnapshot != NULL, "cannot get asset snapshot using NULL asset snapshot." );
-    AssertFatal( pAssetId != NULL, "Cannot get asset snapshot NULL asset Id." );
-
-    // Find asset.
-    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
-
-    // Did we find the asset?
-    if ( pAssetDefinition == NULL )
-    {
-        // No, so warn.
-        Con::warnf( "Asset Manager: Failed to set asset snapshot of asset Id '%s' as it does not exist.", pAssetId );
-        return false;
-    }
-
-    // Acquire asset.
-    AssetBase* pAssetBase = acquireAsset<AssetBase>( pAssetId );
-
-    // Did we acquire the asset?
-    if ( pAssetBase == NULL )
-    {
-        // No, so warn.
-        Con::warnf( "Asset Manager: Failed to set asset snapshot of asset Id '%s' as it could not be acquired.", pAssetId );
-        return false;
-    }
-
-    // Disable asset refresh so we don't perform a refresh on each field change.
-    pAssetDefinition->mAssetRefreshEnable = false;
-
-    // Fetch asset parent abstract class rep.
-    // NOTE: I don't like referring to types in a string but we don't have much choice here.
-    AbstractClassRep* pAssetBaseParentClassRep = AbstractClassRep::findClassRep( "AssetBase" )->getParentClass();
-
-    // Fetch asset name field.
-    StringTableEntry assetNameField = StringTable->insert( ASSET_BASE_ASSETNAME_FIELD );
-
-    SimFieldDictionary* pSnapshotFields = pAssetSnapshot->getFieldDictionary();
-
-    // Iterate snapshot dynamic fields.
-    for( SimFieldDictionaryIterator fieldItr(pSnapshotFields); *fieldItr; ++fieldItr )
-    {
-        // Fetch dynamic field entry.
-        const SimFieldDictionary::Entry* pFieldEntry = *fieldItr;
-
-        // Fetch asset snapshot field name.
-        StringTableEntry assetSnapshotField = pFieldEntry->slotName;
-
-        // Skip asset name field.
-        if ( assetSnapshotField == assetNameField )
-            continue;
-
-        // Skip asset parent field.
-        if ( pAssetBaseParentClassRep->findField( assetSnapshotField ) != NULL )
-            continue;
-
-        // Set asset field.
-        pAssetBase->setDataField( assetSnapshotField, NULL, pFieldEntry->value );
-    }
-
-    // Re-enable asset refresh.
-    pAssetDefinition->mAssetRefreshEnable = true;
-
-    // Refresh asset.
-    refreshAsset( pAssetId );
-
-    // Release asset.
-    releaseAsset( pAssetId );
-
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-
 bool AssetManager::deleteAsset( const char* pAssetId, const bool deleteLooseFiles, const bool deleteDependencies )
 {
     // Debug Profiling.

+ 0 - 8
engine/source/assets/assetManager.h

@@ -47,10 +47,6 @@
 #include "assets/assetDefinition.h"
 #endif
 
-#ifndef _ASSET_SNAPSHOT_H_
-#include "assets/assetSnapshot.h"
-#endif
-
 #ifndef _ASSET_TAGS_MANIFEST_H_
 #include "assets/assetTagsManifest.h"
 #endif
@@ -326,10 +322,6 @@ public:
     bool releaseAsset( const char* pAssetId );
     void purgeAssets( void );
 
-    /// Asset snapshot.
-    bool getAssetSnapshot( AssetSnapshot* pAssetSnapshot, const char* pAssetId );
-    bool setAssetSnapshot( AssetSnapshot* pAssetSnapshot, const char* pAssetId );
-
     /// Asset deletion.
     bool deleteAsset( const char* pAssetId, const bool deleteLooseFiles, const bool deleteDependencies );
 

+ 0 - 50
engine/source/assets/assetManager_ScriptBinding.h

@@ -331,56 +331,6 @@ ConsoleMethod( AssetManager, purgeAssets, void, 2, 2,           "() - Purge all
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod( AssetManager, getAssetSnapshot, bool, 4, 4,      "(assetSnapshot, assetId) - Gets an asset snapshot of the specified asset Id.\n"
-                                                                "@param assetSnapshot The asset snapshot object to populate with the snapshot.\n"
-                                                                "@param assetId The selected asset Id.\n"
-                                                                "@return Whether the getting the asset snapshot was successful or not.")
-{
-    // Fetch asset snapshot.
-    AssetSnapshot* pAssetSnapshot = Sim::findObject<AssetSnapshot>( argv[2] );
-
-    // Did we find the asset snapshot?
-    if ( pAssetSnapshot == NULL )
-    {
-        // No, so warn.
-        Con::warnf( "AssetManager::getAssetSnapshot() - Could not find the asset snapshot object '%s'.", argv[2] );
-        return false;
-    }
-
-    // Fetch asset Id.
-    const char* pAssetId = argv[3];
-
-    // Get asset snapshot.
-    return object->getAssetSnapshot( pAssetSnapshot, pAssetId );
-}
-
-//-----------------------------------------------------------------------------
-
-ConsoleMethod( AssetManager, setAssetSnapshot, bool, 4, 4,      "(assetSnapshot, assetId) - Set an asset snapshot to the specified asset Id.\n"
-                                                                "@param assetSnapshot The asset snapshot object to assign to the specified asset Id.\n"
-                                                                "@param assetId The selected asset Id.\n"
-                                                                "@return Whether setting the asset snapshot was successful or not.")
-{
-    // Fetch asset snapshot.
-    AssetSnapshot* pAssetSnapshot = Sim::findObject<AssetSnapshot>( argv[2] );
-
-    // Did we find the asset snapshot?
-    if ( pAssetSnapshot == NULL )
-    {
-        // No, so warn.
-        Con::warnf( "AssetManager::setAssetSnapshot() - Could not find the asset snapshot object '%s'.", argv[2] );
-        return false;
-    }
-
-    // Fetch asset Id.
-    const char* pAssetId = argv[3];
-
-    // Set asset snapshot.
-    return object->setAssetSnapshot( pAssetSnapshot, pAssetId );
-}
-
-//-----------------------------------------------------------------------------
-
 ConsoleMethod( AssetManager, deleteAsset, bool, 5, 5,   "(assetId, deleteLooseFiles, deleteDependencies) Deletes the specified asset Id and optionally its loose files and asset dependencies.\n"
                                                         "@param assetId The selected asset Id.\n"
                                                         "@param deleteLooseFiles Whether to delete an assets loose files or not.\n"

+ 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 - 1
engine/source/component/behaviors/behaviorInstance.cpp

@@ -84,7 +84,6 @@ void BehaviorInstance::initPersistFields()
    addGroup("Behavior");
       addField("template", TypeSimObjectName, Offset(mTemplate, BehaviorInstance), "Template this instance was created from.");
       addProtectedField( "Owner", TypeSimObjectPtr, Offset(mBehaviorOwner, BehaviorInstance), &setOwner, &defaultProtectedGetFn, "Behavior component owner." );
-      addProtectedField( "Template", TypeSimObjectPtr,0, &defaultProtectedNotSetFn, &getTemplate, "The behavior instances template." );
    endGroup("Behavior");
 
    Parent::initPersistFields();

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

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

@@ -49,13 +49,59 @@ const AbstractClassRep::Field *AbstractClassRep::findField(StringTableEntry name
    return NULL;
 }
 
+//-----------------------------------------------------------------------------
+
+AbstractClassRep* AbstractClassRep::findFieldRoot( StringTableEntry fieldName )
+{
+    // Find the field.
+    const Field* pField = findField( fieldName );
+
+    // Finish if not found.
+    if ( pField == NULL )
+        return NULL;
+
+    // We're the root if we have no parent.
+    if ( getParentClass() == NULL )
+        return this;
+
+    // Find the field root via the parent.
+    AbstractClassRep* pFieldRoot = getParentClass()->findFieldRoot( fieldName );
+
+    // We're the root if the parent does not have it else return the field root.
+    return pFieldRoot == NULL ? this : pFieldRoot;
+}
+
+//-----------------------------------------------------------------------------
+
+AbstractClassRep* AbstractClassRep::findContainerChildRoot( AbstractClassRep* pChild )
+{
+    // Fetch container child.
+    AbstractClassRep* pContainerChildClass = getContainerChildClass( true );
+
+    // Finish if not found.
+    if ( pContainerChildClass == NULL )
+        return NULL;
+
+    // We're the root for the child if we have no parent.
+    if ( getParentClass() == NULL )
+        return this;
+
+    // Find child in parent.
+    AbstractClassRep* pParentContainerChildClass = getParentClass()->findContainerChildRoot( pChild );
+
+    // We;re the root if the parent does not contain the child else return the container root.
+    return pParentContainerChildClass == NULL ? this : pParentContainerChildClass;
+}
+
+//-----------------------------------------------------------------------------
+
 AbstractClassRep* AbstractClassRep::findClassRep(const char* in_pClassName)
 {
    AssertFatal(initialized,
       "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 +115,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 +165,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()

+ 582 - 495
engine/source/console/consoleObject.h

@@ -38,40 +38,56 @@
 #ifndef _CONSOLE_H_
 #include "console/console.h"
 #endif
+#ifndef TINYXML_INCLUDED
+#include "persistence/tinyXML/tinyxml.h"
+#endif
+
+//-----------------------------------------------------------------------------
 
 class Namespace;
 class ConsoleObject;
 
+//-----------------------------------------------------------------------------
+
 enum NetClassTypes {
-   NetClassTypeObject = 0,
-   NetClassTypeDataBlock,
-   NetClassTypeEvent,
-   NetClassTypesCount,
+    NetClassTypeObject = 0,
+    NetClassTypeDataBlock,
+    NetClassTypeEvent,
+    NetClassTypesCount,
 };
 
+//-----------------------------------------------------------------------------
+
 enum NetClassGroups {
-   NetClassGroupGame = 0,
-   NetClassGroupCommunity,
-   NetClassGroup3,
-   NetClassGroup4,
-   NetClassGroupsCount,
+    NetClassGroupGame = 0,
+    NetClassGroupCommunity,
+    NetClassGroup3,
+    NetClassGroup4,
+    NetClassGroupsCount,
 };
 
+//-----------------------------------------------------------------------------
+
 enum NetClassMasks {
-   NetClassGroupGameMask      = BIT(NetClassGroupGame),
-   NetClassGroupCommunityMask = BIT(NetClassGroupCommunity),
+    NetClassGroupGameMask      = BIT(NetClassGroupGame),
+    NetClassGroupCommunityMask = BIT(NetClassGroupCommunity),
 };
 
+//-----------------------------------------------------------------------------
+
 enum NetDirection
 {
-   NetEventDirAny,
-   NetEventDirServerToClient,
-   NetEventDirClientToServer,
+    NetEventDirAny,
+    NetEventDirServerToClient,
+    NetEventDirClientToServer,
 };
 
+//-----------------------------------------------------------------------------
+
 class SimObject;
 class ConsoleTypeValidator;
 
+//-----------------------------------------------------------------------------
 /// Core functionality for class manipulation.
 ///
 /// @section AbstractClassRep_intro Introduction (or, Why AbstractClassRep?)
@@ -164,235 +180,251 @@ class ConsoleTypeValidator;
 ///        bit allocations for network ID fields.
 ///
 /// @nosubgrouping
+//-----------------------------------------------------------------------------
+
 class AbstractClassRep
 {
-   friend class ConsoleObject;
+    friend class ConsoleObject;
 
 public:
+    /// This is a function pointer typedef to support get/set callbacks for fields
+    typedef bool (*SetDataNotify)( void *obj, const char *data );
+    typedef const char *(*GetDataNotify)( void *obj, const char *data );
 
-   /// @name 'Tructors
-   /// @{
-
-   AbstractClassRep() 
-   {
-      VECTOR_SET_ASSOCIATION(mFieldList);
-      parentClass  = NULL;
-   }
-   virtual ~AbstractClassRep() { }
-
-   /// @}
-
-   /// @name Representation Interface
-   /// @{
-
-   S32 mClassGroupMask;                ///< Mask indicating in which NetGroups this object belongs.
-   S32 mClassType;                     ///< Stores the NetClass of this class.
-   S32 mNetEventDir;                   ///< Stores the NetDirection of this class.
-   S32 mClassId[NetClassGroupsCount];  ///< Stores the IDs assigned to this class for each group.
-
-   S32                        getClassId  (U32 netClassGroup)   const;
-   static U32                 getClassCRC (U32 netClassGroup);
-   const char*                getClassName() const;
-   static AbstractClassRep*   getClassList();
-   Namespace*                 getNameSpace();
-   AbstractClassRep*          getNextClass();
-   AbstractClassRep*          getParentClass();
-
-   /// Helper class to see if we are a given class, or a subclass thereof.
-   bool                       isClass(AbstractClassRep  *acr)
-   {
-      AbstractClassRep  *walk = this;
-
-      //  Walk up parents, checking for equivalence.
-      while(walk)
-      {
-         if(walk == acr)
-            return true;
-
-         walk = walk->parentClass;
-      };
+    /// This is a function pointer typedef to support optional writing for fields.
+    typedef bool (*WriteDataNotify)( void* obj, const char* pFieldName );
 
-      return false;
-   }
-
-   virtual ConsoleObject*     create      () const = 0;
+    /// Allows the writing of a custom TAML schema.
+    typedef void (*WriteCustomTamlSchema)( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement );
 
 protected:
-   virtual void init() const = 0;
-
-   const char *       mClassName;
-   AbstractClassRep * nextClass;
-   AbstractClassRep * parentClass;
-   Namespace *        mNamespace;
+    const char *       mClassName;
+    AbstractClassRep * nextClass;
+    AbstractClassRep * parentClass;
+    Namespace *        mNamespace;
 
-   /// @}
+    static AbstractClassRep ** classTable[NetClassGroupsCount][NetClassTypesCount];
+    static AbstractClassRep *  classLinkList;
+    static U32                 classCRC[NetClassGroupsCount];
+    static bool                initialized;
 
+    static ConsoleObject* create(const char*  in_pClassName);
+    static ConsoleObject* create(const U32 groupId, const U32 typeId, const U32 in_classId);
 
-   /// @name Fields
-   /// @{
 public:
-
-   /// This is a function pointer typedef to support get/set callbacks for fields
-   typedef bool (*SetDataNotify)( void *obj, const char *data );
-   typedef const char *(*GetDataNotify)( void *obj, const char *data );
-
-   /// This is a function pointer typedef to support optional writing for fields.
-   typedef bool (*WriteDataNotify)( void* obj, const char* pFieldName );
-
-   enum ACRFieldTypes
-   {
-      StartGroupFieldType = 0xFFFFFFFD,
-      EndGroupFieldType   = 0xFFFFFFFE,
-      DepricatedFieldType = 0xFFFFFFFF
-   };
-
-   struct Field {
-      const char* pFieldname;    ///< Name of the field.
-      const char* pGroupname;      ///< Optionally filled field containing the group name.
-                                 ///
-                                 ///  This is filled when type is StartField or EndField
-
-      const char*    pFieldDocs;    ///< Documentation about this field; see consoleDoc.cc.
-      bool           groupExpand;   ///< Flag to track expanded/not state of this group in the editor.
-      U32            type;          ///< A type ID. @see ACRFieldTypes
-      U32            offset;        ///< Memory offset from beginning of class for this field.
-      S32            elementCount;  ///< Number of elements, if this is an array.
-      EnumTable *    table;         ///< If this is an enum, this points to the table defining it.
-      BitSet32       flag;          ///< Stores various flags
-      ConsoleTypeValidator *validator;     ///< Validator, if any.
-      SetDataNotify  setDataFn;     ///< Set data notify Fn
-      GetDataNotify  getDataFn;     ///< Get data notify Fn
-      WriteDataNotify writeDataFn;   ///< Function to determine whether data should be written or not.
-   };
-   typedef Vector<Field> FieldList;
-
-   FieldList mFieldList;
-
-   bool mDynamicGroupExpand;
-
-   const Field *findField(StringTableEntry fieldName) const;
-   
-   /// @}
-
-   /// @name Abstract Class Database
-   /// @{
-
-protected:
-   static AbstractClassRep ** classTable[NetClassGroupsCount][NetClassTypesCount];
-   static AbstractClassRep *  classLinkList;
-   static U32                 classCRC[NetClassGroupsCount];
-   static bool                initialized;
-
-   static ConsoleObject* create(const char*  in_pClassName);
-   static ConsoleObject* create(const U32 groupId, const U32 typeId, const U32 in_classId);
+    enum ACRFieldTypes
+    {
+        StartGroupFieldType = 0xFFFFFFFD,
+        EndGroupFieldType   = 0xFFFFFFFE,
+        DepricatedFieldType = 0xFFFFFFFF
+    };
+
+    struct Field {
+        const char* pFieldname;    ///< Name of the field.
+        const char* pGroupname;      ///< Optionally filled field containing the group name.
+        ///
+        ///  This is filled when type is StartField or EndField
+
+        const char*    pFieldDocs;    ///< Documentation about this field; see consoleDoc.cc.
+        bool           groupExpand;   ///< Flag to track expanded/not state of this group in the editor.
+        U32            type;          ///< A type ID. @see ACRFieldTypes
+        U32            offset;        ///< Memory offset from beginning of class for this field.
+        S32            elementCount;  ///< Number of elements, if this is an array.
+        EnumTable *    table;         ///< If this is an enum, this points to the table defining it.
+        BitSet32       flag;          ///< Stores various flags
+        ConsoleTypeValidator *validator;     ///< Validator, if any.
+        SetDataNotify  setDataFn;     ///< Set data notify Fn
+        GetDataNotify  getDataFn;     ///< Get data notify Fn
+        WriteDataNotify writeDataFn;   ///< Function to determine whether data should be written or not.
+    };
+    typedef Vector<Field> FieldList;
+
+    FieldList mFieldList;
+
+    bool mDynamicGroupExpand;
+
+    static U32  NetClassCount [NetClassGroupsCount][NetClassTypesCount];
+    static U32  NetClassBitSize[NetClassGroupsCount][NetClassTypesCount];
+
+    static void registerClassRep(AbstractClassRep*);
+    static AbstractClassRep* findClassRep(const char* in_pClassName);
+    static void initialize(); // Called from Con::init once on startup
+    static void destroyFieldValidators(AbstractClassRep::FieldList &mFieldList);
 
 public:
-   static U32  NetClassCount [NetClassGroupsCount][NetClassTypesCount];
-   static U32  NetClassBitSize[NetClassGroupsCount][NetClassTypesCount];
-
-   static void registerClassRep(AbstractClassRep*);
-   static AbstractClassRep* findClassRep(const char* in_pClassName);
-   static void initialize(); // Called from Con::init once on startup
-   static void destroyFieldValidators(AbstractClassRep::FieldList &mFieldList);
+    AbstractClassRep() 
+    {
+        VECTOR_SET_ASSOCIATION(mFieldList);
+        parentClass  = NULL;
+    }
+    virtual ~AbstractClassRep() { }
+
+    S32 mClassGroupMask;                ///< Mask indicating in which NetGroups this object belongs.
+    S32 mClassType;                     ///< Stores the NetClass of this class.
+    S32 mNetEventDir;                   ///< Stores the NetDirection of this class.
+    S32 mClassId[NetClassGroupsCount];  ///< Stores the IDs assigned to this class for each group.
+
+    S32                          getClassId  (U32 netClassGroup)   const;
+    static U32                   getClassCRC (U32 netClassGroup);
+    const char*                  getClassName() const;
+    static AbstractClassRep*     getClassList();
+    Namespace*                   getNameSpace();
+    AbstractClassRep*            getNextClass();
+    AbstractClassRep*            getParentClass();
+    virtual AbstractClassRep*    getContainerChildClass( const bool recurse ) = 0;
+    virtual WriteCustomTamlSchema getCustomTamlSchema( void ) = 0;
+
+    /// Helper class to see if we are a given class, or a subclass thereof.
+    bool                       isClass(AbstractClassRep  *acr)
+    {
+        AbstractClassRep  *walk = this;
+
+        //  Walk up parents, checking for equivalence.
+        while(walk)
+        {
+            if(walk == acr)
+                return true;
+
+            walk = walk->parentClass;
+        };
+
+        return false;
+    }
 
+public:
+    virtual ConsoleObject* create() const = 0;
+    const Field *findField(StringTableEntry fieldName) const;
+    AbstractClassRep* findFieldRoot( StringTableEntry fieldName );
+    AbstractClassRep* findContainerChildRoot( AbstractClassRep* pChild );
 
-   /// @}
+protected:
+    virtual void init() const = 0;
 };
 
+//-----------------------------------------------------------------------------
+
 inline AbstractClassRep *AbstractClassRep::getClassList()
 {
-   return classLinkList;
+    return classLinkList;
 }
 
+//-----------------------------------------------------------------------------
+
 inline U32 AbstractClassRep::getClassCRC(U32 group)
 {
-   return classCRC[group];
+    return classCRC[group];
 }
 
+//-----------------------------------------------------------------------------
+
 inline AbstractClassRep *AbstractClassRep::getNextClass()
 {
-   return nextClass;
+    return nextClass;
 }
 
+//-----------------------------------------------------------------------------
+
 inline AbstractClassRep *AbstractClassRep::getParentClass()
 {
-   return parentClass;
+    return parentClass;
 }
 
+
+//-----------------------------------------------------------------------------
 inline S32 AbstractClassRep::getClassId(U32 group) const
 {
-   return mClassId[group];
+    return mClassId[group];
 }
 
+//-----------------------------------------------------------------------------
+
 inline const char* AbstractClassRep::getClassName() const
 {
-   return mClassName;
+    return mClassName;
 }
 
+//-----------------------------------------------------------------------------
+
 inline Namespace *AbstractClassRep::getNameSpace()
 {
-   return mNamespace;
+    return mNamespace;
 }
 
-//------------------------------------------------------------------------------
-//-------------------------------------- ConcreteClassRep
-//
-
+//-----------------------------------------------------------------------------
 
-/// Helper class for AbstractClassRep.
-///
-/// @see AbtractClassRep
-/// @see ConsoleObject
 template <class T>
 class ConcreteClassRep : public AbstractClassRep
 {
 public:
-   ConcreteClassRep(const char *name, S32 netClassGroupMask, S32 netClassType, S32 netEventDir, AbstractClassRep *parent)
-   {
-      // name is a static compiler string so no need to worry about copying or deleting
-      mClassName = name;
-
-      // Clean up mClassId
-      for(U32 i = 0; i < NetClassGroupsCount; i++)
-         mClassId[i] = -1;
-
-      // Set properties for this ACR
-      mClassType      = netClassType;
-      mClassGroupMask = netClassGroupMask;
-      mNetEventDir    = netEventDir;
-      parentClass     = parent;
-
-      // Finally, register ourselves.
-      registerClassRep(this);
-   };
-
-   /// Perform class specific initialization tasks.
-   ///
-   /// Link namespaces, call initPersistFields() and consoleInit().
-   void init() const
-   {
-      // Get handle to our parent class, if any, and ourselves (we are our parent's child).
-      AbstractClassRep *parent = T::getParentStaticClassRep();
-      AbstractClassRep *child  = T::getStaticClassRep      ();
-
-      // If we got reps, then link those namespaces! (To get proper inheritance.)
-      if(parent && child)
-         Con::classLinkNamespaces(parent->getNameSpace(), child->getNameSpace());
-
-      // Finally, do any class specific initialization...
-      T::initPersistFields();
-      T::consoleInit();
-   }
-
-   /// Wrap constructor.
-   ConsoleObject* create() const { return new T; }
+    ConcreteClassRep(const char *name, S32 netClassGroupMask, S32 netClassType, S32 netEventDir, AbstractClassRep *parent )
+    {
+        // name is a static compiler string so no need to worry about copying or deleting
+        mClassName = name;
+
+        // Clean up mClassId
+        for(U32 i = 0; i < NetClassGroupsCount; i++)
+            mClassId[i] = -1;
+
+        // Set properties for this ACR
+        mClassType      = netClassType;
+        mClassGroupMask = netClassGroupMask;
+        mNetEventDir    = netEventDir;
+        parentClass     = parent;
+
+        // Finally, register ourselves.
+        registerClassRep(this);
+    };
+
+    virtual AbstractClassRep* getContainerChildClass( const bool recurse )
+    {
+        // Fetch container children type.
+        AbstractClassRep* pChildren = T::getContainerChildStaticClassRep();
+        if ( !recurse || pChildren != NULL )
+            return pChildren;
+
+        // Fetch parent type.
+        AbstractClassRep* pParent = T::getParentStaticClassRep();
+        if ( pParent == NULL )
+            return NULL;
+
+        // Get parent container children.
+        return pParent->getContainerChildClass( recurse );
+    }
+
+    virtual WriteCustomTamlSchema getCustomTamlSchema( void )
+    {
+        return T::getStaticWriteCustomTamlSchema();
+    }
+
+    /// Perform class specific initialization tasks.
+    ///
+    /// Link namespaces, call initPersistFields() and consoleInit().
+    void init() const
+    {
+        // Get handle to our parent class, if any, and ourselves (we are our parent's child).
+        AbstractClassRep *parent      = T::getParentStaticClassRep();
+        AbstractClassRep *child       = T::getStaticClassRep();
+
+        // If we got reps, then link those namespaces! (To get proper inheritance.)
+        if(parent && child)
+            Con::classLinkNamespaces(parent->getNameSpace(), child->getNameSpace());
+
+        // Finally, do any class specific initialization...
+        T::initPersistFields();
+        T::consoleInit();
+    }
+
+    /// Wrap constructor.
+    ConsoleObject* create() const { return new T; }
 };
 
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
 // Forward declarations so they can be used in the class
 const char *defaultProtectedGetFn( void *obj, const char *data );
 bool defaultProtectedWriteFn( void* obj, StringTableEntry pFieldName );
 
+//-----------------------------------------------------------------------------
 /// Interface class to the console.
 ///
 /// @section ConsoleObject_basics The Basics
@@ -443,396 +475,451 @@ bool defaultProtectedWriteFn( void* obj, StringTableEntry pFieldName );
 ///
 /// @see AbstractClassRep for gory implementation details.
 /// @nosubgrouping
+//-----------------------------------------------------------------------------
+
 class ConsoleObject
 {
 protected:
-   /// @deprecated This is disallowed.
-   ConsoleObject() { /* disallowed */ }
-   /// @deprecated This is disallowed.
-   ConsoleObject(const ConsoleObject&);
+    /// @deprecated This is disallowed.
+    ConsoleObject() { /* disallowed */ }
+    /// @deprecated This is disallowed.
+    ConsoleObject(const ConsoleObject&);
 
 public:
-   /// Get a reference to a field by name.
-   const AbstractClassRep::Field* findField(StringTableEntry fieldName) const;
+    /// Get a reference to a field by name.
+    const AbstractClassRep::Field* findField(StringTableEntry fieldName) const;
 
-   /// Gets the ClassRep.
-   virtual AbstractClassRep* getClassRep() const;
+    /// Gets the ClassRep.
+    virtual AbstractClassRep* getClassRep() const;
 
-   /// Set the value of a field.
-   bool setField(const char *fieldName, const char *value);
-   virtual ~ConsoleObject();
+    /// Set the value of a field.
+    bool setField(const char *fieldName, const char *value);
+    virtual ~ConsoleObject();
 
 public:
-   /// @name Object Creation
-   /// @{
-   static ConsoleObject* create(const char*  in_pClassName);
-   static ConsoleObject* create(const U32 groupId, const U32 typeId, const U32 in_classId);
-   /// @}
+    /// @name Object Creation
+    /// @{
+    static ConsoleObject* create(const char*  in_pClassName);
+    static ConsoleObject* create(const U32 groupId, const U32 typeId, const U32 in_classId);
+    /// @}
 
 public:
-   /// Get the classname from a class tag.
-   static const char* lookupClassName(const U32 in_classTag);
+    /// Get the classname from a class tag.
+    static const char* lookupClassName(const U32 in_classTag);
 
 protected:
-   /// @name Fields
-   /// @{
-
-   /// Mark the beginning of a group of fields.
-   ///
-   /// This is used in the consoleDoc system.
-   /// @see console_autodoc
-   static void addGroup(const char*  in_pGroupname, const char* in_pGroupDocs = NULL);
-
-   /// Mark the end of a group of fields.
-   ///
-   /// This is used in the consoleDoc system.
-   /// @see console_autodoc
-   static void endGroup(const char*  in_pGroupname);
-
-   /// Register a complex field.
-   ///
-   /// @param  in_pFieldname     Name of the field.
-   /// @param  in_fieldType      Type of the field. @see ConsoleDynamicTypes
-   /// @param  in_fieldOffset    Offset to  the field from the start of the class; calculated using the Offset() macro.
-   /// @param  in_elementCount   Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
-   /// @param  in_table          An EnumTable, if this is an enumerated field.
-   /// @param  in_pFieldDocs     Usage string for this field. @see console_autodoc
-   static void addField(const char*   in_pFieldname,
-      const U32     in_fieldType,
-      const dsize_t in_fieldOffset,
-      const U32     in_elementCount = 1,
-      EnumTable *   in_table        = NULL,
-      const char*   in_pFieldDocs   = NULL);
-
-   /// Register a complex field with a write notify.
-   ///
-   /// @param  in_pFieldname     Name of the field.
-   /// @param  in_fieldType      Type of the field. @see ConsoleDynamicTypes
-   /// @param  in_fieldOffset    Offset to  the field from the start of the class; calculated using the Offset() macro.
-   /// @param  in_writeDataFn    This method will return whether the field should be written or not.
-   /// @param  in_elementCount   Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
-   /// @param  in_table          An EnumTable, if this is an enumerated field.
-   /// @param  in_pFieldDocs     Usage string for this field. @see console_autodoc
-   static void addField(const char*   in_pFieldname,
-      const U32     in_fieldType,
-      const dsize_t in_fieldOffset,
-      AbstractClassRep::WriteDataNotify in_writeDataFn,
-      const U32     in_elementCount = 1,
-      EnumTable *   in_table        = NULL,
-      const char*   in_pFieldDocs   = NULL);
-
-   /// Register a simple field.
-   ///
-   /// @param  in_pFieldname  Name of the field.
-   /// @param  in_fieldType   Type of the field. @see ConsoleDynamicTypes
-   /// @param  in_fieldOffset Offset to  the field from the start of the class; calculated using the Offset() macro.
-   /// @param  in_pFieldDocs  Usage string for this field. @see console_autodoc
-   static void addField(const char*   in_pFieldname,
-      const U32     in_fieldType,
-      const dsize_t in_fieldOffset,
-      const char*   in_pFieldDocs);
-
-
-   /// Register a simple field with a write notify.
-   ///
-   /// @param  in_pFieldname  Name of the field.
-   /// @param  in_fieldType   Type of the field. @see ConsoleDynamicTypes
-   /// @param  in_fieldOffset Offset to  the field from the start of the class; calculated using the Offset() macro.
-   /// @param  in_writeDataFn    This method will return whether the field should be written or not.
-   /// @param  in_pFieldDocs  Usage string for this field. @see console_autodoc
-   static void addField(const char*   in_pFieldname,
-      const U32     in_fieldType,
-      const dsize_t in_fieldOffset,
-      AbstractClassRep::WriteDataNotify in_writeDataFn,
-      const char*   in_pFieldDocs );
-
-   /// Register a validated field.
-   ///
-   /// A validated field is just like a normal field except that you can't
-   /// have it be an array, and that you give it a pointer to a ConsoleTypeValidator
-   /// subclass, which is then used to validate any value placed in it. Invalid
-   /// values are ignored and an error is printed to the console.
-   ///
-   /// @see addField
-   /// @see typeValidators.h
-   static void addFieldV(const char*   in_pFieldname,
-      const U32      in_fieldType,
-      const dsize_t  in_fieldOffset,
-      ConsoleTypeValidator *v,
-      const char *   in_pFieldDocs = NULL);
-
-   /// Register a complex protected field.
-   ///
-   /// @param  in_pFieldname     Name of the field.
-   /// @param  in_fieldType      Type of the field. @see ConsoleDynamicTypes
-   /// @param  in_fieldOffset    Offset to  the field from the start of the class; calculated using the Offset() macro.
-   /// @param  in_setDataFn      When this field gets set, it will call the callback provided. @see console_protected
-   /// @param  in_getDataFn      When this field is accessed for it's data, it will return the value of this function
-   /// @param  in_elementCount   Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
-   /// @param  in_table          An EnumTable, if this is an enumerated field.
-   /// @param  in_pFieldDocs     Usage string for this field. @see console_autodoc
-   static void addProtectedField(const char*   in_pFieldname,
-      const U32     in_fieldType,
-      const dsize_t in_fieldOffset,
-      AbstractClassRep::SetDataNotify in_setDataFn,
-      AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
-      const U32     in_elementCount = 1,
-      EnumTable *   in_table        = NULL,
-      const char*   in_pFieldDocs   = NULL);
-
-   /// Register a complex protected field.
-   ///
-   /// @param  in_pFieldname     Name of the field.
-   /// @param  in_fieldType      Type of the field. @see ConsoleDynamicTypes
-   /// @param  in_fieldOffset    Offset to  the field from the start of the class; calculated using the Offset() macro.
-   /// @param  in_setDataFn      When this field gets set, it will call the callback provided. @see console_protected
-   /// @param  in_getDataFn      When this field is accessed for it's data, it will return the value of this function
-   /// @param  in_writeDataFn    This method will return whether the field should be written or not.
-   /// @param  in_elementCount   Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
-   /// @param  in_table          An EnumTable, if this is an enumerated field.
-   /// @param  in_pFieldDocs     Usage string for this field. @see console_autodoc
-   static void addProtectedField(const char*   in_pFieldname,
-      const U32     in_fieldType,
-      const dsize_t in_fieldOffset,
-      AbstractClassRep::SetDataNotify in_setDataFn,
-      AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
-      AbstractClassRep::WriteDataNotify in_writeDataFn = &defaultProtectedWriteFn,
-      const U32     in_elementCount = 1,
-      EnumTable *   in_table        = NULL,
-      const char*   in_pFieldDocs   = NULL);
-
-   /// Register a simple protected field.
-   ///
-   /// @param  in_pFieldname  Name of the field.
-   /// @param  in_fieldType   Type of the field. @see ConsoleDynamicTypes
-   /// @param  in_fieldOffset Offset to  the field from the start of the class; calculated using the Offset() macro.
-   /// @param  in_setDataFn   When this field gets set, it will call the callback provided. @see console_protected
-   /// @param  in_getDataFn   When this field is accessed for it's data, it will return the value of this function
-   /// @param  in_pFieldDocs  Usage string for this field. @see console_autodoc
-   static void addProtectedField(const char*   in_pFieldname,
-      const U32     in_fieldType,
-      const dsize_t in_fieldOffset,
-      AbstractClassRep::SetDataNotify in_setDataFn,
-      AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
-      const char*   in_pFieldDocs = NULL);
-
-   /// Register a simple protected field.
-   ///
-   /// @param  in_pFieldname  Name of the field.
-   /// @param  in_fieldType   Type of the field. @see ConsoleDynamicTypes
-   /// @param  in_fieldOffset Offset to  the field from the start of the class; calculated using the Offset() macro.
-   /// @param  in_setDataFn   When this field gets set, it will call the callback provided. @see console_protected
-   /// @param  in_getDataFn   When this field is accessed for it's data, it will return the value of this function
-   /// @param  in_writeDataFn    This method will return whether the field should be written or not.
-   /// @param  in_pFieldDocs  Usage string for this field. @see console_autodoc
-   static void addProtectedField(const char*   in_pFieldname,
-      const U32     in_fieldType,
-      const dsize_t in_fieldOffset,
-      AbstractClassRep::SetDataNotify in_setDataFn,
-      AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
-      AbstractClassRep::WriteDataNotify in_writeDataFn = &defaultProtectedWriteFn,
-      const char*   in_pFieldDocs = NULL);
-
-   /// Add a deprecated field.
-   ///
-   /// A deprecated field will always be undefined, even if you assign a value to it. This
-   /// is useful when you need to make sure that a field is not being used anymore.
-   static void addDepricatedField(const char *fieldName);
-
-   /// Remove a field.
-   ///
-   /// Sometimes, you just have to remove a field!
-   /// @returns True on success.
-   static bool removeField(const char* in_pFieldname);
-
-   /// @}
+    /// @name Fields
+    /// @{
+
+    /// Mark the beginning of a group of fields.
+    ///
+    /// This is used in the consoleDoc system.
+    /// @see console_autodoc
+    static void addGroup(const char*  in_pGroupname, const char* in_pGroupDocs = NULL);
+
+    /// Mark the end of a group of fields.
+    ///
+    /// This is used in the consoleDoc system.
+    /// @see console_autodoc
+    static void endGroup(const char*  in_pGroupname);
+
+    /// Register a complex field.
+    ///
+    /// @param  in_pFieldname     Name of the field.
+    /// @param  in_fieldType      Type of the field. @see ConsoleDynamicTypes
+    /// @param  in_fieldOffset    Offset to  the field from the start of the class; calculated using the Offset() macro.
+    /// @param  in_elementCount   Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
+    /// @param  in_table          An EnumTable, if this is an enumerated field.
+    /// @param  in_pFieldDocs     Usage string for this field. @see console_autodoc
+    static void addField(const char*   in_pFieldname,
+        const U32     in_fieldType,
+        const dsize_t in_fieldOffset,
+        const U32     in_elementCount = 1,
+        EnumTable *   in_table        = NULL,
+        const char*   in_pFieldDocs   = NULL);
+
+    /// Register a complex field with a write notify.
+    ///
+    /// @param  in_pFieldname     Name of the field.
+    /// @param  in_fieldType      Type of the field. @see ConsoleDynamicTypes
+    /// @param  in_fieldOffset    Offset to  the field from the start of the class; calculated using the Offset() macro.
+    /// @param  in_writeDataFn    This method will return whether the field should be written or not.
+    /// @param  in_elementCount   Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
+    /// @param  in_table          An EnumTable, if this is an enumerated field.
+    /// @param  in_pFieldDocs     Usage string for this field. @see console_autodoc
+    static void addField(const char*   in_pFieldname,
+        const U32     in_fieldType,
+        const dsize_t in_fieldOffset,
+        AbstractClassRep::WriteDataNotify in_writeDataFn,
+        const U32     in_elementCount = 1,
+        EnumTable *   in_table        = NULL,
+        const char*   in_pFieldDocs   = NULL);
+
+    /// Register a simple field.
+    ///
+    /// @param  in_pFieldname  Name of the field.
+    /// @param  in_fieldType   Type of the field. @see ConsoleDynamicTypes
+    /// @param  in_fieldOffset Offset to  the field from the start of the class; calculated using the Offset() macro.
+    /// @param  in_pFieldDocs  Usage string for this field. @see console_autodoc
+    static void addField(const char*   in_pFieldname,
+        const U32     in_fieldType,
+        const dsize_t in_fieldOffset,
+        const char*   in_pFieldDocs);
+
+
+    /// Register a simple field with a write notify.
+    ///
+    /// @param  in_pFieldname  Name of the field.
+    /// @param  in_fieldType   Type of the field. @see ConsoleDynamicTypes
+    /// @param  in_fieldOffset Offset to  the field from the start of the class; calculated using the Offset() macro.
+    /// @param  in_writeDataFn    This method will return whether the field should be written or not.
+    /// @param  in_pFieldDocs  Usage string for this field. @see console_autodoc
+    static void addField(const char*   in_pFieldname,
+        const U32     in_fieldType,
+        const dsize_t in_fieldOffset,
+        AbstractClassRep::WriteDataNotify in_writeDataFn,
+        const char*   in_pFieldDocs );
+
+    /// Register a validated field.
+    ///
+    /// A validated field is just like a normal field except that you can't
+    /// have it be an array, and that you give it a pointer to a ConsoleTypeValidator
+    /// subclass, which is then used to validate any value placed in it. Invalid
+    /// values are ignored and an error is printed to the console.
+    ///
+    /// @see addField
+    /// @see typeValidators.h
+    static void addFieldV(const char*   in_pFieldname,
+        const U32      in_fieldType,
+        const dsize_t  in_fieldOffset,
+        ConsoleTypeValidator *v,
+        const char *   in_pFieldDocs = NULL);
+
+    /// Register a complex protected field.
+    ///
+    /// @param  in_pFieldname     Name of the field.
+    /// @param  in_fieldType      Type of the field. @see ConsoleDynamicTypes
+    /// @param  in_fieldOffset    Offset to  the field from the start of the class; calculated using the Offset() macro.
+    /// @param  in_setDataFn      When this field gets set, it will call the callback provided. @see console_protected
+    /// @param  in_getDataFn      When this field is accessed for it's data, it will return the value of this function
+    /// @param  in_elementCount   Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
+    /// @param  in_table          An EnumTable, if this is an enumerated field.
+    /// @param  in_pFieldDocs     Usage string for this field. @see console_autodoc
+    static void addProtectedField(const char*   in_pFieldname,
+        const U32     in_fieldType,
+        const dsize_t in_fieldOffset,
+        AbstractClassRep::SetDataNotify in_setDataFn,
+        AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
+        const U32     in_elementCount = 1,
+        EnumTable *   in_table        = NULL,
+        const char*   in_pFieldDocs   = NULL);
+
+    /// Register a complex protected field.
+    ///
+    /// @param  in_pFieldname     Name of the field.
+    /// @param  in_fieldType      Type of the field. @see ConsoleDynamicTypes
+    /// @param  in_fieldOffset    Offset to  the field from the start of the class; calculated using the Offset() macro.
+    /// @param  in_setDataFn      When this field gets set, it will call the callback provided. @see console_protected
+    /// @param  in_getDataFn      When this field is accessed for it's data, it will return the value of this function
+    /// @param  in_writeDataFn    This method will return whether the field should be written or not.
+    /// @param  in_elementCount   Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
+    /// @param  in_table          An EnumTable, if this is an enumerated field.
+    /// @param  in_pFieldDocs     Usage string for this field. @see console_autodoc
+    static void addProtectedField(const char*   in_pFieldname,
+        const U32     in_fieldType,
+        const dsize_t in_fieldOffset,
+        AbstractClassRep::SetDataNotify in_setDataFn,
+        AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
+        AbstractClassRep::WriteDataNotify in_writeDataFn = &defaultProtectedWriteFn,
+        const U32     in_elementCount = 1,
+        EnumTable *   in_table        = NULL,
+        const char*   in_pFieldDocs   = NULL);
+
+    /// Register a simple protected field.
+    ///
+    /// @param  in_pFieldname  Name of the field.
+    /// @param  in_fieldType   Type of the field. @see ConsoleDynamicTypes
+    /// @param  in_fieldOffset Offset to  the field from the start of the class; calculated using the Offset() macro.
+    /// @param  in_setDataFn   When this field gets set, it will call the callback provided. @see console_protected
+    /// @param  in_getDataFn   When this field is accessed for it's data, it will return the value of this function
+    /// @param  in_pFieldDocs  Usage string for this field. @see console_autodoc
+    static void addProtectedField(const char*   in_pFieldname,
+        const U32     in_fieldType,
+        const dsize_t in_fieldOffset,
+        AbstractClassRep::SetDataNotify in_setDataFn,
+        AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
+        const char*   in_pFieldDocs = NULL);
+
+    /// Register a simple protected field.
+    ///
+    /// @param  in_pFieldname  Name of the field.
+    /// @param  in_fieldType   Type of the field. @see ConsoleDynamicTypes
+    /// @param  in_fieldOffset Offset to  the field from the start of the class; calculated using the Offset() macro.
+    /// @param  in_setDataFn   When this field gets set, it will call the callback provided. @see console_protected
+    /// @param  in_getDataFn   When this field is accessed for it's data, it will return the value of this function
+    /// @param  in_writeDataFn    This method will return whether the field should be written or not.
+    /// @param  in_pFieldDocs  Usage string for this field. @see console_autodoc
+    static void addProtectedField(const char*   in_pFieldname,
+        const U32     in_fieldType,
+        const dsize_t in_fieldOffset,
+        AbstractClassRep::SetDataNotify in_setDataFn,
+        AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
+        AbstractClassRep::WriteDataNotify in_writeDataFn = &defaultProtectedWriteFn,
+        const char*   in_pFieldDocs = NULL);
+
+    /// Add a deprecated field.
+    ///
+    /// A deprecated field will always be undefined, even if you assign a value to it. This
+    /// is useful when you need to make sure that a field is not being used anymore.
+    static void addDepricatedField(const char *fieldName);
+
+    /// Remove a field.
+    ///
+    /// Sometimes, you just have to remove a field!
+    /// @returns True on success.
+    static bool removeField(const char* in_pFieldname);
+
+    /// @}
 public:
-   /// Register dynamic fields in a subclass of ConsoleObject.
-   ///
-   /// @see addField(), addFieldV(), addDepricatedField(), addGroup(), endGroup()
-   static void initPersistFields();
-
-   /// Register global constant variables and do other one-time initialization tasks in
-   /// a subclass of ConsoleObject.
-   ///
-   /// @deprecated You should use ConsoleMethod and ConsoleFunction, not this, to
-   ///             register methods or commands.
-   /// @see console
-   static void consoleInit();
-
-   /// @name Field List
-   /// @{
-
-   /// Get a list of all the fields. This information cannot be modified.
-   const AbstractClassRep::FieldList& getFieldList() const;
-
-   /// Get a list of all the fields, set up so we can modify them.
-   ///
-   /// @note This is a bad trick to pull if you aren't very careful,
-   ///       since you can blast field data!
-   AbstractClassRep::FieldList& getModifiableFieldList();
-
-   /// Get a handle to a boolean telling us if we expanded the dynamic group.
-   ///
-   /// @see GuiInspector::Inspect()
-   bool& getDynamicGroupExpand();
-   /// @}
-
-   /// @name ConsoleObject Implementation
-   ///
-   /// These functions are implemented in every subclass of
-   /// ConsoleObject by an IMPLEMENT_CONOBJECT or IMPLEMENT_CO_* macro.
-   /// @{
-
-   /// Get the abstract class information for this class.
-   static AbstractClassRep *getStaticClassRep() { return NULL; }
-
-   /// Get the abstract class information for this class's superclass.
-   static AbstractClassRep *getParentStaticClassRep() { return NULL; }
-
-   /// Get our network-layer class id.
-   ///
-   /// @param  netClassGroup  The net class for which we want our ID.
-   /// @see
-   S32 getClassId(U32 netClassGroup) const;
-
-   /// Get our compiler and platform independent class name.
-   ///
-   /// @note This name can be used to instantiate another instance using create()
-   const char *getClassName() const;
-
-   /// @}
+    /// Register dynamic fields in a subclass of ConsoleObject.
+    ///
+    /// @see addField(), addFieldV(), addDepricatedField(), addGroup(), endGroup()
+    static void initPersistFields();
+
+    /// Register global constant variables and do other one-time initialization tasks in
+    /// a subclass of ConsoleObject.
+    ///
+    /// @deprecated You should use ConsoleMethod and ConsoleFunction, not this, to
+    ///             register methods or commands.
+    /// @see console
+    static void consoleInit();
+
+    /// @name Field List
+    /// @{
+
+    /// Get a list of all the fields. This information cannot be modified.
+    const AbstractClassRep::FieldList& getFieldList() const;
+
+    /// Get a list of all the fields, set up so we can modify them.
+    ///
+    /// @note This is a bad trick to pull if you aren't very careful,
+    ///       since you can blast field data!
+    AbstractClassRep::FieldList& getModifiableFieldList();
+
+    /// Get a handle to a boolean telling us if we expanded the dynamic group.
+    ///
+    /// @see GuiInspector::Inspect()
+    bool& getDynamicGroupExpand();
+    /// @}
+
+    /// @name ConsoleObject Implementation
+    ///
+    /// These functions are implemented in every subclass of
+    /// ConsoleObject by an IMPLEMENT_CONOBJECT or IMPLEMENT_CO_* macro.
+    /// @{
+
+    /// Get the abstract class information for this class.
+    static AbstractClassRep *getStaticClassRep() { return NULL; }
+
+    /// Get the abstract class information for this class's superclass.
+    static AbstractClassRep *getParentStaticClassRep() { return NULL; }
+
+    /// Get our network-layer class id.
+    ///
+    /// @param  netClassGroup  The net class for which we want our ID.
+    /// @see
+    S32 getClassId(U32 netClassGroup) const;
+
+    /// Get our compiler and platform independent class name.
+    ///
+    /// @note This name can be used to instantiate another instance using create()
+    const char *getClassName() const;
+
+    /// @}
 };
 
-// Deprecated? -pw
+//-----------------------------------------------------------------------------
+
 #define addNamedField(fieldName,type,className) addField(#fieldName, type, Offset(fieldName,className))
 #define addNamedFieldV(fieldName,type,className, validator) addFieldV(#fieldName, type, Offset(fieldName,className), validator)
 
-//------------------------------------------------------------------------------
-//-------------------------------------- Inlines
-//
+//-----------------------------------------------------------------------------
+
 inline S32 ConsoleObject::getClassId(U32 netClassGroup) const
 {
-   AssertFatal(getClassRep() != NULL,"Cannot get tag from non-declared dynamic class!");
-   return getClassRep()->getClassId(netClassGroup);
+    AssertFatal(getClassRep() != NULL,"Cannot get tag from non-declared dynamic class!");
+    return getClassRep()->getClassId(netClassGroup);
 }
 
+//-----------------------------------------------------------------------------
+
 inline const char * ConsoleObject::getClassName() const
 {
-   AssertFatal(getClassRep() != NULL,
-      "Cannot get tag from non-declared dynamic class");
-   return getClassRep()->getClassName();
+    AssertFatal(getClassRep() != NULL,
+        "Cannot get tag from non-declared dynamic class");
+    return getClassRep()->getClassName();
 }
 
+//-----------------------------------------------------------------------------
+
 inline const AbstractClassRep::Field * ConsoleObject::findField(StringTableEntry name) const
 {
-   AssertFatal(getClassRep() != NULL,
-      avar("Cannot get field '%s' from non-declared dynamic class.", name));
-   return getClassRep()->findField(name);
+    AssertFatal(getClassRep() != NULL,
+        avar("Cannot get field '%s' from non-declared dynamic class.", name));
+    return getClassRep()->findField(name);
 }
 
+//-----------------------------------------------------------------------------
+
 inline bool ConsoleObject::setField(const char *fieldName, const char *value)
 {
-   //sanity check
-   if ((! fieldName) || (! fieldName[0]) || (! value))
-      return false;
+    //sanity check
+    if ((! fieldName) || (! fieldName[0]) || (! value))
+        return false;
 
-   if (! getClassRep())
-      return false;
+    if (! getClassRep())
+        return false;
 
-   const AbstractClassRep::Field *myField = getClassRep()->findField(StringTable->insert(fieldName));
+    const AbstractClassRep::Field *myField = getClassRep()->findField(StringTable->insert(fieldName));
 
-   if (! myField)
-      return false;
+    if (! myField)
+        return false;
 
-   Con::setData(
-      myField->type,
-      (void *) (((const char *)(this)) + myField->offset),
-      0,
-      1,
-      &value,
-      myField->table,
-      myField->flag);
+    Con::setData(
+        myField->type,
+        (void *) (((const char *)(this)) + myField->offset),
+        0,
+        1,
+        &value,
+        myField->table,
+        myField->flag);
 
-   return true;
+    return true;
 }
 
+//-----------------------------------------------------------------------------
+
 inline ConsoleObject* ConsoleObject::create(const char* in_pClassName)
 {
-   return AbstractClassRep::create(in_pClassName);
+    return AbstractClassRep::create(in_pClassName);
 }
 
+//-----------------------------------------------------------------------------
+
 inline ConsoleObject* ConsoleObject::create(const U32 groupId, const U32 typeId, const U32 in_classId)
 {
-   return AbstractClassRep::create(groupId, typeId, in_classId);
+    return AbstractClassRep::create(groupId, typeId, in_classId);
 }
 
+//-----------------------------------------------------------------------------
+
 inline const AbstractClassRep::FieldList& ConsoleObject::getFieldList() const
 {
-   return getClassRep()->mFieldList;
+    return getClassRep()->mFieldList;
 }
 
+//-----------------------------------------------------------------------------
+
 inline AbstractClassRep::FieldList& ConsoleObject::getModifiableFieldList()
 {
-   return getClassRep()->mFieldList;
+    return getClassRep()->mFieldList;
 }
 
+//-----------------------------------------------------------------------------
+
 inline bool& ConsoleObject::getDynamicGroupExpand()
 {
-   return getClassRep()->mDynamicGroupExpand;
+    return getClassRep()->mDynamicGroupExpand;
 }
 
-/// @name ConsoleObject Macros
-/// @{
-
-#define DECLARE_CONOBJECT(className)                    \
-   static ConcreteClassRep<className> dynClassRep;      \
-   static AbstractClassRep* getParentStaticClassRep();  \
-   static AbstractClassRep* getStaticClassRep();        \
-   virtual AbstractClassRep* getClassRep() const
-
-#define IMPLEMENT_CONOBJECT(className)                                                            \
-   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }           \
-   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                      \
-   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
-   ConcreteClassRep<className> className::dynClassRep(#className, 0, -1, 0, className::getParentStaticClassRep())
-
-#define IMPLEMENT_CO_NETOBJECT_V1(className)                    \
-   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                 \
-   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                            \
-   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }       \
-   ConcreteClassRep<className> className::dynClassRep(#className, NetClassGroupGameMask, NetClassTypeObject, 0, className::getParentStaticClassRep())
-
-#define IMPLEMENT_CO_DATABLOCK_V1(className)                                                            \
-   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                 \
-   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                            \
-   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }       \
-   ConcreteClassRep<className> className::dynClassRep(#className, NetClassGroupGameMask, NetClassTypeDataBlock, 0, className::getParentStaticClassRep())
+//-----------------------------------------------------------------------------
 
-/// @}
+#define DECLARE_CONOBJECT(className)                                                                                \
+    static ConcreteClassRep<className> dynClassRep;                                                                 \
+    static AbstractClassRep* getParentStaticClassRep();                                                             \
+    static AbstractClassRep* getContainerChildStaticClassRep();                                                     \
+    static AbstractClassRep* getStaticClassRep();                                                                   \
+    static AbstractClassRep::WriteCustomTamlSchema getStaticWriteCustomTamlSchema();                                \
+    virtual AbstractClassRep* getClassRep() const
+
+#define IMPLEMENT_CONOBJECT(className)                                                                              \
+    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                            \
+    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                                       \
+    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }                  \
+    AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                                 \
+    AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
+    ConcreteClassRep<className> className::dynClassRep(#className, 0, -1, 0, className::getParentStaticClassRep())
+
+#define IMPLEMENT_CONOBJECT_CHILDREN(className)                                                                     \
+    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                            \
+    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                                       \
+    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }                  \
+    AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); }        \
+    AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
+    ConcreteClassRep<className> className::dynClassRep(#className, 0, -1, 0, className::getParentStaticClassRep())
+
+#define IMPLEMENT_CONOBJECT_SCHEMA(className, schema)                                                               \
+    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                            \
+    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                                       \
+    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }                  \
+    AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                                 \
+    AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return schema; }          \
+    ConcreteClassRep<className> className::dynClassRep(#className, 0, -1, 0, className::getParentStaticClassRep())
+
+#define IMPLEMENT_CONOBJECT_CHILDREN_SCHEMA(className, schema)                                                      \
+    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                            \
+    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                                       \
+    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }                  \
+    AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); }        \
+    AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return schema; }          \
+    ConcreteClassRep<className> className::dynClassRep(#className, 0, -1, 0, className::getParentStaticClassRep())
+
+#define IMPLEMENT_CO_NETOBJECT_V1(className)                                                                        \
+    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                            \
+    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                                       \
+    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }                  \
+    AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                                 \
+    AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
+    ConcreteClassRep<className> className::dynClassRep(#className, NetClassGroupGameMask, NetClassTypeObject, 0, className::getParentStaticClassRep())
+
+#define IMPLEMENT_CO_DATABLOCK_V1(className)                                                                        \
+    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                            \
+    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                                       \
+    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }                  \
+    AbstractClassRep* className::getContainerChildStaticClassRep() {return NULL; }                                  \
+    AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
+    ConcreteClassRep<className> className::dynClassRep(#className, NetClassGroupGameMask, NetClassTypeDataBlock, 0, className::getParentStaticClassRep())
 
-//------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 
 inline bool defaultProtectedSetFn( void *obj, const char *data )
 {
-   return true;
+    return true;
 }
 
+//-----------------------------------------------------------------------------
+
 inline const char *defaultProtectedGetFn( void *obj, const char *data )
 {
-   return data;
+    return data;
 }
 
+//-----------------------------------------------------------------------------
+
 inline bool defaultProtectedWriteFn( void* obj, StringTableEntry pFieldName )
 {
     return true;
 }
 
+//-----------------------------------------------------------------------------
+
 inline bool defaultProtectedNotSetFn(void* obj, const char* data)
 {
     return false;
 }
 
+//-----------------------------------------------------------------------------
+
 inline bool defaultProtectedNotWriteFn( void* obj, StringTableEntry pFieldName )
 {
     return false;

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

+ 383 - 384
engine/source/gui/buttons/guiButtonBaseCtrl.cc

@@ -1,384 +1,383 @@
-//-----------------------------------------------------------------------------
-// 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 "console/console.h"
-#include "graphics/dgl.h"
-#include "console/consoleTypes.h"
-#include "platform/platformAudio.h"
-#include "gui/guiCanvas.h"
-#include "gui/buttons/guiButtonBaseCtrl.h"
-#include "gui/language/lang.h"
-
-IMPLEMENT_CONOBJECT(GuiButtonBaseCtrl);
-
-GuiButtonBaseCtrl::GuiButtonBaseCtrl()
-{
-   mDepressed = false;
-   mMouseOver = false;
-   mActive = true;
-   mButtonText = StringTable->insert("Button");
-   mButtonTextID = StringTable->EmptyString;
-   mStateOn = false;
-    mRadioGroup = -1;
-   mButtonType = ButtonTypePush;
-   mUseMouseEvents = false;
-}
-
-bool GuiButtonBaseCtrl::onWake()
-{
-   if(!Parent::onWake())
-      return false;
-
-   // is we have a script variable, make sure we're in sync
-   if ( mConsoleVariable[0] )
-    mStateOn = Con::getBoolVariable( mConsoleVariable );
-   if(mButtonTextID && *mButtonTextID != 0)
-       setTextID(mButtonTextID);
-
-   return true;
-}
-
-ConsoleMethod( GuiButtonBaseCtrl, performClick, void, 2, 2, "() - simulates a button click from script." )
-{
-   object->onAction();
-}
-
-ConsoleMethod( GuiButtonBaseCtrl, setText, void, 3, 3, "(string text) - Sets the text of the button to the string." )
-{
-   object->setText( argv[2] );
-}
-
-ConsoleMethod( GuiButtonBaseCtrl, setTextID, void, 3, 3, "(string id) - Sets the text of the button to the localized string." )
-{
-    object->setTextID(argv[2]);
-}
-ConsoleMethod( GuiButtonBaseCtrl, getText, const char *, 2, 2, "() - returns the text of the button.\n" 
-              "@return The text member of the button as a char string")
-{
-   return object->getText( );
-}
-ConsoleMethod( GuiButtonBaseCtrl, setStateOn, void, 3, 3, "(bool isStateOn) - sets the state on member and updates siblings of the same group." )
-{
-   object->setStateOn(dAtob(argv[2]));
-}
-
-ConsoleMethod(GuiButtonBaseCtrl, getStateOn, bool, 2, 2, "(bool getStateOn) - gets whether the state of the button is currently 'on'" )
-{
-   return object->getStateOn();
-}
-
-
-static EnumTable::Enums buttonTypeEnums[] = 
-{
-   { GuiButtonBaseCtrl::ButtonTypePush, "PushButton" },
-   { GuiButtonBaseCtrl::ButtonTypeCheck, "ToggleButton" },
-   { GuiButtonBaseCtrl::ButtonTypeRadio, "RadioButton" },
-};
-      
-static EnumTable gButtonTypeTable(3, &buttonTypeEnums[0]); 
-      
-      
-
-void GuiButtonBaseCtrl::initPersistFields()
-{
-   Parent::initPersistFields();
-   addGroup("GuiButtonBaseCtrl");		
-   addField("text", TypeCaseString, Offset(mButtonText, GuiButtonBaseCtrl));
-   addField("textID", TypeString, Offset(mButtonTextID, GuiButtonBaseCtrl));
-   addField("groupNum", TypeS32, Offset(mRadioGroup, GuiButtonBaseCtrl));
-   addField("buttonType", TypeEnum, Offset(mButtonType, GuiButtonBaseCtrl), 1, &gButtonTypeTable);
-   addField("useMouseEvents", TypeBool, Offset(mUseMouseEvents, GuiButtonBaseCtrl));
-   endGroup("GuiButtonBaseCtrl");		
-}
-
-void GuiButtonBaseCtrl::setText(const char *text)
-{
-   mButtonText = StringTable->insert(text);
-}
-
-void GuiButtonBaseCtrl::setStateOn( bool bStateOn )
-{
-   if(!mActive)
-      return;
-
-   if(mButtonType == ButtonTypeCheck)
-   {
-      mStateOn = bStateOn;
-   }
-   else if(mButtonType == ButtonTypeRadio)
-   {
-      messageSiblings(mRadioGroup);
-      mStateOn = bStateOn;
-   }		
-   setUpdate();
-}
-
-void GuiButtonBaseCtrl::setTextID(const char *id)
-{
-    S32 n = Con::getIntVariable(id, -1);
-    if(n != -1)
-    {
-        mButtonTextID = StringTable->insert(id);
-        setTextID(n);
-    }
-}
-void GuiButtonBaseCtrl::setTextID(S32 id)
-{
-    const UTF8 *str = getGUIString(id);
-    if(str)
-        setText((const char*)str);
-    //mButtonTextID = id;
-}
-const char *GuiButtonBaseCtrl::getText()
-{
-   return mButtonText;
-}
-
-//---------------------------------------------------------------------------
-void GuiButtonBaseCtrl::acceleratorKeyPress(U32)
-{
-   if (! mActive)
-      return;
-
-   //set the bool
-   mDepressed = true;
-
-   if (mProfile->mTabable)
-      setFirstResponder();
-}
-
-//---------------------------------------------------------------------------
-void GuiButtonBaseCtrl::acceleratorKeyRelease(U32)
-{
-   if (! mActive)
-      return;
-
-   if (mDepressed)
-   {
-      //set the bool
-      mDepressed = false;
-      //perform the action
-      onAction();
-   }
-
-   //update
-   setUpdate();
-}
-
-void GuiButtonBaseCtrl::onMouseDown(const GuiEvent &event)
-{
-   if (! mActive)
-      return;
-
-   if (mProfile->mCanKeyFocus)
-      setFirstResponder();
-
-   if (mProfile->mSoundButtonDown)
-   {
-      AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonDown);
-      alxPlay(handle);
-   }
-
-   //lock the mouse
-   mouseLock();
-   mDepressed = true;
-
-   //update
-   setUpdate();
-}
-
-void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent &event)
-{
-   setUpdate();
-
-   if(mUseMouseEvents)
-      Con::executef( this, 1, "onMouseEnter" );
-
-   if(isMouseLocked())
-   {
-      mDepressed = true;
-      mMouseOver = true;
-   }
-   else
-   {
-      if ( mActive && mProfile->mSoundButtonOver )
-      {
-         AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonOver);
-         alxPlay(handle);
-      }
-      mMouseOver = true;
-   }
-}
-
-//Luma: Some fixes from the forums, Dave Calabrese
-//http://www.garagegames.com/community/forums/viewthread/93467/1#comment-669559
-void GuiButtonBaseCtrl::onMouseLeave(const GuiEvent &)  
-{  
-    if(isMouseLocked())  
-        mDepressed = false;  
-      
-    mouseUnlock();  
-    setUpdate();  
-  
-   if(mUseMouseEvents)  
-      Con::executef( this, 1, "onMouseLeave" );  
-  
-   mMouseOver = false;  
-}  
-
-void GuiButtonBaseCtrl::onMouseUp(const GuiEvent &event)
-{
-   if (! mActive)
-      return;
-
-   mouseUnlock();
-
-   setUpdate();
-
-   //if we released the mouse within this control, perform the action
-   if (mDepressed)
-      onAction();
-
-   // Execute callback
-   if (mUseMouseEvents)
-   {
-       char buf[3][32];
-       dSprintf(buf[0], 32, "%d", event.modifier);
-       dSprintf(buf[1], 32, "%d %d", event.mousePoint.x, event.mousePoint.y);
-       dSprintf(buf[2], 32, "%d", event.mouseClickCount);
-       Con::executef(this, 4, "onMouseUp", buf[0], buf[1], buf[2]);
-   }
-
-   mDepressed = false;
-}
-
-void GuiButtonBaseCtrl::onRightMouseUp(const GuiEvent &event)
-{
-   Con::executef( this, 2, "onRightClick" );
-
-   Parent::onRightMouseUp( event );
-}
-
-//--------------------------------------------------------------------------
-bool GuiButtonBaseCtrl::onKeyDown(const GuiEvent &event)
-{
-   //if the control is a dead end, kill the event
-   if (!mActive)
-      return true;
-
-   //see if the key down is a return or space or not
-   if ((event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE)
-       && event.modifier == 0)
-   {
-       if ( mProfile->mSoundButtonDown )
-       {
-          AUDIOHANDLE handle = alxCreateSource( mProfile->mSoundButtonDown );
-          alxPlay( handle );
-       }
-      return true;
-   }
-   //otherwise, pass the event to it's parent
-   return Parent::onKeyDown(event);
-}
-
-//--------------------------------------------------------------------------
-bool GuiButtonBaseCtrl::onKeyUp(const GuiEvent &event)
-{
-   //if the control is a dead end, kill the event
-   if (!mActive)
-      return true;
-
-   //see if the key down is a return or space or not
-   if (mDepressed &&
-      (event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE) &&
-      event.modifier == 0)
-   {
-      onAction();
-      return true;
-   }
-
-   //otherwise, pass the event to it's parent
-   return Parent::onKeyUp(event);
-}
-
-//---------------------------------------------------------------------------
-void GuiButtonBaseCtrl::setScriptValue(const char *value)
-{
-    mStateOn = dAtob(value);
-
-    // Update the console variable:
-    if ( mConsoleVariable[0] )
-        Con::setBoolVariable( mConsoleVariable, mStateOn );
-
-   setUpdate();
-}
-
-//---------------------------------------------------------------------------
-const char *GuiButtonBaseCtrl::getScriptValue()
-{
-    return mStateOn ? "1" : "0";
-}
-
-//---------------------------------------------------------------------------
-void GuiButtonBaseCtrl::onAction()
-{
-    if(!mActive)
-        return;
-
-    if(mButtonType == ButtonTypeCheck)
-    {
-        mStateOn = mStateOn ? false : true;
-
-        // Update the console variable:
-        if ( mConsoleVariable[0] )
-            Con::setBoolVariable( mConsoleVariable, mStateOn );
-        // Execute the console command (if any). Unnecessary. Parent does this already.
-        //if( mConsoleCommand[0] )
-        //   Con::evaluate( mConsoleCommand, false );
-
-    }
-    else if(mButtonType == ButtonTypeRadio)
-    {
-        mStateOn = true;
-        messageSiblings(mRadioGroup);
-    }		
-    setUpdate();
-
-
-    // Provide and onClick script callback.
-    if( isMethod("onClick") )
-       Con::executef( this, 2, "onClick" );
-
-    Parent::onAction();
-}
-
-//---------------------------------------------------------------------------
-void GuiButtonBaseCtrl::onMessage( GuiControl *sender, S32 msg )
-{
-    Parent::onMessage(sender, msg);
-    if( mRadioGroup == msg && mButtonType == ButtonTypeRadio )
-    {
-        setUpdate();
-        mStateOn = ( sender == this );
-    }
-}
-
+//-----------------------------------------------------------------------------
+// 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 "console/console.h"
+#include "graphics/dgl.h"
+#include "console/consoleTypes.h"
+#include "platform/platformAudio.h"
+#include "gui/guiCanvas.h"
+#include "gui/buttons/guiButtonBaseCtrl.h"
+#include "gui/language/lang.h"
+
+IMPLEMENT_CONOBJECT(GuiButtonBaseCtrl);
+
+GuiButtonBaseCtrl::GuiButtonBaseCtrl()
+{
+   mDepressed = false;
+   mMouseOver = false;
+   mActive = true;
+   mButtonText = StringTable->insert("Button");
+   mButtonTextID = StringTable->EmptyString;
+   mStateOn = false;
+    mRadioGroup = -1;
+   mButtonType = ButtonTypePush;
+   mUseMouseEvents = false;
+}
+
+bool GuiButtonBaseCtrl::onWake()
+{
+   if(!Parent::onWake())
+      return false;
+
+   // is we have a script variable, make sure we're in sync
+   if ( mConsoleVariable[0] )
+    mStateOn = Con::getBoolVariable( mConsoleVariable );
+   if(mButtonTextID && *mButtonTextID != 0)
+       setTextID(mButtonTextID);
+
+   return true;
+}
+
+ConsoleMethod( GuiButtonBaseCtrl, performClick, void, 2, 2, "() - simulates a button click from script." )
+{
+   object->onAction();
+}
+
+ConsoleMethod( GuiButtonBaseCtrl, setText, void, 3, 3, "(string text) - Sets the text of the button to the string." )
+{
+   object->setText( argv[2] );
+}
+
+ConsoleMethod( GuiButtonBaseCtrl, setTextID, void, 3, 3, "(string id) - Sets the text of the button to the localized string." )
+{
+    object->setTextID(argv[2]);
+}
+ConsoleMethod( GuiButtonBaseCtrl, getText, const char *, 2, 2, "() - returns the text of the button.\n" 
+              "@return The text member of the button as a char string")
+{
+   return object->getText( );
+}
+ConsoleMethod( GuiButtonBaseCtrl, setStateOn, void, 3, 3, "(bool isStateOn) - sets the state on member and updates siblings of the same group." )
+{
+   object->setStateOn(dAtob(argv[2]));
+}
+
+ConsoleMethod(GuiButtonBaseCtrl, getStateOn, bool, 2, 2, "(bool getStateOn) - gets whether the state of the button is currently 'on'" )
+{
+   return object->getStateOn();
+}
+
+
+static EnumTable::Enums buttonTypeEnums[] = 
+{
+   { GuiButtonBaseCtrl::ButtonTypePush, "PushButton" },
+   { GuiButtonBaseCtrl::ButtonTypeCheck, "ToggleButton" },
+   { GuiButtonBaseCtrl::ButtonTypeRadio, "RadioButton" },
+};
+      
+static EnumTable gButtonTypeTable(3, &buttonTypeEnums[0]); 
+      
+      
+
+void GuiButtonBaseCtrl::initPersistFields()
+{
+   Parent::initPersistFields();
+   addGroup("GuiButtonBaseCtrl");		
+   addField("text", TypeCaseString, Offset(mButtonText, GuiButtonBaseCtrl));
+   addField("textID", TypeString, Offset(mButtonTextID, GuiButtonBaseCtrl));
+   addField("groupNum", TypeS32, Offset(mRadioGroup, GuiButtonBaseCtrl));
+   addField("buttonType", TypeEnum, Offset(mButtonType, GuiButtonBaseCtrl), 1, &gButtonTypeTable);
+   addField("useMouseEvents", TypeBool, Offset(mUseMouseEvents, GuiButtonBaseCtrl));
+   endGroup("GuiButtonBaseCtrl");		
+}
+
+void GuiButtonBaseCtrl::setText(const char *text)
+{
+   mButtonText = StringTable->insert(text);
+}
+
+void GuiButtonBaseCtrl::setStateOn( bool bStateOn )
+{
+   if(!mActive)
+      return;
+
+   if(mButtonType == ButtonTypeCheck)
+   {
+      mStateOn = bStateOn;
+   }
+   else if(mButtonType == ButtonTypeRadio)
+   {
+      messageSiblings(mRadioGroup);
+      mStateOn = bStateOn;
+   }		
+   setUpdate();
+}
+
+void GuiButtonBaseCtrl::setTextID(const char *id)
+{
+    S32 n = Con::getIntVariable(id, -1);
+    if(n != -1)
+    {
+        mButtonTextID = StringTable->insert(id);
+        setTextID(n);
+    }
+}
+void GuiButtonBaseCtrl::setTextID(S32 id)
+{
+    const UTF8 *str = getGUIString(id);
+    if(str)
+        setText((const char*)str);
+    //mButtonTextID = id;
+}
+const char *GuiButtonBaseCtrl::getText()
+{
+   return mButtonText;
+}
+
+//---------------------------------------------------------------------------
+void GuiButtonBaseCtrl::acceleratorKeyPress(U32)
+{
+   if (! mActive)
+      return;
+
+   //set the bool
+   mDepressed = true;
+
+   if (mProfile->mTabable)
+      setFirstResponder();
+}
+
+//---------------------------------------------------------------------------
+void GuiButtonBaseCtrl::acceleratorKeyRelease(U32)
+{
+   if (! mActive)
+      return;
+
+   if (mDepressed)
+   {
+      //set the bool
+      mDepressed = false;
+      //perform the action
+      onAction();
+   }
+
+   //update
+   setUpdate();
+}
+
+void GuiButtonBaseCtrl::onMouseDown(const GuiEvent &event)
+{
+   if (! mActive)
+      return;
+
+   if (mProfile->mCanKeyFocus)
+      setFirstResponder();
+
+   if (mProfile->mSoundButtonDown)
+   {
+      AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonDown);
+      alxPlay(handle);
+   }
+
+   //lock the mouse
+   mouseLock();
+   mDepressed = true;
+
+   //update
+   setUpdate();
+}
+
+void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent &event)
+{
+   setUpdate();
+
+   if(mUseMouseEvents)
+      Con::executef( this, 1, "onMouseEnter" );
+
+   if(isMouseLocked())
+   {
+      mDepressed = true;
+      mMouseOver = true;
+   }
+   else
+   {
+      if ( mActive && mProfile->mSoundButtonOver )
+      {
+         AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonOver);
+         alxPlay(handle);
+      }
+      mMouseOver = true;
+   }
+}
+
+//Luma: Some fixes from the forums, Dave Calabrese
+//http://www.garagegames.com/community/forums/viewthread/93467/1#comment-669559
+void GuiButtonBaseCtrl::onMouseLeave(const GuiEvent &)  
+{  
+    if(isMouseLocked())  
+        mDepressed = false;  
+      
+    mouseUnlock();  
+    setUpdate();  
+  
+   if(mUseMouseEvents)  
+      Con::executef( this, 1, "onMouseLeave" );  
+  
+   mMouseOver = false;  
+}  
+
+void GuiButtonBaseCtrl::onMouseUp(const GuiEvent &event)
+{
+   if (! mActive)
+      return;
+
+   mouseUnlock();
+
+   setUpdate();
+
+   //if we released the mouse within this control, perform the action
+   if (mDepressed)
+      onAction();
+
+   // Execute callback
+   if (mUseMouseEvents)
+   {
+       char buf[3][32];
+       dSprintf(buf[0], 32, "%d", event.modifier);
+       dSprintf(buf[1], 32, "%d %d", event.mousePoint.x, event.mousePoint.y);
+       dSprintf(buf[2], 32, "%d", event.mouseClickCount);
+       Con::executef(this, 4, "onMouseUp", buf[0], buf[1], buf[2]);
+   }
+
+   mDepressed = false;
+}
+
+void GuiButtonBaseCtrl::onRightMouseUp(const GuiEvent &event)
+{
+   Con::executef( this, 2, "onRightClick" );
+
+   Parent::onRightMouseUp( event );
+}
+
+//--------------------------------------------------------------------------
+bool GuiButtonBaseCtrl::onKeyDown(const GuiEvent &event)
+{
+   //if the control is a dead end, kill the event
+   if (!mActive)
+      return true;
+
+   //see if the key down is a return or space or not
+   if ((event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE)
+       && event.modifier == 0)
+   {
+       if ( mProfile->mSoundButtonDown )
+       {
+          AUDIOHANDLE handle = alxCreateSource( mProfile->mSoundButtonDown );
+          alxPlay( handle );
+       }
+      return true;
+   }
+   //otherwise, pass the event to it's parent
+   return Parent::onKeyDown(event);
+}
+
+//--------------------------------------------------------------------------
+bool GuiButtonBaseCtrl::onKeyUp(const GuiEvent &event)
+{
+   //if the control is a dead end, kill the event
+   if (!mActive)
+      return true;
+
+   //see if the key down is a return or space or not
+   if (mDepressed &&
+      (event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE) &&
+      event.modifier == 0)
+   {
+      onAction();
+      return true;
+   }
+
+   //otherwise, pass the event to it's parent
+   return Parent::onKeyUp(event);
+}
+
+//---------------------------------------------------------------------------
+void GuiButtonBaseCtrl::setScriptValue(const char *value)
+{
+    mStateOn = dAtob(value);
+
+    // Update the console variable:
+    if ( mConsoleVariable[0] )
+        Con::setBoolVariable( mConsoleVariable, mStateOn );
+
+   setUpdate();
+}
+
+//---------------------------------------------------------------------------
+const char *GuiButtonBaseCtrl::getScriptValue()
+{
+    return mStateOn ? "1" : "0";
+}
+
+//---------------------------------------------------------------------------
+void GuiButtonBaseCtrl::onAction()
+{
+    if(!mActive)
+        return;
+
+    if(mButtonType == ButtonTypeCheck)
+    {
+        mStateOn = mStateOn ? false : true;
+
+        // Update the console variable:
+        if ( mConsoleVariable[0] )
+            Con::setBoolVariable( mConsoleVariable, mStateOn );
+        // Execute the console command (if any). Unnecessary. Parent does this already.
+        //if( mConsoleCommand[0] )
+        //   Con::evaluate( mConsoleCommand, false );
+
+    }
+    else if(mButtonType == ButtonTypeRadio)
+    {
+        mStateOn = true;
+        messageSiblings(mRadioGroup);
+    }		
+    setUpdate();
+
+
+    // Provide and onClick script callback.
+    if( isMethod("onClick") )
+       Con::executef( this, 2, "onClick" );
+
+    Parent::onAction();
+}
+
+//---------------------------------------------------------------------------
+void GuiButtonBaseCtrl::onMessage( GuiControl *sender, S32 msg )
+{
+    Parent::onMessage(sender, msg);
+    if( mRadioGroup == msg && mButtonType == ButtonTypeRadio )
+    {
+        setUpdate();
+        mStateOn = ( sender == this );
+    }
+}

+ 0 - 10
engine/source/gui/editor/guiInspector.cc

@@ -531,16 +531,6 @@ GuiInspectorGroup::~GuiInspectorGroup()
    } 
 }
 
-//////////////////////////////////////////////////////////////////////////
-// Persistence 
-//////////////////////////////////////////////////////////////////////////
-void GuiInspectorGroup::initPersistFields()
-{
-   Parent::initPersistFields();
-
-   addField("Caption", TypeString, Offset(mCaption, GuiInspectorGroup));
-}
-
 //////////////////////////////////////////////////////////////////////////
 // Scene Events
 //////////////////////////////////////////////////////////////////////////

+ 0 - 3
engine/source/gui/editor/guiInspector.h

@@ -152,9 +152,6 @@ public:
    ~GuiInspectorGroup();
    DECLARE_CONOBJECT(GuiInspectorGroup);
 
-   // Persistence ( Inspector Exposed Fields )
-   static void initPersistFields();
-
    virtual GuiInspectorField* constructField( S32 fieldType );
    virtual GuiInspectorField* findField( StringTableEntry fieldName );
 

+ 1 - 11
engine/source/gui/guiControl.cc

@@ -41,7 +41,7 @@
 
 //------------------------------------------------------------------------------
 
-IMPLEMENT_CONOBJECT(GuiControl);
+IMPLEMENT_CONOBJECT_CHILDREN(GuiControl);
 
 //used to locate the next/prev responder when tab is pressed
 S32 GuiControl::smCursorChanged           = -1;
@@ -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();

+ 1 - 0
engine/source/gui/guiControl.h

@@ -94,6 +94,7 @@ class GuiControl : public SimGroup
 {
 private:
    typedef SimGroup Parent;
+   typedef GuiControl Children;
 
 public:
 

+ 0 - 1
engine/source/gui/guiTextEditCtrl.cc

@@ -97,7 +97,6 @@ void GuiTextEditCtrl::initPersistFields()
    addField("validate",          TypeString,    Offset(mValidateCommand,   GuiTextEditCtrl));
    addField("escapeCommand",     TypeString,    Offset(mEscapeCommand,     GuiTextEditCtrl));
    addField("historySize",       TypeS32,       Offset(mHistorySize,       GuiTextEditCtrl));
-   addField("password",          TypeBool,      Offset(mPasswordText,      GuiTextEditCtrl));     
    addField("tabComplete",       TypeBool,      Offset(mTabComplete,       GuiTextEditCtrl));     
    addField("deniedSound",       TypeAudioAssetPtr, Offset(mDeniedSound, GuiTextEditCtrl));
    addField("sinkAllKeyEvents",  TypeBool,      Offset(mSinkAllKeyEvents,  GuiTextEditCtrl));

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

File diff suppressed because it is too large
+ 573 - 561
engine/source/network/netConnection.h


+ 299 - 0
engine/source/persistence/taml/taml.cc

@@ -54,6 +54,26 @@
 #include "assets/assetFieldTypes.h"
 #endif
 
+#ifndef _MATHTYPES_H_
+#include "math/mathTypes.h"
+#endif
+
+#ifndef _VECTOR2_H_
+#include "2d/core/vector2.h"
+#endif
+
+#ifndef _IMAGE_ASSET_H_
+#include "2d/assets/imageAsset.h"
+#endif
+
+#ifndef _ANIMATION_ASSET_H_
+#include "2d/assets/animationAsset.h"
+#endif
+
+#ifndef _AUDIO_ASSET_H_
+#include "audio/audioAsset.h"
+#endif
+
 // Script bindings.
 #include "taml_ScriptBinding.h"
 
@@ -833,3 +853,282 @@ SimObject* Taml::createType( StringTableEntry typeName, const Taml* pTaml, const
 
     return pSimObject;
 }
+
+//-----------------------------------------------------------------------------
+
+bool Taml::generateTamlSchema( const char* pFilename )
+{
+    // Sanity!
+    AssertFatal( pFilename != NULL, "Taml::generateTamlSchema() - Cannot write a NULL filename." );
+
+    // Create document.
+    TiXmlDocument schemaDocument;
+
+    // Add declaration.
+    TiXmlDeclaration schemaDeclaration( "1.0", "iso-8859-1", "no" );
+    schemaDocument.InsertEndChild( schemaDeclaration );
+
+    // Add schema element.
+    TiXmlElement* pSchemaElement = new TiXmlElement( "xs:schema" );
+    pSchemaElement->SetAttribute( "xmlns:xs", "http://www.w3.org/2001/XMLSchema" );
+    schemaDocument.LinkEndChild( pSchemaElement );
+
+    // Fetch class-rep root.
+    AbstractClassRep* pRootType = AbstractClassRep::getClassList();
+
+    // Reset scratch state.
+    char buffer[1024];
+
+    // *************************************************************
+    // Generate console type elements.
+    // *************************************************************
+
+    // Vector2.
+    TiXmlComment* pVector2Comment = new TiXmlComment( "Vector2 Console Type" );
+    pSchemaElement->LinkEndChild( pVector2Comment );
+    TiXmlElement* pVector2TypeElement = new TiXmlElement( "xs:simpleType" );
+    pVector2TypeElement->SetAttribute( "name", "Vector2_ConsoleType" );
+    pSchemaElement->LinkEndChild( pVector2TypeElement );
+    TiXmlElement* pVector2ElementA = new TiXmlElement( "xs:restriction" );
+    pVector2ElementA->SetAttribute( "base", "xs:string" );
+    pVector2TypeElement->LinkEndChild( pVector2ElementA );
+    TiXmlElement* pVector2ElementB = new TiXmlElement( "xs:pattern" );
+    pVector2ElementB->SetAttribute( "value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b" );   
+    pVector2ElementA->LinkEndChild( pVector2ElementB );
+
+    // Point2F.
+    TiXmlComment* pPoint2FComment = new TiXmlComment( "Point2F Console Type" );
+    pSchemaElement->LinkEndChild( pPoint2FComment );
+    TiXmlElement* pPoint2FTypeElement = new TiXmlElement( "xs:simpleType" );
+    pPoint2FTypeElement->SetAttribute( "name", "Point2F_ConsoleType" );
+    pSchemaElement->LinkEndChild( pPoint2FTypeElement );
+    TiXmlElement* pPoint2FElementA = new TiXmlElement( "xs:restriction" );
+    pPoint2FElementA->SetAttribute( "base", "xs:string" );
+    pPoint2FTypeElement->LinkEndChild( pPoint2FElementA );
+    TiXmlElement* pPoint2FElementB = new TiXmlElement( "xs:pattern" );
+    pPoint2FElementB->SetAttribute( "value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b" );   
+    pPoint2FElementA->LinkEndChild( pPoint2FElementB );
+
+    // Point2I.
+    TiXmlComment* pPoint2IComment = new TiXmlComment( "Point2I Console Type" );
+    pSchemaElement->LinkEndChild( pPoint2IComment );
+    TiXmlElement* pPoint2ITypeElement = new TiXmlElement( "xs:simpleType" );
+    pPoint2ITypeElement->SetAttribute( "name", "Point2I_ConsoleType" );
+    pSchemaElement->LinkEndChild( pPoint2ITypeElement );
+    TiXmlElement* pPoint2IElementA = new TiXmlElement( "xs:restriction" );
+    pPoint2IElementA->SetAttribute( "base", "xs:string" );
+    pPoint2ITypeElement->LinkEndChild( pPoint2IElementA );
+    TiXmlElement* pPoint2IElementB = new TiXmlElement( "xs:pattern" );
+    pPoint2IElementB->SetAttribute( "value", "[-]?[0-9]* [-]?[0-9]*" );   
+    pPoint2IElementA->LinkEndChild( pPoint2IElementB );
+
+    // AssetId.
+    TiXmlComment* pAssetIdComment = new TiXmlComment( "AssetId Console Type" );
+    pSchemaElement->LinkEndChild( pAssetIdComment );
+    TiXmlElement* pAssetIdTypeElement = new TiXmlElement( "xs:simpleType" );
+    pAssetIdTypeElement->SetAttribute( "name", "AssetId_ConsoleType" );
+    pSchemaElement->LinkEndChild( pAssetIdTypeElement );
+    TiXmlElement* pAssetIdElementA = new TiXmlElement( "xs:restriction" );
+    pAssetIdElementA->SetAttribute( "base", "xs:string" );
+    pAssetIdTypeElement->LinkEndChild( pAssetIdElementA );
+    TiXmlElement* pAssetIdElementB = new TiXmlElement( "xs:pattern" );
+    dSprintf( buffer, sizeof(buffer), "(%s)?\\b[a-zA-Z0-9]+\\b%s\\b[a-zA-Z0-9]+\\b", ASSET_ID_FIELD_PREFIX, ASSET_SCOPE_TOKEN );
+    pAssetIdElementB->SetAttribute( "value", buffer );
+    pAssetIdElementA->LinkEndChild( pAssetIdElementB );
+
+    // *************************************************************
+    // Generate engine type elements.
+    // *************************************************************
+
+    // Generate the engine type elements.
+    TiXmlComment* pComment = new TiXmlComment( "Type Elements" );
+    pSchemaElement->LinkEndChild( pComment );
+    for ( AbstractClassRep* pType = pRootType; pType != NULL; pType = pType->getNextClass() )
+    {
+        // Add type.
+        TiXmlElement* pTypeElement = new TiXmlElement( "xs:element" );
+        pTypeElement->SetAttribute( "name", pType->getClassName() );
+        dSprintf( buffer, sizeof(buffer), "%s_Type", pType->getClassName() );
+        pTypeElement->SetAttribute( "type", buffer );
+        pSchemaElement->LinkEndChild( pTypeElement );
+    }
+
+    // *************************************************************
+    // Generate the engine complex types.
+    // *************************************************************
+    for ( AbstractClassRep* pType = pRootType; pType != NULL; pType = pType->getNextClass() )
+    {
+        // Add complex type comment.
+        dSprintf( buffer, sizeof(buffer), " %s Type ", pType->getClassName() );
+        TiXmlComment* pComment = new TiXmlComment( buffer );
+        pSchemaElement->LinkEndChild( pComment );
+
+        // Add complex type.
+        TiXmlElement* pComplexTypeElement = new TiXmlElement( "xs:complexType" );
+        dSprintf( buffer, sizeof(buffer), "%s_Type", pType->getClassName() );
+        pComplexTypeElement->SetAttribute( "name", buffer );
+        pSchemaElement->LinkEndChild( pComplexTypeElement );
+
+        // Add sequence.
+        TiXmlElement* pSequenceElement = new TiXmlElement( "xs:sequence" );
+        pComplexTypeElement->LinkEndChild( pSequenceElement );
+
+        // Fetch container child class.
+        AbstractClassRep* pContainerChildClass = pType->getContainerChildClass( true );
+
+        // Is the type allowed children?
+        if ( pContainerChildClass != NULL )
+        {
+            // Yes, so add choice element.
+            TiXmlElement* pChoiceElement = new TiXmlElement( "xs:choice" );
+            pChoiceElement->SetAttribute( "minOccurs", 0 );
+            pChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+            pSequenceElement->LinkEndChild( pChoiceElement );
+
+            // Add choice members.
+            for ( AbstractClassRep* pChoiceType = pRootType; pChoiceType != NULL; pChoiceType = pChoiceType->getNextClass() )
+            {
+                // Skip if not derived from the container child class.
+                if ( !pChoiceType->isClass( pContainerChildClass ) )
+                    continue;
+
+                // Add choice member.
+                TiXmlElement* pChoiceMemberElement = new TiXmlElement( "xs:element" );
+                pChoiceMemberElement->SetAttribute( "name", pChoiceType->getClassName() );
+                dSprintf( buffer, sizeof(buffer), "%s_Type", pChoiceType->getClassName() );
+                pChoiceMemberElement->SetAttribute( "type", buffer );
+                pChoiceElement->LinkEndChild( pChoiceMemberElement );
+            }
+        }
+
+        // Generate the custom Taml schema.
+        for ( AbstractClassRep* pCustomSchemaType = pType; pCustomSchemaType != NULL; pCustomSchemaType = pCustomSchemaType->getParentClass() )
+        {
+            // Fetch the types custom TAML schema function.
+            AbstractClassRep::WriteCustomTamlSchema customSchemaFn = pCustomSchemaType->getCustomTamlSchema();
+
+            // Skip if no function avilable.
+            if ( customSchemaFn == NULL )
+                continue;
+
+            // Call schema generation function.
+            customSchemaFn( pType, pSequenceElement );
+        }
+
+        // Iterate static fields.
+        const AbstractClassRep::FieldList& fields = pType->mFieldList;
+        for( AbstractClassRep::FieldList::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
+        {
+            // Fetch field.
+            const AbstractClassRep::Field& field = *fieldItr;
+
+            // Skip if not a data field.
+            if( field.type == AbstractClassRep::DepricatedFieldType ||
+                field.type == AbstractClassRep::StartGroupFieldType ||
+                field.type == AbstractClassRep::EndGroupFieldType )
+            continue;
+
+            // Add attribute element.
+            TiXmlElement* pAttributeElement = new TiXmlElement( "xs:attribute" );
+            pAttributeElement->SetAttribute( "name", field.pFieldname );
+
+            // Handle the console type appropriately.
+            const S32 fieldType = (S32)field.type;
+
+            // Is the field an enumeration?
+            if ( fieldType == TypeEnum )
+            {
+                // Yes, so add attribute type.
+                TiXmlElement* pAttributeSimpleTypeElement = new TiXmlElement( "xs:simpleType" );
+                pAttributeElement->LinkEndChild( pAttributeSimpleTypeElement );
+
+                // Add restriction element.
+                TiXmlElement* pAttributeRestrictionElement = new TiXmlElement( "xs:restriction" );
+                pAttributeRestrictionElement->SetAttribute( "base", "xs:string" );
+                pAttributeSimpleTypeElement->LinkEndChild( pAttributeRestrictionElement );
+
+                // Yes, so fetch enumeration count.
+                const S32 enumCount = field.table->size;
+
+                // Iterate enumeration.
+                for( S32 index = 0; index < enumCount; ++index )
+                {
+                    // Add enumeration element.
+                    TiXmlElement* pAttributeEnumerationElement = new TiXmlElement( "xs:enumeration" );
+                    pAttributeEnumerationElement->SetAttribute( "value", field.table->table[index].label );
+                    pAttributeRestrictionElement->LinkEndChild( pAttributeEnumerationElement );
+                }
+            }
+            else
+            {
+                // No, so assume it's a string type initially.
+                const char* pFieldTypeDescription = "xs:string";
+
+                // Handle known types.
+                if( fieldType == TypeF32 )
+                {
+                    pFieldTypeDescription = "xs:float";
+                }
+                else if( fieldType == TypeS8 || fieldType == TypeS32 )
+                {
+                    pFieldTypeDescription = "xs:int";
+                }
+                else if( fieldType == TypeBool || fieldType == TypeFlag )
+                {
+                    pFieldTypeDescription = "xs:boolean";
+                }
+                else if( fieldType == TypeVector2 )
+                {
+                    pFieldTypeDescription = "Vector2_ConsoleType";
+                }
+                else if( fieldType == TypePoint2F )
+                {
+                    pFieldTypeDescription = "Point2F_ConsoleType";
+                }
+                else if( fieldType == TypePoint2I )
+                {
+                    pFieldTypeDescription = "Point2I_ConsoleType";
+                }
+                else if(    fieldType == TypeAssetId ||
+                            fieldType == TypeImageAssetPtr ||
+                            fieldType == TypeAnimationAssetPtr ||
+                            fieldType == TypeAudioAssetPtr )
+                {
+                    pFieldTypeDescription = "AssetId_ConsoleType";
+                }
+
+                // Set attribute type.
+                pAttributeElement->SetAttribute( "type", pFieldTypeDescription );
+            }
+
+            pAttributeElement->SetAttribute( "use", "optional" );
+            pComplexTypeElement->LinkEndChild( pAttributeElement );
+        }
+
+        // Add "any" attribute element (dynamic fields).
+        TiXmlElement* pAnyAttributeElement = new TiXmlElement( "xs:anyAttribute" );
+        pAnyAttributeElement->SetAttribute( "processContents", "skip" );
+        pComplexTypeElement->LinkEndChild( pAnyAttributeElement );
+    }
+
+    // Expand the file-name into the file-path buffer.
+    char filePathBuffer[1024];
+    Con::expandPath( filePathBuffer, sizeof(filePathBuffer), pFilename );
+
+    FileStream stream;
+
+    // File opened?
+    if ( !stream.open( filePathBuffer, FileStream::Write ) )
+    {
+        // No, so warn.
+        Con::warnf("Taml::GenerateTamlSchema() - Could not open filename '%s' for write.", filePathBuffer );
+        return false;
+    }
+    // Write the schema document.
+    schemaDocument.SaveFile( stream );
+
+    // Close file.
+    stream.close();
+
+    return true;
+}

+ 3 - 0
engine/source/persistence/taml/taml.h

@@ -192,6 +192,9 @@ public:
     static TamlFormatMode getFormatModeEnum( const char* label );
     static const char* getFormatModeDescription( const TamlFormatMode formatMode );
 
+    /// Schema generation.
+    static bool generateTamlSchema( const char* pFilename );
+
     /// Declare Console Object.
     DECLARE_CONOBJECT( Taml );
 };

+ 23 - 0
engine/source/persistence/taml/tamlBinaryReader.cc

@@ -271,6 +271,9 @@ void TamlBinaryReader::parseChildren( Stream& stream, TamlCallbacks* pCallbacks,
         return;
     }
 
+    // Fetch any container child class specifier.
+    AbstractClassRep* pContainerChildClass = pSimObject->getClassRep()->getContainerChildClass( true );
+
     // Iterate children.
     for ( U32 index = 0; index < childrenCount; ++ index )
     {
@@ -281,6 +284,26 @@ void TamlBinaryReader::parseChildren( Stream& stream, TamlCallbacks* pCallbacks,
         if ( pChildSimObject == NULL )
             return;
 
+        // Do we have a container child class?
+        if ( pContainerChildClass != NULL )
+        {
+            // Yes, so is the child object the correctly derived type?
+            if ( !pChildSimObject->getClassRep()->isClass( pContainerChildClass ) )
+            {
+                // No, so warn.
+                Con::warnf("Taml: Child element '%s' found under parent '%s' but object is restricted to children of type '%s'.",
+                    pChildSimObject->getClassName(),
+                    pSimObject->getClassName(),
+                    pContainerChildClass->getClassName() );
+
+                // NOTE: We can't delete the object as it may be referenced elsewhere!
+                pChildSimObject = NULL;
+
+                // Skip.
+                continue;
+            }
+        }
+
         // Add child.
         pChildren->addTamlChild( pChildSimObject );
 

+ 27 - 4
engine/source/persistence/taml/tamlXmlReader.cc

@@ -174,6 +174,9 @@ SimObject* TamlXmlReader::parseElement( TiXmlElement* pXmlElement )
         // Fetch the Taml children.
         TamlChildren* pChildren = dynamic_cast<TamlChildren*>( pSimObject );
 
+        // Fetch any container child class specifier.
+        AbstractClassRep* pContainerChildClass = pSimObject->getClassRep()->getContainerChildClass( true );
+
         // Iterate siblings.
         do
         {
@@ -209,6 +212,26 @@ SimObject* TamlXmlReader::parseElement( TiXmlElement* pXmlElement )
                 if ( pChildSimObject == NULL )
                     continue;
 
+                // Do we have a container child class?
+                if ( pContainerChildClass != NULL )
+                {
+                    // Yes, so is the child object the correctly derived type?
+                    if ( !pChildSimObject->getClassRep()->isClass( pContainerChildClass ) )
+                    {
+                        // No, so warn.
+                        Con::warnf("Taml: Child element '%s' found under parent '%s' but object is restricted to children of type '%s'.",
+                            pChildSimObject->getClassName(),
+                            pSimObject->getClassName(),
+                            pContainerChildClass->getClassName() );
+
+                        // NOTE: We can't delete the object as it may be referenced elsewhere!
+                        pChildSimObject = NULL;
+
+                        // Skip.
+                        continue;
+                    }
+                }
+
                 // Add child.
                 pChildren->addTamlChild( pChildSimObject );
 
@@ -263,10 +286,10 @@ void TamlXmlReader::parseAttributes( TiXmlElement* pXmlElement, SimObject* pSimO
 
         // Ignore if this is a Taml attribute.
         if (    attributeName == mTamlRefId ||
-                attributeName == mTamlRefToId ||
-                attributeName == mTamlObjectName ||
-                attributeName == mTamlRefField )
-                continue;
+            attributeName == mTamlRefToId ||
+            attributeName == mTamlObjectName ||
+            attributeName == mTamlRefField )
+            continue;
 
         // We can assume this is a field for now.
         pSimObject->setPrefixedDataField( attributeName, NULL, pAttribute->Value() );

+ 13 - 0
engine/source/persistence/taml/taml_ScriptBinding.h

@@ -290,4 +290,17 @@ ConsoleFunction(TamlRead, const char*, 2, 4,    "(filename, [format]) - Read an
     }
 
     return pSimObject->getIdString();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleFunction(GenerateTamlSchema, bool, 2, 2, "(filename) - Generate a TAML schema file of all engine types.\n"
+                                                "@param filename The schema file to generate.\n"
+                                                "@return Whether the schema file was writtent or not." )
+{
+    // Fetch the filename.
+    const char* pFilename = argv[1];
+
+    // Generate the schema.
+    return Taml::generateTamlSchema( pFilename );
 }

+ 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, "")

Some files were not shown because too many files changed in this diff